diff --git a/src/Analyser/MutatingScope.php b/src/Analyser/MutatingScope.php index e031880a6c..ae1b426ab2 100644 --- a/src/Analyser/MutatingScope.php +++ b/src/Analyser/MutatingScope.php @@ -5241,7 +5241,11 @@ private function integerRangeMath(Type $range, Expr $node, Type $operand): Type if ($operand->getMin() === null) { $min = null; } elseif ($rangeMin !== null) { - $min = $rangeMin - $operand->getMin(); + if ($operand->getMax() !== null) { + $min = $rangeMin - $operand->getMax(); + } else { + $min = $rangeMin - $operand->getMin(); + } } else { $min = null; } @@ -5250,7 +5254,14 @@ private function integerRangeMath(Type $range, Expr $node, Type $operand): Type $min = null; $max = null; } elseif ($rangeMax !== null) { - $max = $rangeMax - $operand->getMax(); + if ($rangeMin !== null && $operand->getMin() === null) { + $min = $rangeMin - $operand->getMax(); + $max = null; + } elseif ($operand->getMin() !== null) { + $max = $rangeMax - $operand->getMin(); + } else { + $max = null; + } } else { $max = null; } diff --git a/tests/PHPStan/Analyser/data/integer-range-types.php b/tests/PHPStan/Analyser/data/integer-range-types.php index b0b23c538a..a7ef89e2cd 100644 --- a/tests/PHPStan/Analyser/data/integer-range-types.php +++ b/tests/PHPStan/Analyser/data/integer-range-types.php @@ -202,13 +202,14 @@ public function supportsPhpdocIntegerRange() { * @param positive-int $pi * @param int<1, 10> $r1 * @param int<5, 10> $r2 + * @param int<-9, 100> $r3 * @param int $rMin * @param int<5, max> $rMax * * @param 20|40|60 $x * @param 2|4 $y */ - public function math($i, $j, $z, $pi, $r1, $r2, $rMin, $rMax, $x, $y) { + public function math($i, $j, $z, $pi, $r1, $r2, $r3, $rMin, $rMax, $x, $y) { assertType('int', $r1 + $i); assertType('int', $r1 - $i); assertType('int', $r1 * $i); @@ -254,16 +255,18 @@ public function math($i, $j, $z, $pi, $r1, $r2, $rMin, $rMax, $x, $y) { assertType('float|int<1, max>', $rMax / 4); assertType('int<6, 20>', $r1 + $r2); - assertType('int<-4, 0>', $r1 - $r2); + assertType('int<-9, 5>', $r1 - $r2); assertType('int<5, 100>', $r1 * $r2); assertType('float|int<0, 1>', $r1 / $r2); + assertType('int<-99, 19>', $r1 - $r3); + assertType('int', $r1 + $rMin); - assertType('int', $r1 - $rMin); + assertType('int<-4, max>', $r1 - $rMin); assertType('int', $r1 * $rMin); assertType('float|int', $r1 / $rMin); assertType('int', $rMin + $r1); - assertType('int', $rMin - $r1); + assertType('int', $rMin - $r1); assertType('int', $rMin * $r1); assertType('float|int', $rMin / $r1); @@ -272,7 +275,7 @@ public function math($i, $j, $z, $pi, $r1, $r2, $rMin, $rMax, $x, $y) { assertType('int<5, max>', $r1 * $rMax); assertType('float|int<0, max>', $r1 / $rMax); assertType('int<6, max>', $rMax + $r1); - assertType('int<4, max>', $rMax - $r1); + assertType('int<-5, max>', $rMax - $r1); assertType('int<5, max>', $rMax * $r1); assertType('float|int<5, max>', $rMax / $r1); diff --git a/tests/PHPStan/Analyser/data/math.php b/tests/PHPStan/Analyser/data/math.php index 99a364ab09..6db10a4e70 100644 --- a/tests/PHPStan/Analyser/data/math.php +++ b/tests/PHPStan/Analyser/data/math.php @@ -52,19 +52,19 @@ public function doBaz(int $rangeFiveBoth, int $rangeFiveLeft, int $rangeFiveRigh assertType('int', $rangeFiveRight - $rangeFiveLeft); assertType('int<-10, 10>', $rangeFiveBoth + $rangeFiveBoth); - assertType('0', $rangeFiveBoth - $rangeFiveBoth); + assertType('int<-10, 10>', $rangeFiveBoth - $rangeFiveBoth); assertType('int<-10, max>', $rangeFiveBoth + $rangeFiveLeft); assertType('int', $rangeFiveBoth - $rangeFiveLeft); assertType('int', $rangeFiveBoth + $rangeFiveRight); - assertType('int', $rangeFiveBoth - $rangeFiveRight); + assertType('int<-10, max>', $rangeFiveBoth - $rangeFiveRight); assertType('int<-10, max>', $rangeFiveLeft + $rangeFiveBoth); - assertType('int<0, max>', $rangeFiveLeft - $rangeFiveBoth); + assertType('int<-10, max>', $rangeFiveLeft - $rangeFiveBoth); assertType('int', $rangeFiveRight + $rangeFiveBoth); - assertType('int', $rangeFiveRight - $rangeFiveBoth); + assertType('int', $rangeFiveRight - $rangeFiveBoth); } public function doLorem($a, $b): void