Skip to content

Commit bd2f27a

Browse files
author
Carl Meyer
committed
[py-compiler] relax async comprehension nesting when inlined
Summary: In cinder 3.8 we unintentionally allowed async comprehensions to nest inside non-async ones, due to comprehension inlining. When we ported comprehension inlining to 3.10, we closed this hole for better fidelity to upstream compiler behavior, but that means we have to fix the places in IGSRV that now break this rule. And this doesn't seem worth it considering the restriction is lifted in Python 3.11 anyway: python/cpython#6766 This diff just restores the 3.8 behavior of comprehension inlining allowing async comprehensions nested inside non-async ones. Facebook: this should unblock 3.10 testing on IGSRV. Test Plan: Modified test to specify new behavior. Reviewers: itamaro, emacs, #cinder_porting Reviewed By: itamaro Subscribers: mpage, jackyzhang, orvid Differential Revision: https://phabricator.intern.facebook.com/D39825885 Tags: publish_when_ready, cinder-310-exclusive
1 parent b016da6 commit bd2f27a

File tree

2 files changed

+18
-28
lines changed

2 files changed

+18
-28
lines changed

Lib/compiler/pycodegen.py

Lines changed: 0 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -3026,10 +3026,6 @@ class CinderBaseCodeGenerator(CodeGenerator):
30263026
class CinderCodeGenerator(CinderBaseCodeGenerator):
30273027
_SymbolVisitor = symbols.CinderSymbolVisitor
30283028

3029-
def __init__(self, *args, **kwargs):
3030-
super().__init__(*args, **kwargs)
3031-
self.inlined_comprehensions = []
3032-
30333029
def set_qual_name(self, qualname):
30343030
self._qual_name = qualname
30353031

@@ -3125,24 +3121,6 @@ def compile_comprehension(
31253121
if scope.inlined:
31263122
# for inlined comprehension process with current generator
31273123
gen = self
3128-
if self.inlined_comprehensions:
3129-
# Have a parent inlined comprehension; use that
3130-
is_async_function = self.inlined_comprehensions[-1].coroutine
3131-
else:
3132-
# No parent inlined comprehension; use outer function
3133-
is_async_function = self.scope.coroutine
3134-
self.inlined_comprehensions.append(scope)
3135-
is_async_generator = scope.coroutine
3136-
# TODO also add check for PyCF_ALLOW_TOP_LEVEL_AWAIT
3137-
if (
3138-
is_async_generator
3139-
and not is_async_function
3140-
and not isinstance(node, ast.GeneratorExp)
3141-
):
3142-
raise self.syntax_error(
3143-
"asynchronous comprehension outside of an asynchronous function",
3144-
node,
3145-
)
31463124
else:
31473125
gen = self.make_func_codegen(
31483126
node, self.conjure_arguments([ast.arg(".0", None)]), name, node.lineno
@@ -3193,9 +3171,6 @@ def compile_comprehension(
31933171
self.emit("LOAD_CONST", None)
31943172
self.emit("YIELD_FROM")
31953173

3196-
if scope.inlined:
3197-
self.inlined_comprehensions.pop()
3198-
31993174

32003175
def get_default_generator():
32013176
if "cinder" in sys.version:

Lib/test/test_compiler/test_py310.py

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,10 @@
11
import io
22
from compiler.dis_stable import Disassembler
3+
from compiler.pycodegen import (
4+
BaseCodeGenerator,
5+
CinderCodeGenerator,
6+
PythonCodeGenerator,
7+
)
38
from textwrap import dedent
49

510
from .common import CompilerTest
@@ -21,13 +26,15 @@ def _check(self, src, optimize=-1):
2126
expected = dump_code(compile(src, "", mode="exec", optimize=optimize))
2227
self.assertEqual(actual, expected)
2328

24-
def _check_error(self, src, msg_contains, *, optimize=-1):
29+
def _check_error(
30+
self, src, msg_contains, *, optimize=-1, generator=PythonCodeGenerator
31+
):
2532
src = dedent(src).strip()
2633
with self.assertRaises(SyntaxError) as ctx:
2734
compile(src, "", mode="exec", optimize=optimize)
2835
cmsg = str(ctx.exception.msg)
2936
with self.assertRaises(SyntaxError) as ctx:
30-
self.compile(src, optimize=optimize)
37+
self.compile(src, optimize=optimize, generator=generator)
3138
pymsg = str(ctx.exception.msg)
3239
self.assertEqual(pymsg, cmsg)
3340
self.assertIn(pymsg, msg_contains)
@@ -57,6 +64,14 @@ def test_no_nested_async_comprehension(self):
5764
async def foo(a):
5865
return {k: [y for y in k if await bar(y)] for k in a}
5966
"""
67+
68+
# The base code generator matches 3.10 upstream and thus has this
69+
# restriction, but the restriction has been lifted in 3.11
70+
# (see https://github.com/python/cpython/pull/6766), so we also lift
71+
# it in CinderCodeGenerator.
6072
self._check_error(
61-
codestr, "asynchronous comprehension outside of an asynchronous function"
73+
codestr,
74+
"asynchronous comprehension outside of an asynchronous function",
75+
generator=BaseCodeGenerator,
6276
)
77+
self.compile(codestr, generator=CinderCodeGenerator)

0 commit comments

Comments
 (0)