Skip to content

Commit 59c7fcb

Browse files
authored
compiler set_qualname (RustPython#5930)
* set_qualname * remove qualified_path
1 parent 50c241f commit 59c7fcb

File tree

1 file changed

+105
-48
lines changed

1 file changed

+105
-48
lines changed

compiler/codegen/src/compile.rs

Lines changed: 105 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,6 @@ struct Compiler<'src> {
7474
source_code: SourceCode<'src>,
7575
// current_source_location: SourceLocation,
7676
current_source_range: TextRange,
77-
qualified_path: Vec<String>,
7877
done_with_future_stmts: DoneWithFuture,
7978
future_annotations: bool,
8079
ctx: CompileContext,
@@ -326,7 +325,6 @@ impl<'src> Compiler<'src> {
326325
source_code,
327326
// current_source_location: SourceLocation::default(),
328327
current_source_range: TextRange::default(),
329-
qualified_path: Vec::new(),
330328
done_with_future_stmts: DoneWithFuture::No,
331329
future_annotations: false,
332330
ctx: CompileContext {
@@ -401,12 +399,8 @@ impl Compiler<'_> {
401399
.map(|(var, _)| var.clone())
402400
.collect();
403401

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

411405
// Get the private name from current scope if exists
412406
let private = self.code_stack.last().and_then(|info| info.private.clone());
@@ -467,6 +461,98 @@ impl Compiler<'_> {
467461
.to_u32()
468462
}
469463

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

1550-
self.push_qualified_path(name);
1551-
let qualified_name = self.qualified_path.join(".");
1552-
1553-
// Update the qualname in the current code info
1554-
self.code_stack.last_mut().unwrap().qualname = Some(qualified_name.clone());
1555-
1556-
self.push_qualified_path("<locals>");
1636+
// Set qualname using the new method
1637+
let qualname = self.set_qualname();
15571638

15581639
let (doc_str, body) = split_doc(body, &self.opts);
15591640

@@ -1582,8 +1663,6 @@ impl Compiler<'_> {
15821663
}
15831664

15841665
let code = self.pop_code_object();
1585-
self.qualified_path.pop();
1586-
self.qualified_path.pop();
15871666
self.ctx = prev_ctx;
15881667

15891668
// Prepare generic type parameters:
@@ -1646,7 +1725,7 @@ impl Compiler<'_> {
16461725
code: Box::new(code),
16471726
});
16481727
self.emit_load_const(ConstantData::Str {
1649-
value: qualified_name.into(),
1728+
value: qualname.into(),
16501729
});
16511730

16521731
// Turn code object into function object:
@@ -1758,21 +1837,6 @@ impl Compiler<'_> {
17581837
loop_data: None,
17591838
};
17601839

1761-
// Check if the class is declared global
1762-
let symbol_table = self.symbol_table_stack.last().unwrap();
1763-
let symbol = unwrap_internal(
1764-
self,
1765-
symbol_table
1766-
.lookup(name.as_ref())
1767-
.ok_or_else(|| InternalError::MissingSymbol(name.to_owned())),
1768-
);
1769-
let mut global_path_prefix = Vec::new();
1770-
if symbol.scope == SymbolScope::GlobalExplicit {
1771-
global_path_prefix.append(&mut self.qualified_path);
1772-
}
1773-
self.push_qualified_path(name);
1774-
let qualified_name = self.qualified_path.join(".");
1775-
17761840
// If there are type params, we need to push a special symbol table just for them
17771841
if let Some(type_params) = type_params {
17781842
self.push_symbol_table();
@@ -1790,8 +1854,8 @@ impl Compiler<'_> {
17901854

17911855
self.push_output(bytecode::CodeFlags::empty(), 0, 0, 0, name.to_owned());
17921856

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

17961860
// For class scopes, set u_private to the class name for name mangling
17971861
self.code_stack.last_mut().unwrap().private = Some(name.to_owned());
@@ -1803,10 +1867,10 @@ impl Compiler<'_> {
18031867
let dunder_module = self.name("__module__");
18041868
emit!(self, Instruction::StoreLocal(dunder_module));
18051869
self.emit_load_const(ConstantData::Str {
1806-
value: qualified_name.into(),
1870+
value: qualname.into(),
18071871
});
1808-
let qualname = self.name("__qualname__");
1809-
emit!(self, Instruction::StoreLocal(qualname));
1872+
let qualname_name = self.name("__qualname__");
1873+
emit!(self, Instruction::StoreLocal(qualname_name));
18101874
self.load_docstring(doc_str);
18111875
let doc = self.name("__doc__");
18121876
emit!(self, Instruction::StoreLocal(doc));
@@ -1848,9 +1912,6 @@ impl Compiler<'_> {
18481912
self.emit_return_value();
18491913

18501914
let code = self.pop_code_object();
1851-
1852-
self.qualified_path.pop();
1853-
self.qualified_path.append(global_path_prefix.as_mut());
18541915
self.ctx = prev_ctx;
18551916

18561917
emit!(self, Instruction::LoadBuildClass);
@@ -3606,8 +3667,8 @@ impl Compiler<'_> {
36063667
let mut func_flags = self
36073668
.enter_function(&name, parameters.as_deref().unwrap_or(&Default::default()))?;
36083669

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

36123673
self.ctx = CompileContext {
36133674
loop_data: Option::None,
@@ -4078,7 +4139,7 @@ impl Compiler<'_> {
40784139
self.push_output(flags, 1, 1, 0, name.to_owned());
40794140

40804141
// Set qualname for comprehension
4081-
self.code_stack.last_mut().unwrap().qualname = Some(name.to_owned());
4142+
self.set_qualname();
40824143

40834144
let arg0 = self.varname(".0")?;
40844145

@@ -4336,10 +4397,6 @@ impl Compiler<'_> {
43364397
.line_index(self.current_source_range.start())
43374398
}
43384399

4339-
fn push_qualified_path(&mut self, name: &str) {
4340-
self.qualified_path.push(name.to_owned());
4341-
}
4342-
43434400
fn mark_generator(&mut self) {
43444401
self.current_code_info().flags |= bytecode::CodeFlags::IS_GENERATOR
43454402
}

0 commit comments

Comments
 (0)