From 39e5e0c7f85a73a56edb492e420a479a0f1b88b9 Mon Sep 17 00:00:00 2001 From: Markus Staab Date: Sun, 6 Feb 2022 12:16:07 +0100 Subject: [PATCH] modulo 1 is always zero --- src/Analyser/MutatingScope.php | 20 ++++++++++--- tests/PHPStan/Analyser/data/div-by-zero.php | 5 ++++ .../PHPStan/Analyser/data/modulo-operator.php | 28 +++++++++++++++++++ 3 files changed, 49 insertions(+), 4 deletions(-) diff --git a/src/Analyser/MutatingScope.php b/src/Analyser/MutatingScope.php index fa70cc917a..7acab4ce1f 100644 --- a/src/Analyser/MutatingScope.php +++ b/src/Analyser/MutatingScope.php @@ -1051,12 +1051,24 @@ private function resolveType(Expr $node): Type } else { $right = $node->right; } + $rightType = $this->getType($right); + + $integerType = $rightType->toInteger(); + if ( + $node instanceof Node\Expr\BinaryOp\Mod + || $node instanceof Node\Expr\AssignOp\Mod + ) { + if ($integerType instanceof ConstantIntegerType && $integerType->getValue() === 1) { + return new ConstantIntegerType(0); + } + } + + $rightScalarTypes = TypeUtils::getConstantScalars($rightType->toNumber()); + foreach ($rightScalarTypes as $scalarType) { - $rightTypes = TypeUtils::getConstantScalars($this->getType($right)->toNumber()); - foreach ($rightTypes as $rightType) { if ( - $rightType->getValue() === 0 - || $rightType->getValue() === 0.0 + $scalarType->getValue() === 0 + || $scalarType->getValue() === 0.0 ) { return new ErrorType(); } diff --git a/tests/PHPStan/Analyser/data/div-by-zero.php b/tests/PHPStan/Analyser/data/div-by-zero.php index 0c38a50c10..2dae4d4767 100644 --- a/tests/PHPStan/Analyser/data/div-by-zero.php +++ b/tests/PHPStan/Analyser/data/div-by-zero.php @@ -17,7 +17,12 @@ public function doFoo(int $range1, int $range2, int $int): void assertType('(float|int)', 5 / $range2); assertType('(float|int)', $range1 / $range2); assertType('(float|int)', 5 / $int); + assertType('*ERROR*', 5 / 0); + assertType('*ERROR*', 5 / '0'); + assertType('*ERROR*', 5 / 0.0); + assertType('*ERROR*', 5 / false); + assertType('*ERROR*', 5 / null); } } diff --git a/tests/PHPStan/Analyser/data/modulo-operator.php b/tests/PHPStan/Analyser/data/modulo-operator.php index 6e432eb259..a4876e59f1 100644 --- a/tests/PHPStan/Analyser/data/modulo-operator.php +++ b/tests/PHPStan/Analyser/data/modulo-operator.php @@ -45,4 +45,32 @@ function doBar(int $i, int $j, $p, $range, $zeroOrMore, $intConst, $unionRange, assertType('int', $j % $i); } + + function moduleOne(int $i, float $f) { + assertType('0', true % '1'); + assertType('0', false % '1'); + assertType('0', null % '1'); + assertType('0', -1 % '1'); + assertType('0', 0 % '1'); + assertType('0', 1 % '1'); + assertType('0', '1' % '1'); + assertType('0', 1.24 % '1'); + + assertType('0', $i % 1.0); + assertType('0', $f % 1.0); + + assertType('0', $i % '1.0'); + assertType('0', $f % '1.0'); + + assertType('0', $i % '1'); + assertType('0', $f % '1'); + + assertType('0', $i % true); + assertType('0', $f % true); + + $i %= '1'; + $f %= '1'; + assertType('0', $i); + assertType('0', $f); + } }