From 9442cef9f83d33f61aa9d7d066946637f74654e8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ji=C5=99=C3=AD=20Pudil?= Date: Fri, 20 Sep 2024 20:35:08 +0200 Subject: [PATCH] implement ClosureType::getReferencedTemplateTypes() --- src/Type/ClosureType.php | 20 +++++++++++++++++-- .../MethodSignatureVarianceRuleTest.php | 10 ++++++++++ .../PHPStan/Rules/Generics/data/bug-10609.php | 16 +++++++++++++++ 3 files changed, 44 insertions(+), 2 deletions(-) create mode 100644 tests/PHPStan/Rules/Generics/data/bug-10609.php diff --git a/src/Type/ClosureType.php b/src/Type/ClosureType.php index 6d987f6342..967b850525 100644 --- a/src/Type/ClosureType.php +++ b/src/Type/ClosureType.php @@ -36,10 +36,10 @@ use PHPStan\Type\Generic\TemplateType; use PHPStan\Type\Generic\TemplateTypeHelper; use PHPStan\Type\Generic\TemplateTypeMap; +use PHPStan\Type\Generic\TemplateTypeVariance; use PHPStan\Type\Generic\TemplateTypeVarianceMap; use PHPStan\Type\Traits\NonArrayTypeTrait; use PHPStan\Type\Traits\NonGeneralizableTypeTrait; -use PHPStan\Type\Traits\NonGenericTypeTrait; use PHPStan\Type\Traits\NonIterableTypeTrait; use PHPStan\Type\Traits\NonOffsetAccessibleTypeTrait; use PHPStan\Type\Traits\NonRemoveableTypeTrait; @@ -53,7 +53,6 @@ class ClosureType implements TypeWithClassName, CallableParametersAcceptor { use NonArrayTypeTrait; - use NonGenericTypeTrait; use NonIterableTypeTrait; use UndecidedComparisonTypeTrait; use NonOffsetAccessibleTypeTrait; @@ -540,6 +539,23 @@ private function inferTemplateTypesOnParametersAcceptor(ParametersAcceptor $para return $typeMap->union($this->getReturnType()->inferTemplateTypes($returnType)); } + public function getReferencedTemplateTypes(TemplateTypeVariance $positionVariance): array + { + $references = $this->getReturnType()->getReferencedTemplateTypes( + $positionVariance->compose(TemplateTypeVariance::createCovariant()), + ); + + $paramVariance = $positionVariance->compose(TemplateTypeVariance::createContravariant()); + + foreach ($this->getParameters() as $param) { + foreach ($param->getType()->getReferencedTemplateTypes($paramVariance) as $reference) { + $references[] = $reference; + } + } + + return $references; + } + public function traverse(callable $cb): Type { if ($this->isCommonCallable) { diff --git a/tests/PHPStan/Rules/Generics/MethodSignatureVarianceRuleTest.php b/tests/PHPStan/Rules/Generics/MethodSignatureVarianceRuleTest.php index 8f743f4dc7..f01b15ba3d 100644 --- a/tests/PHPStan/Rules/Generics/MethodSignatureVarianceRuleTest.php +++ b/tests/PHPStan/Rules/Generics/MethodSignatureVarianceRuleTest.php @@ -234,4 +234,14 @@ public function testPr2465(): void ]); } + public function testBug10609(): void + { + $this->analyse([__DIR__ . '/data/bug-10609.php'], [ + [ + 'Template type A is declared as covariant, but occurs in contravariant position in parameter fn of method Bug10609\Collection::tap().', + 13, + ], + ]); + } + } diff --git a/tests/PHPStan/Rules/Generics/data/bug-10609.php b/tests/PHPStan/Rules/Generics/data/bug-10609.php new file mode 100644 index 0000000000..c62a9e0a10 --- /dev/null +++ b/tests/PHPStan/Rules/Generics/data/bug-10609.php @@ -0,0 +1,16 @@ +