Skip to content

gh-132479: Fix crash with multiple comprehensions in annotations #132778

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Apr 21, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
63 changes: 63 additions & 0 deletions Lib/test/test_type_annotations.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Fix compiler crash in certain circumstances where multiple module-level
annotations include comprehensions and other nested scopes.
13 changes: 7 additions & 6 deletions Python/symtable.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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;
}
Expand All @@ -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");
Expand Down Expand Up @@ -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;
}
Expand Down Expand Up @@ -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;
}
Expand Down Expand Up @@ -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;
}
}
Expand Down
Loading