diff --git a/src/Analyser/MutatingScope.php b/src/Analyser/MutatingScope.php index 4c55a61d09..fa70cc917a 100644 --- a/src/Analyser/MutatingScope.php +++ b/src/Analyser/MutatingScope.php @@ -3677,6 +3677,7 @@ private function enterArrowFunctionWithoutReflection(Expr\ArrowFunction $arrowFu $variableTypes = $this->variableTypes; $mixed = new MixedType(); $parameterVariables = []; + $parameterVariableExpressions = []; foreach ($arrowFunction->params as $i => $parameter) { if ($parameter->type === null) { $parameterType = $mixed; @@ -3706,6 +3707,7 @@ private function enterArrowFunctionWithoutReflection(Expr\ArrowFunction $arrowFu $variableTypes[$parameter->var->name] = VariableTypeHolder::createYes($parameterType); $parameterVariables[] = $parameter->var->name; + $parameterVariableExpressions[] = $parameter->var; } if ($arrowFunction->static) { @@ -3767,7 +3769,7 @@ private function enterArrowFunctionWithoutReflection(Expr\ArrowFunction $arrowFu } } - return $this->scopeFactory->create( + $scope = $this->scopeFactory->create( $this->context, $this->isDeclareStrictTypes(), $this->constantTypes, @@ -3785,6 +3787,12 @@ private function enterArrowFunctionWithoutReflection(Expr\ArrowFunction $arrowFu $this->afterExtractCall, $this->parentScope, ); + + foreach ($parameterVariableExpressions as $expr) { + $scope = $scope->invalidateExpression($expr); + } + + return $scope; } public function isParameterValueNullable(Node\Param $parameter): bool diff --git a/tests/PHPStan/Analyser/NodeScopeResolverTest.php b/tests/PHPStan/Analyser/NodeScopeResolverTest.php index a30b5ef684..58f13c6f51 100644 --- a/tests/PHPStan/Analyser/NodeScopeResolverTest.php +++ b/tests/PHPStan/Analyser/NodeScopeResolverTest.php @@ -684,6 +684,7 @@ public function dataFileAsserts(): iterable } yield from $this->gatherAssertTypes(__DIR__ . '/data/bug-6500.php'); + yield from $this->gatherAssertTypes(__DIR__ . '/../Rules/Comparison/data/bug-6473.php'); } /** diff --git a/tests/PHPStan/Rules/Comparison/BooleanNotConstantConditionRuleTest.php b/tests/PHPStan/Rules/Comparison/BooleanNotConstantConditionRuleTest.php index 364eb57b46..bc52e0ef5d 100644 --- a/tests/PHPStan/Rules/Comparison/BooleanNotConstantConditionRuleTest.php +++ b/tests/PHPStan/Rules/Comparison/BooleanNotConstantConditionRuleTest.php @@ -113,4 +113,10 @@ public function testTreatPhpDocTypesAsCertainRegression(bool $treatPhpDocTypesAs $this->analyse([__DIR__ . '/../DeadCode/data/bug-without-issue-1.php'], []); } + public function testBug6473(): void + { + $this->treatPhpDocTypesAsCertain = true; + $this->analyse([__DIR__ . '/data/bug-6473.php'], []); + } + } diff --git a/tests/PHPStan/Rules/Comparison/data/bug-6473.php b/tests/PHPStan/Rules/Comparison/data/bug-6473.php new file mode 100644 index 0000000000..fba7f6a8be --- /dev/null +++ b/tests/PHPStan/Rules/Comparison/data/bug-6473.php @@ -0,0 +1,48 @@ +visited = true; + assertType('true', $p->visited); + $seen = [ + ... $seen, + ... array_filter( $p->getNeighbours(), static fn (Point $p) => !$p->visited ) + ]; + assertType('true', $p->visited); + } + } + + public function doFoo2() + { + $seen = []; + + foreach([new Point, new Point] as $p ) { + + $p->visited = true; + assertType('true', $p->visited); + $seen = [ + ... $seen, + ... array_filter( $p->getNeighbours(), static fn (Point $p2) => !$p2->visited ) + ]; + assertType('true', $p->visited); + } + } +}