Skip to content

Commit 0e505f4

Browse files
committed
Merge branch 2.1.x into 2.2.x
2 parents af32820 + dc2650e commit 0e505f4

2 files changed

Lines changed: 113 additions & 1 deletion

File tree

src/Analyser/MutatingScope.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2871,7 +2871,7 @@ public function invalidateExpression(Expr $expressionToInvalidate, bool $require
28712871
continue;
28722872
}
28732873
$firstExpr = $holders[array_key_first($holders)]->getTypeHolder()->getExpr();
2874-
if ($this->shouldInvalidateExpression($exprStringToInvalidate, $expressionToInvalidate, $firstExpr, $this->getNodeKey($firstExpr), false, $invalidatingClass)) {
2874+
if ($this->shouldInvalidateExpression($exprStringToInvalidate, $expressionToInvalidate, $firstExpr, $this->getNodeKey($firstExpr), $requireMoreCharacters, $invalidatingClass)) {
28752875
$invalidated = true;
28762876
continue;
28772877
}
Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
<?php
2+
3+
declare(strict_types = 1);
4+
5+
namespace Bug14545;
6+
7+
use function PHPStan\Testing\assertType;
8+
9+
interface SomeInterface {
10+
public function test(): void;
11+
}
12+
13+
class ObjectClass {
14+
}
15+
16+
class OtherClass {
17+
}
18+
19+
/**
20+
* @template T of object
21+
* @param class-string<T> $class_name
22+
* @return T
23+
*/
24+
function getObject1(string $class_name): object {
25+
return new $class_name;
26+
}
27+
28+
function testStoredInstanceofWithGenericMethodCall(): void {
29+
$obj = getObject1(ObjectClass::class);
30+
$is_interface = $obj instanceof SomeInterface;
31+
if($is_interface) {
32+
assertType('Bug14545\ObjectClass&Bug14545\SomeInterface', $obj);
33+
$obj->test();
34+
}
35+
36+
if($is_interface) {
37+
assertType('Bug14545\ObjectClass&Bug14545\SomeInterface', $obj);
38+
$obj->test();
39+
}
40+
}
41+
42+
function testStoredInstanceofWithGenericFuncCall(): void {
43+
$obj = getObject1(ObjectClass::class);
44+
$is_interface = $obj instanceof SomeInterface;
45+
if($is_interface) {
46+
var_dump($obj);
47+
}
48+
49+
if($is_interface) {
50+
assertType('Bug14545\ObjectClass&Bug14545\SomeInterface', $obj);
51+
}
52+
}
53+
54+
function testStoredInstanceofWithConcreteClass(): void {
55+
$obj = getObject1(OtherClass::class);
56+
$is_interface = $obj instanceof SomeInterface;
57+
if($is_interface) {
58+
assertType('Bug14545\OtherClass&Bug14545\SomeInterface', $obj);
59+
$obj->test();
60+
}
61+
62+
if($is_interface) {
63+
assertType('Bug14545\OtherClass&Bug14545\SomeInterface', $obj);
64+
}
65+
}
66+
67+
function getObject2(): object {
68+
return new \stdClass();
69+
}
70+
71+
function testStoredInstanceofWithAbstractObject(): void {
72+
$obj = getObject2();
73+
$is_interface = $obj instanceof SomeInterface;
74+
if($is_interface) {
75+
assertType('Bug14545\SomeInterface', $obj);
76+
$obj->test();
77+
}
78+
79+
if($is_interface) {
80+
assertType('Bug14545\SomeInterface', $obj);
81+
$obj->test();
82+
}
83+
}
84+
85+
function testThreeConsecutiveChecks(): void {
86+
$obj = getObject1(ObjectClass::class);
87+
$is_interface = $obj instanceof SomeInterface;
88+
if($is_interface) {
89+
$obj->test();
90+
}
91+
if($is_interface) {
92+
$obj->test();
93+
}
94+
if($is_interface) {
95+
assertType('Bug14545\ObjectClass&Bug14545\SomeInterface', $obj);
96+
}
97+
}
98+
99+
/**
100+
* @param array<mixed, mixed> $data
101+
*/
102+
function testStoredIsArray(array $data): void {
103+
$value = $data['key'] ?? null;
104+
$isArray = is_array($value);
105+
if ($isArray) {
106+
assertType('array<mixed, mixed>', $value);
107+
var_dump($value);
108+
}
109+
if ($isArray) {
110+
assertType('array<mixed, mixed>', $value);
111+
}
112+
}

0 commit comments

Comments
 (0)