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

This commit is contained in:
Jelle Zijlstra 2025-04-21 13:49:59 -07:00 committed by GitHub
parent 08e331d05e
commit 01317bb449
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 72 additions and 6 deletions

View 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)

View file

@ -0,0 +1,2 @@
Fix compiler crash in certain circumstances where multiple module-level
annotations include comprehensions and other nested scopes.

View 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;
}
}