Skip to content

Commit 988f058

Browse files
author
Michael Voříšek
authored
Fix infer new templated type from initial assign into static property
1 parent 05630e6 commit 988f058

File tree

4 files changed

+237
-1
lines changed

4 files changed

+237
-1
lines changed

src/Parser/NewAssignedToPropertyVisitor.php

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,10 @@ final class NewAssignedToPropertyVisitor extends NodeVisitorAbstract
1313
public function enterNode(Node $node): ?Node
1414
{
1515
if ($node instanceof Node\Expr\Assign || $node instanceof Node\Expr\AssignRef) {
16-
if ($node->var instanceof Node\Expr\PropertyFetch && $node->expr instanceof Node\Expr\New_) {
16+
if (
17+
($node->var instanceof Node\Expr\PropertyFetch || $node->var instanceof Node\Expr\StaticPropertyFetch)
18+
&& $node->expr instanceof Node\Expr\New_
19+
) {
1720
$node->expr->setAttribute(self::ATTRIBUTE_NAME, $node->var);
1821
}
1922
}

tests/PHPStan/Rules/Properties/TypesAssignedToPropertiesRuleTest.php

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -223,6 +223,29 @@ public function testBug3777(): void
223223
168,
224224
],
225225
]);
226+
227+
$this->analyse([__DIR__ . '/data/bug-3777-static.php'], [
228+
[
229+
'Static property Bug3777Static\Bar::$foo (Bug3777Static\Foo<stdClass>) does not accept Bug3777Static\Fooo<object>.',
230+
58,
231+
],
232+
[
233+
'Static property Bug3777Static\Ipsum::$ipsum (Bug3777Static\Lorem<stdClass, Exception>) does not accept Bug3777Static\Lorem<Exception, stdClass>.',
234+
95,
235+
],
236+
[
237+
'Static property Bug3777Static\Ipsum2::$lorem2 (Bug3777Static\Lorem2<stdClass, Exception>) does not accept Bug3777Static\Lorem2<stdClass, object>.',
238+
129,
239+
],
240+
[
241+
'Static property Bug3777Static\Ipsum2::$ipsum2 (Bug3777Static\Lorem2<stdClass, Exception>) does not accept Bug3777Static\Lorem2<Exception, object>.',
242+
131,
243+
],
244+
[
245+
'Static property Bug3777Static\Ipsum3::$ipsum3 (Bug3777Static\Lorem3<stdClass, Exception>) does not accept Bug3777Static\Lorem3<Exception, stdClass>.',
246+
168,
247+
],
248+
]);
226249
}
227250

228251
public function testAppendendArrayKey(): void
@@ -629,6 +652,11 @@ public function testGenericsInCallableInConstructor(): void
629652
$this->analyse([__DIR__ . '/data/generics-in-callable-in-constructor.php'], []);
630653
}
631654

