Skip to content

Commit dbd2887

Browse files
committed
set_qualname
1 parent 392f9c2 commit dbd2887

File tree

1 file changed

+106
-13
lines changed

1 file changed

+106
-13
lines changed

compiler/codegen/src/compile.rs

Lines changed: 106 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -467,6 +467,101 @@ impl Compiler<'_> {
467467
.to_u32()
468468
}
469469

470+
/// Set the qualified name for the current code object, based on CPython's compiler_set_qualname
471+
fn set_qualname(&mut self) -> String {
472+
let qualname = self.make_qualname();
473+
self.current_code_info().qualname = Some(qualname.clone());
474+
qualname
475+
}
476+
fn make_qualname(&mut self) -> String {
477+
let stack_size = self.code_stack.len();
478+
assert!(stack_size >= 1);
479+
480+
let current_obj_name = self.current_code_info().obj_name.clone();
481+
482+
// If we're at the module level (stack_size == 1), qualname is just the name
483+
if stack_size <= 1 {
484+
return current_obj_name;
485+
}
486+
487+
// Check parent scope
488+
let mut parent_idx = stack_size - 2;
489+
let mut parent = &self.code_stack[parent_idx];
490+
491+
// If parent is a type parameter scope, look at grandparent
492+
if parent.obj_name.starts_with("<generic parameters of ") {
493+
if stack_size == 2 {
494+
// If we're immediately within the module after type params,
495+
// qualname is just the name
496+
return current_obj_name;
497+
}
498+
parent_idx = stack_size - 3;
499+
parent = &self.code_stack[parent_idx];
500+
}
501+
502+
// Check if this is a global class/function
503+
let mut force_global = false;
504+
if stack_size > self.symbol_table_stack.len() {
505+
// We might be in a situation where symbol table isn't pushed yet
506+
// In this case, check the parent symbol table
507+
if let Some(parent_table) = self.symbol_table_stack.last() {
508+
if let Some(symbol) = parent_table.lookup(&current_obj_name) {
509+
if symbol.scope == SymbolScope::GlobalExplicit {
510+
force_global = true;
511+
}
512+
}
513+
}
514+
} else if let Some(_current_table) = self.symbol_table_stack.last() {
515+
// Mangle the name if necessary (for private names in classes)
516+
let mangled_name = self.mangle(&current_obj_name);
517+
518+
// Look up in parent symbol table to check scope
519+
if self.symbol_table_stack.len() >= 2 {
520+
let parent_table = &self.symbol_table_stack[self.symbol_table_stack.len() - 2];
521+
if let Some(symbol) = parent_table.lookup(&mangled_name) {
522+
if symbol.scope == SymbolScope::GlobalExplicit {
523+
force_global = true;
524+
}
525+
}
526+
}
527+
}
528+
529+
// Build the qualified name
530+
if force_global {
531+
// For global symbols, qualname is just the name
532+
current_obj_name
533+
} else {
534+
// Check parent scope type
535+
let parent_obj_name = &parent.obj_name;
536+
537+
// Determine if parent is a function-like scope
538+
let is_function_parent = parent.flags.contains(bytecode::CodeFlags::IS_OPTIMIZED)
539+
&& !parent_obj_name.starts_with("<") // Not a special scope like <lambda>, <listcomp>, etc.
540+
&& parent_obj_name != "<module>"; // Not the module scope
541+
542+
let path_len = self.qualified_path.len();
543+
544+
if is_function_parent {
545+
// For functions, append .<locals> to parent qualname
546+
// Use parent's qualname if available, otherwise use parent_obj_name
547+
let parent_qualname = parent.qualname.as_ref().unwrap_or(parent_obj_name);
548+
format!("{parent_qualname}.<locals>.{current_obj_name}")
549+
} else {
550+
// For classes and other scopes, use qualified_path without current name
551+
// (since current name is already pushed to qualified_path)
552+
if path_len > 0 && self.qualified_path[path_len - 1] == current_obj_name {
553+
// Current name is already in qualified_path, just join
554+
self.qualified_path.join(".")
555+
} else if self.qualified_path.is_empty() {
556+
current_obj_name
557+
} else {
558+
// Append current name to qualified_path
559+
format!("{}.{}", self.qualified_path.join("."), current_obj_name)
560+
}
561+
}
562+
}
563+
}
564+
470565
fn compile_program(
471566
&mut self,
472567
body: &ModModule,
@@ -1548,10 +1643,9 @@ impl Compiler<'_> {
15481643
};
15491644

