114114 no_err_occurred_op ,
115115 propagate_if_error_op ,
116116 raise_exception_op ,
117+ raise_exception_with_tb_op ,
117118 reraise_exception_op ,
118119 restore_exc_info_op ,
119120)
@@ -1053,7 +1054,7 @@ def _transform_with_contextmanager(
10531054 expr .arg_names ,
10541055 )
10551056 wrapped_call .line = line
1056- gen = builder .accept (wrapped_call )
1057+ gen = builder .maybe_spill ( builder . accept (wrapped_call ) )
10571058
10581059 def raise_runtime_error_from_none (msg : str ) -> None :
10591060 runtime_error = builder .load_module_attr_by_fullname ("builtins.RuntimeError" , line )
@@ -1077,7 +1078,7 @@ def raise_runtime_error_from_none(msg: str) -> None:
10771078 # target = next(gen)
10781079 # except StopIteration:
10791080 # raise RuntimeError("generator didn't yield") from None
1080- mgr_target = builder .call_c (next_raw_op , [gen ], line )
1081+ mgr_target = builder .call_c (next_raw_op , [builder . read ( gen ) ], line )
10811082
10821083 runtime_block , main_block = BasicBlock (), BasicBlock ()
10831084 builder .add (Branch (mgr_target , runtime_block , main_block , Branch .IS_ERROR ))
@@ -1109,6 +1110,8 @@ def raise_runtime_error_from_none(msg: str) -> None:
11091110
11101111 builder .activate_block (main_block )
11111112
1113+ exc = builder .maybe_spill_assignable (builder .true ())
1114+
11121115 # try:
11131116 # {body}
11141117
@@ -1117,33 +1120,58 @@ def try_body() -> None:
11171120 builder .assign (builder .get_assignment_target (target ), mgr_target , line )
11181121 with_body ()
11191122
1120- # except Exception as e:
1123+ # except BaseException as e:
11211124 # try:
1122- # gen.throw(e )
1125+ # gen.throw(type, value, traceback )
11231126 # except StopIteration as e2:
11241127 # if e2 is not e:
11251128 # raise
11261129 # return
11271130 # except RuntimeError:
1128- # # TODO: check the traceback munging
11291131 # raise
11301132 # except BaseException:
11311133 # # approximately
11321134 # raise
11331135
11341136 def except_body () -> None :
1135- exc_original = builder .call_c (get_exc_value_op , [], line )
1137+ builder .assign (exc , builder .false (), line )
1138+ exc_info = builder .call_c (get_exc_info_op , [], line )
1139+ exc_type = builder .add (TupleGet (exc_info , 0 , line ))
1140+ exc_value = builder .add (TupleGet (exc_info , 1 , line ))
1141+ exc_tb = builder .add (TupleGet (exc_info , 2 , line ))
1142+ exc_value_target = builder .maybe_spill_assignable (exc_value )
1143+
1144+ def reraise_original () -> None :
1145+ builder .call_c (
1146+ raise_exception_with_tb_op ,
1147+ [exc_type , builder .read (exc_value_target ), exc_tb ],
1148+ line ,
1149+ )
1150+ builder .add (Unreachable ())
1151+
1152+ # Make sure we have an exception instance so identity comparisons are reliable.
1153+ none = builder .none_object ()
1154+ is_none = builder .binary_op (builder .read (exc_value_target ), none , "is" , line )
1155+ value_block , value_done = BasicBlock (), BasicBlock ()
1156+ builder .add (Branch (is_none , value_block , value_done , Branch .BOOL ))
1157+ builder .activate_block (value_block )
1158+ new_value = builder .py_call (exc_type , [], line )
1159+ builder .assign (exc_value_target , new_value , line )
1160+ builder .goto (value_done )
1161+ builder .activate_block (value_done )
11361162
11371163 error_block , no_error_block = BasicBlock (), BasicBlock ()
1138-
11391164 builder .builder .push_error_handler (error_block )
11401165 builder .goto_and_activate (BasicBlock ())
1141- builder .py_call (builder .py_get_attr (gen , "throw" , line ), [exc_original ], line )
1166+ builder .py_call (
1167+ builder .py_get_attr (builder .read (gen ), "throw" , line ),
1168+ [exc_type , builder .read (exc_value_target ), exc_tb ],
1169+ line ,
1170+ )
11421171 builder .goto (no_error_block )
11431172 builder .builder .pop_error_handler ()
11441173
11451174 builder .activate_block (no_error_block )
1146- builder .py_call (builder .py_get_attr (gen , "close" , line ), [], line )
11471175 builder .add (
11481176 RaiseStandardError (
11491177 RaiseStandardError .RUNTIME_ERROR , "generator didn't stop after throw()" , line
@@ -1155,50 +1183,90 @@ def except_body() -> None:
11551183 throw_old_exc = builder .maybe_spill (builder .call_c (error_catch_op , [], line ))
11561184 stop_iteration = builder .load_module_attr_by_fullname ("builtins.StopIteration" , line )
11571185 is_stop_iteration = builder .call_c (exc_matches_op , [stop_iteration ], line )
1158- stop_block , propagate_block = BasicBlock (), BasicBlock ()
1159- builder .add (Branch (is_stop_iteration , stop_block , propagate_block , Branch .BOOL ))
1186+ stop_block , runtime_check_block = BasicBlock (), BasicBlock ()
1187+ builder .add (Branch (is_stop_iteration , stop_block , runtime_check_block , Branch .BOOL ))
1188+
1189+ suppress_block = BasicBlock ()
1190+
1191+ builder .activate_block (stop_block )
1192+ stop_exc = builder .call_c (get_exc_value_op , [], line )
1193+ is_same_exc = builder .binary_op (stop_exc , builder .read (exc_value_target ), "is" , line )
1194+ propagate_block = BasicBlock ()
1195+ builder .add (Branch (is_same_exc , propagate_block , suppress_block , Branch .BOOL ))
11601196
11611197 builder .activate_block (propagate_block )
1198+ reraise_original ()
1199+
1200+ builder .activate_block (runtime_check_block )
1201+ runtime_error = builder .load_module_attr_by_fullname ("builtins.RuntimeError" , line )
1202+ is_runtime_error = builder .call_c (exc_matches_op , [runtime_error ], line )
1203+ runtime_block , other_block = BasicBlock (), BasicBlock ()
1204+ builder .add (Branch (is_runtime_error , runtime_block , other_block , Branch .BOOL ))
1205+
1206+ builder .activate_block (runtime_block )
1207+ runtime_exc = builder .call_c (get_exc_value_op , [], line )
1208+ is_same_runtime = builder .binary_op (runtime_exc , builder .read (exc_value_target ), "is" , line )
1209+ runtime_same_block , runtime_cause_block = BasicBlock (), BasicBlock ()
1210+ builder .add (Branch (is_same_runtime , runtime_same_block , runtime_cause_block , Branch .BOOL ))
1211+
1212+ builder .activate_block (runtime_same_block )
1213+ reraise_original ()
1214+
1215+ builder .activate_block (runtime_cause_block )
1216+ is_stop = builder .binary_op (exc_type , stop_iteration , "is" , line )
1217+ cause_block , reraise_runtime_block = BasicBlock (), BasicBlock ()
1218+ builder .add (Branch (is_stop , cause_block , reraise_runtime_block , Branch .BOOL ))
1219+
1220+ builder .activate_block (cause_block )
1221+ cause = builder .py_get_attr (runtime_exc , "__cause__" , line )
1222+ is_cause = builder .binary_op (cause , builder .read (exc_value_target ), "is" , line )
1223+ cause_match_block , cause_miss_block = BasicBlock (), BasicBlock ()
1224+ builder .add (Branch (is_cause , cause_match_block , cause_miss_block , Branch .BOOL ))
1225+
1226+ builder .activate_block (cause_match_block )
1227+ reraise_original ()
1228+
1229+ builder .activate_block (cause_miss_block )
11621230 builder .call_c (reraise_exception_op , [], NO_TRACEBACK_LINE_NO )
11631231 builder .add (Unreachable ())
11641232
1165- builder .activate_block (stop_block )
1166- stop_exc = builder .call_c (get_exc_value_op , [], line )
1167- is_same_exc = builder .binary_op ( stop_exc , exc_original , "is" , line )
1233+ builder .activate_block (reraise_runtime_block )
1234+ builder .call_c (reraise_exception_op , [], NO_TRACEBACK_LINE_NO )
1235+ builder .add ( Unreachable () )
11681236
1169- suppress_block , reraise_block = BasicBlock (), BasicBlock ()
1170- builder .add (Branch (is_same_exc , reraise_block , suppress_block , Branch .BOOL ))
1237+ builder .activate_block (other_block )
1238+ other_exc = builder .call_c (get_exc_value_op , [], line )
1239+ is_same_other = builder .binary_op (other_exc , builder .read (exc_value_target ), "is" , line )
1240+ other_same_block , other_reraise_block = BasicBlock (), BasicBlock ()
1241+ builder .add (Branch (is_same_other , other_same_block , other_reraise_block , Branch .BOOL ))
11711242
1172- builder .activate_block (reraise_block )
1243+ builder .activate_block (other_same_block )
1244+ reraise_original ()
1245+
1246+ builder .activate_block (other_reraise_block )
11731247 builder .call_c (reraise_exception_op , [], NO_TRACEBACK_LINE_NO )
11741248 builder .add (Unreachable ())
11751249
11761250 builder .activate_block (suppress_block )
11771251 builder .call_c (restore_exc_info_op , [builder .read (throw_old_exc )], line )
11781252 builder .call_c (error_clear_op , [], - 1 )
11791253
1180- # TODO: actually do the exceptions
11811254 handlers = [(None , None , except_body )]
11821255
1183- # else :
1256+ # finally (normal exit path) :
11841257 # try:
11851258 # next(gen)
11861259 # except StopIteration:
11871260 # pass
11881261 # else:
1189- # try:
1190- # raise RuntimeError("generator didn't stop")
1191- # finally:
1192- # gen.close()
1262+ # raise RuntimeError("generator didn't stop")
11931263
1194- def else_body () -> None :
1264+ def normal_exit_body () -> None :
11951265 value = builder .call_c (next_raw_op , [builder .read (gen )], line )
1196- stop_block , close_block = BasicBlock (), BasicBlock ()
1197- builder .add (Branch (value , stop_block , close_block , Branch .IS_ERROR ))
1266+ stop_block , error_block = BasicBlock (), BasicBlock ()
1267+ builder .add (Branch (value , stop_block , error_block , Branch .IS_ERROR ))
11981268
1199- builder .activate_block (close_block )
1200- # TODO: this isn't exactly the right order
1201- builder .py_call (builder .py_get_attr (gen , "close" , line ), [], line )
1269+ builder .activate_block (error_block )
12021270 builder .add (
12031271 RaiseStandardError (RaiseStandardError .RUNTIME_ERROR , "generator didn't stop" , line )
12041272 )
@@ -1229,7 +1297,19 @@ def else_body() -> None:
12291297 builder .activate_block (implicit_stop_block )
12301298 builder .call_c (error_clear_op , [], - 1 )
12311299
1232- transform_try_except (builder , try_body , handlers , else_body , line )
1300+ def finally_body () -> None :
1301+ out_block , exit_block = BasicBlock (), BasicBlock ()
1302+ builder .add (Branch (builder .read (exc ), exit_block , out_block , Branch .BOOL ))
1303+ builder .activate_block (exit_block )
1304+ normal_exit_body ()
1305+ builder .goto_and_activate (out_block )
1306+
1307+ transform_try_finally_stmt (
1308+ builder ,
1309+ lambda : transform_try_except (builder , try_body , handlers , None , line ),
1310+ finally_body ,
1311+ line ,
1312+ )
12331313
12341314
12351315def transform_with_stmt (builder : IRBuilder , o : WithStmt ) -> None :
0 commit comments