8686
8787GenFunc = Callable [[], None ]
8888
89-
9089def for_loop_helper (
9190 builder : IRBuilder ,
9291 index : Lvalue ,
@@ -95,6 +94,7 @@ def for_loop_helper(
9594 else_insts : GenFunc | None ,
9695 is_async : bool ,
9796 line : int ,
97+ can_unroll : bool = True ,
9898) -> None :
9999 """Generate IR for a loop.
100100
@@ -103,6 +103,7 @@ def for_loop_helper(
103103 expr: the expression to iterate over
104104 body_insts: a function that generates the body of the loop
105105 else_insts: a function that generates the else block instructions
106+ can_unroll: whether unrolling is allowed (for semantic safety)
106107 """
107108 # Body of the loop
108109 body_block = BasicBlock ()
@@ -117,15 +118,19 @@ def for_loop_helper(
117118 normal_loop_exit = else_block if else_insts is not None else exit_block
118119
119120 for_gen = make_for_loop_generator (
120- builder , index , expr , body_block , normal_loop_exit , line , is_async = is_async , body_insts = body_insts
121+ builder , index , expr , body_block , normal_loop_exit , line , is_async = is_async , body_insts = body_insts , can_unroll = can_unroll
121122 )
122123
123124 is_literal_loop : bool = getattr (for_gen , "handles_body_insts" , False )
124125
125126 # Only call body_insts if not handled by unrolled generator
126127 if is_literal_loop :
127- for_gen .begin_body ()
128- return
128+ try :
129+ for_gen .begin_body ()
130+ return
131+ except AssertionError :
132+ # For whatever reason, we can't unpack the loop in this case.
133+ pass
129134
130135 builder .push_loop_stack (step_block , exit_block )
131136 condition_block = BasicBlock ()
@@ -420,10 +425,12 @@ def make_for_loop_generator(
420425 is_async : bool = False ,
421426 nested : bool = False ,
422427 body_insts : GenFunc = None ,
428+ can_unroll : bool = True ,
423429) -> ForGenerator :
424430 """Return helper object for generating a for loop over an iterable.
425431
426432 If "nested" is True, this is a nested iterator such as "e" in "enumerate(e)".
433+ can_unroll: whether unrolling is allowed (for semantic safety)
427434 """
428435
429436 # Do an async loop if needed. async is always generic
@@ -437,22 +444,24 @@ def make_for_loop_generator(
437444
438445 rtyp = builder .node_type (expr )
439446
440- # Special case: tuple literal (unroll the loop)
441- if is_iterable_expr_with_literal_mambers (expr ):
442- return ForUnrolledSequenceLiteral (builder , index , body_block , loop_exit , line , expr , body_insts )
443-
444- # Special case: RTuple (known-length tuple, struct field iteration)
445- if isinstance (rtyp , RTuple ):
446- expr_reg = builder .accept (expr )
447- return ForUnrolledRTuple (builder , index , body_block , loop_exit , line , rtyp , expr_reg , expr , body_insts )
448-
449- # Special case: string literal (unroll the loop)
450- if isinstance (expr , StrExpr ):
451- return ForUnrolledStringLiteral (builder , index , body_block , loop_exit , line , expr .value , expr , body_insts )
452-
453- # Special case: string literal (unroll the loop)
454- if isinstance (expr , BytesExpr ):
455- return ForUnrolledBytesLiteral (builder , index , body_block , loop_exit , line , expr .value , expr , body_insts )
447+
448+ if can_unroll :
449+ # Special case: tuple/list/set literal (unroll the loop)
450+ if is_iterable_expr_with_literal_mambers (expr ):
451+ return ForUnrolledSequenceLiteral (builder , index , body_block , loop_exit , line , expr , body_insts )
452+
453+ # Special case: RTuple (known-length tuple, struct field iteration)
454+ if isinstance (rtyp , RTuple ):
455+ expr_reg = builder .accept (expr )
456+ return ForUnrolledRTuple (builder , index , body_block , loop_exit , line , rtyp , expr_reg , expr , body_insts )
457+
458+ # Special case: string literal (unroll the loop)
459+ if isinstance (expr , StrExpr ):
460+ return ForUnrolledStringLiteral (builder , index , body_block , loop_exit , line , expr .value , expr , body_insts )
461+
462+ # Special case: string literal (unroll the loop)
463+ if isinstance (expr , BytesExpr ):
464+ return ForUnrolledBytesLiteral (builder , index , body_block , loop_exit , line , expr .value , expr , body_insts )
456465
457466 if is_sequence_rprimitive (rtyp ):
458467 # Special case "for x in <list>".
0 commit comments