https://github.com/python/cpython/commit/01317bb449612ea1dbbf36e439437909abd79a45 commit: 01317bb449612ea1dbbf36e439437909abd79a45 branch: main author: Jelle Zijlstra <jelle.zijls...@gmail.com> committer: JelleZijlstra <jelle.zijls...@gmail.com> 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 -- python-checkins@python.org To unsubscribe send an email to python-checkins-le...@python.org https://mail.python.org/mailman3/lists/python-checkins.python.org/ Member address: arch...@mail-archive.com