From 0dbe3ab24dd40d6e291413aa64db5eca9f0f6d68 Mon Sep 17 00:00:00 2001 From: Ondrej Mirtes Date: Tue, 7 Mar 2023 08:13:12 +0100 Subject: [PATCH] Fix interface accepting a Closure --- src/Type/ObjectType.php | 12 +++++++++ tests/PHPStan/Type/ObjectTypeTest.php | 21 +++++++++++++++ tests/PHPStan/Type/TypeCombinatorTest.php | 33 +++++++++++++++++++++++ tests/PHPStan/Type/data/bug-9006.php | 8 ++++++ 4 files changed, 74 insertions(+) create mode 100644 tests/PHPStan/Type/data/bug-9006.php diff --git a/src/Type/ObjectType.php b/src/Type/ObjectType.php index 0b22ba7778..6128f61856 100644 --- a/src/Type/ObjectType.php +++ b/src/Type/ObjectType.php @@ -325,6 +325,10 @@ public function isSuperTypeOf(Type $type): TrinaryLogic return self::$superTypes[$thisDescription][$description] = $type->isSubTypeOf($this); } + if ($type instanceof ClosureType) { + return self::$superTypes[$thisDescription][$description] = $this->isInstanceOf(Closure::class); + } + if ($type instanceof ObjectWithoutClassType) { if ($type->getSubtractedType() !== null) { $isSuperType = $type->getSubtractedType()->isSuperTypeOf($this); @@ -1289,6 +1293,14 @@ public function isInstanceOf(string $className): TrinaryLogic return TrinaryLogic::createYes(); } + $reflectionProvider = ReflectionProviderStaticAccessor::getInstance(); + if ($reflectionProvider->hasClass($className)) { + $thatClassReflection = $reflectionProvider->getClass($className); + if ($thatClassReflection->isFinal()) { + return TrinaryLogic::createNo(); + } + } + if ($classReflection->isInterface()) { return TrinaryLogic::createMaybe(); } diff --git a/tests/PHPStan/Type/ObjectTypeTest.php b/tests/PHPStan/Type/ObjectTypeTest.php index 3b21b4c179..e78e6c438a 100644 --- a/tests/PHPStan/Type/ObjectTypeTest.php +++ b/tests/PHPStan/Type/ObjectTypeTest.php @@ -5,6 +5,7 @@ use ArrayAccess; use ArrayObject; use Bug8850\UserInSessionInRoleEndpointExtension; +use Bug9006\TestInterface; use Closure; use Countable; use DateInterval; @@ -438,6 +439,16 @@ public function dataIsSuperTypeOf(): array new ThisType($reflectionProvider->getClass(UserInSessionInRoleEndpointExtension::class)), TrinaryLogic::createYes(), ], + 62 => [ + new ObjectType(TestInterface::class), + new ClosureType([], new MixedType(), false), + TrinaryLogic::createNo(), + ], + 63 => [ + new ObjectType(TestInterface::class), + new ObjectType(Closure::class), + TrinaryLogic::createNo(), + ], ]; } @@ -492,6 +503,16 @@ public function dataAccepts(): array ), TrinaryLogic::createNo(), ], + [ + new ObjectType(TestInterface::class), + new ClosureType([], new MixedType(), false), + TrinaryLogic::createNo(), + ], + 63 => [ + new ObjectType(TestInterface::class), + new ObjectType(Closure::class), + TrinaryLogic::createNo(), + ], ]; } diff --git a/tests/PHPStan/Type/TypeCombinatorTest.php b/tests/PHPStan/Type/TypeCombinatorTest.php index 3064e7a0e6..aed1568a4f 100644 --- a/tests/PHPStan/Type/TypeCombinatorTest.php +++ b/tests/PHPStan/Type/TypeCombinatorTest.php @@ -2,6 +2,7 @@ namespace PHPStan\Type; +use Bug9006\TestInterface; use CheckTypeFunctionCall\FinalClassWithMethodExists; use CheckTypeFunctionCall\FinalClassWithPropertyExists; use Closure; @@ -2331,6 +2332,22 @@ public function dataUnion(): iterable IntersectionType::class, 'array&oversized-array', ]; + yield [ + [ + new ObjectType(TestInterface::class), + new ClosureType([], new MixedType(), false), + ], + UnionType::class, + 'Bug9006\TestInterface|(Closure(): mixed)', + ]; + yield [ + [ + new ObjectType(TestInterface::class), + new ObjectType(Closure::class), + ], + UnionType::class, + 'Bug9006\TestInterface|Closure', + ]; } /** @@ -3783,6 +3800,22 @@ public function dataIntersect(): iterable IntersectionType::class, 'array&oversized-array', ]; + yield [ + [ + new ObjectType(TestInterface::class), + new ClosureType([], new MixedType(), false), + ], + NeverType::class, + '*NEVER*=implicit', + ]; + yield [ + [ + new ObjectType(TestInterface::class), + new ObjectType(Closure::class), + ], + NeverType::class, + '*NEVER*=implicit', + ]; } /** diff --git a/tests/PHPStan/Type/data/bug-9006.php b/tests/PHPStan/Type/data/bug-9006.php new file mode 100644 index 0000000000..60aa97a005 --- /dev/null +++ b/tests/PHPStan/Type/data/bug-9006.php @@ -0,0 +1,8 @@ +