diff --git a/src/Analyser/MutatingScope.php b/src/Analyser/MutatingScope.php index 4c95eb828a..c99f4d07b0 100644 --- a/src/Analyser/MutatingScope.php +++ b/src/Analyser/MutatingScope.php @@ -2574,15 +2574,14 @@ public function assignExpression(Expr $expr, Type $type): self return $scope->specifyExpressionType($expr, $type); } - public function invalidateExpression(Expr $expressionToInvalidate): self + public function invalidateExpression(Expr $expressionToInvalidate, bool $requireMoreCharacters = false): self { $exprStringToInvalidate = $this->printer->prettyPrintExpr($expressionToInvalidate); $moreSpecificTypeHolders = $this->moreSpecificTypes; foreach (array_keys($moreSpecificTypeHolders) as $exprString) { $exprString = (string) $exprString; if (Strings::startsWith($exprString, $exprStringToInvalidate)) { - if ($exprString === $exprStringToInvalidate) { - unset($moreSpecificTypeHolders[$exprString]); + if ($exprString === $exprStringToInvalidate && $requireMoreCharacters) { continue; } $nextLetter = substr($exprString, strlen($exprStringToInvalidate), 1); diff --git a/src/Analyser/NodeScopeResolver.php b/src/Analyser/NodeScopeResolver.php index 7be35fb298..0c4453ab44 100644 --- a/src/Analyser/NodeScopeResolver.php +++ b/src/Analyser/NodeScopeResolver.php @@ -1492,7 +1492,7 @@ function (MutatingScope $scope) use ($expr, $nodeCallback, $context): Expression $result = $this->processArgs($methodReflection, $parametersAcceptor, $expr->args, $scope, $nodeCallback, $context); $scope = $result->getScope(); if ($methodReflection !== null && $methodReflection->hasSideEffects()->yes()) { - $scope = $scope->invalidateExpression($expr->var); + $scope = $scope->invalidateExpression($expr->var, true); } $hasYield = $hasYield || $result->hasYield(); } elseif ($expr instanceof StaticCall) { diff --git a/tests/PHPStan/Analyser/NodeScopeResolverTest.php b/tests/PHPStan/Analyser/NodeScopeResolverTest.php index b2515354d8..39bd42b2ee 100644 --- a/tests/PHPStan/Analyser/NodeScopeResolverTest.php +++ b/tests/PHPStan/Analyser/NodeScopeResolverTest.php @@ -9772,6 +9772,11 @@ public function dataBug2750(): array return $this->gatherAssertTypes(__DIR__ . '/data/bug-2750.php'); } + public function dataBug2850(): array + { + return $this->gatherAssertTypes(__DIR__ . '/data/bug-2850.php'); + } + /** * @dataProvider dataBug2574 * @dataProvider dataBug2577 @@ -9799,6 +9804,7 @@ public function dataBug2750(): array * @dataProvider dataBug2835 * @dataProvider dataBug2443 * @dataProvider dataBug2750 + * @dataProvider dataBug2850 * @param ConstantStringType $expectedType * @param Type $actualType */ diff --git a/tests/PHPStan/Analyser/data/bug-2850.php b/tests/PHPStan/Analyser/data/bug-2850.php new file mode 100644 index 0000000000..58873f0faa --- /dev/null +++ b/tests/PHPStan/Analyser/data/bug-2850.php @@ -0,0 +1,34 @@ +x === null) { + $this->x = new Foo(); + assertType(Foo::class, $this->x); + $this->x->y(); + assertType(Foo::class, $this->x); + $this->y(); + assertType(Foo::class . '|null', $this->x); + } + return $this->x; + } + + public function y(): void + { + $this->x = null; + } +}