Skip to content

Commit 1017dc7

Browse files
committed
Parent template type should respect child class bound when unspecified
1 parent 95a8777 commit 1017dc7

File tree

3 files changed

+36
-2
lines changed

3 files changed

+36
-2
lines changed

Diff for: src/Reflection/ClassReflection.php

+1-2
Original file line numberDiff line numberDiff line change
@@ -199,7 +199,6 @@ public function getParentClass(): ?ClassReflection
199199
$extendedType = TemplateTypeHelper::resolveTemplateTypes(
200200
$extendedType,
201201
$this->getPossiblyIncompleteActiveTemplateTypeMap(),
202-
true,
203202
);
204203
}
205204

@@ -1266,7 +1265,7 @@ public function typeMapFromList(array $types): TemplateTypeMap
12661265
$map = [];
12671266
$i = 0;
12681267
foreach ($resolvedPhpDoc->getTemplateTags() as $tag) {
1269-
$map[$tag->getName()] = $types[$i] ?? new ErrorType();
1268+
$map[$tag->getName()] = $types[$i] ?? $tag->getBound();
12701269
$i++;
12711270
}
12721271

Diff for: tests/PHPStan/Rules/Methods/data/bug-4008.php

+9
Original file line numberDiff line numberDiff line change
@@ -29,3 +29,12 @@ class OtherGenericClass{}
2929
abstract class BaseModel{}
3030

3131
class Model extends BaseModel{}
32+
33+
/**
34+
* @template T of Model
35+
* @extends GenericClass<T>
36+
*/
37+
class ChildGenericGenericClass extends GenericClass
38+
{
39+
40+
}

Diff for: tests/PHPStan/Type/ObjectTypeTest.php

+26
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,10 @@
44

55
use ArrayAccess;
66
use ArrayObject;
7+
use Bug4008\BaseModel;
8+
use Bug4008\ChildGenericGenericClass;
9+
use Bug4008\GenericClass;
10+
use Bug4008\Model;
711
use Bug8850\UserInSessionInRoleEndpointExtension;
812
use Bug9006\TestInterface;
913
use Closure;
@@ -665,4 +669,26 @@ public function testGetEnumCases(
665669
}
666670
}
667671

672+
public function testClassReflectionWithTemplateBound(): void
673+
{
674+
$type = new ObjectType(GenericClass::class);
675+
$classReflection = $type->getClassReflection();
676+
$this->assertNotNull($classReflection);
677+
$tModlel = $classReflection->getActiveTemplateTypeMap()->getType('TModlel');
678+
$this->assertNotNull($tModlel);
679+
$this->assertSame(BaseModel::class, $tModlel->describe(VerbosityLevel::precise()));
680+
}
681+
682+
public function testClassReflectionParentWithTemplateBound(): void
683+
{
684+
$type = new ObjectType(ChildGenericGenericClass::class);
685+
$classReflection = $type->getClassReflection();
686+
$this->assertNotNull($classReflection);
687+
$ancestor = $classReflection->getAncestorWithClassName(GenericClass::class);
688+
$this->assertNotNull($ancestor);
689+
$tModlel = $ancestor->getActiveTemplateTypeMap()->getType('TModlel');
690+
$this->assertNotNull($tModlel);
691+
$this->assertSame(Model::class, $tModlel->describe(VerbosityLevel::precise()));
692+
}
693+
668694
}

0 commit comments

Comments
 (0)