15501645
self.push_qualified_path(name);
1551-
let qualified_name = self.qualified_path.join(".");
15521646

1553-
// Update the qualname in the current code info
1554-
self.code_stack.last_mut().unwrap().qualname = Some(qualified_name.clone());
1647+
// Set qualname using the new method
1648+
let qualname = self.set_qualname();
15551649

15561650
self.push_qualified_path("<locals>");
15571651

@@ -1646,7 +1740,7 @@ impl Compiler<'_> {
16461740
code: Box::new(code),
16471741
});
16481742
self.emit_load_const(ConstantData::Str {
1649-
value: qualified_name.into(),
1743+
value: qualname.into(),
16501744
});
16511745

16521746
// Turn code object into function object:
@@ -1771,7 +1865,6 @@ impl Compiler<'_> {
17711865
global_path_prefix.append(&mut self.qualified_path);
17721866
}
17731867
self.push_qualified_path(name);
1774-
let qualified_name = self.qualified_path.join(".");
17751868

17761869
// If there are type params, we need to push a special symbol table just for them
17771870
if let Some(type_params) = type_params {
@@ -1790,8 +1883,8 @@ impl Compiler<'_> {
17901883

17911884
self.push_output(bytecode::CodeFlags::empty(), 0, 0, 0, name.to_owned());
17921885

1793-
// Update the qualname in the current code info
1794-
self.code_stack.last_mut().unwrap().qualname = Some(qualified_name.clone());
1886+
// Set qualname using the new method
1887+
let qualname = self.set_qualname();
17951888

17961889
// For class scopes, set u_private to the class name for name mangling
17971890
self.code_stack.last_mut().unwrap().private = Some(name.to_owned());
@@ -1803,10 +1896,10 @@ impl Compiler<'_> {
18031896
let dunder_module = self.name("__module__");
18041897
emit!(self, Instruction::StoreLocal(dunder_module));
18051898
self.emit_load_const(ConstantData::Str {
1806-
value: qualified_name.into(),
1899+
value: qualname.into(),
18071900
});
1808-
let qualname = self.name("__qualname__");
1809-
emit!(self, Instruction::StoreLocal(qualname));
1901+
let qualname_name = self.name("__qualname__");
1902+
emit!(self, Instruction::StoreLocal(qualname_name));
18101903
self.load_docstring(doc_str);
18111904
let doc = self.name("__doc__");
18121905
emit!(self, Instruction::StoreLocal(doc));
@@ -3606,8 +3699,8 @@ impl Compiler<'_> {
36063699
let mut func_flags = self
36073700
.enter_function(&name, parameters.as_deref().unwrap_or(&Default::default()))?;
36083701

3609-
// Lambda qualname should be <lambda>
3610-
self.code_stack.last_mut().unwrap().qualname = Some(name.clone());
3702+
// Set qualname for lambda
3703+
self.set_qualname();
36113704

36123705
self.ctx = CompileContext {
36133706
loop_data: Option::None,
@@ -4078,7 +4171,7 @@ impl Compiler<'_> {
40784171
self.push_output(flags, 1, 1, 0, name.to_owned());
40794172

40804173
// Set qualname for comprehension
4081-
self.code_stack.last_mut().unwrap().qualname = Some(name.to_owned());
4174+
self.set_qualname();
40824175

40834176
let arg0 = self.varname(".0")?;
40844177

0 commit comments

Comments
 (0)