diff --git a/compiler/codegen/src/compile.rs b/compiler/codegen/src/compile.rs index 6e8ab9554a..62c8508cbf 100644 --- a/compiler/codegen/src/compile.rs +++ b/compiler/codegen/src/compile.rs @@ -11,7 +11,7 @@ use crate::{ IndexMap, IndexSet, ToPythonName, error::{CodegenError, CodegenErrorType, PatternUnreachableReason}, ir::{self, BlockIdx}, - symboltable::{self, SymbolFlags, SymbolScope, SymbolTable, SymbolTableType}, + symboltable::{self, CompilerScope, SymbolFlags, SymbolScope, SymbolTable}, unparse::unparse_expr, }; @@ -409,7 +409,7 @@ impl Compiler<'_> { fn enter_scope( &mut self, name: &str, - scope_type: SymbolTableType, + scope_type: CompilerScope, key: usize, // In RustPython, we use the index in symbol_table_stack as key lineno: u32, ) -> CompileResult<()> { @@ -452,14 +452,14 @@ impl Compiler<'_> { // Handle implicit __class__ cell if needed if ste.needs_class_closure { // Cook up an implicit __class__ cell - debug_assert_eq!(scope_type, SymbolTableType::Class); + debug_assert_eq!(scope_type, CompilerScope::Class); cellvar_cache.insert("__class__".to_string()); } // Handle implicit __classdict__ cell if needed if ste.needs_classdict { // Cook up an implicit __classdict__ cell - debug_assert_eq!(scope_type, SymbolTableType::Class); + debug_assert_eq!(scope_type, CompilerScope::Class); cellvar_cache.insert("__classdict__".to_string()); } @@ -480,21 +480,21 @@ impl Compiler<'_> { // Initialize u_metadata fields let (flags, posonlyarg_count, arg_count, kwonlyarg_count) = match scope_type { - SymbolTableType::Module => (bytecode::CodeFlags::empty(), 0, 0, 0), - SymbolTableType::Class => (bytecode::CodeFlags::empty(), 0, 0, 0), - SymbolTableType::Function | SymbolTableType::Lambda => ( + CompilerScope::Module => (bytecode::CodeFlags::empty(), 0, 0, 0), + CompilerScope::Class => (bytecode::CodeFlags::empty(), 0, 0, 0), + CompilerScope::Function | CompilerScope::AsyncFunction | CompilerScope::Lambda => ( bytecode::CodeFlags::NEW_LOCALS | bytecode::CodeFlags::IS_OPTIMIZED, 0, // Will be set later in enter_function 0, // Will be set later in enter_function 0, // Will be set later in enter_function ), - SymbolTableType::Comprehension => ( + CompilerScope::Comprehension => ( bytecode::CodeFlags::NEW_LOCALS | bytecode::CodeFlags::IS_OPTIMIZED, 0, 1, // comprehensions take one argument (.0) 0, ), - SymbolTableType::TypeParams => ( + CompilerScope::TypeParams => ( bytecode::CodeFlags::NEW_LOCALS | bytecode::CodeFlags::IS_OPTIMIZED, 0, 0, @@ -530,7 +530,7 @@ impl Compiler<'_> { kwonlyargcount: kwonlyarg_count, firstlineno: OneIndexed::new(lineno as usize).unwrap_or(OneIndexed::MIN), }, - static_attributes: if scope_type == SymbolTableType::Class { + static_attributes: if scope_type == CompilerScope::Class { Some(IndexSet::default()) } else { None @@ -544,12 +544,12 @@ impl Compiler<'_> { self.code_stack.push(code_info); // Set qualname after pushing (uses compiler_set_qualname logic) - if scope_type != SymbolTableType::Module { + if scope_type != CompilerScope::Module { self.set_qualname(); } // Emit RESUME instruction - let _resume_loc = if scope_type == SymbolTableType::Module { + let _resume_loc = if scope_type == CompilerScope::Module { // Module scope starts with lineno 0 ruff_source_file::SourceLocation { row: OneIndexed::MIN, @@ -569,7 +569,7 @@ impl Compiler<'_> { } ); - if scope_type == SymbolTableType::Module { + if scope_type == CompilerScope::Module { // This would be loc.lineno = -1 in CPython // We handle this differently in RustPython } @@ -950,11 +950,7 @@ impl Compiler<'_> { cache = &mut info.metadata.cellvars; NameOpType::Deref } // TODO: is this right? - SymbolScope::TypeParams => { - // Type parameters are always cell variables - cache = &mut info.metadata.cellvars; - NameOpType::Deref - } // SymbolScope::Unknown => NameOpType::Global, + // SymbolScope::Unknown => NameOpType::Global, }; if NameUsage::Load == usage && name == "__debug__" { @@ -1999,7 +1995,7 @@ impl Compiler<'_> { let table = self.symbol_table_stack.last().unwrap(); match table.lookup(name) { Some(symbol) => match symbol.scope { - SymbolScope::Cell | SymbolScope::TypeParams => Ok(SymbolScope::Cell), + SymbolScope::Cell => Ok(SymbolScope::Cell), SymbolScope::Free => Ok(SymbolScope::Free), _ if symbol.flags.contains(SymbolFlags::FREE_CLASS) => Ok(SymbolScope::Free), _ => Err(CodegenErrorType::SyntaxError(format!( @@ -2204,7 +2200,7 @@ impl Compiler<'_> { // Use enter_scope instead of push_output to match CPython let key = self.symbol_table_stack.len(); self.push_symbol_table(); - self.enter_scope(name, SymbolTableType::Class, key, firstlineno)?; + self.enter_scope(name, CompilerScope::Class, key, firstlineno)?; // Set qualname using the new method let qualname = self.set_qualname(); diff --git a/compiler/codegen/src/symboltable.rs b/compiler/codegen/src/symboltable.rs index 7f7355bd73..e158514f87 100644 --- a/compiler/codegen/src/symboltable.rs +++ b/compiler/codegen/src/symboltable.rs @@ -31,7 +31,7 @@ pub struct SymbolTable { pub name: String, /// The type of symbol table - pub typ: SymbolTableType, + pub typ: CompilerScope, /// The line number in the source code where this symboltable begins. pub line_number: u32, @@ -57,7 +57,7 @@ pub struct SymbolTable { } impl SymbolTable { - fn new(name: String, typ: SymbolTableType, line_number: u32, is_nested: bool) -> Self { + fn new(name: String, typ: CompilerScope, line_number: u32, is_nested: bool) -> Self { Self { name, typ, @@ -88,21 +88,23 @@ impl SymbolTable { } #[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub enum SymbolTableType { +pub enum CompilerScope { Module, Class, Function, + AsyncFunction, Lambda, Comprehension, TypeParams, } -impl fmt::Display for SymbolTableType { +impl fmt::Display for CompilerScope { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { Self::Module => write!(f, "module"), Self::Class => write!(f, "class"), Self::Function => write!(f, "function"), + Self::AsyncFunction => write!(f, "async function"), Self::Lambda => write!(f, "lambda"), Self::Comprehension => write!(f, "comprehension"), Self::TypeParams => write!(f, "type parameter"), @@ -127,8 +129,6 @@ pub enum SymbolScope { GlobalImplicit, Free, Cell, - // TODO: wrong place. not a symbol scope, but a COMPILER_SCOPE_TYPEPARAMS - TypeParams, } bitflags! { @@ -323,7 +323,7 @@ use stack::StackStack; #[derive(Default)] #[repr(transparent)] struct SymbolTableAnalyzer { - tables: StackStack<(SymbolMap, SymbolTableType)>, + tables: StackStack<(SymbolMap, CompilerScope)>, } impl SymbolTableAnalyzer { @@ -349,7 +349,7 @@ impl SymbolTableAnalyzer { } // Handle class-specific implicit cells (like CPython) - if symbol_table.typ == SymbolTableType::Class { + if symbol_table.typ == CompilerScope::Class { drop_class_free(symbol_table); } @@ -359,13 +359,13 @@ impl SymbolTableAnalyzer { fn analyze_symbol( &mut self, symbol: &mut Symbol, - st_typ: SymbolTableType, + st_typ: CompilerScope, sub_tables: &[SymbolTable], ) -> SymbolTableResult { if symbol .flags .contains(SymbolFlags::ASSIGNED_IN_COMPREHENSION) - && st_typ == SymbolTableType::Comprehension + && st_typ == CompilerScope::Comprehension { // propagate symbol to next higher level that can hold it, // i.e., function or module. Comprehension is skipped and @@ -405,10 +405,6 @@ impl SymbolTableAnalyzer { SymbolScope::Local | SymbolScope::Cell => { // all is well } - SymbolScope::TypeParams => { - // Type parameters are always cell variables in their scope - symbol.scope = SymbolScope::Cell; - } SymbolScope::Unknown => { // Try hard to figure out what the scope of this symbol is. let scope = if symbol.is_bound() { @@ -433,8 +429,8 @@ impl SymbolTableAnalyzer { fn found_in_outer_scope(&mut self, name: &str) -> Option { let mut decl_depth = None; for (i, (symbols, typ)) in self.tables.iter().rev().enumerate() { - if matches!(typ, SymbolTableType::Module) - || matches!(typ, SymbolTableType::Class if name != "__class__") + if matches!(typ, CompilerScope::Module) + || matches!(typ, CompilerScope::Class if name != "__class__") { continue; } @@ -456,7 +452,7 @@ impl SymbolTableAnalyzer { // decl_depth is the number of tables between the current one and // the one that declared the cell var for (table, typ) in self.tables.iter_mut().rev().take(decl_depth) { - if let SymbolTableType::Class = typ { + if let CompilerScope::Class = typ { if let Some(free_class) = table.get_mut(name) { free_class.flags.insert(SymbolFlags::FREE_CLASS) } else { @@ -481,12 +477,12 @@ impl SymbolTableAnalyzer { &self, sub_tables: &[SymbolTable], name: &str, - st_typ: SymbolTableType, + st_typ: CompilerScope, ) -> Option { sub_tables.iter().find_map(|st| { let sym = st.symbols.get(name)?; if sym.scope == SymbolScope::Free || sym.flags.contains(SymbolFlags::FREE_CLASS) { - if st_typ == SymbolTableType::Class && name != "__class__" { + if st_typ == CompilerScope::Class && name != "__class__" { None } else { Some(SymbolScope::Cell) @@ -527,10 +523,10 @@ impl SymbolTableAnalyzer { } match table_type { - SymbolTableType::Module => { + CompilerScope::Module => { symbol.scope = SymbolScope::GlobalImplicit; } - SymbolTableType::Class => { + CompilerScope::Class => { // named expressions are forbidden in comprehensions on class scope return Err(SymbolTableError { error: "assignment expression within a comprehension cannot be used in a class body".to_string(), @@ -538,7 +534,7 @@ impl SymbolTableAnalyzer { location: None, }); } - SymbolTableType::Function | SymbolTableType::Lambda => { + CompilerScope::Function | CompilerScope::AsyncFunction | CompilerScope::Lambda => { if let Some(parent_symbol) = symbols.get_mut(&symbol.name) { if let SymbolScope::Unknown = parent_symbol.scope { // this information is new, as the assignment is done in inner scope @@ -556,7 +552,7 @@ impl SymbolTableAnalyzer { last.0.insert(cloned_sym.name.to_owned(), cloned_sym); } } - SymbolTableType::Comprehension => { + CompilerScope::Comprehension => { // TODO check for conflicts - requires more context information about variables match symbols.get_mut(&symbol.name) { Some(parent_symbol) => { @@ -587,7 +583,7 @@ impl SymbolTableAnalyzer { self.analyze_symbol_comprehension(symbol, parent_offset + 1)?; } - SymbolTableType::TypeParams => { + CompilerScope::TypeParams => { todo!("analyze symbol comprehension for type params"); } } @@ -642,7 +638,7 @@ impl<'src> SymbolTableBuilder<'src> { source_code, current_varnames: Vec::new(), }; - this.enter_scope("top", SymbolTableType::Module, 0); + this.enter_scope("top", CompilerScope::Module, 0); this } } @@ -657,11 +653,11 @@ impl SymbolTableBuilder<'_> { Ok(symbol_table) } - fn enter_scope(&mut self, name: &str, typ: SymbolTableType, line_number: u32) { + fn enter_scope(&mut self, name: &str, typ: CompilerScope, line_number: u32) { let is_nested = self .tables .last() - .map(|table| table.is_nested || table.typ == SymbolTableType::Function) + .map(|table| table.is_nested || table.typ == CompilerScope::Function) .unwrap_or(false); let table = SymbolTable::new(name.to_owned(), typ, line_number, is_nested); self.tables.push(table); @@ -752,7 +748,7 @@ impl SymbolTableBuilder<'_> { if let Some(type_params) = type_params { self.enter_scope( &format!("", name.as_str()), - SymbolTableType::TypeParams, + CompilerScope::TypeParams, // FIXME: line no self.line_index_start(*range), ); @@ -780,14 +776,14 @@ impl SymbolTableBuilder<'_> { if let Some(type_params) = type_params { self.enter_scope( &format!("", name.as_str()), - SymbolTableType::TypeParams, + CompilerScope::TypeParams, self.line_index_start(type_params.range), ); self.scan_type_params(type_params)?; } self.enter_scope( name.as_str(), - SymbolTableType::Class, + CompilerScope::Class, self.line_index_start(*range), ); let prev_class = self.class_name.replace(name.to_string()); @@ -972,7 +968,7 @@ impl SymbolTableBuilder<'_> { self.enter_scope( // &name.to_string(), "TypeAlias", - SymbolTableType::TypeParams, + CompilerScope::TypeParams, self.line_index_start(type_params.range), ); self.scan_type_params(type_params)?; @@ -1174,7 +1170,7 @@ impl SymbolTableBuilder<'_> { // Interesting stuff about the __class__ variable: // https://docs.python.org/3/reference/datamodel.html?highlight=__class__#creating-the-class-object if context == ExpressionContext::Load - && self.tables.last().unwrap().typ == SymbolTableType::Function + && self.tables.last().unwrap().typ == CompilerScope::Function && id == "super" { self.register_name("__class__", SymbolUsage::Used, *range)?; @@ -1194,7 +1190,7 @@ impl SymbolTableBuilder<'_> { } else { self.enter_scope( "lambda", - SymbolTableType::Lambda, + CompilerScope::Lambda, self.line_index_start(expression.range()), ); } @@ -1260,7 +1256,7 @@ impl SymbolTableBuilder<'_> { if let Expr::Name(ExprName { id, .. }) = &**target { let id = id.as_str(); let table = self.tables.last().unwrap(); - if table.typ == SymbolTableType::Comprehension { + if table.typ == CompilerScope::Comprehension { self.register_name( id, SymbolUsage::AssignedNamedExprInComprehension, @@ -1291,7 +1287,7 @@ impl SymbolTableBuilder<'_> { // Comprehensions are compiled as functions, so create a scope for them: self.enter_scope( scope_name, - SymbolTableType::Comprehension, + CompilerScope::Comprehension, self.line_index_start(range), ); @@ -1457,7 +1453,7 @@ impl SymbolTableBuilder<'_> { self.scan_annotation(annotation)?; } - self.enter_scope(name, SymbolTableType::Function, line_number); + self.enter_scope(name, CompilerScope::Function, line_number); // Fill scope with parameter names: self.scan_parameters(¶meters.posonlyargs)?; diff --git a/vm/src/stdlib/symtable.rs b/vm/src/stdlib/symtable.rs index 9178006b36..e37a2f45bb 100644 --- a/vm/src/stdlib/symtable.rs +++ b/vm/src/stdlib/symtable.rs @@ -6,7 +6,7 @@ mod symtable { PyObjectRef, PyPayload, PyRef, PyResult, VirtualMachine, builtins::PyStrRef, compiler, }; use rustpython_codegen::symboltable::{ - Symbol, SymbolFlags, SymbolScope, SymbolTable, SymbolTableType, + CompilerScope, Symbol, SymbolFlags, SymbolScope, SymbolTable, }; use std::fmt; @@ -70,7 +70,7 @@ mod symtable { #[pymethod] fn is_optimized(&self) -> bool { - self.symtable.typ == SymbolTableType::Function + self.symtable.typ == CompilerScope::Function } #[pymethod]