Skip to content

Commit 13798c2

Browse files
herndlmondrejmirtes
authored andcommitted
Only use last for condition to filter scope
1 parent 9798bd4 commit 13798c2

File tree

2 files changed

+21
-8
lines changed

2 files changed

+21
-8
lines changed

src/Analyser/NodeScopeResolver.php

+13-8
Original file line numberDiff line numberDiff line change
@@ -1315,13 +1315,18 @@ private function processStmtNode(
13151315

13161316
$bodyScope = $initScope;
13171317
$isIterableAtLeastOnce = TrinaryLogic::createYes();
1318+
$lastCondExpr = $stmt->cond[count($stmt->cond) - 1] ?? null;
13181319
foreach ($stmt->cond as $condExpr) {
13191320
$condResult = $this->processExprNode($stmt, $condExpr, $bodyScope, static function (): void {
13201321
}, ExpressionContext::createDeep());
13211322
$initScope = $condResult->getScope();
13221323
$condResultScope = $condResult->getScope();
1323-
$condTruthiness = ($this->treatPhpDocTypesAsCertain ? $condResultScope->getType($condExpr) : $condResultScope->getNativeType($condExpr))->toBoolean();
1324-
$isIterableAtLeastOnce = $isIterableAtLeastOnce->and($condTruthiness->isTrue());
1324+
1325+
if ($condExpr === $lastCondExpr) {
1326+
$condTruthiness = ($this->treatPhpDocTypesAsCertain ? $condResultScope->getType($condExpr) : $condResultScope->getNativeType($condExpr))->toBoolean();
1327+
$isIterableAtLeastOnce = $isIterableAtLeastOnce->and($condTruthiness->isTrue());
1328+
}
1329+
13251330
$hasYield = $hasYield || $condResult->hasYield();
13261331
$throwPoints = array_merge($throwPoints, $condResult->getThrowPoints());
13271332
$impurePoints = array_merge($impurePoints, $condResult->getImpurePoints());
@@ -1333,8 +1338,8 @@ private function processStmtNode(
13331338
do {
13341339
$prevScope = $bodyScope;
13351340
$bodyScope = $bodyScope->mergeWith($initScope);
1336-
foreach ($stmt->cond as $condExpr) {
1337-
$bodyScope = $this->processExprNode($stmt, $condExpr, $bodyScope, static function (): void {
1341+
if ($lastCondExpr !== null) {
1342+
$bodyScope = $this->processExprNode($stmt, $lastCondExpr, $bodyScope, static function (): void {
13381343
}, ExpressionContext::createDeep())->getTruthyScope();
13391344
}
13401345
$bodyScopeResult = $this->processStmtNodes($stmt, $stmt->stmts, $bodyScope, static function (): void {
@@ -1364,8 +1369,8 @@ private function processStmtNode(
13641369
}
13651370

13661371
$bodyScope = $bodyScope->mergeWith($initScope);
1367-
foreach ($stmt->cond as $condExpr) {
1368-
$bodyScope = $this->processExprNode($stmt, $condExpr, $bodyScope, $nodeCallback, ExpressionContext::createDeep())->getTruthyScope();
1372+
if ($lastCondExpr !== null) {
1373+
$bodyScope = $this->processExprNode($stmt, $lastCondExpr, $bodyScope, $nodeCallback, ExpressionContext::createDeep())->getTruthyScope();
13691374
}
13701375

13711376
$finalScopeResult = $this->processStmtNodes($stmt, $stmt->stmts, $bodyScope, $nodeCallback, $context)->filterOutLoopExitPoints();
@@ -1379,8 +1384,8 @@ private function processStmtNode(
13791384
$loopScope = $this->processExprNode($stmt, $loopExpr, $loopScope, $nodeCallback, ExpressionContext::createTopLevel())->getScope();
13801385
}
13811386
$finalScope = $finalScope->generalizeWith($loopScope);
1382-
foreach ($stmt->cond as $condExpr) {
1383-
$finalScope = $finalScope->filterByFalseyValue($condExpr);
1387+
if ($lastCondExpr !== null) {
1388+
$finalScope = $finalScope->filterByFalseyValue($lastCondExpr);
13841389
}
13851390

13861391
foreach ($finalScopeResult->getExitPointsByType(Break_::class) as $breakExitPoint) {

tests/PHPStan/Analyser/nsrt/for-loop-i-type.php

+8
Original file line numberDiff line numberDiff line change
@@ -94,4 +94,12 @@ public static function groupCapacities(array $startTimes): array
9494

9595
return $capacities;
9696
}
97+
98+
public function lastConditionResult(): void
99+
{
100+
for ($i = 0, $j = 5; $i < 10, $j > 0; $i++, $j--) {
101+
assertType('int<0, max>', $i); // int<0,4> would be more precise, see https://github.com/phpstan/phpstan/issues/11872
102+
assertType('int<1, 5>', $j);
103+
}
104+
}
97105
}

0 commit comments

Comments
 (0)