8000 GH-90997: Wrap `yield from`/`await` in a virtual `try`/`except StopIteration` by brandtbucher · Pull Request #96010 · python/cpython · GitHub
[go: up one dir, main page]

Skip to content

GH-90997: Wrap yield from/await in a virtual try/except StopIteration #96010

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 13 commits into from
Aug 19, 2022
Prev Previous commit
Next Next commit
Cleanup
  • Loading branch information
brandtbucher committed Aug 15, 2022
commit a0953b13257de36d47ff41af6f8ef5171e63ab25
39 changes: 20 additions & 19 deletions Python/compile.c
8000
Original file line number Diff line number Diff line change
Expand Up @@ -1946,35 +1946,36 @@ compiler_call_exit_with_nones(struct compiler *c) {
static int
compiler_add_yield_from(struct compiler *c, int await)
{
NEW_JUMP_TARGET_LABEL(c, start);
NEW_JUMP_TARGET_LABEL(c, resume);
NEW_JUMP_TARGET_LABEL(c, error);
NEW_JUMP_TARGET_LABEL(c, stopiter);
NEW_JUMP_TARGET_LABEL(c, send);
NEW_JUMP_TARGET_LABEL(c, fail);
NEW_JUMP_TARGET_LABEL(c, stop);
NEW_JUMP_TARGET_LABEL(c, exit);
USE_LABEL(c, start);

USE_LABEL(c, send);
ADDOP_JUMP(c, SEND, exit);
USE_LABEL(c, resume);
// Set up a virtual try/except to handle StopIteration raised during a
// close() or throw():
ADDOP_JUMP(c, SETUP_FINALLY, error);
RETURN_IF_FALSE(compiler_push_fblock(c, TRY_EXCEPT, resume, NO_LABEL, NULL));
// The only way YIELD_VALUE can raise is if close() or throw() raises:
// Set up a virtual try/except to handle when StopIteration is raised during
// a close or throw call. The only way YIELD_VALUE raises if they do!
ADDOP_JUMP(c, SETUP_FINALLY, fail);
RETURN_IF_FALSE(compiler_push_fblock(c, TRY_EXCEPT, send, NO_LABEL, NULL));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There can be no call to compiler_unwind_fblock before this block is popped, so we don't need to push a block here.

ADDOP_I(c, YIELD_VALUE, 0);
compiler_pop_fblock(c, TRY_EXCEPT, resume);
compiler_pop_fblock(c, TRY_EXCEPT, send);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nor pop it here

ADDOP_NOLINE(c, POP_BLOCK);
ADDOP_I(c, RESUME, await ? 3 : 2);
ADDOP_JUMP(c, JUMP_NO_INTERRUPT, start);
USE_LABEL(c, error);
ADDOP_JUMP(c, JUMP_NO_INTERRUPT, send);

USE_LABEL(c, fail);
ADDOP_I(c, LOAD_EXCEPTION_TYPE, 1); // StopIteration
ADDOP(c, CHECK_EXC_MATCH);
ADDOP_JUMP(c, POP_JUMP_IF_TRUE, stopiter);
ADDOP_JUMP(c, POP_JUMP_IF_TRUE, stop);
ADDOP_I(c, RERAISE, 0);
USE_LABEL(c, stopiter);
// StopIteration was raised. Push the return value and continue execution:

USE_LABEL(c, stop);
// StopIteration was raised. Push the value and break out of the loop:
ADDOP_NAME(c, LOAD_ATTR, &_Py_ID(value), names);
ADDOP_I(c, SWAP, 3);
ADDOP(c, POP_TOP);
ADDOP(c, POP_TOP);
ADDOP(c, POP_TOP); // The thing we're yielding from.
ADDOP(c, POP_TOP); // The last sent value

USE_LABEL(c, exit);
return 1;
}
Expand Down
0