Skip to content

Commit 386b5bc

Browse files
authored
Fixed InterRangeType multiplication/division of maximas by a negative constant
1 parent 755bd66 commit 386b5bc

File tree

2 files changed

+39
-8
lines changed

2 files changed

+39
-8
lines changed

src/Analyser/MutatingScope.php

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1021,12 +1021,7 @@ private function resolveType(Expr $node): Type
10211021
}
10221022

10231023
if ($type instanceof IntegerRangeType) {
1024-
$negativeRange = $this->resolveType(new Node\Expr\BinaryOp\Mul($node->expr, new LNumber(-1)));
1025-
1026-
if ( $negativeRange instanceof IntegerRangeType && ($negativeRange->getMin() === null || $negativeRange->getMax() === null)) {
1027-
return IntegerRangeType::fromInterval($negativeRange->getMax(), $negativeRange->getMin());
1028-
}
1029-
return $negativeRange;
1024+
return $this->resolveType(new Node\Expr\BinaryOp\Mul($node->expr, new LNumber(-1)));
10301025
}
10311026

10321027
return $type;
@@ -5221,6 +5216,13 @@ private function integerRangeMath(Type $range, Expr $node, Type $operand): Type
52215216
[$min, $max] = [$max, $min];
52225217
}
52235218

5219+
// invert maximas on multiplication with negative constants
5220+
if ((($range instanceof ConstantIntegerType && $range->getValue() < 0)
5221+
|| ($operand instanceof ConstantIntegerType && $operand->getValue() < 0))
5222+
&& ($min === null || $max === null)) {
5223+
[$min, $max] = [$max, $min];
5224+
}
5225+
52245226
} else {
52255227
if ($operand instanceof ConstantIntegerType) {
52265228
$min = $rangeMin !== null && $operand->getValue() !== 0 ? $rangeMin / $operand->getValue() : null;
@@ -5246,6 +5248,13 @@ private function integerRangeMath(Type $range, Expr $node, Type $operand): Type
52465248
[$min, $max] = [$max, $min];
52475249
}
52485250

5251+
// invert maximas on division with negative constants
5252+
if ((($range instanceof ConstantIntegerType && $range->getValue() < 0)
5253+
|| ($operand instanceof ConstantIntegerType && $operand->getValue() < 0))
5254+
&& ($min === null || $max === null)) {
5255+
[$min, $max] = [$max, $min];
5256+
}
5257+
52495258
if ($min === null && $max === null) {
52505259
return new BenevolentUnionType([new IntegerType(), new FloatType()]);
52515260
}

tests/PHPStan/Analyser/data/integer-range-types.php

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -232,8 +232,8 @@ public function math($i, $j, $z, $pi, $r1, $r2, $rMin, $rMax, $x, $y) {
232232
assertType('int<-2, 9>|int<21, 30>', $r1 - $z);
233233
assertType('int<-200, -20>|int<1, 30>', $r1 * $z);
234234
assertType('float|int<0, 10>', $r1 / $z);
235-
assertType('int<min, 15>', $rMin * $z);
236-
assertType('int<-100, max>', $rMax * $z);
235+
assertType('int', $rMin * $z);
236+
assertType('int<min, -100>|int<5, max>', $rMax * $z);
237237

238238
assertType('int<2, max>', $pi + 1);
239239
assertType('int<-1, max>', $pi - 2);
@@ -277,6 +277,28 @@ public function math($i, $j, $z, $pi, $r1, $r2, $rMin, $rMax, $x, $y) {
277277
assertType('float|int<5, max>', $rMax / $r1);
278278

279279
assertType('5|10|15|20|30', $x / $y);
280+
281+
}
282+
283+
/**
284+
* @param int<min, 5> $rMin
285+
* @param int<5, max> $rMax
286+
*
287+
* @see https://www.wolframalpha.com/input/?i=%28interval%5B2%2C%E2%88%9E%5D+%2F+-1%29
288+
* @see https://3v4l.org/ur9Wf
289+
*/
290+
public function maximaInversion($rMin, $rMax) {
291+
assertType('int<-5, max>', -1 * $rMin);
292+
assertType('int<min, -10>', -2 * $rMax);
293+
294+
assertType('int<-5, max>', $rMin * -1);
295+
assertType('int<min, -10>', $rMax * -2);
296+
297+
assertType('float|int<0, max>', -1 / $rMin);
298+
assertType('float|int<min, 0>', -2 / $rMax);
299+
300+
assertType('float|int<-5, max>', $rMin / -1);
301+
assertType('float|int<min, -2>', $rMax / -2);
280302
}
281303

282304
/**

0 commit comments

Comments
 (0)