Skip to content

Commit 61e0866

Browse files
committed
set_qualname
1 parent 18d7c1b commit 61e0866

File tree

1 file changed

+107
-17
lines changed

1 file changed

+107
-17
lines changed

compiler/codegen/src/compile.rs

Lines changed: 107 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -402,12 +402,8 @@ impl Compiler<'_> {
402402
.map(|(var, _)| var.clone())
403403
.collect();
404404

405-
// Calculate qualname based on the current qualified path
406-
let qualname = if self.qualified_path.is_empty() {
407-
Some(obj_name.clone())
408-
} else {
409-
Some(self.qualified_path.join("."))
410-
};
405+
// Qualname will be set later by set_qualname for non-module scopes
406+
let qualname = None;
411407

412408
let info = ir::CodeInfo {
413409
flags,
@@ -464,6 +460,101 @@ impl Compiler<'_> {
464460
.to_u32()
465461
}
466462

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

15051596
self.push_qualified_path(name);
1506-
let qualified_name = self.qualified_path.join(".");
15071597

1508-
// Update the qualname in the current code info
1509-
self.code_stack.last_mut().unwrap().qualname = Some(qualified_name.clone());
1598+
// Set the qualified name using set_qualname
1599+
let qualname = self.set_qualname();
15101600

15111601
self.push_qualified_path("<locals>");
15121602

@@ -1593,7 +1683,7 @@ impl Compiler<'_> {
15931683
code: Box::new(code),
15941684
});
15951685
self.emit_load_const(ConstantData::Str {
1596-
value: qualified_name.into(),
1686+
value: qualname.into(),
15971687
});
15981688

15991689
// Turn code object into function object:
@@ -1719,7 +1809,6 @@ impl Compiler<'_> {
17191809
global_path_prefix.append(&mut self.qualified_path);
17201810
}
17211811
self.push_qualified_path(name);
1722-
let qualified_name = self.qualified_path.join(".");
17231812

17241813
// If there are type params, we need to push a special symbol table just for them
17251814
if let Some(type_params) = type_params {
@@ -1732,17 +1821,18 @@ impl Compiler<'_> {
17321821

17331822
self.push_output(bytecode::CodeFlags::empty(), 0, 0, 0, name.to_owned());
17341823

1735-
// Update the qualname in the current code info
1736-
self.code_stack.last_mut().unwrap().qualname = Some(qualified_name.clone());
1824+
// Set the qualified name using set_qualname
1825+
let qualname = self.set_qualname();
17371826

17381827
let (doc_str, body) = split_doc(body, &self.opts);
17391828

17401829
let dunder_name = self.name("__name__");
17411830
emit!(self, Instruction::LoadGlobal(dunder_name));
17421831
let dunder_module = self.name("__module__");
17431832
emit!(self, Instruction::StoreLocal(dunder_module));
1833+
17441834
self.emit_load_const(ConstantData::Str {
1745-
value: qualified_name.into(),
1835+
value: qualname.into(),
17461836
});
17471837
let qualname = self.name("__qualname__");
17481838
emit!(self, Instruction::StoreLocal(qualname));
@@ -3510,8 +3600,8 @@ impl Compiler<'_> {
35103600
let mut func_flags = self
35113601
.enter_function(&name, parameters.as_deref().unwrap_or(&Default::default()))?;
35123602

3513-
// Lambda qualname should be <lambda>
3514-
self.code_stack.last_mut().unwrap().qualname = Some(name.clone());
3603+
// Set qualname for lambda
3604+
self.set_qualname();
35153605

35163606
self.ctx = CompileContext {
35173607
loop_data: Option::None,
@@ -3976,7 +4066,7 @@ impl Compiler<'_> {
39764066
self.push_output(flags, 1, 1, 0, name.to_owned());
39774067

39784068
// Set qualname for comprehension
3979-
self.code_stack.last_mut().unwrap().qualname = Some(name.to_owned());
4069+
self.set_qualname();
39804070

39814071
let arg0 = self.varname(".0")?;
39824072

0 commit comments

Comments
 (0)