Skip to content

Commit af38f03

Browse files
committedFeb 1, 2022
Forget remembered specific type when entering arrow function with same-named parameter
1 parent cd289bd commit af38f03

File tree

4 files changed

+64
-1
lines changed

4 files changed

+64
-1
lines changed
 

Diff for: ‎src/Analyser/MutatingScope.php

+9-1
Original file line numberDiff line numberDiff line change
@@ -3677,6 +3677,7 @@ private function enterArrowFunctionWithoutReflection(Expr\ArrowFunction $arrowFu
36773677
$variableTypes = $this->variableTypes;
36783678
$mixed = new MixedType();
36793679
$parameterVariables = [];
3680+
$parameterVariableExpressions = [];
36803681
foreach ($arrowFunction->params as $i => $parameter) {
36813682
if ($parameter->type === null) {
36823683
$parameterType = $mixed;
@@ -3706,6 +3707,7 @@ private function enterArrowFunctionWithoutReflection(Expr\ArrowFunction $arrowFu
37063707

37073708
$variableTypes[$parameter->var->name] = VariableTypeHolder::createYes($parameterType);
37083709
$parameterVariables[] = $parameter->var->name;
3710+
$parameterVariableExpressions[] = $parameter->var;
37093711
}
37103712

37113713
if ($arrowFunction->static) {
@@ -3767,7 +3769,7 @@ private function enterArrowFunctionWithoutReflection(Expr\ArrowFunction $arrowFu
37673769
}
37683770
}
37693771

3770-
return $this->scopeFactory->create(
3772+
$scope = $this->scopeFactory->create(
37713773
$this->context,
37723774
$this->isDeclareStrictTypes(),
37733775
$this->constantTypes,
@@ -3785,6 +3787,12 @@ private function enterArrowFunctionWithoutReflection(Expr\ArrowFunction $arrowFu
37853787
$this->afterExtractCall,
37863788
$this->parentScope,
37873789
);
3790+
3791+
foreach ($parameterVariableExpressions as $expr) {
3792+
$scope = $scope->invalidateExpression($expr);
3793+
}
3794+
3795+
return $scope;
37883796
}
37893797

37903798
public function isParameterValueNullable(Node\Param $parameter): bool

Diff for: ‎tests/PHPStan/Analyser/NodeScopeResolverTest.php

+1
Original file line numberDiff line numberDiff line change
@@ -684,6 +684,7 @@ public function dataFileAsserts(): iterable
684684
}
685685

686686
yield from $this->gatherAssertTypes(__DIR__ . '/data/bug-6500.php');
687+
yield from $this->gatherAssertTypes(__DIR__ . '/../Rules/Comparison/data/bug-6473.php');
687688
}
688689

689690
/**

Diff for: ‎tests/PHPStan/Rules/Comparison/BooleanNotConstantConditionRuleTest.php

+6
Original file line numberDiff line numberDiff line change
@@ -113,4 +113,10 @@ public function testTreatPhpDocTypesAsCertainRegression(bool $treatPhpDocTypesAs
113113
$this->analyse([__DIR__ . '/../DeadCode/data/bug-without-issue-1.php'], []);
114114
}
115115

116+
public function testBug6473(): void
117+
{
118+
$this->treatPhpDocTypesAsCertain = true;
119+
$this->analyse([__DIR__ . '/data/bug-6473.php'], []);
120+
}
121+
116122
}

Diff for: ‎tests/PHPStan/Rules/Comparison/data/bug-6473.php

+48
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
<?php
2+
3+
namespace Bug6473;
4+
5+
use function PHPStan\Testing\assertType;
6+
7+
class Point {
8+
public bool $visited = false;
9+
10+
/**
11+
* @return Point[]
12+
*/
13+
public function getNeighbours(): array {
14+
return [ new Point ];
15+
}
16+
17+
public function doFoo()
18+
{
19+
$seen = [];
20+
21+
foreach([new Point, new Point] as $p ) {
22+
23+
$p->visited = true;
24+
assertType('true', $p->visited);
25+
$seen = [
26+
... $seen,
27+
... array_filter( $p->getNeighbours(), static fn (Point $p) => !$p->visited )
28+
];
29+
assertType('true', $p->visited);
30+
}
31+
}
32+
33+
public function doFoo2()
34+
{
35+
$seen = [];
36+
37+
foreach([new Point, new Point] as $p ) {
38+
39+
$p->visited = true;
40+
assertType('true', $p->visited);
41+
$seen = [
42+
... $seen,
43+
... array_filter( $p->getNeighbours(), static fn (Point $p2) => !$p2->visited )
44+
];
45+
assertType('true', $p->visited);
46+
}
47+
}
48+
}

0 commit comments

Comments
 (0)