655+
public function testBug10686(): void
656+
{
657+
$this->analyse([__DIR__ . '/data/bug-10686.php'], []);
658+
}
659+
632660
public function testBug11275(): void
633661
{
634662
if (PHP_VERSION_ID < 80000) {
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
<?php // lint >= 7.4
2+
3+
namespace Bug10686;
4+
5+
class Model {}
6+
7+
/**
8+
* @template T of object|array<mixed>
9+
*/
10+
class WeakAnalysingMap
11+
{
12+
/** @var list<T> */
13+
public array $values = [];
14+
}
15+
16+
class Reference
17+
{
18+
/** @var WeakAnalysingMap<Model> */
19+
private static WeakAnalysingMap $analysingTheirModelMap;
20+
21+
public function createAnalysingTheirModel(): Model
22+
{
23+
if ((self::$analysingTheirModelMap ?? null) === null) {
24+
self::$analysingTheirModelMap = new WeakAnalysingMap();
25+
}
26+
27+
$theirModel = new Model();
28+
29+
self::$analysingTheirModelMap->values[] = $theirModel;
30+
31+
return end(self::$analysingTheirModelMap->values);
32+
}
33+
}
Lines changed: 172 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,172 @@
1+
<?php
2+
3+
namespace Bug3777Static;
4+
5+
use function PHPStan\Testing\assertType;
6+
7+
class HelloWorld
8+
{
9+
/**
10+
* @var \SplObjectStorage<\DateTimeImmutable, null>
11+
*/
12+
public static $dates;
13+
14+
public function __construct()
15+
{
16+
static::$dates = new \SplObjectStorage();
17+
assertType('SplObjectStorage<DateTimeImmutable, null>', static::$dates);
18+
}
19+
}
20+
21+
/** @template T of object */
22+
class Foo
23+
{
24+
25+
public function __construct()
26+
{
27+
28+
}
29+
30+
}
31+
32+
/** @template T of object */
33+
class Fooo
34+
{
35+
36+
}
37+
38+
class Bar
39+
{
40+
41+
/** @var Foo<\stdClass> */
42+
private static $foo;
43+
44+
/** @var Fooo<\stdClass> */
45+
private static $fooo;
46+
47+
public function __construct()
48+
{
49+
static::$foo = new Foo();
50+
assertType('Bug3777Static\Foo<stdClass>', static::$foo);
51+
52+
static::$fooo = new Fooo();
53+
assertType('Bug3777Static\Fooo<stdClass>', static::$fooo);
54+
}
55+
56+
public function doBar()
57+
{
58+
static::$foo = new Fooo();
59+
assertType('Bug3777Static\Fooo<object>', static::$foo);
60+
}
61+
62+
}
63+
64+
/**
65+
* @template T of object
66+
* @template U of object
67+
*/
68+
class Lorem
69+
{
70+
71+
/**
72+
* @param T $t
73+
* @param U $u
74+
*/
75+
public function __construct($t, $u)
76+
{
77+
78+
}
79+
80+
}
81+
82+
class Ipsum
83+
{
84+
85+
/** @var Lorem<\stdClass, \Exception> */
86+
private static $lorem;
87+
88+
/** @var Lorem<\stdClass, \Exception> */
89+
private static $ipsum;
90+
91+
public function __construct()
92+
{
93+
static::$lorem = new Lorem(new \stdClass, new \Exception());
94+
assertType('Bug3777Static\Lorem<stdClass, Exception>', static::$lorem);
95+
static::$ipsum = new Lorem(new \Exception(), new \stdClass);
96+
assertType('Bug3777Static\Lorem<Exception, stdClass>', static::$ipsum);
97+
}
98+
99+
}
100+
101+
/**
102+
* @template T of object
103+
* @template U of object
104+
*/
105+
class Lorem2
106+
{
107+
108+
/**
109+
* @param T $t
110+
*/
111+
public function __construct($t)
112+
{
113+
114+
}
115+
116+
}
117+
118+
class Ipsum2
119+
{
120+
121+
/** @var Lorem2<\stdClass, \Exception> */
122+
private static $lorem2;
123+
124+
/** @var Lorem2<\stdClass, \Exception> */
125+
private static $ipsum2;
126+
127+
public function __construct()
128+
{
129+
static::$lorem2 = new Lorem2(new \stdClass);
130+
assertType('Bug3777Static\Lorem2<stdClass, object>', static::$lorem2);
131+
static::$ipsum2 = new Lorem2(new \Exception());
132+
assertType('Bug3777Static\Lorem2<Exception, object>', static::$ipsum2);
133+
}
134+
135+
}
136+
137+
/**
138+
* @template T of object
139+
* @template U of object
140+
*/
141+
class Lorem3
142+
{
143+
144+
/**
145+
* @param T $t
146+
* @param U $u
147+
*/
148+
public function __construct($t, $u)
149+
{
150+
151+
}
152+
153+
}
154+
155+
class Ipsum3
156+
{
157+
158+
/** @var Lorem3<\stdClass, \Exception> */
159+
private static $lorem3;
160+
161+
/** @var Lorem3<\stdClass, \Exception> */
162+
private static $ipsum3;
163+
164+
public function __construct()
165+
{
166+
static::$lorem3 = new Lorem3(new \stdClass, new \Exception());
167+
assertType('Bug3777Static\Lorem3<stdClass, Exception>', static::$lorem3);
168+
static::$ipsum3 = new Lorem3(new \Exception(), new \stdClass());
169+
assertType('Bug3777Static\Lorem3<Exception, stdClass>', static::$ipsum3);
170+
}
171+
172+
}

0 commit comments

Comments
 (0)