Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
153 changes: 105 additions & 48 deletions compiler/codegen/src/compile.rs
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,6 @@ struct Compiler<'src> {
source_code: SourceCode<'src>,
// current_source_location: SourceLocation,
current_source_range: TextRange,
qualified_path: Vec<String>,
done_with_future_stmts: DoneWithFuture,
future_annotations: bool,
ctx: CompileContext,
Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -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());
Expand Down Expand Up @@ -467,6 +461,98 @@ 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("<generic parameters of ") {
if stack_size == 2 {
// If we're immediately within the module after type params,
// qualname is just the name
return current_obj_name;
}
parent_idx = stack_size - 3;
parent = &self.code_stack[parent_idx];
}

// Check if this is a global class/function
let mut force_global = false;
if stack_size > 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(&current_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(&current_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 <lambda>, <listcomp>, etc.
&& parent_obj_name != "<module>"; // Not the module scope

if is_function_parent {
// For functions, append .<locals> 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}.<locals>.{current_obj_name}")
} else {
// 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>" {
// Module level, just use the name
current_obj_name
} else {
// Concatenate parent qualname with current name
format!("{parent_qualname}.{current_obj_name}")
}
}
}
}

fn compile_program(
&mut self,
body: &ModModule,
Expand Down Expand Up @@ -1547,13 +1633,8 @@ 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());

self.push_qualified_path("<locals>");
// Set qualname using the new method
let qualname = self.set_qualname();

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

Expand Down Expand Up @@ -1582,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:
Expand Down Expand Up @@ -1646,7 +1725,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:
Expand Down Expand Up @@ -1758,21 +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);
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 {
self.push_symbol_table();
Expand All @@ -1790,8 +1854,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());
Expand All @@ -1803,10 +1867,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));
Expand Down Expand Up @@ -1848,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);
Expand Down Expand Up @@ -3606,8 +3667,8 @@ impl Compiler<'_> {
let mut func_flags = self
.enter_function(&name, parameters.as_deref().unwrap_or(&Default::default()))?;

// Lambda qualname should be <lambda>
self.code_stack.last_mut().unwrap().qualname = Some(name.clone());
// Set qualname for lambda
self.set_qualname();

self.ctx = CompileContext {
loop_data: Option::None,
Expand Down Expand Up @@ -4078,7 +4139,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")?;

Expand Down Expand Up @@ -4336,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
}
Expand Down
Loading