diff --git a/src/Type/Accessory/HasMethodType.php b/src/Type/Accessory/HasMethodType.php index 66d8365595..132cd36c33 100644 --- a/src/Type/Accessory/HasMethodType.php +++ b/src/Type/Accessory/HasMethodType.php @@ -2,6 +2,7 @@ namespace PHPStan\Type\Accessory; +use Closure; use PHPStan\PhpDocParser\Ast\Type\IdentifierTypeNode; use PHPStan\PhpDocParser\Ast\Type\TypeNode; use PHPStan\Reflection\ClassMemberAccessAnswerer; @@ -17,6 +18,7 @@ use PHPStan\Type\ErrorType; use PHPStan\Type\IntersectionType; use PHPStan\Type\IsSuperTypeOfResult; +use PHPStan\Type\ObjectType; use PHPStan\Type\StringType; use PHPStan\Type\Traits\NonGeneralizableTypeTrait; use PHPStan\Type\Traits\NonGenericTypeTrait; @@ -83,7 +85,11 @@ public function isSubTypeOf(Type $otherType): IsSuperTypeOfResult return $otherType->isSuperTypeOf($this); } - if ($this->isCallable()->yes() && $otherType->isCallable()->yes()) { + if ( + $this->isCallable()->yes() + && $otherType->isCallable()->yes() + && !(new ObjectType(Closure::class))->isSuperTypeOf($otherType)->yes() + ) { return IsSuperTypeOfResult::createYes(); } diff --git a/tests/PHPStan/Rules/Classes/ImpossibleInstanceOfRuleTest.php b/tests/PHPStan/Rules/Classes/ImpossibleInstanceOfRuleTest.php index 5fb37f5340..9f76c85b25 100644 --- a/tests/PHPStan/Rules/Classes/ImpossibleInstanceOfRuleTest.php +++ b/tests/PHPStan/Rules/Classes/ImpossibleInstanceOfRuleTest.php @@ -569,4 +569,17 @@ public function testBug13469(): void ]); } + public static function dataBug13975(): iterable + { + yield [__DIR__ . '/data/bug-13975-1.php']; + yield [__DIR__ . '/data/bug-13975-2.php']; + } + + #[DataProvider('dataBug13975')] + public function testBug13975(string $file): void + { + $this->treatPhpDocTypesAsCertain = true; + $this->analyse([$file], []); + } + } diff --git a/tests/PHPStan/Rules/Classes/data/bug-13975-1.php b/tests/PHPStan/Rules/Classes/data/bug-13975-1.php new file mode 100644 index 0000000000..d218a1c380 --- /dev/null +++ b/tests/PHPStan/Rules/Classes/data/bug-13975-1.php @@ -0,0 +1,18 @@ +