mirror of
https://github.com/python/cpython
synced 2024-09-15 22:10:19 +00:00
gh-109118: Disallow nested scopes within PEP 695 scopes within classes (#109196)
Fixes #109118. Fixes #109194. Co-authored-by: Carl Meyer <carl@oddbird.net>
This commit is contained in:
parent
2b1e2f1cd1
commit
b88d9e75f6
|
@ -412,6 +412,99 @@ def test_comprehension_02(self):
|
|||
func, = T.__bound__
|
||||
self.assertEqual(func(), 1)
|
||||
|
||||
def test_gen_exp_in_nested_class(self):
|
||||
code = """
|
||||
from test.test_type_params import make_base
|
||||
|
||||
class C[T]:
|
||||
T = "class"
|
||||
class Inner(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")
|
||||
|
||||
def test_gen_exp_in_nested_generic_class(self):
|
||||
code = """
|
||||
from test.test_type_params import make_base
|
||||
|
||||
class C[T]:
|
||||
T = "class"
|
||||
class Inner[U](make_base(T for _ in (1,)), make_base(T)):
|
||||
pass
|
||||
"""
|
||||
with self.assertRaisesRegex(SyntaxError,
|
||||
"Cannot use comprehension in annotation scope within class scope"):
|
||||
run_code(code)
|
||||
|
||||
def test_listcomp_in_nested_class(self):
|
||||
code = """
|
||||
from test.test_type_params import make_base
|
||||
|
||||
class C[T]:
|
||||
T = "class"
|
||||
class Inner(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")
|
||||
|
||||
def test_listcomp_in_nested_generic_class(self):
|
||||
code = """
|
||||
from test.test_type_params import make_base
|
||||
|
||||
class C[T]:
|
||||
T = "class"
|
||||
class Inner[U](make_base([T for _ in (1,)]), make_base(T)):
|
||||
pass
|
||||
"""
|
||||
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_nested_scope_in_generic_alias(self):
|
||||
code = """
|
||||
class C[T]:
|
||||
T = "class"
|
||||
{}
|
||||
"""
|
||||
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):
|
||||
class Base:
|
||||
__arg__ = arg
|
||||
return Base
|
||||
|
||||
|
||||
def global_generic_func[T]():
|
||||
pass
|
||||
|
|
|
@ -0,0 +1,2 @@
|
|||
Disallow nested scopes (lambdas, generator expressions, and comprehensions)
|
||||
within PEP 695 annotation scopes that are nested within classes.
|
|
@ -2010,6 +2010,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)
|
||||
|
@ -2459,6 +2470,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));
|
||||
|
|
Loading…
Reference in a new issue