From 473fbb117d28e71639af14d2bb10af72362684e7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ji=C5=99=C3=AD=20Pudil?= Date: Mon, 11 Nov 2024 13:54:39 +0100 Subject: [PATCH] ClassReflection: resolve missing template type to its default (if set) rather than bound --- src/Reflection/ClassReflection.php | 2 +- src/Type/Generic/TemplateTypeHelper.php | 11 ++++++++ src/Type/GenericTypeVariableResolver.php | 2 +- src/Type/ObjectType.php | 2 +- tests/PHPStan/Analyser/nsrt/bug-11899.php | 34 +++++++++++++++++++++++ 5 files changed, 48 insertions(+), 3 deletions(-) create mode 100644 tests/PHPStan/Analyser/nsrt/bug-11899.php diff --git a/src/Reflection/ClassReflection.php b/src/Reflection/ClassReflection.php index c79f2a6bed..ff45172fd8 100644 --- a/src/Reflection/ClassReflection.php +++ b/src/Reflection/ClassReflection.php @@ -1374,7 +1374,7 @@ public function getActiveTemplateTypeMap(): TemplateTypeMap if ($type instanceof ErrorType) { $templateType = $templateTypeMap->getType($name); if ($templateType !== null) { - return TemplateTypeHelper::resolveToBounds($templateType); + return TemplateTypeHelper::resolveToDefaults($templateType); } } diff --git a/src/Type/Generic/TemplateTypeHelper.php b/src/Type/Generic/TemplateTypeHelper.php index 58460efaee..29ecd48720 100644 --- a/src/Type/Generic/TemplateTypeHelper.php +++ b/src/Type/Generic/TemplateTypeHelper.php @@ -68,6 +68,17 @@ public static function resolveTemplateTypes( }); } + public static function resolveToDefaults(Type $type): Type + { + return TypeTraverser::map($type, static function (Type $type, callable $traverse): Type { + if ($type instanceof TemplateType) { + return $traverse($type->getDefault() ?? $type->getBound()); + } + + return $traverse($type); + }); + } + public static function resolveToBounds(Type $type): Type { return TypeTraverser::map($type, static function (Type $type, callable $traverse): Type { diff --git a/src/Type/GenericTypeVariableResolver.php b/src/Type/GenericTypeVariableResolver.php index 8c3f7d2da5..eee42d0f1b 100644 --- a/src/Type/GenericTypeVariableResolver.php +++ b/src/Type/GenericTypeVariableResolver.php @@ -44,7 +44,7 @@ public static function getType( return new MixedType(false); } - return $bound; + return TemplateTypeHelper::resolveToDefaults($templateType); } return $type; diff --git a/src/Type/ObjectType.php b/src/Type/ObjectType.php index 3e8ac1371f..7427aa167c 100644 --- a/src/Type/ObjectType.php +++ b/src/Type/ObjectType.php @@ -841,7 +841,7 @@ public function getTemplateType(string $ancestorClassName, string $templateTypeN return new MixedType(false); } - return $bound; + return TemplateTypeHelper::resolveToDefaults($templateType); } return $type; diff --git a/tests/PHPStan/Analyser/nsrt/bug-11899.php b/tests/PHPStan/Analyser/nsrt/bug-11899.php new file mode 100644 index 0000000000..c56b47dfcb --- /dev/null +++ b/tests/PHPStan/Analyser/nsrt/bug-11899.php @@ -0,0 +1,34 @@ +test); +} + +/** + * @param UserTest $ut + */ +function acceptUserTest2(UserTest $ut) : void { + assertType('Bug11899\\UserTest', $ut); + assertType('Bug11899\\InvertedQuestions|null', $ut->test); +}