Skip to content

Commit bb4c853

Browse files
committed
Fix static return type resolution on union class types
- In UnionType::getUnresolvedMethodPrototype(), stopped overriding each member's calledOnType with the full union for non-template unions - Template union types (TemplateUnionType, TemplateBenevolentUnionType) still propagate the union as calledOnType to preserve template identity - Updated existing test assertion in static-late-binding.php - Added regression test tests/PHPStan/Analyser/nsrt/bug-11687.php Closes phpstan/phpstan#11687
1 parent 106fc93 commit bb4c853

File tree

3 files changed

+66
-2
lines changed

3 files changed

+66
-2
lines changed

src/Type/UnionType.php

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -581,7 +581,11 @@ public function getUnresolvedMethodPrototype(string $methodName, ClassMemberAcce
581581
continue;
582582
}
583583

584-
$methodPrototypes[] = $type->getUnresolvedMethodPrototype($methodName, $scope)->withCalledOnType($this);
584+
$prototype = $type->getUnresolvedMethodPrototype($methodName, $scope);
585+
if ($this instanceof TemplateType) {
586+
$prototype = $prototype->withCalledOnType($this);
587+
}
588+
$methodPrototypes[] = $prototype;
585589
}
586590

587591
$methodsCount = count($methodPrototypes);
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
<?php declare(strict_types = 1);
2+
3+
namespace Bug11687;
4+
5+
use function PHPStan\Testing\assertType;
6+
7+
class A
8+
{
9+
public static function retStaticConst(): int
10+
{
11+
return 1;
12+
}
13+
14+
/**
15+
* @return static
16+
*/
17+
public static function retStatic()
18+
{
19+
return new static(); // @phpstan-ignore new.static
20+
}
21+
}
22+
23+
class B extends A
24+
{
25+
/**
26+
* @return 2
27+
*/
28+
public static function retStaticConst(): int
29+
{
30+
return 2;
31+
}
32+
33+
public function foo(): void
34+
{
35+
$clUnioned = mt_rand() === 0
36+
? A::class
37+
: X::class;
38+
39+
assertType('int', A::retStaticConst());
40+
assertType('bool', X::retStaticConst());
41+
assertType('bool|int', $clUnioned::retStaticConst());
42+
43+
assertType('Bug11687\A', A::retStatic());
44+
assertType('bool', X::retStatic());
45+
assertType('bool|Bug11687\A', $clUnioned::retStatic());
46+
}
47+
}
48+
49+
class X
50+
{
51+
public static function retStaticConst(): bool
52+
{
53+
return false;
54+
}
55+
56+
public static function retStatic(): bool
57+
{
58+
return false;
59+
}
60+
}

tests/PHPStan/Analyser/nsrt/static-late-binding.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,7 @@ public function foo(): void
8585
assertType('static(StaticLateBinding\B)', parent::retStatic());
8686
assertType('static(StaticLateBinding\B)', $this->retStatic());
8787
assertType('bool', X::retStatic());
88-
assertType('bool|StaticLateBinding\A|StaticLateBinding\X', $clUnioned::retStatic()); // should be bool|StaticLateBinding\A https://github.com/phpstan/phpstan/issues/11687
88+
assertType('bool|StaticLateBinding\A', $clUnioned::retStatic()); // should be bool|StaticLateBinding\A https://github.com/phpstan/phpstan/issues/11687
8989

9090
assertType('StaticLateBinding\A', A::retStatic(...)());
9191
assertType('StaticLateBinding\B', B::retStatic(...)());

0 commit comments

Comments
 (0)