mirror of https://github.com/python/cpython.git
gh-109118: Allow lambdas in annotation scopes in classes (#118019)
This commit is contained in:
parent
4c7bfdff90
commit
85f727c5fb
|
@ -241,6 +241,9 @@ Other Language Changes
|
||||||
ones if configured to do so.
|
ones if configured to do so.
|
||||||
(Contributed by Pedro Sousa Lacerda in :gh:`66449`.)
|
(Contributed by Pedro Sousa Lacerda in :gh:`66449`.)
|
||||||
|
|
||||||
|
* :ref:`annotation scope <annotation-scopes>` within class scopes can now
|
||||||
|
contain lambdas. (Contributed by Jelle Zijlstra in :gh:`109118`.)
|
||||||
|
|
||||||
|
|
||||||
New Modules
|
New Modules
|
||||||
===========
|
===========
|
||||||
|
|
|
@ -486,8 +486,6 @@ class C[T]:
|
||||||
{}
|
{}
|
||||||
"""
|
"""
|
||||||
error_cases = [
|
error_cases = [
|
||||||
"type Alias1[T] = lambda: T",
|
|
||||||
"type Alias2 = lambda: T",
|
|
||||||
"type Alias3[T] = (T for _ in (1,))",
|
"type Alias3[T] = (T for _ in (1,))",
|
||||||
"type Alias4 = (T for _ in (1,))",
|
"type Alias4 = (T for _ in (1,))",
|
||||||
"type Alias5[T] = [T for _ in (1,)]",
|
"type Alias5[T] = [T for _ in (1,)]",
|
||||||
|
@ -499,6 +497,54 @@ class C[T]:
|
||||||
r"Cannot use [a-z]+ in annotation scope within class scope"):
|
r"Cannot use [a-z]+ in annotation scope within class scope"):
|
||||||
run_code(code.format(case))
|
run_code(code.format(case))
|
||||||
|
|
||||||
|
def test_lambda_in_alias_in_class(self):
|
||||||
|
code = """
|
||||||
|
T = "global"
|
||||||
|
class C:
|
||||||
|
T = "class"
|
||||||
|
type Alias = lambda: T
|
||||||
|
"""
|
||||||
|
C = run_code(code)["C"]
|
||||||
|
self.assertEqual(C.Alias.__value__(), "global")
|
||||||
|
|
||||||
|
def test_lambda_in_alias_in_generic_class(self):
|
||||||
|
code = """
|
||||||
|
class C[T]:
|
||||||
|
T = "class"
|
||||||
|
type Alias = lambda: T
|
||||||
|
"""
|
||||||
|
C = run_code(code)["C"]
|
||||||
|
self.assertIs(C.Alias.__value__(), C.__type_params__[0])
|
||||||
|
|
||||||
|
def test_lambda_in_generic_alias_in_class(self):
|
||||||
|
# A lambda nested in the alias cannot see the class scope, but can see
|
||||||
|
# a surrounding annotation scope.
|
||||||
|
code = """
|
||||||
|
T = U = "global"
|
||||||
|
class C:
|
||||||
|
T = "class"
|
||||||
|
U = "class"
|
||||||
|
type Alias[T] = lambda: (T, U)
|
||||||
|
"""
|
||||||
|
C = run_code(code)["C"]
|
||||||
|
T, U = C.Alias.__value__()
|
||||||
|
self.assertIs(T, C.Alias.__type_params__[0])
|
||||||
|
self.assertEqual(U, "global")
|
||||||
|
|
||||||
|
def test_lambda_in_generic_alias_in_generic_class(self):
|
||||||
|
# A lambda nested in the alias cannot see the class scope, but can see
|
||||||
|
# a surrounding annotation scope.
|
||||||
|
code = """
|
||||||
|
class C[T, U]:
|
||||||
|
T = "class"
|
||||||
|
U = "class"
|
||||||
|
type Alias[T] = lambda: (T, U)
|
||||||
|
"""
|
||||||
|
C = run_code(code)["C"]
|
||||||
|
T, U = C.Alias.__value__()
|
||||||
|
self.assertIs(T, C.Alias.__type_params__[0])
|
||||||
|
self.assertIs(U, C.__type_params__[1])
|
||||||
|
|
||||||
|
|
||||||
def make_base(arg):
|
def make_base(arg):
|
||||||
class Base:
|
class Base:
|
||||||
|
|
|
@ -0,0 +1,2 @@
|
||||||
|
:ref:`annotation scope <annotation-scopes>` within class scopes can now
|
||||||
|
contain lambdas.
|
|
@ -2140,17 +2140,6 @@ symtable_visit_expr(struct symtable *st, expr_ty e)
|
||||||
VISIT(st, expr, e->v.UnaryOp.operand);
|
VISIT(st, expr, e->v.UnaryOp.operand);
|
||||||
break;
|
break;
|
||||||
case Lambda_kind: {
|
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)
|
if (e->v.Lambda.args->defaults)
|
||||||
VISIT_SEQ(st, expr, e->v.Lambda.args->defaults);
|
VISIT_SEQ(st, expr, e->v.Lambda.args->defaults);
|
||||||
if (e->v.Lambda.args->kw_defaults)
|
if (e->v.Lambda.args->kw_defaults)
|
||||||
|
|
Loading…
Reference in New Issue