diff --git a/src/Type/CallableTypeHelper.php b/src/Type/CallableTypeHelper.php index eb58de74bb..d9155f3259 100644 --- a/src/Type/CallableTypeHelper.php +++ b/src/Type/CallableTypeHelper.php @@ -74,7 +74,7 @@ public static function isParametersAcceptorSuperTypeOf( if ($treatMixedAsAny) { $isSuperType = $theirParameter->getType()->acceptsWithReason($ourParameterType, true); } else { - $isSuperType = new AcceptsResult($theirParameter->getType()->isSuperTypeOf($ourParameterType), []); + $isSuperType = new AcceptsResult($ourParameterType->isSuperTypeOf($theirParameter->getType()), []); } if ($isSuperType->maybe()) { diff --git a/tests/PHPStan/Analyser/nsrt/bug-11285.php b/tests/PHPStan/Analyser/nsrt/bug-11285.php new file mode 100644 index 0000000000..452c22d99e --- /dev/null +++ b/tests/PHPStan/Analyser/nsrt/bug-11285.php @@ -0,0 +1,58 @@ += 8.0 + +declare(strict_types = 1); + +namespace Bug11285; + +use function PHPStan\Testing\assertType; + +/** + * @template T + * @template U + */ +class Templated +{ + + /** + * @param callable(T|U): void $callback + */ + public function compare(callable $callback): void { + + } +} + +class ClassA {} +class ClassB {} + + +class Test +{ + /** + * @param Templated|Templated $t + */ + public function broken( + Templated $t, + ): void + { + $t->compare( + static function (ClassA|ClassB $crate): void { + assertType('Bug11285\\ClassA|Bug11285\\ClassB', $crate); + } + ); + } + + /** + * @param Templated $t + */ + public function working( + Templated $t, + ): void + { + $t->compare( + static function (ClassA|ClassB $crate): void { + assertType('Bug11285\\ClassA|Bug11285\\ClassB', $crate); + } + ); + } + +} diff --git a/tests/PHPStan/Type/CallableTypeTest.php b/tests/PHPStan/Type/CallableTypeTest.php index 87d3bae274..9d5c0fcd09 100644 --- a/tests/PHPStan/Type/CallableTypeTest.php +++ b/tests/PHPStan/Type/CallableTypeTest.php @@ -43,12 +43,12 @@ public function dataIsSuperTypeOf(): array [ new CallableType([new NativeParameterReflection('foo', false, new MixedType(), PassedByReference::createNo(), false, null)], new MixedType(), false), new CallableType([new NativeParameterReflection('foo', false, new IntegerType(), PassedByReference::createNo(), false, null)], new MixedType(), false), - TrinaryLogic::createMaybe(), + TrinaryLogic::createYes(), ], [ new CallableType([new NativeParameterReflection('foo', false, new IntegerType(), PassedByReference::createNo(), false, null)], new MixedType(), false), new CallableType([new NativeParameterReflection('foo', false, new MixedType(), PassedByReference::createNo(), false, null)], new MixedType(), false), - TrinaryLogic::createYes(), + TrinaryLogic::createMaybe(), ], [ new CallableType([ diff --git a/tests/PHPStan/Type/TypeCombinatorTest.php b/tests/PHPStan/Type/TypeCombinatorTest.php index b50517c033..3ed382c127 100644 --- a/tests/PHPStan/Type/TypeCombinatorTest.php +++ b/tests/PHPStan/Type/TypeCombinatorTest.php @@ -16,6 +16,7 @@ use ObjectShapesAcceptance\ClassWithFooIntProperty; use PHPStan\Fixture\FinalClass; use PHPStan\Reflection\Callables\SimpleImpurePoint; +use PHPStan\Reflection\Php\DummyParameter; use PHPStan\Testing\PHPStanTestCase; use PHPStan\TrinaryLogic; use PHPStan\Type\Accessory\AccessoryLiteralStringType; @@ -2568,6 +2569,36 @@ public function dataUnion(): iterable ClosureType::class, 'Closure(): mixed', ]; + yield [ + [ + new CallableType([ + new DummyParameter('callback', new ObjectType('stdClass'), false, null, false, null), + ], new VoidType(), false), + new CallableType([ + new DummyParameter('callback', new UnionType([ + new ObjectType('stdClass'), + new ObjectType('Exception'), + ]), false, null, false, null), + ], new VoidType(), false), + ], + CallableType::class, + 'callable(Exception|stdClass): void', + ]; + yield [ + [ + new CallableType([ + new DummyParameter('callback', new ObjectType('stdClass'), false, null, false, null), + ], new VoidType(), false), + new CallableType([ + new DummyParameter('callback', new UnionType([ + new IntegerType(), + new ObjectType('Exception'), + ]), false, null, false, null), + ], new VoidType(), false), + ], + UnionType::class, + '(callable(Exception|int): void)|(callable(stdClass): void)', + ]; } /**