code += "): yield a"
return code
- CO_MAXBLOCKS = 20 # static nesting limit of the compiler
+ CO_MAXBLOCKS = 21 # static nesting limit of the compiler
+ MAX_MANAGERS = CO_MAXBLOCKS - 1 # One for the StopIteration block
- for n in range(CO_MAXBLOCKS):
+ for n in range(MAX_MANAGERS):
with self.subTest(f"within range: {n=}"):
compile(get_code(n), "<string>", "exec")
- for n in range(CO_MAXBLOCKS, CO_MAXBLOCKS + 5):
+ for n in range(MAX_MANAGERS, MAX_MANAGERS + 5):
+ with self.subTest(f"out of range: {n=}"):
+ self._check_error(get_code(n), "too many statically nested blocks")
+
+ @support.cpython_only
+ def test_async_with_statement_many_context_managers(self):
+ # See gh-116767
+
+ def get_code(n):
+ code = [ textwrap.dedent("""
+ async def bug():
+ async with (
+ a
+ """) ]
+ for i in range(n):
+ code.append(f" as a{i}, a\n")
+ code.append("): yield a")
+ return "".join(code)
+
+ CO_MAXBLOCKS = 21 # static nesting limit of the compiler
+ MAX_MANAGERS = CO_MAXBLOCKS - 1 # One for the StopIteration block
+
+ for n in range(MAX_MANAGERS):
+ with self.subTest(f"within range: {n=}"):
+ compile(get_code(n), "<string>", "exec")
+
+ for n in range(MAX_MANAGERS, MAX_MANAGERS + 5):
with self.subTest(f"out of range: {n=}"):
self._check_error(get_code(n), "too many statically nested blocks")
while 20:
while 21:
while 22:
- break
+ while 23:
+ break
"""
self._check_error(source, "too many statically nested blocks")
enum fblocktype { WHILE_LOOP, FOR_LOOP, TRY_EXCEPT, FINALLY_TRY, FINALLY_END,
WITH, ASYNC_WITH, HANDLER_CLEANUP, POP_VALUE, EXCEPTION_HANDLER,
- EXCEPTION_GROUP_HANDLER, ASYNC_COMPREHENSION_GENERATOR };
+ EXCEPTION_GROUP_HANDLER, ASYNC_COMPREHENSION_GENERATOR,
+ STOP_ITERATION };
struct fblockinfo {
enum fblocktype fb_type;
case EXCEPTION_HANDLER:
case EXCEPTION_GROUP_HANDLER:
case ASYNC_COMPREHENSION_GENERATOR:
+ case STOP_ITERATION:
return SUCCESS;
case FOR_LOOP:
c->u->u_metadata.u_argcount = asdl_seq_LEN(args->args);
c->u->u_metadata.u_posonlyargcount = asdl_seq_LEN(args->posonlyargs);
c->u->u_metadata.u_kwonlyargcount = asdl_seq_LEN(args->kwonlyargs);
+
+ NEW_JUMP_TARGET_LABEL(c, start);
+ USE_LABEL(c, start);
+ bool add_stopiteration_handler = c->u->u_ste->ste_coroutine || c->u->u_ste->ste_generator;
+ if (add_stopiteration_handler) {
+ /* wrap_in_stopiteration_handler will push a block, so we need to account for that */
+ RETURN_IF_ERROR(
+ compiler_push_fblock(c, NO_LOCATION, STOP_ITERATION,
+ start, NO_LABEL, NULL));
+ }
+
for (Py_ssize_t i = docstring ? 1 : 0; i < asdl_seq_LEN(body); i++) {
VISIT_IN_SCOPE(c, stmt, (stmt_ty)asdl_seq_GET(body, i));
}
- if (c->u->u_ste->ste_coroutine || c->u->u_ste->ste_generator) {
+ if (add_stopiteration_handler) {
if (wrap_in_stopiteration_handler(c) < 0) {
compiler_exit_scope(c);
return ERROR;
}
+ compiler_pop_fblock(c, STOP_ITERATION, start);
}
PyCodeObject *co = optimize_and_assemble(c, 1);
compiler_exit_scope(c);