@@ -721,16 +721,19 @@ def transform_try_finally_stmt_async(
721
721
builder : IRBuilder , try_body : GenFunc , finally_body : GenFunc , line : int = - 1
722
722
) -> None :
723
723
"""Async-aware try/finally handling for when finally contains await.
724
-
724
+
725
725
This version uses a modified approach that preserves exceptions across await."""
726
-
726
+
727
727
# We need to handle returns properly, so we'll use TryFinallyNonlocalControl
728
728
# to track return values, similar to the regular try/finally implementation
729
-
729
+
730
730
err_handler , main_entry , return_entry , finally_entry = (
731
- BasicBlock (), BasicBlock (), BasicBlock (), BasicBlock ()
731
+ BasicBlock (),
732
+ BasicBlock (),
733
+ BasicBlock (),
734
+ BasicBlock (),
732
735
)
733
-
736
+
734
737
# Track if we're returning from the try block
735
738
control = TryFinallyNonlocalControl (return_entry )
736
739
builder .builder .push_error_handler (err_handler )
@@ -741,76 +744,76 @@ def transform_try_finally_stmt_async(
741
744
builder .nonlocal_control .pop ()
742
745
builder .builder .pop_error_handler ()
743
746
ret_reg = control .ret_reg
744
-
747
+
745
748
# Normal case - no exception or return
746
749
builder .activate_block (main_entry )
747
750
builder .goto (finally_entry )
748
-
751
+
749
752
# Return case
750
753
builder .activate_block (return_entry )
751
754
builder .goto (finally_entry )
752
-
755
+
753
756
# Exception case - need to catch to clear the error indicator
754
757
builder .activate_block (err_handler )
755
758
# Catch the error to clear Python's error indicator
756
759
old_exc = builder .call_c (error_catch_op , [], line )
757
760
# We're not going to use old_exc since it won't survive await
758
761
# The exception is now in sys.exc_info()
759
762
builder .goto (finally_entry )
760
-
763
+
761
764
# Finally block
762
765
builder .activate_block (finally_entry )
763
-
766
+
764
767
# Execute finally body
765
768
finally_body ()
766
-
769
+
767
770
# After finally, we need to handle exceptions carefully:
768
771
# 1. If finally raised a new exception, it's in the error indicator - let it propagate
769
772
# 2. If finally didn't raise, check if we need to reraise the original from sys.exc_info()
770
773
# 3. If there was a return, return that value
771
774
# 4. Otherwise, normal exit
772
-
775
+
773
776
# First, check if there's a current exception in the error indicator
774
777
# (this would be from the finally block)
775
778
no_current_exc = builder .call_c (no_err_occurred_op , [], line )
776
779
finally_raised = BasicBlock ()
777
780
check_original = BasicBlock ()
778
781
builder .add (Branch (no_current_exc , check_original , finally_raised , Branch .BOOL ))
779
-
782
+
780
783
# Finally raised an exception - let it propagate naturally
781
784
builder .activate_block (finally_raised )
782
785
builder .call_c (keep_propagating_op , [], NO_TRACEBACK_LINE_NO )
783
786
builder .add (Unreachable ())
784
-
787
+
785
788
# No exception from finally, check if we need to handle return or original exception
786
789
builder .activate_block (check_original )
787
-
790
+
788
791
# Check if we have a return value
789
792
if ret_reg :
790
793
return_block , check_old_exc = BasicBlock (), BasicBlock ()
791
794
builder .add (Branch (builder .read (ret_reg ), check_old_exc , return_block , Branch .IS_ERROR ))
792
-
795
+
793
796
builder .activate_block (return_block )
794
797
builder .nonlocal_control [- 1 ].gen_return (builder , builder .read (ret_reg ), - 1 )
795
-
798
+
796
799
builder .activate_block (check_old_exc )
797
-
800
+
798
801
# Check if we need to reraise the original exception from sys.exc_info
799
802
exc_info = builder .call_c (get_exc_info_op , [], line )
800
803
exc_type = builder .add (TupleGet (exc_info , 0 , line ))
801
-
804
+
802
805
# Check if exc_type is None
803
806
none_obj = builder .none_object ()
804
807
has_exc = builder .binary_op (exc_type , none_obj , "is not" , line )
805
-
808
+
806
809
reraise_block , exit_block = BasicBlock (), BasicBlock ()
807
810
builder .add (Branch (has_exc , reraise_block , exit_block , Branch .BOOL ))
808
-
811
+
809
812
# Reraise the original exception
810
813
builder .activate_block (reraise_block )
811
814
builder .call_c (reraise_exception_op , [], NO_TRACEBACK_LINE_NO )
812
815
builder .add (Unreachable ())
813
-
816
+
814
817
# Normal exit
815
818
builder .activate_block (exit_block )
816
819
@@ -856,9 +859,13 @@ def transform_try_body() -> None:
856
859
body = t .finally_body
857
860
858
861
if use_async_version :
859
- transform_try_finally_stmt_async (builder , transform_try_body , lambda : builder .accept (body ), t .line )
862
+ transform_try_finally_stmt_async (
863
+ builder , transform_try_body , lambda : builder .accept (body ), t .line
864
+ )
860
865
else :
861
- transform_try_finally_stmt (builder , transform_try_body , lambda : builder .accept (body ), t .line )
866
+ transform_try_finally_stmt (
867
+ builder , transform_try_body , lambda : builder .accept (body ), t .line
868
+ )
862
869
else :
863
870
transform_try_except_stmt (builder , t )
864
871
@@ -949,7 +956,7 @@ def finally_body() -> None:
949
956
builder ,
950
957
lambda : transform_try_except (builder , try_body , [(None , None , except_body )], None , line ),
951
958
finally_body ,
952
- line
959
+ line ,
953
960
)
954
961
955
962
0 commit comments