]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
gh-132479: Fix crash with multiple comprehensions in annotations (#132778)
authorJelle Zijlstra <jelle.zijlstra@gmail.com>
Mon, 21 Apr 2025 20:49:59 +0000 (13:49 -0700)
committerGitHub <noreply@github.com>
Mon, 21 Apr 2025 20:49:59 +0000 (13:49 -0700)
Lib/test/test_type_annotations.py
Misc/NEWS.d/next/Core_and_Builtins/2025-04-21-09-22-15.gh-issue-132479.CCe2sE.rst [new file with mode: 0644]
Python/symtable.c

index f903f9bb51f9193eb31788b82b82a2930c4534d4..fb441976694b34900336fe668c10897444d83198 100644 (file)
@@ -723,3 +723,66 @@ class ConditionalAnnotationTests(unittest.TestCase):
         """
         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 (file)
index 0000000..851bb4f
--- /dev/null
@@ -0,0 +1,2 @@
+Fix compiler crash in certain circumstances where multiple module-level
+annotations include comprehensions and other nested scopes.
index 35c9a0e295c60c6e6450c0a9e289190cbbc9f0e0..66f6c4a89aaee30cfef496806d71009b3dd2b259 100644 (file)
@@ -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;
         }
     }