From 3ecdd0c33e20a9ae0ee0611bdcbe7dd46b0b1872 Mon Sep 17 00:00:00 2001 From: "Jeong, YunWon" Date: Mon, 2 Mar 2026 00:04:09 +0900 Subject: [PATCH 1/3] Fix symbol table sub_table desync for non-simple annotation targets Non-simple annotations (subscript/attribute/parenthesized targets like `a[0]: expr`) were scanned in the annotation scope during symbol table analysis, creating sub_tables for any comprehensions. But codegen only compiles simple name annotations into __annotate__, so those sub_tables were never consumed. This caused subsequent simple annotations' comprehension sub_tables to get the wrong index, resulting in "the symbol 'X' must be present in the symbol table" errors. Fix: skip entering annotation scope for non-simple annotations since they are never compiled into __annotate__. --- Lib/test/test_type_annotations.py | 1 - crates/codegen/src/symboltable.rs | 9 ++++++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/Lib/test/test_type_annotations.py b/Lib/test/test_type_annotations.py index a7b87bb2ee0..4c58fade1b4 100644 --- a/Lib/test/test_type_annotations.py +++ b/Lib/test/test_type_annotations.py @@ -776,7 +776,6 @@ def test_non_name_annotations(self): class RegressionTests(unittest.TestCase): # gh-132479 - @unittest.expectedFailure # TODO: RUSTPYTHON; SyntaxError: the symbol 'unique_name_6' must be present in the symbol table def test_complex_comprehension_inlining(self): # Test that the various repro cases from the issue don't crash cases = [ diff --git a/crates/codegen/src/symboltable.rs b/crates/codegen/src/symboltable.rs index 22bea20fa6c..cbc38c4f298 100644 --- a/crates/codegen/src/symboltable.rs +++ b/crates/codegen/src/symboltable.rs @@ -1462,7 +1462,14 @@ impl SymbolTableBuilder { self.scan_expression(target, ExpressionContext::Store)?; } } - self.scan_annotation(annotation)?; + // Only scan annotation in annotation scope for simple name targets. + // Non-simple annotations (subscript, attribute, parenthesized) are + // never compiled into __annotate__, so scanning them would create + // sub_tables that de-synchronize the annotation scope's sub_table index. + let is_simple_name = *simple && matches!(&**target, Expr::Name(_)); + if is_simple_name { + self.scan_annotation(annotation)?; + } if let Some(value) = value { self.scan_expression(value, ExpressionContext::Load)?; } From 8b61e74cbdb0973eeff7801a7149366df97a7935 Mon Sep 17 00:00:00 2001 From: "Jeong, YunWon" Date: Mon, 2 Mar 2026 11:06:01 +0900 Subject: [PATCH 2/3] Validate forbidden expressions in non-simple annotation targets Fix cspell "desynchronize" warning and validate yield/await/named/async comprehension expressions in non-simple annotations without creating annotation scopes. --- crates/codegen/src/symboltable.rs | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/crates/codegen/src/symboltable.rs b/crates/codegen/src/symboltable.rs index cbc38c4f298..cfa3f565023 100644 --- a/crates/codegen/src/symboltable.rs +++ b/crates/codegen/src/symboltable.rs @@ -1053,6 +1053,11 @@ impl SymbolTableBuilder { /// Annotation and TypeParams scopes act as async barriers (always non-async). /// Comprehension scopes are transparent (inherit parent's async context). fn is_in_async_context(&self) -> bool { + // Annotations are evaluated in a non-async scope even when + // the enclosing function is async. + if self.in_annotation { + return false; + } for table in self.tables.iter().rev() { match table.typ { CompilerScope::AsyncFunction => return true, @@ -1465,10 +1470,17 @@ impl SymbolTableBuilder { // Only scan annotation in annotation scope for simple name targets. // Non-simple annotations (subscript, attribute, parenthesized) are // never compiled into __annotate__, so scanning them would create - // sub_tables that de-synchronize the annotation scope's sub_table index. + // sub_tables that cause mismatch in the annotation scope's sub_table index. let is_simple_name = *simple && matches!(&**target, Expr::Name(_)); if is_simple_name { self.scan_annotation(annotation)?; + } else { + // Still validate annotation for forbidden expressions + // (yield, await, named) even for non-simple targets. + let was_in_annotation = self.in_annotation; + self.in_annotation = true; + self.scan_expression(annotation, ExpressionContext::Load)?; + self.in_annotation = was_in_annotation; } if let Some(value) = value { self.scan_expression(value, ExpressionContext::Load)?; From 8bd6e976986336061611bda7706265f535167b1f Mon Sep 17 00:00:00 2001 From: "Jeong, YunWon" Date: Mon, 2 Mar 2026 13:16:15 +0900 Subject: [PATCH 3/3] Restore in_annotation flag before propagating error --- crates/codegen/src/symboltable.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/crates/codegen/src/symboltable.rs b/crates/codegen/src/symboltable.rs index cfa3f565023..0d868bc0468 100644 --- a/crates/codegen/src/symboltable.rs +++ b/crates/codegen/src/symboltable.rs @@ -1479,8 +1479,9 @@ impl SymbolTableBuilder { // (yield, await, named) even for non-simple targets. let was_in_annotation = self.in_annotation; self.in_annotation = true; - self.scan_expression(annotation, ExpressionContext::Load)?; + let result = self.scan_expression(annotation, ExpressionContext::Load); self.in_annotation = was_in_annotation; + result?; } if let Some(value) = value { self.scan_expression(value, ExpressionContext::Load)?;