Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

PHP8.2: (A&B)|D as a param should allow AB or D. Not just A. #9516

Closed
kschatzle opened this issue Sep 9, 2022 · 4 comments
Closed

PHP8.2: (A&B)|D as a param should allow AB or D. Not just A. #9516

kschatzle opened this issue Sep 9, 2022 · 4 comments

Comments

@kschatzle
Copy link

Description

The following code:

<?php

interface A { }
interface B { }
interface D { }

class A_ implements A {}
class B_ implements B {}
class AB_ implements A, B {}
class D_ implements D {}

class T {
    public function method((A&B)|D $arg): void {}
    public function method2((B&A)|D $arg): void {}
}

$t = new T;

try {
    $t->method(new A_);     // Bug?
    echo 'Fail', \PHP_EOL;
} catch (\Throwable $throwable) {
    echo $throwable->getMessage(), \PHP_EOL;
}

try {
    $t->method(new B_);
    echo 'Fail', \PHP_EOL;
} catch (\Throwable $throwable) {
    echo $throwable->getMessage(), \PHP_EOL;
}

try {
    $t->method(new AB_);
    echo 'Pass', \PHP_EOL;
} catch (\Throwable $throwable) {
    echo $throwable->getMessage(), \PHP_EOL;
}

try {
    $t->method(new D_);
    echo 'Pass', \PHP_EOL;
} catch (\Throwable $throwable) {
    echo $throwable->getMessage(), \PHP_EOL;
}

// Lets try in reverse?
try {
    $t->method2(new A_);
    echo 'Fail', \PHP_EOL;
} catch (\Throwable $throwable) {
    echo $throwable->getMessage(), \PHP_EOL;
}

try {
    $t->method2(new B_);     // Bug?
    echo 'Fail', \PHP_EOL;
} catch (\Throwable $throwable) {
    echo $throwable->getMessage(), \PHP_EOL;
}

try {
    $t->method2(new AB_);
    echo 'Pass', \PHP_EOL;
} catch (\Throwable $throwable) {
    echo $throwable->getMessage(), \PHP_EOL;
}

try {
    $t->method2(new D_);
    echo 'Pass', \PHP_EOL;
} catch (\Throwable $throwable) {
    echo $throwable->getMessage(), \PHP_EOL;
}


?>

Resulted in this output:

Fail
T::method(): Argument #1 ($arg) must be of type (A&B)|D, B_ given, called in %s on line %d
Pass
Pass
T::method2(): Argument #1 ($arg) must be of type (B&A)|D, A_ given, called in %s on line %d
Fail
Pass
Pass

But I expected this output instead:

T::method(): Argument #1 ($arg) must be of type (A&B)|D, A_ given, called in %s on line %d
T::method(): Argument #1 ($arg) must be of type (A&B)|D, B_ given, called in %s on line %d
Pass
Pass
T::method2(): Argument #1 ($arg) must be of type (B&A)|D, A_ given, called in %s on line %d
T::method2(): Argument #1 ($arg) must be of type (B&A)|D, B_ given, called in %s on line %d
Pass
Pass

PHP Version

PHP 8.2.0-dev

Operating System

macOS Monterey Version 12.5.1 arm64

@kschatzle
Copy link
Author

kschatzle commented Sep 9, 2022

The phpt file contents below "passes", but shouldn't. I thought the output would throw 4 times total.

--TEST--
DNF bug?  (A&B)|D as a param should allow AB and D.  Not A
--FILE--
<?php

interface A { }
interface B { }
interface D { }

class A_ implements A {}
class B_ implements B {}
class AB_ implements A, B {}
class D_ implements D {}

class T {
    public function method((A&B)|D $arg): void {}
    public function method2((B&A)|D $arg): void {}
}

$t = new T;

try {
    $t->method(new A_);     // Bug?
    echo 'Fail', \PHP_EOL;
} catch (\Throwable $throwable) {
    echo $throwable->getMessage(), \PHP_EOL;
}

try {
    $t->method(new B_);
    echo 'Fail', \PHP_EOL;
} catch (\Throwable $throwable) {
    echo $throwable->getMessage(), \PHP_EOL;
}

try {
    $t->method(new AB_);
    echo 'Pass', \PHP_EOL;
} catch (\Throwable $throwable) {
    echo $throwable->getMessage(), \PHP_EOL;
}

try {
    $t->method(new D_);
    echo 'Pass', \PHP_EOL;
} catch (\Throwable $throwable) {
    echo $throwable->getMessage(), \PHP_EOL;
}

// Lets try in reverse?
try {
    $t->method2(new A_);
    echo 'Fail', \PHP_EOL;
} catch (\Throwable $throwable) {
    echo $throwable->getMessage(), \PHP_EOL;
}

try {
    $t->method2(new B_);     // Bug?
    echo 'Fail', \PHP_EOL;
} catch (\Throwable $throwable) {
    echo $throwable->getMessage(), \PHP_EOL;
}

try {
    $t->method2(new AB_);
    echo 'Pass', \PHP_EOL;
} catch (\Throwable $throwable) {
    echo $throwable->getMessage(), \PHP_EOL;
}

try {
    $t->method2(new D_);
    echo 'Pass', \PHP_EOL;
} catch (\Throwable $throwable) {
    echo $throwable->getMessage(), \PHP_EOL;
}


?>
===DONE===
--EXPECTF--
Fail
T::method(): Argument #1 ($arg) must be of type (A&B)|D, B_ given, called in %s on line %d
Pass
Pass
T::method2(): Argument #1 ($arg) must be of type (B&A)|D, A_ given, called in %s on line %d
Fail
Pass
Pass
===DONE===

@cmb69
Copy link
Member

cmb69 commented Sep 9, 2022

Yeah, that looks wrong: https://3v4l.org/712pm

@Girgias
Copy link
Member

Girgias commented Sep 10, 2022

Just an update: I have figured out why the issue happens, it's due to some cache slot issues. However solving this might take me a while.

@Girgias
Copy link
Member

Girgias commented Sep 10, 2022

Obviously the moment I say that I manage to fix the issue...

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

4 participants