From dbd2887943b4b7c763254b034e61b5a17911851e Mon Sep 17 00:00:00 2001 From: Jeong YunWon Date: Fri, 11 Jul 2025 16:19:58 +0900 Subject: [PATCH 1/2] set_qualname --- compiler/codegen/src/compile.rs | 119 ++++++++++++++++++++++++++++---- 1 file changed, 106 insertions(+), 13 deletions(-) diff --git a/compiler/codegen/src/compile.rs b/compiler/codegen/src/compile.rs index 98b70dfbb20..68342c7ba6b 100644 --- a/compiler/codegen/src/compile.rs +++ b/compiler/codegen/src/compile.rs @@ -467,6 +467,101 @@ impl Compiler<'_> { .to_u32() } + /// Set the qualified name for the current code object, based on CPython's compiler_set_qualname + fn set_qualname(&mut self) -> String { + let qualname = self.make_qualname(); + self.current_code_info().qualname = Some(qualname.clone()); + qualname + } + fn make_qualname(&mut self) -> String { + let stack_size = self.code_stack.len(); + assert!(stack_size >= 1); + + let current_obj_name = self.current_code_info().obj_name.clone(); + + // If we're at the module level (stack_size == 1), qualname is just the name + if stack_size <= 1 { + return current_obj_name; + } + + // Check parent scope + let mut parent_idx = stack_size - 2; + let mut parent = &self.code_stack[parent_idx]; + + // If parent is a type parameter scope, look at grandparent + if parent.obj_name.starts_with(" self.symbol_table_stack.len() { + // We might be in a situation where symbol table isn't pushed yet + // In this case, check the parent symbol table + if let Some(parent_table) = self.symbol_table_stack.last() { + if let Some(symbol) = parent_table.lookup(¤t_obj_name) { + if symbol.scope == SymbolScope::GlobalExplicit { + force_global = true; + } + } + } + } else if let Some(_current_table) = self.symbol_table_stack.last() { + // Mangle the name if necessary (for private names in classes) + let mangled_name = self.mangle(¤t_obj_name); + + // Look up in parent symbol table to check scope + if self.symbol_table_stack.len() >= 2 { + let parent_table = &self.symbol_table_stack[self.symbol_table_stack.len() - 2]; + if let Some(symbol) = parent_table.lookup(&mangled_name) { + if symbol.scope == SymbolScope::GlobalExplicit { + force_global = true; + } + } + } + } + + // Build the qualified name + if force_global { + // For global symbols, qualname is just the name + current_obj_name + } else { + // Check parent scope type + let parent_obj_name = &parent.obj_name; + + // Determine if parent is a function-like scope + let is_function_parent = parent.flags.contains(bytecode::CodeFlags::IS_OPTIMIZED) + && !parent_obj_name.starts_with("<") // Not a special scope like , , etc. + && parent_obj_name != ""; // Not the module scope + + let path_len = self.qualified_path.len(); + + if is_function_parent { + // For functions, append . to parent qualname + // Use parent's qualname if available, otherwise use parent_obj_name + let parent_qualname = parent.qualname.as_ref().unwrap_or(parent_obj_name); + format!("{parent_qualname}..{current_obj_name}") + } else { + // For classes and other scopes, use qualified_path without current name + // (since current name is already pushed to qualified_path) + if path_len > 0 && self.qualified_path[path_len - 1] == current_obj_name { + // Current name is already in qualified_path, just join + self.qualified_path.join(".") + } else if self.qualified_path.is_empty() { + current_obj_name + } else { + // Append current name to qualified_path + format!("{}.{}", self.qualified_path.join("."), current_obj_name) + } + } + } + } + fn compile_program( &mut self, body: &ModModule, @@ -1548,10 +1643,9 @@ impl Compiler<'_> { }; self.push_qualified_path(name); - let qualified_name = self.qualified_path.join("."); - // Update the qualname in the current code info - self.code_stack.last_mut().unwrap().qualname = Some(qualified_name.clone()); + // Set qualname using the new method + let qualname = self.set_qualname(); self.push_qualified_path(""); @@ -1646,7 +1740,7 @@ impl Compiler<'_> { code: Box::new(code), }); self.emit_load_const(ConstantData::Str { - value: qualified_name.into(), + value: qualname.into(), }); // Turn code object into function object: @@ -1771,7 +1865,6 @@ impl Compiler<'_> { global_path_prefix.append(&mut self.qualified_path); } self.push_qualified_path(name); - let qualified_name = self.qualified_path.join("."); // If there are type params, we need to push a special symbol table just for them if let Some(type_params) = type_params { @@ -1790,8 +1883,8 @@ impl Compiler<'_> { self.push_output(bytecode::CodeFlags::empty(), 0, 0, 0, name.to_owned()); - // Update the qualname in the current code info - self.code_stack.last_mut().unwrap().qualname = Some(qualified_name.clone()); + // Set qualname using the new method + let qualname = self.set_qualname(); // For class scopes, set u_private to the class name for name mangling self.code_stack.last_mut().unwrap().private = Some(name.to_owned()); @@ -1803,10 +1896,10 @@ impl Compiler<'_> { let dunder_module = self.name("__module__"); emit!(self, Instruction::StoreLocal(dunder_module)); self.emit_load_const(ConstantData::Str { - value: qualified_name.into(), + value: qualname.into(), }); - let qualname = self.name("__qualname__"); - emit!(self, Instruction::StoreLocal(qualname)); + let qualname_name = self.name("__qualname__"); + emit!(self, Instruction::StoreLocal(qualname_name)); self.load_docstring(doc_str); let doc = self.name("__doc__"); emit!(self, Instruction::StoreLocal(doc)); @@ -3606,8 +3699,8 @@ impl Compiler<'_> { let mut func_flags = self .enter_function(&name, parameters.as_deref().unwrap_or(&Default::default()))?; - // Lambda qualname should be - self.code_stack.last_mut().unwrap().qualname = Some(name.clone()); + // Set qualname for lambda + self.set_qualname(); self.ctx = CompileContext { loop_data: Option::None, @@ -4078,7 +4171,7 @@ impl Compiler<'_> { self.push_output(flags, 1, 1, 0, name.to_owned()); // Set qualname for comprehension - self.code_stack.last_mut().unwrap().qualname = Some(name.to_owned()); + self.set_qualname(); let arg0 = self.varname(".0")?; From e075538ddfda8359cb8678015fdba14dacb642c7 Mon Sep 17 00:00:00 2001 From: Jeong YunWon Date: Fri, 11 Jul 2025 17:27:34 +0900 Subject: [PATCH 2/2] remove qualified_path --- compiler/codegen/src/compile.rs | 54 ++++++--------------------------- 1 file changed, 9 insertions(+), 45 deletions(-) diff --git a/compiler/codegen/src/compile.rs b/compiler/codegen/src/compile.rs index 68342c7ba6b..5aef2020d09 100644 --- a/compiler/codegen/src/compile.rs +++ b/compiler/codegen/src/compile.rs @@ -74,7 +74,6 @@ struct Compiler<'src> { source_code: SourceCode<'src>, // current_source_location: SourceLocation, current_source_range: TextRange, - qualified_path: Vec, done_with_future_stmts: DoneWithFuture, future_annotations: bool, ctx: CompileContext, @@ -326,7 +325,6 @@ impl<'src> Compiler<'src> { source_code, // current_source_location: SourceLocation::default(), current_source_range: TextRange::default(), - qualified_path: Vec::new(), done_with_future_stmts: DoneWithFuture::No, future_annotations: false, ctx: CompileContext { @@ -401,12 +399,8 @@ impl Compiler<'_> { .map(|(var, _)| var.clone()) .collect(); - // Calculate qualname based on the current qualified path - let qualname = if self.qualified_path.is_empty() { - Some(obj_name.clone()) - } else { - Some(self.qualified_path.join(".")) - }; + // Qualname will be set later by set_qualname + let qualname = None; // Get the private name from current scope if exists let private = self.code_stack.last().and_then(|info| info.private.clone()); @@ -539,24 +533,21 @@ impl Compiler<'_> { && !parent_obj_name.starts_with("<") // Not a special scope like , , etc. && parent_obj_name != ""; // Not the module scope - let path_len = self.qualified_path.len(); - if is_function_parent { // For functions, append . to parent qualname // Use parent's qualname if available, otherwise use parent_obj_name let parent_qualname = parent.qualname.as_ref().unwrap_or(parent_obj_name); format!("{parent_qualname}..{current_obj_name}") } else { - // For classes and other scopes, use qualified_path without current name - // (since current name is already pushed to qualified_path) - if path_len > 0 && self.qualified_path[path_len - 1] == current_obj_name { - // Current name is already in qualified_path, just join - self.qualified_path.join(".") - } else if self.qualified_path.is_empty() { + // For classes and other scopes, use parent's qualname directly + // Use parent's qualname if available, otherwise use parent_obj_name + let parent_qualname = parent.qualname.as_ref().unwrap_or(parent_obj_name); + if parent_qualname == "" { + // Module level, just use the name current_obj_name } else { - // Append current name to qualified_path - format!("{}.{}", self.qualified_path.join("."), current_obj_name) + // Concatenate parent qualname with current name + format!("{parent_qualname}.{current_obj_name}") } } } @@ -1642,13 +1633,9 @@ impl Compiler<'_> { }, }; - self.push_qualified_path(name); - // Set qualname using the new method let qualname = self.set_qualname(); - self.push_qualified_path(""); - let (doc_str, body) = split_doc(body, &self.opts); self.current_code_info() @@ -1676,8 +1663,6 @@ impl Compiler<'_> { } let code = self.pop_code_object(); - self.qualified_path.pop(); - self.qualified_path.pop(); self.ctx = prev_ctx; // Prepare generic type parameters: @@ -1852,20 +1837,6 @@ impl Compiler<'_> { loop_data: None, }; - // Check if the class is declared global - let symbol_table = self.symbol_table_stack.last().unwrap(); - let symbol = unwrap_internal( - self, - symbol_table - .lookup(name.as_ref()) - .ok_or_else(|| InternalError::MissingSymbol(name.to_owned())), - ); - let mut global_path_prefix = Vec::new(); - if symbol.scope == SymbolScope::GlobalExplicit { - global_path_prefix.append(&mut self.qualified_path); - } - self.push_qualified_path(name); - // If there are type params, we need to push a special symbol table just for them if let Some(type_params) = type_params { self.push_symbol_table(); @@ -1941,9 +1912,6 @@ impl Compiler<'_> { self.emit_return_value(); let code = self.pop_code_object(); - - self.qualified_path.pop(); - self.qualified_path.append(global_path_prefix.as_mut()); self.ctx = prev_ctx; emit!(self, Instruction::LoadBuildClass); @@ -4429,10 +4397,6 @@ impl Compiler<'_> { .line_index(self.current_source_range.start()) } - fn push_qualified_path(&mut self, name: &str) { - self.qualified_path.push(name.to_owned()); - } - fn mark_generator(&mut self) { self.current_code_info().flags |= bytecode::CodeFlags::IS_GENERATOR }