Visitar URL original
more PEP695 by youknowone · Pull Request #5917 · RustPython/RustPython · GitHub
Skip to content
Merged
Changes from 1 commit
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
Next Next commit
compile_class_body
  • Loading branch information
youknowone committed Jul 12, 2025
commit a903bea52be1f44d900bcbed225152832f7dbaf0
106 changes: 71 additions & 35 deletions compiler/codegen/src/compile.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2069,66 +2069,56 @@ impl Compiler<'_> {
false
}

fn compile_class_def(
/// Compile the class body into a code object
/// This is similar to CPython's compiler_class_body
fn compile_class_body(
&mut self,
name: &str,
body: &[Stmt],
decorator_list: &[Decorator],
type_params: Option<&TypeParams>,
arguments: Option<&Arguments>,
) -> CompileResult<()> {
self.prepare_decorators(decorator_list)?;

let prev_ctx = self.ctx;
self.ctx = CompileContext {
func: FunctionContext::NoFunction,
in_class: true,
loop_data: None,
};

// 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();
// Save current private name to restore later
let saved_private = self.code_stack.last().and_then(|info| info.private.clone());
// Compile type parameters and store as .type_params
self.compile_type_params(type_params)?;
// Restore private name after type param scope
if let Some(private) = saved_private {
self.code_stack.last_mut().unwrap().private = Some(private);
}
let dot_type_params = self.name(".type_params");
emit!(self, Instruction::StoreLocal(dot_type_params));
}

self.push_output(bytecode::CodeFlags::empty(), 0, 0, 0, name.to_owned());
firstlineno: u32,
) -> CompileResult<CodeObject> {
// 1. Enter class scope
// Use enter_scope instead of push_output to match CPython
let key = self.symbol_table_stack.len();
self.push_symbol_table();
self.enter_scope(name, SymbolTableType::Class, key, firstlineno)?;

// 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());

// 2. Set up class namespace
let (doc_str, body) = split_doc(body, &self.opts);

// Load (global) __name__ and store as __module__
let dunder_name = self.name("__name__");
emit!(self, Instruction::LoadGlobal(dunder_name));
let dunder_module = self.name("__module__");
emit!(self, Instruction::StoreLocal(dunder_module));

// Store __qualname__
self.emit_load_const(ConstantData::Str {
value: qualname.into(),
});
let qualname_name = self.name("__qualname__");
emit!(self, Instruction::StoreLocal(qualname_name));

// Store __doc__
self.load_docstring(doc_str);
let doc = self.name("__doc__");
emit!(self, Instruction::StoreLocal(doc));
// setup annotations
if Self::find_ann(body) {
emit!(self, Instruction::SetupAnnotation);
}

// Set __type_params__ from .type_params if we have type parameters (PEP 695)
// Store __firstlineno__ (new in Python 3.12+)
self.emit_load_const(ConstantData::Integer {
value: BigInt::from(firstlineno),
});
let firstlineno_name = self.name("__firstlineno__");
emit!(self, Instruction::StoreLocal(firstlineno_name));

// Set __type_params__ if we have type parameters
if type_params.is_some() {
// Load .type_params from enclosing scope
let dot_type_params = self.name(".type_params");
Expand All @@ -2139,8 +2129,15 @@ impl Compiler<'_> {
emit!(self, Instruction::StoreLocal(dunder_type_params));
}

// Setup annotations if needed
if Self::find_ann(body) {
emit!(self, Instruction::SetupAnnotation);
}

// 3. Compile the class body
self.compile_statements(body)?;

// 4. Handle __classcell__ if needed
let classcell_idx = self
.code_stack
.last_mut()
Expand All @@ -2159,9 +2156,48 @@ impl Compiler<'_> {
self.emit_load_const(ConstantData::None);
}

// Return the class namespace
self.emit_return_value();

let code = self.exit_scope();
// Exit scope and return the code object
Ok(self.exit_scope())
}

fn compile_class_def(
&mut self,
name: &str,
body: &[Stmt],
decorator_list: &[Decorator],
type_params: Option<&TypeParams>,
arguments: Option<&Arguments>,
) -> CompileResult<()> {
self.prepare_decorators(decorator_list)?;

let prev_ctx = self.ctx;
self.ctx = CompileContext {
func: FunctionContext::NoFunction,
in_class: true,
loop_data: None,
};

// 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();
// Save current private name to restore later
let saved_private = self.code_stack.last().and_then(|info| info.private.clone());
// Compile type parameters and store as .type_params
self.compile_type_params(type_params)?;
// Restore private name after type param scope
if let Some(private) = saved_private {
self.code_stack.last_mut().unwrap().private = Some(private);
}
let dot_type_params = self.name(".type_params");
emit!(self, Instruction::StoreLocal(dot_type_params));
}

// Compile the class body into a code object
let firstlineno = self.get_source_line_number().get().to_u32();
let code = self.compile_class_body(name, body, type_params, firstlineno)?;
self.ctx = prev_ctx;

emit!(self, Instruction::LoadBuildClass);
Expand Down