diff --git a/src/Reflection/InitializerExprTypeResolver.php b/src/Reflection/InitializerExprTypeResolver.php index d3f4e7abf5..97ac6041ba 100644 --- a/src/Reflection/InitializerExprTypeResolver.php +++ b/src/Reflection/InitializerExprTypeResolver.php @@ -1240,6 +1240,20 @@ public function getDivType(Expr $left, Expr $right, callable $getTypeCallback): $leftType = $getTypeCallback($left); $rightType = $getTypeCallback($right); + $result = $this->getDivTypeFromTypes($left, $right, $leftType, $rightType); + + if ($leftType->isInteger()->yes() && $rightType->isInteger()->yes()) { + $modType = $getTypeCallback(new BinaryOp\Mod($left, $right)); + if ($modType->isInteger()->yes() && (new ConstantIntegerType(0))->isSuperTypeOf($modType)->yes()) { + return TypeCombinator::remove($result, new FloatType()); + } + } + + return $result; + } + + private function getDivTypeFromTypes(Expr $left, Expr $right, Type $leftType, Type $rightType): Type + { $leftTypes = $leftType->getConstantScalarTypes(); $rightTypes = $rightType->getConstantScalarTypes(); $leftTypesCount = count($leftTypes); diff --git a/tests/PHPStan/Analyser/nsrt/bug-9724.php b/tests/PHPStan/Analyser/nsrt/bug-9724.php new file mode 100644 index 0000000000..2658a5e6a1 --- /dev/null +++ b/tests/PHPStan/Analyser/nsrt/bug-9724.php @@ -0,0 +1,35 @@ +|int<1, max>', $offset / $limit); + assertType('int|int<2, max>', ($offset / $limit) + 1); + } + } + + /** @param int<-2, 2> $offsetRange */ + public function withRange(int $limit, int $offset, int $offsetRange): void + { + if ($limit) { + assertType('(float|int)', $offset / $limit); + assertType('float|int<-2, 2>', $offsetRange / $limit); + } + } +} diff --git a/tests/PHPStan/Rules/Methods/CallMethodsRuleTest.php b/tests/PHPStan/Rules/Methods/CallMethodsRuleTest.php index d7a4d6766d..7dec818cc8 100644 --- a/tests/PHPStan/Rules/Methods/CallMethodsRuleTest.php +++ b/tests/PHPStan/Rules/Methods/CallMethodsRuleTest.php @@ -4106,4 +4106,12 @@ public function testBug14596(): void ]); } + public function testBug9724(): void + { + $this->checkThisOnly = false; + $this->checkNullables = true; + $this->checkUnionTypes = true; + $this->analyse([__DIR__ . '/data/bug-9724.php'], []); + } + } diff --git a/tests/PHPStan/Rules/Methods/data/bug-9724.php b/tests/PHPStan/Rules/Methods/data/bug-9724.php new file mode 100644 index 0000000000..ac09822212 --- /dev/null +++ b/tests/PHPStan/Rules/Methods/data/bug-9724.php @@ -0,0 +1,19 @@ +expectInt(($offset / $limit) + 1); + } + } +}