Skip to content

Commit e242091

Browse files
committed
Consider static<T, U> same as static when the template types match
1 parent 885d7e9 commit e242091

File tree

3 files changed

+83
-0
lines changed

3 files changed

+83
-0
lines changed

src/PhpDoc/TypeNodeResolver.php

+24
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@
6565
use PHPStan\Type\FloatType;
6666
use PHPStan\Type\Generic\GenericClassStringType;
6767
use PHPStan\Type\Generic\GenericObjectType;
68+
use PHPStan\Type\Generic\TemplateType;
6869
use PHPStan\Type\Generic\TemplateTypeVariance;
6970
use PHPStan\Type\Helper\GetTemplateTypeType;
7071
use PHPStan\Type\IntegerRangeType;
@@ -758,6 +759,29 @@ static function (string $variance): TemplateTypeVariance {
758759

759760
$classReflection = $this->getReflectionProvider()->getClass($mainTypeClassName);
760761
if ($classReflection->isGeneric()) {
762+
if ($mainTypeName === 'static') {
763+
$templateTags = $classReflection->getTemplateTags();
764+
$templateTypeMap = $classReflection->getTemplateTypeMap();
765+
if (count($genericTypes) === $templateTypeMap->count()) {
766+
$templateTypeList = $classReflection->typeMapToList($templateTypeMap);
767+
foreach ($genericTypes as $i => $genericType) {
768+
if (!$genericType instanceof TemplateType) {
769+
break;
770+
}
771+
$templateType = $templateTypeList[$i];
772+
if (!$templateType instanceof TemplateType) {
773+
break;
774+
}
775+
if ($templateType->getName() !== $genericType->getName()) {
776+
break;
777+
}
778+
unset($templateTags[$genericType->getName()]);
779+
}
780+
if (count($templateTags) === 0) {
781+
return new StaticType($classReflection);
782+
}
783+
}
784+
}
761785
if (in_array($mainTypeClassName, [
762786
Traversable::class,
763787
IteratorAggregate::class,

tests/PHPStan/Analyser/NodeScopeResolverTest.php

+1
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,7 @@ public function dataFileAsserts(): iterable
149149
yield from $this->gatherAssertTypes(__DIR__ . '/../Reflection/data/staticReturnType.php');
150150

151151
yield from $this->gatherAssertTypes(__DIR__ . '/data/minmax.php');
152+
yield from $this->gatherAssertTypes(__DIR__ . '/data/consistent-static.php');
152153
if (PHP_VERSION_ID < 80000) {
153154
yield from $this->gatherAssertTypes(__DIR__ . '/data/minmax-arrays.php');
154155
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
<?php
2+
3+
namespace ConsistentStaticGenerics;
4+
5+
use function PHPStan\Testing\assertType;
6+
7+
/**
8+
* @template T
9+
* @template U
10+
*/
11+
class Foo
12+
{
13+
14+
/**
15+
* @return static
16+
*/
17+
public function doFoo(): self
18+
{
19+
20+
}
21+
22+
/**
23+
* @return static<T, U>
24+
*/
25+
public function doBar(): self
26+
{
27+
28+
}
29+
30+
/**
31+
* @return static<T>
32+
*/
33+
public function doBaz(): self
34+
{
35+
36+
}
37+
38+
/**
39+
* @return static<U, T>
40+
*/
41+
public function doLorem(): self
42+
{
43+
44+
}
45+
46+
}
47+
48+
class Bar extends Foo
49+
{
50+
51+
}
52+
53+
function (Bar $bar): void {
54+
assertType(Bar::class, $bar->doFoo());
55+
assertType(Bar::class, $bar->doBar());
56+
assertType('ConsistentStaticGenerics\Foo<mixed>', $bar->doBaz()); // the definition should error
57+
assertType('ConsistentStaticGenerics\Foo<mixed, mixed>', $bar->doLorem());
58+
};

0 commit comments

Comments
 (0)