Skip to content

Commit d6412b8

Browse files
jiripudilondrejmirtes
authored andcommitted
ClassReflection: resolve missing template type to its default (if set) rather than bound
1 parent 80c1df2 commit d6412b8

File tree

5 files changed

+48
-3
lines changed

5 files changed

+48
-3
lines changed

src/Reflection/ClassReflection.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1374,7 +1374,7 @@ public function getActiveTemplateTypeMap(): TemplateTypeMap
13741374
if ($type instanceof ErrorType) {
13751375
$templateType = $templateTypeMap->getType($name);
13761376
if ($templateType !== null) {
1377-
return TemplateTypeHelper::resolveToBounds($templateType);
1377+
return TemplateTypeHelper::resolveToDefaults($templateType);
13781378
}
13791379
}
13801380

src/Type/Generic/TemplateTypeHelper.php

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,17 @@ public static function resolveTemplateTypes(
6868
});
6969
}
7070

71+
public static function resolveToDefaults(Type $type): Type
72+
{
73+
return TypeTraverser::map($type, static function (Type $type, callable $traverse): Type {
74+
if ($type instanceof TemplateType) {
75+
return $traverse($type->getDefault() ?? $type->getBound());
76+
}
77+
78+
return $traverse($type);
79+
});
80+
}
81+
7182
public static function resolveToBounds(Type $type): Type
7283
{
7384
return TypeTraverser::map($type, static function (Type $type, callable $traverse): Type {

src/Type/GenericTypeVariableResolver.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ public static function getType(
4444
return new MixedType(false);
4545
}
4646

47-
return $bound;
47+
return TemplateTypeHelper::resolveToDefaults($templateType);
4848
}
4949

5050
return $type;

src/Type/ObjectType.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -841,7 +841,7 @@ public function getTemplateType(string $ancestorClassName, string $templateTypeN
841841
return new MixedType(false);
842842
}
843843

844-
return $bound;
844+
return TemplateTypeHelper::resolveToDefaults($templateType);
845845
}
846846

847847
return $type;
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
<?php
2+
3+
namespace Bug11899;
4+
5+
use function PHPStan\Testing\assertType;
6+
7+
abstract class Test {}
8+
9+
interface InvertedQuestions {}
10+
11+
class SomeTest extends Test implements InvertedQuestions {}
12+
13+
/**
14+
* @template TTestType = Test
15+
* @property-read ?TTestType $test
16+
*/
17+
class UserTest {
18+
public function __get() : mixed {
19+
return new SomeTest();
20+
}
21+
}
22+
23+
function acceptUserTest1(UserTest $ut) : void {
24+
assertType('Bug11899\\UserTest', $ut);
25+
assertType('Bug11899\\Test|null', $ut->test);
26+
}
27+
28+
/**
29+
* @param UserTest<InvertedQuestions> $ut
30+
*/
31+
function acceptUserTest2(UserTest $ut) : void {
32+
assertType('Bug11899\\UserTest<Bug11899\\InvertedQuestions>', $ut);
33+
assertType('Bug11899\\InvertedQuestions|null', $ut->test);
34+
}

0 commit comments

Comments
 (0)