From d925bf5226e140de844e713fbc9f970e922c727f Mon Sep 17 00:00:00 2001 From: robchett Date: Sun, 8 Oct 2023 16:56:03 +0100 Subject: [PATCH] Correct decrement min/max ranges --- .../BinaryOp/ArithmeticOpAnalyzer.php | 11 +++++++++-- tests/BinaryOperationTest.php | 17 +++++++++++++++++ 2 files changed, 26 insertions(+), 2 deletions(-) diff --git a/src/Psalm/Internal/Analyzer/Statements/Expression/BinaryOp/ArithmeticOpAnalyzer.php b/src/Psalm/Internal/Analyzer/Statements/Expression/BinaryOp/ArithmeticOpAnalyzer.php index 478c34c28..4a14d1f25 100644 --- a/src/Psalm/Internal/Analyzer/Statements/Expression/BinaryOp/ArithmeticOpAnalyzer.php +++ b/src/Psalm/Internal/Analyzer/Statements/Expression/BinaryOp/ArithmeticOpAnalyzer.php @@ -24,6 +24,8 @@ use Psalm\Issue\PossiblyInvalidOperand; use Psalm\Issue\PossiblyNullOperand; use Psalm\Issue\StringIncrement; use Psalm\IssueBuffer; +use Psalm\Node\Expr\BinaryOp\VirtualMinus; +use Psalm\Node\Expr\BinaryOp\VirtualPlus; use Psalm\StatementsSource; use Psalm\Type; use Psalm\Type\Atomic; @@ -821,10 +823,15 @@ final class ArithmeticOpAnalyzer $result_type = Type::getInt(); } } - } else { + } elseif ($parent instanceof VirtualPlus) { $start = $left_type_part instanceof TLiteralInt ? $left_type_part->value : 1; + $result_type = Type::combineUnionTypes(Type::getIntRange($start, null), $result_type); + } elseif ($parent instanceof VirtualMinus) { + $start = $left_type_part instanceof TLiteralInt ? $left_type_part->value : 1; + $result_type = Type::combineUnionTypes(Type::getIntRange(null, $start), $result_type); + } else { $result_type = Type::combineUnionTypes( - $always_positive ? Type::getIntRange($start, null) : Type::getInt(true), + $always_positive ? Type::getIntRange(1, null) : Type::getInt(true), $result_type, ); } diff --git a/tests/BinaryOperationTest.php b/tests/BinaryOperationTest.php index b1013c654..c2463e43d 100644 --- a/tests/BinaryOperationTest.php +++ b/tests/BinaryOperationTest.php @@ -972,6 +972,23 @@ class BinaryOperationTest extends TestCase '$j' => 'int<100, 110>', ], ], + 'decrementInLoop' => [ + 'code' => ' 0; $i--) { + if (rand(0,1)) { + break; + } + } + for ($j = 110; $j > 100; $j--) { + if (rand(0,1)) { + break; + } + }', + 'assertions' => [ + '$i' => 'int<0, 10>', + '$j' => 'int<100, 110>', + ], + ], 'coalesceFilterOutNullEvenWithTernary' => [ 'code' => '