diff --git a/src/Type/Generic/TemplateTypeHelper.php b/src/Type/Generic/TemplateTypeHelper.php index 6f09c29ccb..5ea7cea18d 100644 --- a/src/Type/Generic/TemplateTypeHelper.php +++ b/src/Type/Generic/TemplateTypeHelper.php @@ -54,6 +54,22 @@ public static function resolveTemplateTypes( $callSiteVariance = $callSiteVariances->getVariance($type->getName()); if ($callSiteVariance === null || $callSiteVariance->invariant()) { + if ( + $newType instanceof TemplateType + && $newType->getName() === $type->getName() + && $newType->getScope()->equals($type->getScope()) + && !$type->getBound()->equals($newType->getBound()) + && $newType->getBound()->isSuperTypeOf($type->getBound())->yes() + ) { + return TemplateTypeFactory::create( + $newType->getScope(), + $newType->getName(), + $type->getBound(), + $newType->getVariance(), + $newType->getStrategy(), + $newType->getDefault(), + ); + } return $newType; } diff --git a/tests/PHPStan/Analyser/nsrt/bug-11776.php b/tests/PHPStan/Analyser/nsrt/bug-11776.php new file mode 100644 index 0000000000..94dff45625 --- /dev/null +++ b/tests/PHPStan/Analyser/nsrt/bug-11776.php @@ -0,0 +1,32 @@ += 8.2 + +declare(strict_types=1); + +namespace Bug11776; + +use function PHPStan\Testing\assertType; + +/** + * @template TOperation of int|string + */ +interface EnumAsFilterInterface {} + +/** + * @template TOperation of scalar + */ +final readonly class ScalarableChoice +{ + /** + * @param class-string> $choiceClassName + */ + public function __construct(private string $choiceClassName) {} + + /** + * @return class-string> + */ + public function getChoiceClassName(): string + { + assertType('class-string>', $this->choiceClassName); + return $this->choiceClassName; + } +}