@@ -1433,7 +1433,7 @@ impl Compiler {
14331433 if matches ! ( info. fb_type, FBlockType :: AsyncWith ) {
14341434 emit ! ( self , Instruction :: GetAwaitable { arg: 2 } ) ;
14351435 self . emit_load_const ( ConstantData :: None ) ;
1436- self . compile_yield_from_sequence ( true ) ?;
1436+ let _ = self . compile_yield_from_sequence ( true ) ?;
14371437 }
14381438
14391439 // Pop the __exit__ result
@@ -2371,12 +2371,16 @@ impl Compiler {
23712371 }
23722372 }
23732373 ast:: Stmt :: Break ( _) => {
2374+ // Match CPython line-tracing behavior (codegen_break emits NOP).
2375+ emit ! ( self , Instruction :: Nop ) ;
23742376 // Unwind fblock stack until we find a loop, emitting cleanup for each fblock
23752377 self . compile_break_continue ( statement. range ( ) , true ) ?;
23762378 let dead = self . new_block ( ) ;
23772379 self . switch_to_block ( dead) ;
23782380 }
23792381 ast:: Stmt :: Continue ( _) => {
2382+ // Match CPython line-tracing behavior (codegen_continue emits NOP).
2383+ emit ! ( self , Instruction :: Nop ) ;
23802384 // Unwind fblock stack until we find a loop, emitting cleanup for each fblock
23812385 self . compile_break_continue ( statement. range ( ) , false ) ?;
23822386 let dead = self . new_block ( ) ;
@@ -2449,7 +2453,8 @@ impl Compiler {
24492453 }
24502454 }
24512455 ast:: Stmt :: Pass ( _) => {
2452- // No need to emit any code here :)
2456+ // Match CPython line-tracing behavior (Pass_kind emits NOP).
2457+ emit ! ( self , Instruction :: Nop ) ;
24532458 }
24542459 ast:: Stmt :: TypeAlias ( ast:: StmtTypeAlias {
24552460 name,
@@ -4942,7 +4947,7 @@ impl Compiler {
49424947 emit ! ( self , Instruction :: Call { nargs: 0 } ) ; // [bound_aexit, awaitable]
49434948 emit ! ( self , Instruction :: GetAwaitable { arg: 1 } ) ;
49444949 self . emit_load_const ( ConstantData :: None ) ;
4945- self . compile_yield_from_sequence ( true ) ?;
4950+ let _ = self . compile_yield_from_sequence ( true ) ?;
49464951 } else {
49474952 // Load __exit__ and __enter__, then call __enter__
49484953 emit ! (
@@ -5025,7 +5030,7 @@ impl Compiler {
50255030 if is_async {
50265031 emit ! ( self , Instruction :: GetAwaitable { arg: 2 } ) ;
50275032 self . emit_load_const ( ConstantData :: None ) ;
5028- self . compile_yield_from_sequence ( true ) ?;
5033+ let _ = self . compile_yield_from_sequence ( true ) ?;
50295034 }
50305035 emit ! ( self , Instruction :: PopTop ) ; // Pop __exit__ result
50315036 emit ! (
@@ -5063,7 +5068,7 @@ impl Compiler {
50635068 if is_async {
50645069 emit ! ( self , Instruction :: GetAwaitable { arg: 2 } ) ;
50655070 self . emit_load_const ( ConstantData :: None ) ;
5066- self . compile_yield_from_sequence ( true ) ?;
5071+ let _ = self . compile_yield_from_sequence ( true ) ?;
50675072 }
50685073
50695074 // TO_BOOL + POP_JUMP_IF_TRUE: check if exception is suppressed
@@ -5137,6 +5142,7 @@ impl Compiler {
51375142 let for_block = self . new_block ( ) ;
51385143 let else_block = self . new_block ( ) ;
51395144 let after_block = self . new_block ( ) ;
5145+ let mut end_async_for_target = BlockIdx :: NULL ;
51405146
51415147 // The thing iterated:
51425148 self . compile_expression ( iter) ?;
@@ -5156,9 +5162,10 @@ impl Compiler {
51565162 emit ! ( self , PseudoInstruction :: SetupFinally { target: else_block } ) ;
51575163 emit ! ( self , Instruction :: GetANext ) ;
51585164 self . emit_load_const ( ConstantData :: None ) ;
5159- self . compile_yield_from_sequence ( true ) ?;
5165+ end_async_for_target = self . compile_yield_from_sequence ( true ) ?;
51605166 // POP_BLOCK for SETUP_FINALLY - only GetANext/yield_from are protected
51615167 emit ! ( self , PseudoInstruction :: PopBlock ) ;
5168+ emit ! ( self , Instruction :: NotTaken ) ;
51625169
51635170 // Success block for __anext__
51645171 self . compile_store ( target) ?;
@@ -5192,7 +5199,7 @@ impl Compiler {
51925199 let saved_range = self . current_source_range ;
51935200 self . set_source_range ( iter. range ( ) ) ;
51945201 if is_async {
5195- emit ! ( self , Instruction :: EndAsyncFor ) ;
5202+ self . emit_end_async_for ( end_async_for_target ) ;
51965203 } else {
51975204 emit ! ( self , Instruction :: EndFor ) ;
51985205 emit ! ( self , Instruction :: PopIter ) ;
@@ -6786,7 +6793,7 @@ impl Compiler {
67866793 /// CLEANUP_THROW
67876794 /// exit:
67886795 /// END_SEND
6789- fn compile_yield_from_sequence ( & mut self , is_await : bool ) -> CompileResult < ( ) > {
6796+ fn compile_yield_from_sequence ( & mut self , is_await : bool ) -> CompileResult < BlockIdx > {
67906797 let send_block = self . new_block ( ) ;
67916798 let fail_block = self . new_block ( ) ;
67926799 let exit_block = self . new_block ( ) ;
@@ -6842,7 +6849,7 @@ impl Compiler {
68426849 self . switch_to_block ( exit_block) ;
68436850 emit ! ( self , Instruction :: EndSend ) ;
68446851
6845- Ok ( ( ) )
6852+ Ok ( send_block )
68466853 }
68476854
68486855 fn compile_expression ( & mut self , expression : & ast:: Expr ) -> CompileResult < ( ) > {
@@ -6897,7 +6904,11 @@ impl Compiler {
68976904 if let Some ( super_type) = self . can_optimize_super_call ( value, attr. as_str ( ) ) {
68986905 // super().attr or super(cls, self).attr optimization
68996906 // Stack: [global_super, class, self] → LOAD_SUPER_ATTR → [attr]
6907+ // Set source range to super() call for arg-loading instructions
6908+ let super_range = value. range ( ) ;
6909+ self . set_source_range ( super_range) ;
69006910 self . load_args_for_super ( & super_type) ?;
6911+ self . set_source_range ( super_range) ;
69016912 let idx = self . name ( attr. as_str ( ) ) ;
69026913 match super_type {
69036914 SuperCallType :: TwoArg { .. } => {
@@ -6983,7 +6994,7 @@ impl Compiler {
69836994 self . compile_expression ( value) ?;
69846995 emit ! ( self , Instruction :: GetAwaitable { arg: 0 } ) ;
69856996 self . emit_load_const ( ConstantData :: None ) ;
6986- self . compile_yield_from_sequence ( true ) ?;
6997+ let _ = self . compile_yield_from_sequence ( true ) ?;
69876998 }
69886999 ast:: Expr :: YieldFrom ( ast:: ExprYieldFrom { value, .. } ) => {
69897000 match self . ctx . func {
@@ -6999,7 +7010,7 @@ impl Compiler {
69997010 self . compile_expression ( value) ?;
70007011 emit ! ( self , Instruction :: GetYieldFromIter ) ;
70017012 self . emit_load_const ( ConstantData :: None ) ;
7002- self . compile_yield_from_sequence ( false ) ?;
7013+ let _ = self . compile_yield_from_sequence ( false ) ?;
70037014 }
70047015 ast:: Expr :: Name ( ast:: ExprName { id, .. } ) => self . load_name ( id. as_str ( ) ) ?,
70057016 ast:: Expr :: Lambda ( ast:: ExprLambda {
@@ -7354,7 +7365,11 @@ impl Compiler {
73547365 if let Some ( super_type) = self . can_optimize_super_call ( value, attr. as_str ( ) ) {
73557366 // super().method() or super(cls, self).method() optimization
73567367 // Stack: [global_super, class, self] → LOAD_SUPER_METHOD → [method, self]
7368+ // Set source range to the super() call for LOAD_GLOBAL/LOAD_DEREF/etc.
7369+ let super_range = value. range ( ) ;
7370+ self . set_source_range ( super_range) ;
73577371 self . load_args_for_super ( & super_type) ?;
7372+ self . set_source_range ( super_range) ;
73587373 let idx = self . name ( attr. as_str ( ) ) ;
73597374 match super_type {
73607375 SuperCallType :: TwoArg { .. } => {
@@ -7364,7 +7379,11 @@ impl Compiler {
73647379 self . emit_load_zero_super_method ( idx) ;
73657380 }
73667381 }
7367- self . codegen_call_helper ( 0 , args, call_range) ?;
7382+ // NOP for line tracking at .method( line
7383+ self . set_source_range ( attr. range ( ) ) ;
7384+ emit ! ( self , Instruction :: Nop ) ;
7385+ // CALL at .method( line (not the full expression line)
7386+ self . codegen_call_helper ( 0 , args, attr. range ( ) ) ?;
73687387 } else {
73697388 // Normal method call: compile object, then LOAD_ATTR with method flag
73707389 // LOAD_ATTR(method=1) pushes [method, self_or_null] on stack
@@ -7654,6 +7673,7 @@ impl Compiler {
76547673 let mut loop_labels = vec ! [ ] ;
76557674 for generator in generators {
76567675 let loop_block = self . new_block ( ) ;
7676+ let if_cleanup_block = self . new_block ( ) ;
76577677 let after_block = self . new_block ( ) ;
76587678
76597679 if loop_labels. is_empty ( ) {
@@ -7671,8 +7691,8 @@ impl Compiler {
76717691 }
76727692 }
76737693
7674- loop_labels. push ( ( loop_block, after_block, generator. is_async ) ) ;
76757694 self . switch_to_block ( loop_block) ;
7695+ let mut end_async_for_target = BlockIdx :: NULL ;
76767696 if generator. is_async {
76777697 emit ! (
76787698 self ,
@@ -7687,7 +7707,7 @@ impl Compiler {
76877707 after_block,
76887708 ) ?;
76897709 self . emit_load_const ( ConstantData :: None ) ;
7690- self . compile_yield_from_sequence ( true ) ?;
7710+ end_async_for_target = self . compile_yield_from_sequence ( true ) ?;
76917711 // POP_BLOCK before store: only __anext__/yield_from are
76927712 // protected by SetupFinally targeting END_ASYNC_FOR.
76937713 emit ! ( self , PseudoInstruction :: PopBlock ) ;
@@ -7702,23 +7722,35 @@ impl Compiler {
77027722 ) ;
77037723 self . compile_store ( & generator. target ) ?;
77047724 }
7725+ loop_labels. push ( (
7726+ loop_block,
7727+ if_cleanup_block,
7728+ after_block,
7729+ generator. is_async ,
7730+ end_async_for_target,
7731+ ) ) ;
77057732
77067733 // Now evaluate the ifs:
77077734 for if_condition in & generator. ifs {
7708- self . compile_jump_if ( if_condition, false , loop_block ) ?
7735+ self . compile_jump_if ( if_condition, false , if_cleanup_block ) ?
77097736 }
77107737 }
77117738
77127739 compile_element ( self ) ?;
77137740
7714- for ( loop_block, after_block, is_async) in loop_labels. iter ( ) . rev ( ) . copied ( ) {
7741+ for ( loop_block, if_cleanup_block, after_block, is_async, end_async_for_target) in
7742+ loop_labels. iter ( ) . rev ( ) . copied ( )
7743+ {
7744+ emit ! ( self , PseudoInstruction :: Jump { target: loop_block } ) ;
7745+
7746+ self . switch_to_block ( if_cleanup_block) ;
77157747 emit ! ( self , PseudoInstruction :: Jump { target: loop_block } ) ;
77167748
77177749 self . switch_to_block ( after_block) ;
77187750 if is_async {
77197751 // EndAsyncFor pops both the exception and the aiter
77207752 // (handler depth is before GetANext, so aiter is at handler depth)
7721- emit ! ( self , Instruction :: EndAsyncFor ) ;
7753+ self . emit_end_async_for ( end_async_for_target ) ;
77227754 } else {
77237755 // END_FOR + POP_ITER pattern (CPython 3.14)
77247756 emit ! ( self , Instruction :: EndFor ) ;
@@ -7756,7 +7788,7 @@ impl Compiler {
77567788 if is_async_list_set_dict_comprehension {
77577789 emit ! ( self , Instruction :: GetAwaitable { arg: 0 } ) ;
77587790 self . emit_load_const ( ConstantData :: None ) ;
7759- self . compile_yield_from_sequence ( true ) ?;
7791+ let _ = self . compile_yield_from_sequence ( true ) ?;
77607792 }
77617793
77627794 Ok ( ( ) )
@@ -7867,6 +7899,7 @@ impl Compiler {
78677899 let mut loop_labels = vec ! [ ] ;
78687900 for ( i, generator) in generators. iter ( ) . enumerate ( ) {
78697901 let loop_block = self . new_block ( ) ;
7902+ let if_cleanup_block = self . new_block ( ) ;
78707903 let after_block = self . new_block ( ) ;
78717904
78727905 if i > 0 {
@@ -7879,13 +7912,13 @@ impl Compiler {
78797912 }
78807913 }
78817914
7882- loop_labels. push ( ( loop_block, after_block, generator. is_async ) ) ;
78837915 self . switch_to_block ( loop_block) ;
7916+ let mut end_async_for_target = BlockIdx :: NULL ;
78847917
78857918 if generator. is_async {
78867919 emit ! ( self , Instruction :: GetANext ) ;
78877920 self . emit_load_const ( ConstantData :: None ) ;
7888- self . compile_yield_from_sequence ( true ) ?;
7921+ end_async_for_target = self . compile_yield_from_sequence ( true ) ?;
78897922 self . compile_store ( & generator. target ) ?;
78907923 } else {
78917924 emit ! (
@@ -7896,22 +7929,35 @@ impl Compiler {
78967929 ) ;
78977930 self . compile_store ( & generator. target ) ?;
78987931 }
7932+ loop_labels. push ( (
7933+ loop_block,
7934+ if_cleanup_block,
7935+ after_block,
7936+ generator. is_async ,
7937+ end_async_for_target,
7938+ ) ) ;
78997939
79007940 // Evaluate the if conditions
79017941 for if_condition in & generator. ifs {
7902- self . compile_jump_if ( if_condition, false , loop_block ) ?;
7942+ self . compile_jump_if ( if_condition, false , if_cleanup_block ) ?;
79037943 }
79047944 }
79057945
79067946 // Step 6: Compile the element expression and append to collection
79077947 compile_element ( self ) ?;
79087948
79097949 // Step 7: Close all loops
7910- for ( loop_block, after_block, is_async) in loop_labels. iter ( ) . rev ( ) . copied ( ) {
7950+ for ( loop_block, if_cleanup_block, after_block, is_async, end_async_for_target) in
7951+ loop_labels. iter ( ) . rev ( ) . copied ( )
7952+ {
7953+ emit ! ( self , PseudoInstruction :: Jump { target: loop_block } ) ;
7954+
7955+ self . switch_to_block ( if_cleanup_block) ;
79117956 emit ! ( self , PseudoInstruction :: Jump { target: loop_block } ) ;
7957+
79127958 self . switch_to_block ( after_block) ;
79137959 if is_async {
7914- emit ! ( self , Instruction :: EndAsyncFor ) ;
7960+ self . emit_end_async_for ( end_async_for_target ) ;
79157961 // Pop the iterator
79167962 emit ! ( self , Instruction :: PopTop ) ;
79177963 } else {
@@ -8048,6 +8094,10 @@ impl Compiler {
80488094 emit ! ( self , Instruction :: ReturnValue )
80498095 }
80508096
8097+ fn emit_end_async_for ( & mut self , send_target : BlockIdx ) {
8098+ self . _emit ( Instruction :: EndAsyncFor , OpArg :: NULL , send_target) ;
8099+ }
8100+
80518101 /// Emit LOAD_ATTR for attribute access (method=false).
80528102 /// Encodes: (name_idx << 1) | 0
80538103 fn emit_load_attr ( & mut self , name_idx : u32 ) {
@@ -8260,7 +8310,7 @@ impl Compiler {
82608310 if is_async {
82618311 emit ! ( self , Instruction :: GetAwaitable { arg: 2 } ) ;
82628312 self . emit_load_const ( ConstantData :: None ) ;
8263- self . compile_yield_from_sequence ( true ) ?;
8313+ let _ = self . compile_yield_from_sequence ( true ) ?;
82648314 }
82658315
82668316 emit ! ( self , Instruction :: PopTop ) ;
0 commit comments