Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions crates/codegen/src/compile.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2406,7 +2406,13 @@ impl<'warnings> Compiler<'warnings> {
}

if let FBlockDatum::FinallyBody(ref body) = info.fb_datum {
// This is an extra copy of the finally body, emitted for the
// path that leaves the try block early. The try statement
// emits its own copies afterwards, so rewind the symbol table
// cursors and leave the nested scopes for those copies.
let symbol_table_cursors = self.current_symbol_table_cursors();
self.compile_statements(body)?;
self.set_symbol_table_cursors(symbol_table_cursors);
}

if preserve_tos {
Expand Down
82 changes: 82 additions & 0 deletions extra_tests/snippets/syntax_try.py
Original file line number Diff line number Diff line change
Expand Up @@ -285,3 +285,85 @@ def y():
try:
pass
""")


# leaving the try block early emits an extra copy of the finally body, which
# must not consume the symbol tables of the nested scopes it contains
def return_from_try():
log = []
try:
return "returned"
finally:
log.append((lambda x: x * 2)(3))
log.append({t for t in [1, 2]})
log.append([t for t in [3]])
log.append({k: k for k in [4]})

def nested():
return 5

class Nested:
value = 6

assert log == [6, {1, 2}, [3], {4: 4}], log
assert nested() == 5
assert Nested.value == 6


assert return_from_try() == "returned"


def break_and_continue_from_try():
seen = []
for i in range(4):
try:
if i == 1:
continue
if i == 3:
break
seen.append(i)
finally:
seen.append({t for t in [i]})
return seen


assert break_and_continue_from_try() == [0, {0}, {1}, 2, {2}, {3}]


def return_from_try_runs_finally_once():
log = []

def inner():
try:
return "value"
finally:
log.append(sorted({t for t in "ab"}))

assert inner() == "value"
return log


assert return_from_try_runs_finally_once() == [["a", "b"]]


def generator_return_from_try():
log = []

def gen():
try:
return (yield "yielded")
finally:
log.append([t for t in "z"])

g = gen()
assert g.send(None) == "yielded"
try:
g.send("sent")
except StopIteration as stop:
assert stop.value == "sent", stop.value
else:
assert False, "generator did not stop"
return log


assert generator_return_from_try() == [["z"]]
Loading