Skip to content

Commit e09ca05

Browse files
committed
codex yolo
1 parent 37b4381 commit e09ca05

File tree

2 files changed

+263
-26
lines changed

2 files changed

+263
-26
lines changed

mypyc/irbuild/statement.py

Lines changed: 92 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,7 @@
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))
@@ -1117,33 +1118,57 @@ def try_body() -> None:
11171118
builder.assign(builder.get_assignment_target(target), mgr_target, line)
11181119
with_body()
11191120

1120-
# except Exception as e:
1121+
# except BaseException as e:
11211122
# try:
1122-
# gen.throw(e)
1123+
# gen.throw(type, value, traceback)
11231124
# except StopIteration as e2:
11241125
# if e2 is not e:
11251126
# raise
11261127
# return
11271128
# except RuntimeError:
1128-
# # TODO: check the traceback munging
11291129
# raise
11301130
# except BaseException:
11311131
# # approximately
11321132
# raise
11331133

11341134
def except_body() -> None:
1135-
exc_original = builder.call_c(get_exc_value_op, [], line)
1135+
exc_info = builder.call_c(get_exc_info_op, [], line)
1136+
exc_type = builder.add(TupleGet(exc_info, 0, line))
1137+
exc_value = builder.add(TupleGet(exc_info, 1, line))
1138+
exc_tb = builder.add(TupleGet(exc_info, 2, line))
1139+
exc_value_target = builder.maybe_spill_assignable(exc_value)
1140+
1141+
def reraise_original() -> None:
1142+
builder.call_c(
1143+
raise_exception_with_tb_op,
1144+
[exc_type, builder.read(exc_value_target), exc_tb],
1145+
line,
1146+
)
1147+
builder.add(Unreachable())
1148+
1149+
# Make sure we have an exception instance so identity comparisons are reliable.
1150+
none = builder.none_object()
1151+
is_none = builder.binary_op(builder.read(exc_value_target), none, "is", line)
1152+
value_block, value_done = BasicBlock(), BasicBlock()
1153+
builder.add(Branch(is_none, value_block, value_done, Branch.BOOL))
1154+
builder.activate_block(value_block)
1155+
new_value = builder.py_call(exc_type, [], line)
1156+
builder.assign(exc_value_target, new_value, line)
1157+
builder.goto(value_done)
1158+
builder.activate_block(value_done)
11361159

11371160
error_block, no_error_block = BasicBlock(), BasicBlock()
1138-
11391161
builder.builder.push_error_handler(error_block)
11401162
builder.goto_and_activate(BasicBlock())
1141-
builder.py_call(builder.py_get_attr(gen, "throw", line), [exc_original], line)
1163+
builder.py_call(
1164+
builder.py_get_attr(builder.read(gen), "throw", line),
1165+
[exc_type, builder.read(exc_value_target), exc_tb],
1166+
line,
1167+
)
11421168
builder.goto(no_error_block)
11431169
builder.builder.pop_error_handler()
11441170

11451171
builder.activate_block(no_error_block)
1146-
builder.py_call(builder.py_get_attr(gen, "close", line), [], line)
11471172
builder.add(
11481173
RaiseStandardError(
11491174
RaiseStandardError.RUNTIME_ERROR, "generator didn't stop after throw()", line
@@ -1155,21 +1180,67 @@ def except_body() -> None:
11551180
throw_old_exc = builder.maybe_spill(builder.call_c(error_catch_op, [], line))
11561181
stop_iteration = builder.load_module_attr_by_fullname("builtins.StopIteration", line)
11571182
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))
1183+
stop_block, runtime_check_block = BasicBlock(), BasicBlock()
1184+
builder.add(Branch(is_stop_iteration, stop_block, runtime_check_block, Branch.BOOL))
1185+
1186+
suppress_block = BasicBlock()
1187+
1188+
builder.activate_block(stop_block)
1189+
stop_exc = builder.call_c(get_exc_value_op, [], line)
1190+
is_same_exc = builder.binary_op(stop_exc, builder.read(exc_value_target), "is", line)
1191+
propagate_block = BasicBlock()
1192+
builder.add(Branch(is_same_exc, propagate_block, suppress_block, Branch.BOOL))
11601193

