Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit 01317bb

Browse filesBrowse files
gh-132479: Fix crash with multiple comprehensions in annotations (#132778)
1 parent 08e331d commit 01317bb
Copy full SHA for 01317bb

File tree

Expand file treeCollapse file tree

3 files changed

+72
-6
lines changed
Filter options
Expand file treeCollapse file tree

3 files changed

+72
-6
lines changed

‎Lib/test/test_type_annotations.py

Copy file name to clipboardExpand all lines: Lib/test/test_type_annotations.py
+63Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -723,3 +723,66 @@ def test_non_name_annotations(self):
723723
"""
724724
expected = {"before": "before", "after": "after"}
725725
self.check_scopes(code, expected, expected)
726+
727+
728+
class RegressionTests(unittest.TestCase):
729+
# gh-132479
730+
def test_complex_comprehension_inlining(self):
731+
# Test that the various repro cases from the issue don't crash
732+
cases = [
733+
"""
734+
(unique_name_0): 0
735+
unique_name_1: (
736+
0
737+
for (
738+
0
739+
for unique_name_2 in 0
740+
for () in (0 for unique_name_3 in unique_name_4 for unique_name_5 in name_1)
741+
).name_3 in {0: 0 for name_1 in unique_name_8}
742+
if name_1
743+
)
744+
""",
745+
"""
746+
unique_name_0: 0
747+
unique_name_1: {
748+
0: 0
749+
for unique_name_2 in [0 for name_0 in unique_name_4]
750+
if {
751+
0: 0
752+
for unique_name_5 in 0
753+
if name_0
754+
if ((name_0 for unique_name_8 in unique_name_9) for [] in 0)
755+
}
756+
}
757+
""",
758+
"""
759+
0[0]: {0 for name_0 in unique_name_1}
760+
unique_name_2: {
761+
0: (lambda: name_0 for unique_name_4 in unique_name_5)
762+
for unique_name_6 in ()
763+
if name_0
764+
}
765+
""",
766+
]
767+
for case in cases:
768+
case = textwrap.dedent(case)
769+
compile(case, "<test>", "exec")
770+
771+
def test_complex_comprehension_inlining_exec(self):
772+
code = """
773+
unique_name_1 = unique_name_5 = [1]
774+
name_0 = 42
775+
unique_name_7: {name_0 for name_0 in unique_name_1}
776+
unique_name_2: {
777+
0: (lambda: name_0 for unique_name_4 in unique_name_5)
778+
for unique_name_6 in [1]
779+
if name_0
780+
}
781+
"""
782+
mod = build_module(code)
783+
annos = mod.__annotations__
784+
self.assertEqual(annos.keys(), {"unique_name_7", "unique_name_2"})
785+
self.assertEqual(annos["unique_name_7"], {True})
786+
genexp = annos["unique_name_2"][0]
787+
lamb = list(genexp)[0]
788+
self.assertEqual(lamb(), 42)
+2Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Fix compiler crash in certain circumstances where multiple module-level
2+
annotations include comprehensions and other nested scopes.

‎Python/symtable.c

Copy file name to clipboardExpand all lines: Python/symtable.c
+7-6Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1394,7 +1394,7 @@ symtable_exit_block(struct symtable *st)
13941394
}
13951395

13961396
static int
1397-
symtable_enter_existing_block(struct symtable *st, PySTEntryObject* ste)
1397+
symtable_enter_existing_block(struct symtable *st, PySTEntryObject* ste, bool add_to_children)
13981398
{
13991399
if (PyList_Append(st->st_stack, (PyObject *)ste) < 0) {
14001400
return 0;
@@ -1425,7 +1425,7 @@ symtable_enter_existing_block(struct symtable *st, PySTEntryObject* ste)
14251425
if (ste->ste_type == ModuleBlock)
14261426
st->st_global = st->st_cur->ste_symbols;
14271427

1428-
if (prev) {
1428+
if (add_to_children && prev) {
14291429
if (PyList_Append(prev->ste_children, (PyObject *)ste) < 0) {
14301430
return 0;
14311431
}
@@ -1440,7 +1440,7 @@ symtable_enter_block(struct symtable *st, identifier name, _Py_block_ty block,
14401440
PySTEntryObject *ste = ste_new(st, name, block, ast, loc);
14411441
if (ste == NULL)
14421442
return 0;
1443-
int result = symtable_enter_existing_block(st, ste);
1443+
int result = symtable_enter_existing_block(st, ste, /* add_to_children */true);
14441444
Py_DECREF(ste);
14451445
if (block == AnnotationBlock || block == TypeVariableBlock || block == TypeAliasBlock) {
14461446
_Py_DECLARE_STR(format, ".format");
@@ -1866,7 +1866,7 @@ symtable_visit_stmt(struct symtable *st, stmt_ty s)
18661866
Py_DECREF(new_ste);
18671867
return 0;
18681868
}
1869-
if (!symtable_enter_existing_block(st, new_ste)) {
1869+
if (!symtable_enter_existing_block(st, new_ste, /* add_to_children */true)) {
18701870
Py_DECREF(new_ste);
18711871
return 0;
18721872
}
@@ -2223,7 +2223,7 @@ symtable_visit_stmt(struct symtable *st, stmt_ty s)
22232223
Py_DECREF(new_ste);
22242224
return 0;
22252225
}
2226-
if (!symtable_enter_existing_block(st, new_ste)) {
2226+
if (!symtable_enter_existing_block(st, new_ste, /* add_to_children */true)) {
22272227
Py_DECREF(new_ste);
22282228
return 0;
22292229
}
@@ -2776,7 +2776,8 @@ symtable_visit_annotation(struct symtable *st, expr_ty annotation, void *key)
27762776
}
27772777
}
27782778
else {
2779-
if (!symtable_enter_existing_block(st, parent_ste->ste_annotation_block)) {
2779+
if (!symtable_enter_existing_block(st, parent_ste->ste_annotation_block,
2780+
/* add_to_children */false)) {
27802781
return 0;
27812782
}
27822783
}

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.