From 1017dc7bc7c997e07c488088a199427790c5ef5a Mon Sep 17 00:00:00 2001 From: Ondrej Mirtes Date: Wed, 5 Apr 2023 13:26:53 +0200 Subject: [PATCH] Parent template type should respect child class bound when unspecified --- src/Reflection/ClassReflection.php | 3 +-- tests/PHPStan/Rules/Methods/data/bug-4008.php | 9 +++++++ tests/PHPStan/Type/ObjectTypeTest.php | 26 +++++++++++++++++++ 3 files changed, 36 insertions(+), 2 deletions(-) diff --git a/src/Reflection/ClassReflection.php b/src/Reflection/ClassReflection.php index ea21710247..6a32e34a6b 100644 --- a/src/Reflection/ClassReflection.php +++ b/src/Reflection/ClassReflection.php @@ -199,7 +199,6 @@ public function getParentClass(): ?ClassReflection $extendedType = TemplateTypeHelper::resolveTemplateTypes( $extendedType, $this->getPossiblyIncompleteActiveTemplateTypeMap(), - true, ); } @@ -1266,7 +1265,7 @@ public function typeMapFromList(array $types): TemplateTypeMap $map = []; $i = 0; foreach ($resolvedPhpDoc->getTemplateTags() as $tag) { - $map[$tag->getName()] = $types[$i] ?? new ErrorType(); + $map[$tag->getName()] = $types[$i] ?? $tag->getBound(); $i++; } diff --git a/tests/PHPStan/Rules/Methods/data/bug-4008.php b/tests/PHPStan/Rules/Methods/data/bug-4008.php index 7d93147d5f..68414bb3cb 100644 --- a/tests/PHPStan/Rules/Methods/data/bug-4008.php +++ b/tests/PHPStan/Rules/Methods/data/bug-4008.php @@ -29,3 +29,12 @@ class OtherGenericClass{} abstract class BaseModel{} class Model extends BaseModel{} + +/** + * @template T of Model + * @extends GenericClass + */ +class ChildGenericGenericClass extends GenericClass +{ + +} diff --git a/tests/PHPStan/Type/ObjectTypeTest.php b/tests/PHPStan/Type/ObjectTypeTest.php index e78e6c438a..fb0d70ed33 100644 --- a/tests/PHPStan/Type/ObjectTypeTest.php +++ b/tests/PHPStan/Type/ObjectTypeTest.php @@ -4,6 +4,10 @@ use ArrayAccess; use ArrayObject; +use Bug4008\BaseModel; +use Bug4008\ChildGenericGenericClass; +use Bug4008\GenericClass; +use Bug4008\Model; use Bug8850\UserInSessionInRoleEndpointExtension; use Bug9006\TestInterface; use Closure; @@ -665,4 +669,26 @@ public function testGetEnumCases( } } + public function testClassReflectionWithTemplateBound(): void + { + $type = new ObjectType(GenericClass::class); + $classReflection = $type->getClassReflection(); + $this->assertNotNull($classReflection); + $tModlel = $classReflection->getActiveTemplateTypeMap()->getType('TModlel'); + $this->assertNotNull($tModlel); + $this->assertSame(BaseModel::class, $tModlel->describe(VerbosityLevel::precise())); + } + + public function testClassReflectionParentWithTemplateBound(): void + { + $type = new ObjectType(ChildGenericGenericClass::class); + $classReflection = $type->getClassReflection(); + $this->assertNotNull($classReflection); + $ancestor = $classReflection->getAncestorWithClassName(GenericClass::class); + $this->assertNotNull($ancestor); + $tModlel = $ancestor->getActiveTemplateTypeMap()->getType('TModlel'); + $this->assertNotNull($tModlel); + $this->assertSame(Model::class, $tModlel->describe(VerbosityLevel::precise())); + } + }