diff --git a/src/Type/ValueSet.php b/src/Type/ValueSet.php index 9f5a54343e9..69f61442070 100644 --- a/src/Type/ValueSet.php +++ b/src/Type/ValueSet.php @@ -948,7 +948,7 @@ private function calculateShift(string $operator, self $right, PhpVersion $phpVe /** * Operands with more pairs of constants than are computed one by one become the - * type all their constants are: int, float, string or null; anything else can + * type all their constants are: int, float, int|float, string or null; anything else can * only be an error. * * @return array{self, self} @@ -976,12 +976,13 @@ private function generalize(): self $hasStrings = $this->strings !== null; $hasNumbers = $this->numbers !== null && !$this->numbers->isEmpty(); if (!$hasBooleans && !$hasStrings && !$this->null && $hasNumbers) { - if ($this->numbers->getFloatIntervals() === [] && !$this->numbers->hasNan()) { - return self::createNumbers(new NumberSet([[null, null]], [], false)); - } - if ($this->numbers->getIntegerIntervals() === []) { - return self::createNumbers(new NumberSet([], [[-INF, INF]], true)); - } + $hasFloats = $this->numbers->getFloatIntervals() !== [] || $this->numbers->hasNan(); + + return self::createNumbers(new NumberSet( + $this->numbers->getIntegerIntervals() !== [] ? [[null, null]] : [], + $hasFloats ? [[-INF, INF]] : [], + $hasFloats, + )); } if (!$hasBooleans && !$hasNumbers && !$this->null && $hasStrings) { return self::createStrings(new StringType()); diff --git a/tests/PHPStan/Analyser/nsrt/bug-15670.php b/tests/PHPStan/Analyser/nsrt/bug-15670.php new file mode 100644 index 00000000000..b1a2bf0aa3b --- /dev/null +++ b/tests/PHPStan/Analyser/nsrt/bug-15670.php @@ -0,0 +1,38 @@ + 0.0761, 2 => 0.0720, 3 => 0.0811, 4 => 0.0812, 5 => 0.0813, 6 => 0.0814, 7 => 0.0815, 8 => 0.0816, 9 => 0.0817, 10 => 0.0818, 11 => 0.0819, 12 => 0.1290]; + + /** @param list> $months */ + public function doFoo(array $months): void + { + $weight = 0; + foreach ($months as $month) { + if ($month === 0) { + break; + } + $weight += self::WEIGHTS[$month] ?? 0.0; + } + assertType('0|float', $weight); + } + +} diff --git a/turbo-ext/src/ValueSet.cpp b/turbo-ext/src/ValueSet.cpp index 4f8db4095f8..3b426d0eca7 100644 --- a/turbo-ext/src/ValueSet.cpp +++ b/turbo-ext/src/ValueSet.cpp @@ -1172,13 +1172,13 @@ class ValueSetOps bool hasNumbers = !numbersEmpty(s.numbers()); if (!hasBooleans && !hasStrings && !s.null_() && hasNumbers) { NumbersView n(s.numbers()); - if (n.floatCount() == 0 && !n.nan()) return createNumbersOf(anyInteger()); - if (n.integerCount() == 0) { - NumberSetData anyFloat; - anyFloat.floatIntervals.push_back({-HUGE_VAL, HUGE_VAL}); - anyFloat.nan = true; - return createNumbersOf(anyFloat); + bool hasFloats = n.floatCount() != 0 || n.nan(); + NumberSetData generalized = n.integerCount() != 0 ? anyInteger() : NumberSetData(); + if (hasFloats) { + generalized.floatIntervals.push_back({-HUGE_VAL, HUGE_VAL}); + generalized.nan = true; } + return createNumbersOf(generalized); } if (!hasBooleans && !hasNumbers && !s.null_() && hasStrings) { IETR_VAL(stringType, newStringType());