Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 17 additions & 1 deletion src/Type/Php/RangeFunctionReturnTypeExtension.php
Original file line number Diff line number Diff line change
Expand Up @@ -79,12 +79,17 @@ public function getTypeFromFunctionCall(FunctionReflection $functionReflection,
}

if (count($rangeValues) > self::RANGE_LENGTH_THRESHOLD) {
if ($startConstant instanceof ConstantIntegerType && $endConstant instanceof ConstantIntegerType) {
if (
$startConstant instanceof ConstantIntegerType
&& $endConstant instanceof ConstantIntegerType
&& $stepConstant instanceof ConstantIntegerType
) {
if ($startConstant->getValue() > $endConstant->getValue()) {
$tmp = $startConstant;
$startConstant = $endConstant;
$endConstant = $tmp;
}

return AccessoryArrayListType::intersectWith(TypeCombinator::intersect(
new ArrayType(
new IntegerType(),
Expand All @@ -94,12 +99,23 @@ public function getTypeFromFunctionCall(FunctionReflection $functionReflection,
));
}

if ($stepType->isFloat()->yes()) {
return AccessoryArrayListType::intersectWith(TypeCombinator::intersect(
new ArrayType(
new IntegerType(),
new FloatType(),
),
new NonEmptyArrayType(),
));
}

return AccessoryArrayListType::intersectWith(TypeCombinator::intersect(
new ArrayType(
new IntegerType(),
TypeCombinator::union(
$startConstant->generalize(GeneralizePrecision::moreSpecific()),
$endConstant->generalize(GeneralizePrecision::moreSpecific()),
$stepType->generalize(GeneralizePrecision::moreSpecific()),
),
),
new NonEmptyArrayType(),
Expand Down
24 changes: 24 additions & 0 deletions tests/PHPStan/Analyser/nsrt/bug-11692.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
<?php

namespace Bug11692;

use function PHPStan\Testing\assertType;

/** @param int|float $floatOrInt */
function doFoo(int $i, float $f, $floatOrInt): void {
assertType('non-empty-list<float>', range(1, 9, .01));
assertType('array{1, 4, 7}', range(1, 9, 3));

assertType('non-empty-list<float>', range(1, 9999, .01));
assertType('non-empty-list<int<1, 9999>>', range(1, 9999, 3));

assertType('list<float|int>', range(1, 9999, $floatOrInt));
assertType('list<float|int>', range(1, 9999, $floatOrInt));

assertType('list<int>', range(1, 3, $i));
assertType('list<float|int>', range(1, 3, $f));

assertType('list<int>', range(1, 9999, $i));
assertType('list<float|int>', range(1, 9999, $f));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The type depends on PHP version - https://3v4l.org/vIjsa

if step could be intepreted as int, int is used

and if either start or stop (or step after the transformation to int described above) is float, the type is always list<float>

Copy link
Contributor Author

@staabm staabm Sep 17, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

while I agree with your sentiment I think the extension is already too complicated because it tries to be too smart for the value it produces (and I am pretty sure the already existing logic contains more bugs then the one this PR fixes)

}

Loading