mirror of
https://github.com/RustPython/RustPython.git
synced 2026-10-29 03:04:38 +08:00
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
This commit is contained in:
1 parent
f95be1c82b
commit
2013d8f03e
2 files changed
+21
-2
No files matched your search
Vendored
-1
@@ -776,7 +776,6 @@ class ConditionalAnnotationTests(unittest.TestCase):
|
||||
|
||||
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 = [
|
||||
|
||||
@@ -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,
|
||||
@@ -1462,7 +1467,22 @@ 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 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;
|
||||
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)?;
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user