Skip to content

Commit

Permalink
Merge in-foreach scope even for non-iterable expr
Browse files Browse the repository at this point in the history
  • Loading branch information
ondrejmirtes committed Dec 6, 2023
1 parent d27d57a commit 942afbf
Show file tree
Hide file tree
Showing 2 changed files with 19 additions and 4 deletions.
9 changes: 5 additions & 4 deletions src/Analyser/NodeScopeResolver.php
Original file line number Diff line number Diff line change
Expand Up @@ -927,10 +927,9 @@ private function processStmtNode(
$finalScope = $breakExitPoint->getScope()->mergeWith($finalScope);
}

$isIterableAtLeastOnce = $scope->getType($stmt->expr)->isIterableAtLeastOnce();
if ($isIterableAtLeastOnce->no() || $finalScopeResult->isAlwaysTerminating()) {
$finalScope = $scope;
} elseif ($isIterableAtLeastOnce->maybe()) {
$exprType = $scope->getType($stmt->expr);
$isIterableAtLeastOnce = $exprType->isIterableAtLeastOnce();
if ($exprType->isIterable()->no() || $isIterableAtLeastOnce->maybe()) {
if ($this->polluteScopeWithAlwaysIterableForeach) {
$finalScope = $finalScope->mergeWith($scope->filterByTruthyValue(new BooleanOr(
new BinaryOp\Identical(
Expand All @@ -944,6 +943,8 @@ private function processStmtNode(
} else {
$finalScope = $finalScope->mergeWith($scope);
}
} elseif ($isIterableAtLeastOnce->no() || $finalScopeResult->isAlwaysTerminating()) {
$finalScope = $scope;
} elseif (!$this->polluteScopeWithAlwaysIterableForeach) {
$finalScope = $scope->processAlwaysIterableForeachScopeWithoutPollute($finalScope);
// get types from finalScope, but don't create new variables
Expand Down
14 changes: 14 additions & 0 deletions tests/PHPStan/Analyser/data/foreach-partially-non-iterable.php
Original file line number Diff line number Diff line change
Expand Up @@ -19,3 +19,17 @@ public function doFoo($a): void
}

}

class Bar
{

public function sayHello(\stdClass $s): void
{
$a = null;
foreach ($s as $k => $v) {
$a .= 'test';
}
assertType('(literal-string&non-falsy-string)|null', $a);
}

}

0 comments on commit 942afbf

Please sign in to comment.