diff --git a/src/Psalm/Internal/Diff/FileDiffer.php b/src/Psalm/Internal/Diff/FileDiffer.php index 6d72bc038ce..4673d21a5c7 100644 --- a/src/Psalm/Internal/Diff/FileDiffer.php +++ b/src/Psalm/Internal/Diff/FileDiffer.php @@ -77,8 +77,6 @@ private static function extractDiff(array $trace, int $x, int $y, array $a, arra { $result = []; for ($d = count($trace) - 1; $d >= 0; --$d) { - // Todo: fix integer ranges in fors - /** @var int<0, max> $d */ $v = $trace[$d]; $k = $x - $y; diff --git a/src/Psalm/Internal/Type/Comparator/ArrayTypeComparator.php b/src/Psalm/Internal/Type/Comparator/ArrayTypeComparator.php index 0e0210a1605..975c6a32e3e 100644 --- a/src/Psalm/Internal/Type/Comparator/ArrayTypeComparator.php +++ b/src/Psalm/Internal/Type/Comparator/ArrayTypeComparator.php @@ -123,10 +123,6 @@ public static function isContainedBy( } foreach ($input_type_part->type_params as $i => $input_param) { - if ($i > 1) { - break; - } - $container_param = $container_type_part->type_params[$i]; if ($i === 0 diff --git a/src/Psalm/Internal/Type/SimpleAssertionReconciler.php b/src/Psalm/Internal/Type/SimpleAssertionReconciler.php index f05ba1ef504..ba1d7f5eb51 100644 --- a/src/Psalm/Internal/Type/SimpleAssertionReconciler.php +++ b/src/Psalm/Internal/Type/SimpleAssertionReconciler.php @@ -1962,10 +1962,6 @@ private static function reconcileIsGreaterThan( } foreach ($existing_var_type->getAtomicTypes() as $atomic_type) { - if ($inside_loop) { - continue; - } - if ($atomic_type instanceof TIntRange) { if ($atomic_type->contains($assertion_value)) { // if the range contains the assertion, the range must be adapted @@ -1995,15 +1991,15 @@ private static function reconcileIsGreaterThan( if ($atomic_type->value < $assertion_value) { $did_remove_type = true; $existing_var_type->removeType($atomic_type->getKey()); - } /*elseif ($inside_loop) { + } elseif ($inside_loop) { //when inside a loop, allow the range to extends the type - $existing_var_type->removeType($atomic_type->getKey()); + /*$existing_var_type->removeType($atomic_type->getKey()); if ($atomic_type->value < $assertion_value) { $existing_var_type->addType(new TIntRange($atomic_type->value, $assertion_value)); } else { $existing_var_type->addType(new TIntRange($assertion_value, $atomic_type->value)); - } - }*/ + }*/ + } } elseif ($atomic_type instanceof TInt) { $did_remove_type = true; $existing_var_type->removeType($atomic_type->getKey()); @@ -2075,10 +2071,6 @@ private static function reconcileIsLessThan( } foreach ($existing_var_type->getAtomicTypes() as $atomic_type) { - if ($inside_loop) { - continue; - } - if ($atomic_type instanceof TIntRange) { if ($atomic_type->contains($assertion_value)) { // if the range contains the assertion, the range must be adapted @@ -2105,15 +2097,15 @@ private static function reconcileIsLessThan( if ($atomic_type->value > $assertion_value) { $did_remove_type = true; $existing_var_type->removeType($atomic_type->getKey()); - } /* elseif ($inside_loop) { + } elseif ($inside_loop) { //when inside a loop, allow the range to extends the type - $existing_var_type->removeType($atomic_type->getKey()); + /*$existing_var_type->removeType($atomic_type->getKey()); if ($atomic_type->value < $assertion_value) { $existing_var_type->addType(new TIntRange($atomic_type->value, $assertion_value)); } else { $existing_var_type->addType(new TIntRange($assertion_value, $atomic_type->value)); - } - }*/ + }*/ + } } elseif ($atomic_type instanceof TInt) { $did_remove_type = true; $existing_var_type->removeType($atomic_type->getKey()); diff --git a/src/Psalm/Internal/Type/SimpleNegatedAssertionReconciler.php b/src/Psalm/Internal/Type/SimpleNegatedAssertionReconciler.php index edeef3adb43..dec5a62931b 100644 --- a/src/Psalm/Internal/Type/SimpleNegatedAssertionReconciler.php +++ b/src/Psalm/Internal/Type/SimpleNegatedAssertionReconciler.php @@ -1840,10 +1840,6 @@ private static function reconcileIsLessThanOrEqualTo( } foreach ($existing_var_type->getAtomicTypes() as $atomic_type) { - if ($inside_loop) { - continue; - } - if ($atomic_type instanceof TIntRange) { if ($atomic_type->contains($assertion_value)) { // if the range contains the assertion, the range must be adapted @@ -1872,15 +1868,15 @@ private static function reconcileIsLessThanOrEqualTo( if ($atomic_type->value > $assertion_value) { $did_remove_type = true; $existing_var_type->removeType($atomic_type->getKey()); - } /*elseif ($inside_loop) { + } elseif ($inside_loop) { //when inside a loop, allow the range to extends the type - $existing_var_type->removeType($atomic_type->getKey()); + /*$existing_var_type->removeType($atomic_type->getKey()); if ($atomic_type->value < $assertion_value) { $existing_var_type->addType(new TIntRange($atomic_type->value, $assertion_value)); } else { $existing_var_type->addType(new TIntRange($assertion_value, $atomic_type->value)); - } - }*/ + }*/ + } } elseif ($atomic_type instanceof TInt) { $did_remove_type = true; $existing_var_type->removeType($atomic_type->getKey()); @@ -1951,10 +1947,6 @@ private static function reconcileIsGreaterThanOrEqualTo( } foreach ($existing_var_type->getAtomicTypes() as $atomic_type) { - if ($inside_loop) { - continue; - } - if ($atomic_type instanceof TIntRange) { if ($atomic_type->contains($assertion_value)) { // if the range contains the assertion, the range must be adapted @@ -1981,15 +1973,15 @@ private static function reconcileIsGreaterThanOrEqualTo( if ($atomic_type->value < $assertion_value) { $did_remove_type = true; $existing_var_type->removeType($atomic_type->getKey()); - } /* elseif ($inside_loop) { + } elseif ($inside_loop) { //when inside a loop, allow the range to extends the type - $existing_var_type->removeType($atomic_type->getKey()); + /*$existing_var_type->removeType($atomic_type->getKey()); if ($atomic_type->value < $assertion_value) { $existing_var_type->addType(new TIntRange($atomic_type->value, $assertion_value)); } else { $existing_var_type->addType(new TIntRange($assertion_value, $atomic_type->value)); - } - }*/ + }*/ + } } elseif ($atomic_type instanceof TInt) { $did_remove_type = true; $existing_var_type->removeType($atomic_type->getKey()); diff --git a/tests/IntRangeTest.php b/tests/IntRangeTest.php index 1a9b78a6124..c3e5f51af76 100644 --- a/tests/IntRangeTest.php +++ b/tests/IntRangeTest.php @@ -443,9 +443,8 @@ function getInt() '$remainder===' => 'int' ] ], - 'SKIPPED-IntRangeRestrictWhenUntouched' => [ + 'IntRangeRestrictWhenUntouched' => [ 'code' => ' 1) { takesInt($i); @@ -457,6 +456,35 @@ function takesInt(int $i): void{ return; }', ], + 'intRangeExpandedByLoop' => [ + 'code' => ' $i */ + function takesInt(int $i): void{ + return; + }', + ], + 'statementsInLoopPreserveNonNegativeIntRange' => [ + 'code' => ' 0) { + $sum += $i; + } + } + takesNonNegativeInt($sum); + + /** @psalm-param int<0, max> $i */ + function takesNonNegativeInt(int $i): void{ + return; + }', + ], 'SKIPPED-wrongLoopAssertion' => [ 'code' => '