Skip to content

Commit baba1f9

Browse files
authored
Fix symbol table sub_table desync for non-simple annotation targets (#7300)
* 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__. * 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. * Restore in_annotation flag before propagating error
1 parent c315033 commit baba1f9

File tree

2 files changed

+21
-2
lines changed

2 files changed

+21
-2
lines changed

Lib/test/test_type_annotations.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -776,7 +776,6 @@ def test_non_name_annotations(self):
776776

777777
class RegressionTests(unittest.TestCase):
778778
# gh-132479
779-
@unittest.expectedFailure # TODO: RUSTPYTHON; SyntaxError: the symbol 'unique_name_6' must be present in the symbol table
780779
def test_complex_comprehension_inlining(self):
781780
# Test that the various repro cases from the issue don't crash
782781
cases = [

crates/codegen/src/symboltable.rs

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1053,6 +1053,11 @@ impl SymbolTableBuilder {
10531053
/// Annotation and TypeParams scopes act as async barriers (always non-async).
10541054
/// Comprehension scopes are transparent (inherit parent's async context).
10551055
fn is_in_async_context(&self) -> bool {
1056+
// Annotations are evaluated in a non-async scope even when
1057+
// the enclosing function is async.
1058+
if self.in_annotation {
1059+
return false;
1060+
}
10561061
for table in self.tables.iter().rev() {
10571062
match table.typ {
10581063
CompilerScope::AsyncFunction => return true,
@@ -1462,7 +1467,22 @@ impl SymbolTableBuilder {
14621467
self.scan_expression(target, ExpressionContext::Store)?;
14631468
}
14641469
}
1465-
self.scan_annotation(annotation)?;
1470+
// Only scan annotation in annotation scope for simple name targets.
1471+
// Non-simple annotations (subscript, attribute, parenthesized) are
1472+
// never compiled into __annotate__, so scanning them would create
1473+
// sub_tables that cause mismatch in the annotation scope's sub_table index.
1474+
let is_simple_name = *simple && matches!(&**target, Expr::Name(_));
1475+
if is_simple_name {
1476+
self.scan_annotation(annotation)?;
1477+
} else {
1478+
// Still validate annotation for forbidden expressions
1479+
// (yield, await, named) even for non-simple targets.
1480+
let was_in_annotation = self.in_annotation;
1481+
self.in_annotation = true;
1482+
let result = self.scan_expression(annotation, ExpressionContext::Load);
1483+
self.in_annotation = was_in_annotation;
1484+
result?;
1485+
}
14661486
if let Some(value) = value {
14671487
self.scan_expression(value, ExpressionContext::Load)?;
14681488
}

0 commit comments

Comments
 (0)