Skip to content

Commit

Permalink
pythongh-109118: Disallow nested scopes within PEP 695 scopes within …
Browse files Browse the repository at this point in the history
…classes

Fixes python#109118. Fixes python#109194.
  • Loading branch information
JelleZijlstra committed Sep 9, 2023
1 parent 725ca36 commit d7be560
Show file tree
Hide file tree
Showing 3 changed files with 56 additions and 28 deletions.
59 changes: 31 additions & 28 deletions Lib/test/test_type_params.py
Expand Up @@ -436,11 +436,9 @@ class C[T]:
class Inner[U](make_base(T for _ in (1,)), make_base(T)):
pass
"""
C = run_code(code)["C"]
T, = C.__type_params__
base1, base2, _ = C.Inner.__bases__
self.assertEqual(list(base1.__arg__), [T])
self.assertEqual(base2.__arg__, "class")
with self.assertRaisesRegex(SyntaxError,
"Cannot use comprehension in annotation scope within class scope"):
run_code(code)

def test_listcomp_in_nested_class(self):
code = """
Expand All @@ -466,35 +464,40 @@ class C[T]:
class Inner[U](make_base([T for _ in (1,)]), make_base(T)):
pass
"""
C = run_code(code)["C"]
T, = C.__type_params__
base1, base2, _ = C.Inner.__bases__
self.assertEqual(base1.__arg__, [T])
self.assertEqual(base2.__arg__, "class")
with self.assertRaisesRegex(SyntaxError,
"Cannot use comprehension in annotation scope within class scope"):
run_code(code)

def test_gen_exp_in_generic_method(self):
code = """
class C[T]:
T = "class"
def meth[U](x: (T for _ in (1,)), y: T):
pass
"""
with self.assertRaisesRegex(SyntaxError,
"Cannot use comprehension in annotation scope within class scope"):
run_code(code)

def test_lambda_in_generic_alias(self):
code = """
class C[T]:
T = "class"
type Alias1[T] = lambda: T
type Alias2 = lambda: T
type Alias3[T] = (T for _ in (1,))
type Alias4 = (T for _ in (1,))
type Alias5[T] = [T for _ in (1,)]
type Alias6 = [T for _ in (1,)]
{}
"""
C = run_code(code)["C"]
outer_T = C.__type_params__[0]
T1 = C.Alias1.__type_params__[0]
self.assertIs(C.Alias1.__value__(), T1)
# Shouldn't pick up the T from the class scope
self.assertIs(C.Alias2.__value__(), outer_T)
T3 = C.Alias3.__type_params__[0]
self.assertEqual(list(C.Alias3.__value__), [T3])
self.assertEqual(list(C.Alias4.__value__), [outer_T])
T5 = C.Alias5.__type_params__[0]
self.assertEqual(C.Alias5.__value__, [T5])
self.assertEqual(C.Alias6.__value__, [outer_T])
error_cases = [
"type Alias1[T] = lambda: T",
"type Alias2 = lambda: T",
"type Alias3[T] = (T for _ in (1,))",
"type Alias4 = (T for _ in (1,))",
"type Alias5[T] = [T for _ in (1,)]",
"type Alias6 = [T for _ in (1,)]",
]
for case in error_cases:
with self.subTest(case=case):
with self.assertRaisesRegex(SyntaxError,
r"Cannot use [a-z]+ in annotation scope within class scope"):
run_code(code.format(case))


def make_base(arg):
Expand Down
@@ -0,0 +1,2 @@
Disallow nested scopes (lambdas, generator expressions, and comprehensions)
within PEP 695 annotation scopes that are nested within classes.
23 changes: 23 additions & 0 deletions Python/symtable.c
Expand Up @@ -2011,6 +2011,17 @@ symtable_visit_expr(struct symtable *st, expr_ty e)
VISIT(st, expr, e->v.UnaryOp.operand);
break;
case Lambda_kind: {
if (st->st_cur->ste_can_see_class_scope) {
// gh-109118
PyErr_Format(PyExc_SyntaxError,
"Cannot use lambda in annotation scope within class scope");
PyErr_RangedSyntaxLocationObject(st->st_filename,
e->lineno,
e->col_offset + 1,
e->end_lineno,
e->end_col_offset + 1);
VISIT_QUIT(st, 0);
}
if (e->v.Lambda.args->defaults)
VISIT_SEQ(st, expr, e->v.Lambda.args->defaults);
if (e->v.Lambda.args->kw_defaults)
Expand Down Expand Up @@ -2460,6 +2471,18 @@ symtable_handle_comprehension(struct symtable *st, expr_ty e,
identifier scope_name, asdl_comprehension_seq *generators,
expr_ty elt, expr_ty value)
{
if (st->st_cur->ste_can_see_class_scope) {
// gh-109118
PyErr_Format(PyExc_SyntaxError,
"Cannot use comprehension in annotation scope within class scope");
PyErr_RangedSyntaxLocationObject(st->st_filename,
e->lineno,
e->col_offset + 1,
e->end_lineno,
e->end_col_offset + 1);
VISIT_QUIT(st, 0);
}

int is_generator = (e->kind == GeneratorExp_kind);
comprehension_ty outermost = ((comprehension_ty)
asdl_seq_GET(generators, 0));
Expand Down

0 comments on commit d7be560

Please sign in to comment.