Skip to content

Commit cf1470b

Browse files
committed
[mypyc] fix: builder crashes on 3-arg range if step isnt foldable
1 parent b266dd1 commit cf1470b

File tree

1 file changed

+27
-33
lines changed

1 file changed

+27
-33
lines changed

mypyc/irbuild/for_helpers.py

Lines changed: 27 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -454,39 +454,33 @@ def make_for_loop_generator(
454454
return for_dict
455455

456456
if isinstance(expr, CallExpr) and isinstance(expr.callee, RefExpr):
457-
if (
458-
is_range_ref(expr.callee)
459-
and (
460-
len(expr.args) <= 2
461-
or (len(expr.args) == 3 and builder.extract_int(expr.args[2]) is not None)
462-
)
463-
and set(expr.arg_kinds) == {ARG_POS}
464-
):
465-
# Special case "for x in range(...)".
466-
# We support the 3 arg form but only for int literals, since it doesn't
467-
# seem worth the hassle of supporting dynamically determining which
468-
# direction of comparison to do.
469-
if len(expr.args) == 1:
470-
start_reg: Value = Integer(0)
471-
end_reg = builder.accept(expr.args[0])
472-
else:
473-
start_reg = builder.accept(expr.args[0])
474-
end_reg = builder.accept(expr.args[1])
475-
if len(expr.args) == 3:
476-
step = builder.extract_int(expr.args[2])
477-
assert step is not None
478-
if step == 0:
479-
builder.error("range() step can't be zero", expr.args[2].line)
480-
else:
481-
step = 1
482-
483-
for_range = ForRange(builder, index, body_block, loop_exit, line, nested)
484-
for_range.init(start_reg, end_reg, step)
485-
return for_range
457+
num_args = len(expr.args)
458+
459+
if is_range_ref(expr.callee) and set(expr.arg_kinds) == {ARG_POS}:
460+
if num_args <= 2 or (num_args == 3 and builder.extract_int(expr.args[2]) is not None):
461+
# Special case "for x in range(...)".
462+
# We support the 3 arg form but only for int literals, since it doesn't
463+
# seem worth the hassle of supporting dynamically determining which
464+
# direction of comparison to do.
465+
if num_args == 1:
466+
start_reg: Value = Integer(0)
467+
end_reg = builder.accept(expr.args[0])
468+
step = 1
469+
else:
470+
start_reg = builder.accept(expr.args[0])
471+
end_reg = builder.accept(expr.args[1])
472+
step = 1 if num_args == 2 else builder.extract_int(expr.args[2])
473+
474+
if step:
475+
for_range = ForRange(builder, index, body_block, loop_exit, line, nested)
476+
for_range.init(start_reg, end_reg, step)
477+
return for_range
478+
479+
# If we could not constant fold `step`, we just fallback to calling stdlib implementation
486480

487481
elif (
488482
expr.callee.fullname == "builtins.enumerate"
489-
and len(expr.args) == 1
483+
and num_args == 1
490484
and expr.arg_kinds == [ARG_POS]
491485
and isinstance(index, TupleExpr)
492486
and len(index.items) == 2
@@ -500,10 +494,10 @@ def make_for_loop_generator(
500494

501495
elif (
502496
expr.callee.fullname == "builtins.zip"
503-
and len(expr.args) >= 2
497+
and num_args >= 2
504498
and set(expr.arg_kinds) == {ARG_POS}
505499
and isinstance(index, TupleExpr)
506-
and len(index.items) == len(expr.args)
500+
and len(index.items) == num_args
507501
):
508502
# Special case "for x, y in zip(a, b)".
509503
for_zip = ForZip(builder, index, body_block, loop_exit, line, nested)
@@ -512,7 +506,7 @@ def make_for_loop_generator(
512506

513507
if (
514508
expr.callee.fullname == "builtins.reversed"
515-
and len(expr.args) == 1
509+
and num_args == 1
516510
and expr.arg_kinds == [ARG_POS]
517511
and is_sequence_rprimitive(builder.node_type(expr.args[0]))
518512
):

0 commit comments

Comments
 (0)