Content-Length: 13562 | pFad | http://github.com/python/cpython/pull/118160.patch
69D67F44
From ad56c5fbc2c598ead76bc9a1bbbd31b9287a193e Mon Sep 17 00:00:00 2001
From: Jelle Zijlstra
Date: Wed, 17 Apr 2024 18:03:20 -0700
Subject: [PATCH 1/6] Desired behavior
---
Lib/test/test_type_params.py | 44 ++++++++++++++++++++++--------------
Python/symtable.c | 12 ----------
2 files changed, 27 insertions(+), 29 deletions(-)
diff --git a/Lib/test/test_type_params.py b/Lib/test/test_type_params.py
index fbb80d9aac9942..cbb576be8126f2 100644
--- a/Lib/test/test_type_params.py
+++ b/Lib/test/test_type_params.py
@@ -436,9 +436,11 @@ class C[T]:
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)
+ ns = run_code(code)
+ inner = ns["C"].Inner
+ base1, base2, _ = inner.__bases__
+ self.assertEqual(list(base1.__arg__), [ns["C"].__type_params__[0]])
+ self.assertEqual(base2.__arg__, "class")
def test_listcomp_in_nested_class(self):
code = """
@@ -464,9 +466,11 @@ class C[T]:
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)
+ ns = run_code(code)
+ inner = ns["C"].Inner
+ base1, base2, _ = inner.__bases__
+ self.assertEqual(base1.__arg__, [ns["C"].__type_params__[0]])
+ self.assertEqual(base2.__arg__, "class")
def test_gen_exp_in_generic_method(self):
code = """
@@ -475,27 +479,33 @@ class C[T]:
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)
+ ns = run_code(code)
+ meth = ns["C"].meth
+ self.assertEqual(list(meth.__annotations__["x"]), [ns["C"].__type_params__[0]])
+ self.assertEqual(meth.__annotations__["y"], "class")
def test_nested_scope_in_generic_alias(self):
code = """
- class C[T]:
+ T = "global"
+ class C:
T = "class"
{}
"""
error_cases = [
- "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,)]",
+ "type Alias[T] = (T for _ in (1,))",
+ "type Alias = (T for _ in (1,))",
+ "type Alias[T] = [T for _ in (1,)]",
+ "type Alias = [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))
+ ns = run_code(code.format(case))
+ alias = ns["C"].Alias
+ value = list(alias.__value__)[0]
+ if alias.__type_params__:
+ self.assertIs(value, alias.__type_params__[0])
+ else:
+ self.assertEqual(value, "global")
def test_lambda_in_alias_in_class(self):
code = """
diff --git a/Python/symtable.c b/Python/symtable.c
index 483ef1c3c46542..47a92eb6bf0504 100644
--- a/Python/symtable.c
+++ b/Python/symtable.c
@@ -2589,18 +2589,6 @@ 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));
From 5ade8d4836a23567eddff7251ae385c502f7d981 Mon Sep 17 00:00:00 2001
From: Jelle Zijlstra
Date: Wed, 17 Apr 2024 18:12:41 -0700
Subject: [PATCH 2/6] not correct
---
Python/compile.c | 5 ++++-
Python/symtable.c | 3 ++-
2 files changed, 6 insertions(+), 2 deletions(-)
diff --git a/Python/compile.c b/Python/compile.c
index 3d856b7e4ddd97..4ade34d104d7a8 100644
--- a/Python/compile.c
+++ b/Python/compile.c
@@ -371,6 +371,9 @@ static PyCodeObject *optimize_and_assemble(struct compiler *, int addNone);
#define CAPSULE_NAME "compile.c compiler unit"
+static inline bool in_class_like_block(struct compiler *c) {
+ return c->u->u_ste->ste_type == ClassBlock || c->u->u_ste->ste_can_see_class_scope;
+}
static int
compiler_setup(struct compiler *c, mod_ty mod, PyObject *filename,
@@ -5460,7 +5463,7 @@ push_inlined_comprehension_state(struct compiler *c, location loc,
PySTEntryObject *entry,
inlined_comprehension_state *state)
{
- int in_class_block = (c->u->u_ste->ste_type == ClassBlock) && !c->u->u_in_inlined_comp;
+ int in_class_block = in_class_like_block(c) && !c->u->u_in_inlined_comp;
c->u->u_in_inlined_comp++;
// iterate over names bound in the comprehension and ensure we isolate
// them from the outer scope as needed
diff --git a/Python/symtable.c b/Python/symtable.c
index 47a92eb6bf0504..4a369819231fbe 100644
--- a/Python/symtable.c
+++ b/Python/symtable.c
@@ -810,7 +810,8 @@ inline_comprehension(PySTEntryObject *ste, PySTEntryObject *comp,
// free vars in comprehension that are locals in outer scope can
// now simply be locals, unless they are free in comp children,
// or if the outer scope is a class block
- if (!is_free_in_any_child(comp, k) && ste->ste_type != ClassBlock) {
+ if (!is_free_in_any_child(comp, k) && ste->ste_type != ClassBlock
+ && !ste->ste_can_see_class_scope) {
if (PySet_Discard(comp_free, k) < 0) {
return 0;
}
From ba90c9764ba62b288ef0b262ff3b57ecb9e16161 Mon Sep 17 00:00:00 2001
From: Jelle Zijlstra
Date: Thu, 25 Apr 2024 21:03:42 -0700
Subject: [PATCH 3/6] Revert "not correct"
This reverts commit 5ade8d4836a23567eddff7251ae385c502f7d981.
---
Python/compile.c | 5 +----
Python/symtable.c | 3 +--
2 files changed, 2 insertions(+), 6 deletions(-)
diff --git a/Python/compile.c b/Python/compile.c
index 4ade34d104d7a8..3d856b7e4ddd97 100644
--- a/Python/compile.c
+++ b/Python/compile.c
@@ -371,9 +371,6 @@ static PyCodeObject *optimize_and_assemble(struct compiler *, int addNone);
#define CAPSULE_NAME "compile.c compiler unit"
-static inline bool in_class_like_block(struct compiler *c) {
- return c->u->u_ste->ste_type == ClassBlock || c->u->u_ste->ste_can_see_class_scope;
-}
static int
compiler_setup(struct compiler *c, mod_ty mod, PyObject *filename,
@@ -5463,7 +5460,7 @@ push_inlined_comprehension_state(struct compiler *c, location loc,
PySTEntryObject *entry,
inlined_comprehension_state *state)
{
- int in_class_block = in_class_like_block(c) && !c->u->u_in_inlined_comp;
+ int in_class_block = (c->u->u_ste->ste_type == ClassBlock) && !c->u->u_in_inlined_comp;
c->u->u_in_inlined_comp++;
// iterate over names bound in the comprehension and ensure we isolate
// them from the outer scope as needed
diff --git a/Python/symtable.c b/Python/symtable.c
index 4a369819231fbe..47a92eb6bf0504 100644
--- a/Python/symtable.c
+++ b/Python/symtable.c
@@ -810,8 +810,7 @@ inline_comprehension(PySTEntryObject *ste, PySTEntryObject *comp,
// free vars in comprehension that are locals in outer scope can
// now simply be locals, unless they are free in comp children,
// or if the outer scope is a class block
- if (!is_free_in_any_child(comp, k) && ste->ste_type != ClassBlock
- && !ste->ste_can_see_class_scope) {
+ if (!is_free_in_any_child(comp, k) && ste->ste_type != ClassBlock) {
if (PySet_Discard(comp_free, k) < 0) {
return 0;
}
From 1a9b8eda9f4782534ec3930039a2e2633c677a8f Mon Sep 17 00:00:00 2001
From: Jelle Zijlstra
Date: Thu, 25 Apr 2024 21:18:31 -0700
Subject: [PATCH 4/6] Do not inline them
---
.../2024-04-25-21-18-19.gh-issue-118160.GH5SMc.rst | 3 +++
1 file changed, 3 insertions(+)
create mode 100644 Misc/NEWS.d/next/Core and Builtins/2024-04-25-21-18-19.gh-issue-118160.GH5SMc.rst
diff --git a/Misc/NEWS.d/next/Core and Builtins/2024-04-25-21-18-19.gh-issue-118160.GH5SMc.rst b/Misc/NEWS.d/next/Core and Builtins/2024-04-25-21-18-19.gh-issue-118160.GH5SMc.rst
new file mode 100644
index 00000000000000..c4e798df5de702
--- /dev/null
+++ b/Misc/NEWS.d/next/Core and Builtins/2024-04-25-21-18-19.gh-issue-118160.GH5SMc.rst
@@ -0,0 +1,3 @@
+:ref:`Annotation scopes ` within classes can now contain
+comprehensions. However, such comprehensions are not inlined into their
+parent scope at runtime. Patch by Jelle Zijlstra.
From 79e9332f87e5f4a051d03eb52e1dae795d9ae18d Mon Sep 17 00:00:00 2001
From: Jelle Zijlstra
Date: Thu, 25 Apr 2024 21:19:12 -0700
Subject: [PATCH 5/6] Rename "error_cases"
---
Doc/whatsnew/3.13.rst | 4 +++-
Lib/test/test_type_params.py | 4 ++--
Python/symtable.c | 6 ++++--
3 files changed, 9 insertions(+), 5 deletions(-)
diff --git a/Doc/whatsnew/3.13.rst b/Doc/whatsnew/3.13.rst
index ad107aad5db3bd..0cd8b4784e712c 100644
--- a/Doc/whatsnew/3.13.rst
+++ b/Doc/whatsnew/3.13.rst
@@ -276,7 +276,9 @@ Other Language Changes
(Contributed by Pedro Sousa Lacerda in :gh:`66449`.)
* :ref:`annotation scope ` within class scopes can now
- contain lambdas. (Contributed by Jelle Zijlstra in :gh:`109118`.)
+ contain lambdas and comprehensions. Comprehensions that are located within
+ class scopes are not inliked into their parent scope. (Contributed by
+ Jelle Zijlstra in :gh:`109118` and :gh:`118160`.)
New Modules
diff --git a/Lib/test/test_type_params.py b/Lib/test/test_type_params.py
index cbb576be8126f2..4b86395ee74f75 100644
--- a/Lib/test/test_type_params.py
+++ b/Lib/test/test_type_params.py
@@ -491,13 +491,13 @@ class C:
T = "class"
{}
"""
- error_cases = [
+ cases = [
"type Alias[T] = (T for _ in (1,))",
"type Alias = (T for _ in (1,))",
"type Alias[T] = [T for _ in (1,)]",
"type Alias = [T for _ in (1,)]",
]
- for case in error_cases:
+ for case in cases:
with self.subTest(case=case):
ns = run_code(code.format(case))
alias = ns["C"].Alias
diff --git a/Python/symtable.c b/Python/symtable.c
index 47a92eb6bf0504..eecd159b2c3f17 100644
--- a/Python/symtable.c
+++ b/Python/symtable.c
@@ -1154,10 +1154,12 @@ analyze_block(PySTEntryObject *ste, PyObject *bound, PyObject *free,
}
}
- // we inline all non-generator-expression comprehensions
+ // we inline all non-generator-expression comprehensions,
+ // except those in annotation scopes that are nested in classes
int inline_comp =
entry->ste_comprehension &&
- !entry->ste_generator;
+ !entry->ste_generator &&
+ !ste->ste_can_see_class_scope;
if (!analyze_child_block(entry, newbound, newfree, newglobal,
type_params, new_class_entry, &child_free))
From 9e6ade7446bffa32eb39ac4f7903a2fd3a9d4add Mon Sep 17 00:00:00 2001
From: Jelle Zijlstra
Date: Fri, 26 Apr 2024 16:46:10 -0700
Subject: [PATCH 6/6] Update Doc/whatsnew/3.13.rst
Co-authored-by: Carl Meyer
---
Doc/whatsnew/3.13.rst | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/Doc/whatsnew/3.13.rst b/Doc/whatsnew/3.13.rst
index 0cd8b4784e712c..13252d99de6c68 100644
--- a/Doc/whatsnew/3.13.rst
+++ b/Doc/whatsnew/3.13.rst
@@ -277,7 +277,7 @@ Other Language Changes
* :ref:`annotation scope ` within class scopes can now
contain lambdas and comprehensions. Comprehensions that are located within
- class scopes are not inliked into their parent scope. (Contributed by
+ class scopes are not inlined into their parent scope. (Contributed by
Jelle Zijlstra in :gh:`109118` and :gh:`118160`.)
--- a PPN by Garber Painting Akron. With Image Size Reduction included!Fetched URL: http://github.com/python/cpython/pull/118160.patch
Alternative Proxies:
Alternative Proxy
pFad Proxy
pFad v3 Proxy
pFad v4 Proxy