Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
Next Next commit
gh-138349: Fix crash when combining module-level annotation and listc…
…omp (#138363)

(cherry picked from commit 7a6fd4a)
  • Loading branch information
JelleZijlstra authored and vstinner committed Sep 10, 2025
commit ebf4863ad73cb2bc03ff1ec51a60f74a51842b0d
3 changes: 2 additions & 1 deletion Include/internal/pycore_magic_number.h
Original file line number Diff line number Diff line change
Expand Up @@ -279,6 +279,7 @@ Known values:
Python 3.14b1 3624 (Don't optimize LOAD_FAST when local is killed by DELETE_FAST)
Python 3.14b3 3625 (Fix handling of opcodes that may leave operands on the stack when optimizing LOAD_FAST)
Python 3.14rc2 3626 (Fix missing exception handlers in logical expression)
Python 3.14rc3 3627 (Fix miscompilation of some module-level annotations)

Python 3.15 will start with 3650

Expand All @@ -291,7 +292,7 @@ PC/launcher.c must also be updated.

*/

#define PYC_MAGIC_NUMBER 3626
#define PYC_MAGIC_NUMBER 3627
/* This is equivalent to converting PYC_MAGIC_NUMBER to 2 bytes
(little-endian) and then appending b'\r\n'. */
#define PYC_MAGIC_NUMBER_TOKEN \
Expand Down
37 changes: 37 additions & 0 deletions Lib/test/test_type_annotations.py
Original file line number Diff line number Diff line change
Expand Up @@ -835,3 +835,40 @@ def test_complex_comprehension_inlining_exec(self):
genexp = annos["unique_name_2"][0]
lamb = list(genexp)[0]
self.assertEqual(lamb(), 42)

# gh-138349
def test_module_level_annotation_plus_listcomp(self):
cases = [
"""
def report_error():
pass
try:
[0 for name_2 in unique_name_0 if (lambda: name_2)]
except:
pass
annotated_name: 0
""",
"""
class Generic:
pass
try:
[0 for name_2 in unique_name_0 if (0 for unique_name_1 in unique_name_2 for unique_name_3 in name_2)]
except:
pass
annotated_name: 0
""",
"""
class Generic:
pass
annotated_name: 0
try:
[0 for name_2 in [[0]] for unique_name_1 in unique_name_2 if (lambda: name_2)]
except:
pass
""",
]
for code in cases:
with self.subTest(code=code):
mod = build_module(code)
annos = mod.__annotations__
self.assertEqual(annos, {"annotated_name": 0})
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Fix crash in certain cases where a module contains both a module-level
annotation and a comprehension.
10 changes: 6 additions & 4 deletions Python/codegen.c
Original file line number Diff line number Diff line change
Expand Up @@ -5500,10 +5500,12 @@ codegen_annassign(compiler *c, stmt_ty s)
RETURN_IF_ERROR(_PyCompile_AddDeferredAnnotation(
c, s, &conditional_annotation_index));
if (conditional_annotation_index != NULL) {
ADDOP_NAME(
c, loc,
SCOPE_TYPE(c) == COMPILE_SCOPE_CLASS ? LOAD_DEREF : LOAD_NAME,
&_Py_ID(__conditional_annotations__), cellvars);
if (SCOPE_TYPE(c) == COMPILE_SCOPE_CLASS) {
ADDOP_NAME(c, loc, LOAD_DEREF, &_Py_ID(__conditional_annotations__), cellvars);
}
else {
ADDOP_NAME(c, loc, LOAD_NAME, &_Py_ID(__conditional_annotations__), names);
}
ADDOP_LOAD_CONST_NEW(c, loc, conditional_annotation_index);
ADDOP_I(c, loc, SET_ADD, 1);
ADDOP(c, loc, POP_TOP);
Expand Down
Loading