11611194
builder.activate_block(propagate_block)
1195+
reraise_original()
1196+
1197+
builder.activate_block(runtime_check_block)
1198+
runtime_error = builder.load_module_attr_by_fullname("builtins.RuntimeError", line)
1199+
is_runtime_error = builder.call_c(exc_matches_op, [runtime_error], line)
1200+
runtime_block, other_block = BasicBlock(), BasicBlock()
1201+
builder.add(Branch(is_runtime_error, runtime_block, other_block, Branch.BOOL))
1202+
1203+
builder.activate_block(runtime_block)
1204+
runtime_exc = builder.call_c(get_exc_value_op, [], line)
1205+
is_same_runtime = builder.binary_op(runtime_exc, builder.read(exc_value_target), "is", line)
1206+
runtime_same_block, runtime_cause_block = BasicBlock(), BasicBlock()
1207+
builder.add(Branch(is_same_runtime, runtime_same_block, runtime_cause_block, Branch.BOOL))
1208+
1209+
builder.activate_block(runtime_same_block)
1210+
reraise_original()
1211+
1212+
builder.activate_block(runtime_cause_block)
1213+
is_stop = builder.binary_op(exc_type, stop_iteration, "is", line)
1214+
cause_block, reraise_runtime_block = BasicBlock(), BasicBlock()
1215+
builder.add(Branch(is_stop, cause_block, reraise_runtime_block, Branch.BOOL))
1216+
1217+
builder.activate_block(cause_block)
1218+
cause = builder.py_get_attr(runtime_exc, "__cause__", line)
1219+
is_cause = builder.binary_op(cause, builder.read(exc_value_target), "is", line)
1220+
cause_match_block, cause_miss_block = BasicBlock(), BasicBlock()
1221+
builder.add(Branch(is_cause, cause_match_block, cause_miss_block, Branch.BOOL))
1222+
1223+
builder.activate_block(cause_match_block)
1224+
reraise_original()
1225+
1226+
builder.activate_block(cause_miss_block)
11621227
builder.call_c(reraise_exception_op, [], NO_TRACEBACK_LINE_NO)
11631228
builder.add(Unreachable())
11641229

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)
1230+
builder.activate_block(reraise_runtime_block)
1231+
builder.call_c(reraise_exception_op, [], NO_TRACEBACK_LINE_NO)
1232+
builder.add(Unreachable())
11681233

1169-
suppress_block, reraise_block = BasicBlock(), BasicBlock()
1170-
builder.add(Branch(is_same_exc, reraise_block, suppress_block, Branch.BOOL))
1234+
builder.activate_block(other_block)
1235+
other_exc = builder.call_c(get_exc_value_op, [], line)
1236+
is_same_other = builder.binary_op(other_exc, builder.read(exc_value_target), "is", line)
1237+
other_same_block, other_reraise_block = BasicBlock(), BasicBlock()
1238+
builder.add(Branch(is_same_other, other_same_block, other_reraise_block, Branch.BOOL))
11711239

1172-
builder.activate_block(reraise_block)
1240+
builder.activate_block(other_same_block)
1241+
reraise_original()
1242+
1243+
builder.activate_block(other_reraise_block)
11731244
builder.call_c(reraise_exception_op, [], NO_TRACEBACK_LINE_NO)
11741245
builder.add(Unreachable())
11751246

@@ -1186,19 +1257,14 @@ def except_body() -> None:
11861257
# except StopIteration:
11871258
# pass
11881259
# else:
1189-
# try:
1190-
# raise RuntimeError("generator didn't stop")
1191-
# finally:
1192-
# gen.close()
1260+
# raise RuntimeError("generator didn't stop")
11931261

11941262
def else_body() -> None:
11951263
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))
1264+
stop_block, error_block = BasicBlock(), BasicBlock()
1265+
builder.add(Branch(value, stop_block, error_block, Branch.IS_ERROR))
11981266

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)
1267+
builder.activate_block(error_block)
12021268
builder.add(
12031269
RaiseStandardError(RaiseStandardError.RUNTIME_ERROR, "generator didn't stop", line)
12041270
)

mypyc/test-data/run-functions.test

Lines changed: 171 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1240,6 +1240,177 @@ def test_special_case() -> None:
12401240
with f():
12411241
a.pop()
12421242

