@@ -49,10 +49,6 @@ enum BlockType {
49
49
FinallyHandler {
50
50
reason : Option < UnwindReason > ,
51
51
} ,
52
- With {
53
- end : bytecode:: Label ,
54
- context_manager : PyObjectRef ,
55
- } ,
56
52
ExceptHandler ,
57
53
}
58
54
@@ -431,29 +427,69 @@ impl Frame {
431
427
}
432
428
bytecode:: Instruction :: SetupWith { end } => {
433
429
let context_manager = self . pop_value ( ) ;
430
+ let exit = vm. get_attribute ( context_manager. clone ( ) , "__exit__" ) ?;
431
+ self . push_value ( exit) ;
434
432
// Call enter:
435
- let obj = vm. call_method ( & context_manager, "__enter__" , vec ! [ ] ) ?;
436
- self . push_block ( BlockType :: With {
437
- end : * end,
438
- context_manager : context_manager. clone ( ) ,
433
+ let enter_res = vm. call_method ( & context_manager, "__enter__" , vec ! [ ] ) ?;
434
+ self . push_block ( BlockType :: Finally { handler : * end } ) ;
435
+ self . push_value ( enter_res) ;
436
+ Ok ( None )
437
+ }
438
+ bytecode:: Instruction :: BeforeAsyncWith => {
439
+ let mgr = self . pop_value ( ) ;
440
+ let aexit = vm. get_attribute ( mgr. clone ( ) , "__aexit__" ) ?;
441
+ self . push_value ( aexit) ;
442
+ let aenter_res = vm. call_method ( & mgr, "__aenter__" , vec ! [ ] ) ?;
443
+ self . push_value ( aenter_res) ;
444
+
445
+ Ok ( None )
446
+ }
447
+ bytecode:: Instruction :: SetupAsyncWith { end } => {
448
+ self . push_block ( BlockType :: Finally { handler : * end } ) ;
449
+ Ok ( None )
450
+ }
451
+ bytecode:: Instruction :: WithCleanupStart => {
452
+ let block = self . current_block ( ) . unwrap ( ) ;
453
+ let reason = match block. typ {
454
+ BlockType :: FinallyHandler { reason } => reason,
455
+ _ => panic ! ( "WithCleanupStart expects a FinallyHandler block on stack" ) ,
456
+ } ;
457
+ let exc = reason. and_then ( |reason| match reason {
458
+ UnwindReason :: Raising { exception } => Some ( exception) ,
459
+ _ => None ,
439
460
} ) ;
440
- self . push_value ( obj) ;
461
+
462
+ let exit = self . pop_value ( ) ;
463
+
464
+ let args = if let Some ( exc) = exc {
465
+ let exc_type = exc. class ( ) . into_object ( ) ;
466
+ let exc_val = exc. clone ( ) ;
467
+ let exc_tb = vm. ctx . none ( ) ; // TODO: retrieve traceback?
468
+ vec ! [ exc_type, exc_val, exc_tb]
469
+ } else {
470
+ vec ! [ vm. ctx. none( ) , vm. ctx. none( ) , vm. ctx. none( ) ]
471
+ } ;
472
+ let exit_res = vm. invoke ( & exit, args) ?;
473
+ self . push_value ( exit_res) ;
474
+
441
475
Ok ( None )
442
476
}
443
- bytecode:: Instruction :: CleanupWith { end : end1 } => {
477
+ bytecode:: Instruction :: WithCleanupFinish => {
444
478
let block = self . pop_block ( ) ;
445
- if let BlockType :: With {
446
- end : end2,
447
- context_manager,
448
- } = & block. typ
449
- {
450
- debug_assert ! ( end1 == end2) ;
451
- self . call_context_manager_exit ( vm, & context_manager, None ) ?;
479
+ let reason = match block. typ {
480
+ BlockType :: FinallyHandler { reason } => reason,
481
+ _ => panic ! ( "WithCleanupFinish expects a FinallyHandler block on stack" ) ,
482
+ } ;
483
+
484
+ let suppress_exception = objbool:: boolval ( vm, self . pop_value ( ) ) ?;
485
+ if suppress_exception {
486
+ // suppress exception
487
+ Ok ( None )
488
+ } else if let Some ( reason) = reason {
489
+ self . unwind_blocks ( vm, reason)
452
490
} else {
453
- unreachable ! ( "Block stack is incorrect, expected a with block" ) ;
491
+ Ok ( None )
454
492
}
455
-
456
- Ok ( None )
457
493
}
458
494
bytecode:: Instruction :: PopBlock => {
459
495
self . pop_block ( ) ;
@@ -663,7 +699,7 @@ impl Frame {
663
699
/// unwinding a block.
664
700
/// Optionally returns an exception.
665
701
#[ cfg_attr( feature = "flame-it" , flame( "Frame" ) ) ]
666
- fn unwind_blocks ( & self , vm : & VirtualMachine , mut reason : UnwindReason ) -> FrameResult {
702
+ fn unwind_blocks ( & self , vm : & VirtualMachine , reason : UnwindReason ) -> FrameResult {
667
703
// First unwind all existing blocks on the block stack:
668
704
while let Some ( block) = self . current_block ( ) {
669
705
match block. typ {
@@ -699,60 +735,6 @@ impl Frame {
699
735
return Ok ( None ) ;
700
736
}
701
737
}
702
- BlockType :: With {
703
- context_manager,
704
- end,
705
- } => {
706
- self . pop_block ( ) ;
707
- match & reason {
708
- UnwindReason :: Raising { exception } => {
709
- match self . call_context_manager_exit (
710
- vm,
711
- & context_manager,
712
- Some ( exception. clone ( ) ) ,
713
- ) {
714
- Ok ( exit_result_obj) => {
715
- match objbool:: boolval ( vm, exit_result_obj) {
716
- // If __exit__ method returned True, suppress the exception and continue execution.
717
- Ok ( suppress_exception) => {
718
- if suppress_exception {
719
- self . jump ( end) ;
720
- return Ok ( None ) ;
721
- } else {
722
- // go on with the stack unwinding.
723
- }
724
- }
725
- Err ( exit_exc) => {
726
- reason = UnwindReason :: Raising {
727
- exception : exit_exc,
728
- } ;
729
- // return Err(exit_exc);
730
- }
731
- }
732
- }
733
- Err ( exit_exc) => {
734
- // TODO: what about original exception?
735
- reason = UnwindReason :: Raising {
736
- exception : exit_exc,
737
- } ;
738
- // return Err(exit_exc);
739
- }
740
- }
741
- }
742
- _ => {
743
- match self . call_context_manager_exit ( vm, & context_manager, None ) {
744
- Ok ( ..) => { }
745
- Err ( exit_exc) => {
746
- // __exit__ went wrong,
747
- reason = UnwindReason :: Raising {
748
- exception : exit_exc,
749
- } ;
750
- // return Err(exc);
751
- }
752
- }
753
- }
754
- }
755
- }
756
738
BlockType :: FinallyHandler { .. } => {
757
739
self . pop_block ( ) ;
758
740
}
@@ -773,26 +755,6 @@ impl Frame {
773
755
}
774
756
}
775
757
776
- fn call_context_manager_exit (
777
- & self ,
778
- vm : & VirtualMachine ,
779
- context_manager : & PyObjectRef ,
780
- exc : Option < PyObjectRef > ,
781
- ) -> PyResult {
782
- // TODO: do we want to put the exit call on the stack?
783
- // TODO: what happens when we got an error during execution of __exit__?
784
- let ( exc_type, exc_val, exc_tb) = if let Some ( exc) = exc {
785
- let exc_type = exc. class ( ) . into_object ( ) ;
786
- let exc_val = exc. clone ( ) ;
787
- let exc_tb = vm. ctx . none ( ) ; // TODO: retrieve traceback?
788
- ( exc_type, exc_val, exc_tb)
789
- } else {
790
- ( vm. ctx . none ( ) , vm. ctx . none ( ) , vm. ctx . none ( ) )
791
- } ;
792
-
793
- vm. call_method ( context_manager, "__exit__" , vec ! [ exc_type, exc_val, exc_tb] )
794
- }
795
-
796
758
fn store_name (
797
759
& self ,
798
760
vm : & VirtualMachine ,
0 commit comments