@@ -1755,12 +1755,6 @@ impl ExecutingFrame<'_> {
17551755 exc_tb : PyObjectRef ,
17561756 ) -> PyResult < ExecutionResult > {
17571757 self . monitoring_mask = vm. state . monitoring_events . load ( ) ;
1758- // Reset prev_line so that LINE monitoring events fire even if
1759- // the exception handler is on the same line as the yield point.
1760- // In CPython, _Py_call_instrumentation_line has a special case
1761- // for RESUME: it fires LINE even when prev_line == current_line.
1762- // Since gen_throw bypasses RESUME, we reset prev_line instead.
1763- * self . prev_line = 0 ;
17641758 if let Some ( jen) = self . yield_from_target ( ) {
17651759 // Check if the exception is GeneratorExit (type or instance).
17661760 // For GeneratorExit, close the sub-iterator instead of throwing.
@@ -1796,7 +1790,10 @@ impl ExecutingFrame<'_> {
17961790 self . push_value ( vm. ctx . none ( ) ) ;
17971791 vm. contextualize_exception ( & err) ;
17981792 return match self . unwind_blocks ( vm, UnwindReason :: Raising { exception : err } ) {
1799- Ok ( None ) => self . run ( vm) ,
1793+ Ok ( None ) => {
1794+ * self . prev_line = 0 ;
1795+ self . run ( vm)
1796+ }
18001797 Ok ( Some ( result) ) => Ok ( result) ,
18011798 Err ( exception) => Err ( exception) ,
18021799 } ;
@@ -1838,7 +1835,10 @@ impl ExecutingFrame<'_> {
18381835 self . push_value ( vm. ctx . none ( ) ) ;
18391836 vm. contextualize_exception ( & err) ;
18401837 match self . unwind_blocks ( vm, UnwindReason :: Raising { exception : err } ) {
1841- Ok ( None ) => self . run ( vm) ,
1838+ Ok ( None ) => {
1839+ * self . prev_line = 0 ;
1840+ self . run ( vm)
1841+ }
18421842 Ok ( Some ( result) ) => Ok ( result) ,
18431843 Err ( exception) => Err ( exception) ,
18441844 }
@@ -1906,7 +1906,13 @@ impl ExecutingFrame<'_> {
19061906 self . push_value ( vm. ctx . none ( ) ) ;
19071907
19081908 match self . unwind_blocks ( vm, UnwindReason :: Raising { exception } ) {
1909- Ok ( None ) => self . run ( vm) ,
1909+ Ok ( None ) => {
1910+ // Reset prev_line so that the first instruction in the handler
1911+ // fires a LINE event. In CPython, gen_send_ex re-enters the
1912+ // eval loop which reinitializes its local prev_instr tracker.
1913+ * self . prev_line = 0 ;
1914+ self . run ( vm)
1915+ }
19101916 Ok ( Some ( result) ) => Ok ( result) ,
19111917 Err ( exception) => {
19121918 // Fire PY_UNWIND: exception escapes the generator frame.
@@ -9440,20 +9446,25 @@ impl ExecutingFrame<'_> {
94409446 Ok ( vm. ctx . new_tuple ( list. borrow_vec ( ) . to_vec ( ) ) . into ( ) )
94419447 }
94429448 bytecode:: IntrinsicFunction1 :: StopIterationError => {
9443- // Convert StopIteration to RuntimeError
9444- // Used to ensure async generators don't raise StopIteration directly
9445- // _PyGen_FetchStopIterationValue
9446- // Use fast_isinstance to handle subclasses of StopIteration
9449+ // Convert StopIteration to RuntimeError (PEP 479)
9450+ // Returns the exception object; RERAISE will re-raise it
94479451 if arg. fast_isinstance ( vm. ctx . exceptions . stop_iteration ) {
9448- Err ( vm. new_runtime_error ( "coroutine raised StopIteration" ) )
9452+ let flags = & self . code . flags ;
9453+ let msg = if flags
9454+ . contains ( bytecode:: CodeFlags :: COROUTINE | bytecode:: CodeFlags :: GENERATOR )
9455+ {
9456+ "async generator raised StopIteration"
9457+ } else if flags. contains ( bytecode:: CodeFlags :: COROUTINE ) {
9458+ "coroutine raised StopIteration"
9459+ } else {
9460+ "generator raised StopIteration"
9461+ } ;
9462+ let err = vm. new_runtime_error ( msg) ;
9463+ err. set___cause__ ( arg. downcast ( ) . ok ( ) ) ;
9464+ Ok ( err. into ( ) )
94499465 } else {
9450- // If not StopIteration, just re-raise the original exception
9451- Err ( arg. downcast ( ) . unwrap_or_else ( |obj| {
9452- vm. new_runtime_error ( format ! (
9453- "unexpected exception type: {:?}" ,
9454- obj. class( )
9455- ) )
9456- } ) )
9466+ // Not StopIteration, pass through for RERAISE
9467+ Ok ( arg)
94579468 }
94589469 }
94599470 bytecode:: IntrinsicFunction1 :: AsyncGenWrap => {
0 commit comments