From f2dbc9102251f092e93b7c87cd8ffa5e9e5b880b Mon Sep 17 00:00:00 2001 From: Jeff Epler Date: Sun, 1 Mar 2020 09:40:43 -0600 Subject: [PATCH] py/compile: Raise an error on async with/for outside an async function. A simple reproducer is: async for x in (): x Before this change, it would cause an assertion error in mpy-cross and micropython-coverage. --- py/compile.c | 22 ++++++++++++++++------ tests/basics/async_syntaxerror.py | 19 +++++++++++++++++++ tests/basics/async_syntaxerror.py.exp | 2 ++ 3 files changed, 37 insertions(+), 6 deletions(-) create mode 100644 tests/basics/async_syntaxerror.py create mode 100644 tests/basics/async_syntaxerror.py.exp diff --git a/py/compile.c b/py/compile.c index 1182b8b1eb..0b02746a56 100644 --- a/py/compile.c +++ b/py/compile.c @@ -1970,13 +1970,23 @@ STATIC void compile_async_stmt(compiler_t *comp, mp_parse_node_struct_t *pns) { compile_funcdef(comp, pns0); scope_t *fscope = (scope_t *)pns0->nodes[4]; fscope->scope_flags |= MP_SCOPE_FLAG_GENERATOR; - } else if (MP_PARSE_NODE_STRUCT_KIND(pns0) == PN_for_stmt) { - // async for - compile_async_for_stmt(comp, pns0); } else { - // async with - assert(MP_PARSE_NODE_STRUCT_KIND(pns0) == PN_with_stmt); - compile_async_with_stmt(comp, pns0); + // async for/with; first verify the scope is a generator + int scope_flags = comp->scope_cur->scope_flags; + if (!(scope_flags & MP_SCOPE_FLAG_GENERATOR)) { + compile_syntax_error(comp, (mp_parse_node_t)pns0, + MP_ERROR_TEXT("async for/with outside async function")); + return; + } + + if (MP_PARSE_NODE_STRUCT_KIND(pns0) == PN_for_stmt) { + // async for + compile_async_for_stmt(comp, pns0); + } else { + // async with + assert(MP_PARSE_NODE_STRUCT_KIND(pns0) == PN_with_stmt); + compile_async_with_stmt(comp, pns0); + } } } #endif diff --git a/tests/basics/async_syntaxerror.py b/tests/basics/async_syntaxerror.py new file mode 100644 index 0000000000..ddd2c4b59e --- /dev/null +++ b/tests/basics/async_syntaxerror.py @@ -0,0 +1,19 @@ +# test syntax errors using async + +try: + exec +except NameError: + print("SKIP") + raise SystemExit + + +def test_syntax(code): + try: + exec(code) + print("no SyntaxError") + except SyntaxError: + print("SyntaxError") + + +test_syntax("async for x in (): x") +test_syntax("async with x: x") diff --git a/tests/basics/async_syntaxerror.py.exp b/tests/basics/async_syntaxerror.py.exp new file mode 100644 index 0000000000..5275689b41 --- /dev/null +++ b/tests/basics/async_syntaxerror.py.exp @@ -0,0 +1,2 @@ +SyntaxError +SyntaxError