2828use function abs ;
2929use function count ;
3030use function floor ;
31+ use function intdiv ;
3132use function is_array ;
3233use function is_finite ;
3334use function is_numeric ;
3435use function is_string ;
3536use function max ;
3637use function min ;
3738use function range ;
39+ use const PHP_INT_MAX ;
3840
3941#[AutowiredService]
4042final class RangeFunctionReturnTypeExtension implements DynamicFunctionReturnTypeExtension
@@ -186,11 +188,13 @@ private static function getLongRangeType(
186188 && $ endConstant instanceof ConstantIntegerType
187189 && $ stepConstant instanceof ConstantIntegerType
188190 ) {
191+ $ low = min ($ startConstant ->getValue (), $ endConstant ->getValue ());
192+ $ high = max ($ startConstant ->getValue (), $ endConstant ->getValue ());
193+
189194 return self ::getNonEmptyListOfType (
190- IntegerRangeType ::fromInterval (
191- min ($ startConstant ->getValue (), $ endConstant ->getValue ()),
192- max ($ startConstant ->getValue (), $ endConstant ->getValue ()),
193- ),
195+ IntegerRangeType ::fromInterval ($ low , $ high ),
196+ // the keys stay unbounded when $high - $low overflows
197+ $ low >= 0 || $ high <= PHP_INT_MAX + $ low ? intdiv ($ high - $ low , abs ($ stepConstant ->getValue ())) : null ,
194198 );
195199 }
196200
@@ -207,11 +211,11 @@ private static function getLongRangeType(
207211 );
208212 }
209213
210- private static function getNonEmptyListOfType (Type $ type ): IntersectionType
214+ private static function getNonEmptyListOfType (Type $ type, ? int $ maxKey = null ): IntersectionType
211215 {
212216 return new IntersectionType ([
213217 new ArrayType (
214- IntegerRangeType ::createAllGreaterThanOrEqualTo ( 0 ),
218+ IntegerRangeType ::fromInterval ( 0 , $ maxKey ),
215219 $ type ,
216220 ),
217221 new NonEmptyArrayType (),
0 commit comments