Skip to content

Commit ab61ec2

Browse files
authored
[mypyc] Free coroutine after await encounters StopIteration (#19231)
Previously the awaited coroutine could stay alive until the coroutine that performed the await was freed, delaying object reclamation. The reference counting analysis doesn't understand registers spilled to the environment, so we need to manually clear the value. Consider code like this: ``` async def foo() -> None: await bar() await zar() ``` Previously, the `bar()` coroutine was only freed at end of `foo()`. Now we release it before `await zar()`, as expected.
1 parent 71942c0 commit ab61ec2

File tree

1 file changed

+4
-0
lines changed

1 file changed

+4
-0
lines changed

mypyc/irbuild/statement.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -940,6 +940,10 @@ def emit_yield_from_or_await(
940940
# If it wasn't, this reraises the exception.
941941
builder.activate_block(stop_block)
942942
builder.assign(result, builder.call_c(check_stop_op, [], line), line)
943+
# Clear the spilled iterator/coroutine so that it will be freed.
944+
# Otherwise, the freeing of the spilled register would likely be delayed.
945+
err = builder.add(LoadErrorValue(object_rprimitive))
946+
builder.assign(iter_reg, err, line)
943947
builder.goto(done_block)
944948

945949
builder.activate_block(main_block)

0 commit comments

Comments
 (0)