Skip to content

Commit

Permalink
Only use last for condition to filter scope
Browse files Browse the repository at this point in the history
  • Loading branch information
herndlm committed Oct 18, 2024
1 parent c875e83 commit 142e734
Show file tree
Hide file tree
Showing 2 changed files with 25 additions and 12 deletions.
29 changes: 17 additions & 12 deletions src/Analyser/NodeScopeResolver.php
Original file line number Diff line number Diff line change
Expand Up @@ -1314,18 +1314,23 @@ private function processStmtNode(

$bodyScope = $initScope;
$isIterableAtLeastOnce = TrinaryLogic::createYes();
$lastCondExpr = $stmt->cond[count($stmt->cond) - 1] ?? null;
foreach ($stmt->cond as $condExpr) {
$condResult = $this->processExprNode($stmt, $condExpr, $bodyScope, static function (): void {
}, ExpressionContext::createDeep());
$initScope = $condResult->getScope();
$condResultScope = $condResult->getScope();
$condTruthiness = ($this->treatPhpDocTypesAsCertain ? $condResultScope->getType($condExpr) : $condResultScope->getNativeType($condExpr))->toBoolean();
if ($condTruthiness instanceof ConstantBooleanType) {
$condTruthinessTrinary = TrinaryLogic::createFromBoolean($condTruthiness->getValue());
} else {
$condTruthinessTrinary = TrinaryLogic::createMaybe();

if ($condExpr === $lastCondExpr) {
$condTruthiness = ($this->treatPhpDocTypesAsCertain ? $condResultScope->getType($condExpr) : $condResultScope->getNativeType($condExpr))->toBoolean();
if ($condTruthiness instanceof ConstantBooleanType) {
$condTruthinessTrinary = TrinaryLogic::createFromBoolean($condTruthiness->getValue());
} else {
$condTruthinessTrinary = TrinaryLogic::createMaybe();
}
$isIterableAtLeastOnce = $isIterableAtLeastOnce->and($condTruthinessTrinary);
}
$isIterableAtLeastOnce = $isIterableAtLeastOnce->and($condTruthinessTrinary);

$hasYield = $hasYield || $condResult->hasYield();
$throwPoints = array_merge($throwPoints, $condResult->getThrowPoints());
$impurePoints = array_merge($impurePoints, $condResult->getImpurePoints());
Expand All @@ -1337,8 +1342,8 @@ private function processStmtNode(
do {
$prevScope = $bodyScope;
$bodyScope = $bodyScope->mergeWith($initScope);
foreach ($stmt->cond as $condExpr) {
$bodyScope = $this->processExprNode($stmt, $condExpr, $bodyScope, static function (): void {
if ($lastCondExpr !== null) {
$bodyScope = $this->processExprNode($stmt, $lastCondExpr, $bodyScope, static function (): void {
}, ExpressionContext::createDeep())->getTruthyScope();
}
$bodyScopeResult = $this->processStmtNodes($stmt, $stmt->stmts, $bodyScope, static function (): void {
Expand Down Expand Up @@ -1368,8 +1373,8 @@ private function processStmtNode(
}

$bodyScope = $bodyScope->mergeWith($initScope);
foreach ($stmt->cond as $condExpr) {
$bodyScope = $this->processExprNode($stmt, $condExpr, $bodyScope, $nodeCallback, ExpressionContext::createDeep())->getTruthyScope();
if ($lastCondExpr !== null) {
$bodyScope = $this->processExprNode($stmt, $lastCondExpr, $bodyScope, $nodeCallback, ExpressionContext::createDeep())->getTruthyScope();
}

$finalScopeResult = $this->processStmtNodes($stmt, $stmt->stmts, $bodyScope, $nodeCallback, $context)->filterOutLoopExitPoints();
Expand All @@ -1383,8 +1388,8 @@ private function processStmtNode(
$loopScope = $this->processExprNode($stmt, $loopExpr, $loopScope, $nodeCallback, ExpressionContext::createTopLevel())->getScope();
}
$finalScope = $finalScope->generalizeWith($loopScope);
foreach ($stmt->cond as $condExpr) {
$finalScope = $finalScope->filterByFalseyValue($condExpr);
if ($lastCondExpr !== null) {
$finalScope = $finalScope->filterByFalseyValue($lastCondExpr);
}

foreach ($finalScopeResult->getExitPointsByType(Break_::class) as $breakExitPoint) {
Expand Down
8 changes: 8 additions & 0 deletions tests/PHPStan/Analyser/nsrt/for-loop-i-type.php
Original file line number Diff line number Diff line change
Expand Up @@ -94,4 +94,12 @@ public static function groupCapacities(array $startTimes): array

return $capacities;
}

public function lastConditionResult(): void
{
for ($i = 0, $j = 5; $i < 10, $j > 0; $i++, $j--) {
assertType('int<0, max>', $i); // int<0,4> would be more precise, see https://github.com/phpstan/phpstan/issues/11872
assertType('int<1, 5>', $j);
}
}
}

0 comments on commit 142e734

Please sign in to comment.