https://github.com/python/cpython/commit/01317bb449612ea1dbbf36e439437909abd79a45
commit: 01317bb449612ea1dbbf36e439437909abd79a45
branch: main
author: Jelle Zijlstra <[email protected]>
committer: JelleZijlstra <[email protected]>
date: 2025-04-21T13:49:59-07:00
summary:
gh-132479: Fix crash with multiple comprehensions in annotations (#132778)
files:
A
Misc/NEWS.d/next/Core_and_Builtins/2025-04-21-09-22-15.gh-issue-132479.CCe2sE.rst
M Lib/test/test_type_annotations.py
M Python/symtable.c
diff --git a/Lib/test/test_type_annotations.py
b/Lib/test/test_type_annotations.py
index f903f9bb51f919..fb441976694b34 100644
--- a/Lib/test/test_type_annotations.py
+++ b/Lib/test/test_type_annotations.py
@@ -723,3 +723,66 @@ def test_non_name_annotations(self):
"""
expected = {"before": "before", "after": "after"}
self.check_scopes(code, expected, expected)
+
+
+class RegressionTests(unittest.TestCase):
+ # gh-132479
+ def test_complex_comprehension_inlining(self):
+ # Test that the various repro cases from the issue don't crash
+ cases = [
+ """
+ (unique_name_0): 0
+ unique_name_1: (
+ 0
+ for (
+ 0
+ for unique_name_2 in 0
+ for () in (0 for unique_name_3 in unique_name_4 for
unique_name_5 in name_1)
+ ).name_3 in {0: 0 for name_1 in unique_name_8}
+ if name_1
+ )
+ """,
+ """
+ unique_name_0: 0
+ unique_name_1: {
+ 0: 0
+ for unique_name_2 in [0 for name_0 in unique_name_4]
+ if {
+ 0: 0
+ for unique_name_5 in 0
+ if name_0
+ if ((name_0 for unique_name_8 in unique_name_9) for [] in
0)
+ }
+ }
+ """,
+ """
+ 0[0]: {0 for name_0 in unique_name_1}
+ unique_name_2: {
+ 0: (lambda: name_0 for unique_name_4 in unique_name_5)
+ for unique_name_6 in ()
+ if name_0
+ }
+ """,
+ ]
+ for case in cases:
+ case = textwrap.dedent(case)
+ compile(case, "<test>", "exec")
+
+ def test_complex_comprehension_inlining_exec(self):
+ code = """
+ unique_name_1 = unique_name_5 = [1]
+ name_0 = 42
+ unique_name_7: {name_0 for name_0 in unique_name_1}
+ unique_name_2: {
+ 0: (lambda: name_0 for unique_name_4 in unique_name_5)
+ for unique_name_6 in [1]
+ if name_0
+ }
+ """
+ mod = build_module(code)
+ annos = mod.__annotations__
+ self.assertEqual(annos.keys(), {"unique_name_7", "unique_name_2"})
+ self.assertEqual(annos["unique_name_7"], {True})
+ genexp = annos["unique_name_2"][0]
+ lamb = list(genexp)[0]
+ self.assertEqual(lamb(), 42)
diff --git
a/Misc/NEWS.d/next/Core_and_Builtins/2025-04-21-09-22-15.gh-issue-132479.CCe2sE.rst
b/Misc/NEWS.d/next/Core_and_Builtins/2025-04-21-09-22-15.gh-issue-132479.CCe2sE.rst
new file mode 100644
index 00000000000000..851bb4fb70e4a1
--- /dev/null
+++
b/Misc/NEWS.d/next/Core_and_Builtins/2025-04-21-09-22-15.gh-issue-132479.CCe2sE.rst
@@ -0,0 +1,2 @@
+Fix compiler crash in certain circumstances where multiple module-level
+annotations include comprehensions and other nested scopes.
diff --git a/Python/symtable.c b/Python/symtable.c
index 35c9a0e295c60c..66f6c4a89aaee3 100644
--- a/Python/symtable.c
+++ b/Python/symtable.c
@@ -1394,7 +1394,7 @@ symtable_exit_block(struct symtable *st)
}
static int
-symtable_enter_existing_block(struct symtable *st, PySTEntryObject* ste)
+symtable_enter_existing_block(struct symtable *st, PySTEntryObject* ste, bool
add_to_children)
{
if (PyList_Append(st->st_stack, (PyObject *)ste) < 0) {
return 0;
@@ -1425,7 +1425,7 @@ symtable_enter_existing_block(struct symtable *st,
PySTEntryObject* ste)
if (ste->ste_type == ModuleBlock)
st->st_global = st->st_cur->ste_symbols;
- if (prev) {
+ if (add_to_children && prev) {
if (PyList_Append(prev->ste_children, (PyObject *)ste) < 0) {
return 0;
}
@@ -1440,7 +1440,7 @@ symtable_enter_block(struct symtable *st, identifier
name, _Py_block_ty block,
PySTEntryObject *ste = ste_new(st, name, block, ast, loc);
if (ste == NULL)
return 0;
- int result = symtable_enter_existing_block(st, ste);
+ int result = symtable_enter_existing_block(st, ste, /* add_to_children
*/true);
Py_DECREF(ste);
if (block == AnnotationBlock || block == TypeVariableBlock || block ==
TypeAliasBlock) {
_Py_DECLARE_STR(format, ".format");
@@ -1866,7 +1866,7 @@ symtable_visit_stmt(struct symtable *st, stmt_ty s)
Py_DECREF(new_ste);
return 0;
}
- if (!symtable_enter_existing_block(st, new_ste)) {
+ if (!symtable_enter_existing_block(st, new_ste, /* add_to_children
*/true)) {
Py_DECREF(new_ste);
return 0;
}
@@ -2223,7 +2223,7 @@ symtable_visit_stmt(struct symtable *st, stmt_ty s)
Py_DECREF(new_ste);
return 0;
}
- if (!symtable_enter_existing_block(st, new_ste)) {
+ if (!symtable_enter_existing_block(st, new_ste, /* add_to_children
*/true)) {
Py_DECREF(new_ste);
return 0;
}
@@ -2776,7 +2776,8 @@ symtable_visit_annotation(struct symtable *st, expr_ty
annotation, void *key)
}
}
else {
- if (!symtable_enter_existing_block(st,
parent_ste->ste_annotation_block)) {
+ if (!symtable_enter_existing_block(st,
parent_ste->ste_annotation_block,
+ /* add_to_children */false)) {
return 0;
}
}
_______________________________________________
Python-checkins mailing list -- [email protected]
To unsubscribe send an email to [email protected]
https://mail.python.org/mailman3/lists/python-checkins.python.org/
Member address: [email protected]