-
-
Couldn't load subscription status.
- Fork 3k
[mypyc] fix: builder crashes on 3-arg range(x, y, z) if step isnt foldable
#20098
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from 4 commits
cf1470b
2b0407b
9efe377
1dbaa15
a266982
b5d519c
4fda932
3ad0bad
b1c9e3f
0bb8e0e
57be7b8
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -454,39 +454,31 @@ def make_for_loop_generator( | |
| return for_dict | ||
|
|
||
| if isinstance(expr, CallExpr) and isinstance(expr.callee, RefExpr): | ||
| if ( | ||
| is_range_ref(expr.callee) | ||
| and ( | ||
| len(expr.args) <= 2 | ||
| or (len(expr.args) == 3 and builder.extract_int(expr.args[2]) is not None) | ||
| ) | ||
| and set(expr.arg_kinds) == {ARG_POS} | ||
| ): | ||
| # Special case "for x in range(...)". | ||
| # We support the 3 arg form but only for int literals, since it doesn't | ||
| # seem worth the hassle of supporting dynamically determining which | ||
| # direction of comparison to do. | ||
| if len(expr.args) == 1: | ||
| start_reg: Value = Integer(0) | ||
| end_reg = builder.accept(expr.args[0]) | ||
| else: | ||
| start_reg = builder.accept(expr.args[0]) | ||
| end_reg = builder.accept(expr.args[1]) | ||
| if len(expr.args) == 3: | ||
| step = builder.extract_int(expr.args[2]) | ||
| assert step is not None | ||
| if step == 0: | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. we no longer need to check this because we validate that it isn't |
||
| builder.error("range() step can't be zero", expr.args[2].line) | ||
| else: | ||
| step = 1 | ||
| num_args = len(expr.args) | ||
|
|
||
| for_range = ForRange(builder, index, body_block, loop_exit, line, nested) | ||
| for_range.init(start_reg, end_reg, step) | ||
| return for_range | ||
| if is_range_ref(expr.callee) and set(expr.arg_kinds) == {ARG_POS}: | ||
| # Special case "for x in range(...)". | ||
| # NOTE We support the 3 arg form but only when `step` is constant- | ||
| # foldable, since it doesn't seem worth the hassle of supporting | ||
| # dynamically determining which direction of comparison to do. | ||
| # If we cannot constant fold `step`, we just fallback to stdlib range. | ||
| if num_args <= 2 or (num_args == 3 and builder.extract_int(expr.args[2])): | ||
| if num_args == 1: | ||
| start_reg: Value = Integer(0) | ||
| end_reg = builder.accept(expr.args[0]) | ||
| step = 1 | ||
| else: | ||
| start_reg = builder.accept(expr.args[0]) | ||
| end_reg = builder.accept(expr.args[1]) | ||
| step = 1 if num_args == 2 else cast(int, builder.extract_int(expr.args[2])) | ||
|
||
|
|
||
| for_range = ForRange(builder, index, body_block, loop_exit, line, nested) | ||
| for_range.init(start_reg, end_reg, step) | ||
| return for_range | ||
|
|
||
| elif ( | ||
| expr.callee.fullname == "builtins.enumerate" | ||
| and len(expr.args) == 1 | ||
| and num_args == 1 | ||
| and expr.arg_kinds == [ARG_POS] | ||
| and isinstance(index, TupleExpr) | ||
| and len(index.items) == 2 | ||
|
|
@@ -500,10 +492,10 @@ def make_for_loop_generator( | |
|
|
||
| elif ( | ||
| expr.callee.fullname == "builtins.zip" | ||
| and len(expr.args) >= 2 | ||
| and num_args >= 2 | ||
| and set(expr.arg_kinds) == {ARG_POS} | ||
| and isinstance(index, TupleExpr) | ||
| and len(index.items) == len(expr.args) | ||
| and len(index.items) == num_args | ||
| ): | ||
| # Special case "for x, y in zip(a, b)". | ||
| for_zip = ForZip(builder, index, body_block, loop_exit, line, nested) | ||
|
|
@@ -512,7 +504,7 @@ def make_for_loop_generator( | |
|
|
||
| if ( | ||
| expr.callee.fullname == "builtins.reversed" | ||
| and len(expr.args) == 1 | ||
| and num_args == 1 | ||
| and expr.arg_kinds == [ARG_POS] | ||
| and is_sequence_rprimitive(builder.node_type(expr.args[0])) | ||
| ): | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Huh, why did this fail with an assertion error? (I'm not used to mypyc...)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeh, I'm realizing while re-reading this that it doesn't
I discovered this assert when working on #20100 and made this PR as an intermediate step which could be merged in before the full feature.
In hindsight I suppose this is no longer necessary, but I'll leave it open so maintainers can decide if we want to merge it before #20100