1243+
[case testContextManagerSpecialCaseSemantics]
1244+
from contextlib import contextmanager
1245+
from typing import Any, Generator, Iterator, cast
1246+
import traceback
1247+
1248+
@contextmanager
1249+
def cm_no_yield() -> Iterator[None]:
1250+
if False:
1251+
yield
1252+
return
1253+
1254+
@contextmanager
1255+
def cm_no_stop() -> Iterator[str]:
1256+
print("enter cm_no_stop")
1257+
yield "first"
1258+
print("after first")
1259+
yield "second"
1260+
1261+
@contextmanager
1262+
def cm_value_error_suppress() -> Iterator[None]:
1263+
try:
1264+
yield
1265+
except ValueError as e:
1266+
print("suppress", str(e))
1267+
1268+
@contextmanager
1269+
def cm_throw_twice() -> Iterator[None]:
1270+
try:
1271+
yield
1272+
except ValueError:
1273+
print("throw yield")
1274+
yield
1275+
1276+
@contextmanager
1277+
def cm_stop_passthrough() -> Iterator[None]:
1278+
yield
1279+
1280+
@contextmanager
1281+
def cm_stop_suppress() -> Iterator[None]:
1282+
try:
1283+
yield
1284+
except StopIteration as e:
1285+
print("suppress stop", str(e))
1286+
1287+
@contextmanager
1288+
def cm_value() -> Iterator[int]:
1289+
print("enter cm_value")
1290+
try:
1291+
yield 1
1292+
finally:
1293+
print("exit cm_value")
1294+
1295+
@contextmanager
1296+
def cm_gen() -> Iterator[int]:
1297+
print("cm enter")
1298+
try:
1299+
yield 1
1300+
finally:
1301+
print("cm exit")
1302+
1303+
def test_no_yield() -> None:
1304+
try:
1305+
with cm_no_yield():
1306+
print("body no yield")
1307+
except RuntimeError as e:
1308+
e_any = cast(Any, e)
1309+
print(
1310+
"no_yield",
1311+
str(e),
1312+
e_any.__cause__ is None,
1313+
e_any.__suppress_context__,
1314+
)
1315+
1316+
def test_no_stop() -> None:
1317+
try:
1318+
with cm_no_stop() as v:
1319+
print("body", v)
1320+
except RuntimeError as e:
1321+
print("no_stop", str(e))
1322+
1323+
def test_suppress_value_error() -> None:
1324+
with cm_value_error_suppress():
1325+
raise ValueError("boom")
1326+
print("after suppress value")
1327+
1328+
def test_throw_twice() -> None:
1329+
try:
1330+
with cm_throw_twice():
1331+
raise ValueError("oops")
1332+
except RuntimeError as e:
1333+
print("throw_twice", str(e))
1334+
1335+
def test_stop_iteration_passthrough() -> None:
1336+
try:
1337+
with cm_stop_passthrough():
1338+
raise StopIteration("stop")
1339+
except Exception as e:
1340+
print("stop passthrough", type(e).__name__, str(e))
1341+
1342+
def test_stop_iteration_suppress() -> None:
1343+
with cm_stop_suppress():
1344+
raise StopIteration("stop2")
1345+
print("after suppress stop")
1346+
1347+
def test_traceback() -> None:
1348+
try:
1349+
with cm_value():
1350+
raise ValueError("trace")
1351+
except Exception as e:
1352+
e_any = cast(Any, e)
1353+
tb = e_any.__traceback__
1354+
assert tb is not None
1355+
tb_mod = cast(Any, traceback)
1356+
names = [frame.name for frame in tb_mod.extract_tb(tb)]
1357+
print("traceback_has_cm_value", "cm_value" in names)
1358+
1359+
def test_generator_with_yield() -> None:
1360+
def gen() -> Generator[int, None, None]:
1361+
with cm_gen() as v:
1362+
yield v
1363+
print("after yield in with")
1364+
1365+
g = gen()
1366+
print(next(g))
1367+
try:
1368+
next(g)
1369+
except StopIteration:
1370+
print("gen done")
1371+
1372+
[file driver.py]
1373+
from native import (
1374+
test_no_yield,
1375+
test_no_stop,
1376+
test_suppress_value_error,
1377+
test_throw_twice,
1378+
test_stop_iteration_passthrough,
1379+
test_stop_iteration_suppress,
1380+
test_traceback,
1381+
test_generator_with_yield,
1382+
)
1383+
1384+
test_no_yield()
1385+
test_no_stop()
1386+
test_suppress_value_error()
1387+
test_throw_twice()
1388+
test_stop_iteration_passthrough()
1389+
test_stop_iteration_suppress()
1390+
test_traceback()
1391+
test_generator_with_yield()
1392+
[out]
1393+
no_yield generator didn't yield True True
1394+
enter cm_no_stop
1395+
body first
1396+
after first
1397+
no_stop generator didn't stop
1398+
suppress boom
1399+
after suppress value
1400+
throw yield
1401+
throw_twice generator didn't stop after throw()
1402+
stop passthrough StopIteration stop
1403+
suppress stop stop2
1404+
after suppress stop
1405+
enter cm_value
1406+
exit cm_value
1407+
traceback_has_cm_value False
1408+
cm enter
1409+
1
1410+
after yield in with
1411+
cm exit
1412+
gen done
1413+
12431414
[case testUnpackKwargsCompiled]
12441415
from typing import TypedDict
12451416
from typing_extensions import Unpack

0 commit comments

Comments
 (0)