Skip to content

Commit 9403919

Browse files
committed
refactor compile_class_def
1 parent 3c6e2cd commit 9403919

File tree

2 files changed

+36
-54
lines changed

2 files changed

+36
-54
lines changed

Lib/test/test_descr.py

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5124,8 +5124,6 @@ def test_iter_keys(self):
51245124
self.assertEqual(keys, ['__dict__', '__doc__', '__module__',
51255125
'__weakref__', 'meth'])
51265126

5127-
# TODO: RUSTPYTHON
5128-
@unittest.expectedFailure
51295127
@unittest.skipIf(hasattr(sys, 'gettrace') and sys.gettrace(),
51305128
'trace function introduces __local__')
51315129
def test_iter_values(self):

compiler/codegen/src/compile.rs

Lines changed: 36 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -2173,24 +2173,18 @@ impl Compiler<'_> {
21732173
) -> CompileResult<()> {
21742174
self.prepare_decorators(decorator_list)?;
21752175

2176-
let has_type_params = type_params.is_some();
2176+
let is_generic = type_params.is_some();
21772177
let firstlineno = self.get_source_line_number().get().to_u32();
21782178

2179-
if has_type_params {
2180-
// For PEP 695 classes, we need to:
2181-
// 1. Enter type params scope
2182-
// 2. Compile type params
2183-
// 3. Call compile_class_body (creates nested scope)
2184-
// 4. Generate class creation code
2185-
// 5. Exit type params scope and wrap everything in a function
2186-
2187-
let type_params_name = format!("<generic parameters of {}>", name);
2179+
// Step 1: If generic, enter type params scope and compile type params
2180+
if is_generic {
2181+
let type_params_name = format!("<generic parameters of {name}>");
21882182
self.push_output(
21892183
bytecode::CodeFlags::IS_OPTIMIZED | bytecode::CodeFlags::NEW_LOCALS,
21902184
0,
21912185
0,
21922186
0,
2193-
type_params_name.clone(),
2187+
type_params_name,
21942188
);
21952189

21962190
// Set private name for name mangling
@@ -2200,35 +2194,39 @@ impl Compiler<'_> {
22002194
self.compile_type_params(type_params.unwrap())?;
22012195
let dot_type_params = self.name(".type_params");
22022196
emit!(self, Instruction::StoreLocal(dot_type_params));
2197+
}
22032198

2204-
// Compile the class body (creates its own scope)
2205-
let prev_ctx = self.ctx;
2206-
self.ctx = CompileContext {
2207-
func: FunctionContext::NoFunction,
2208-
in_class: true,
2209-
loop_data: None,
2210-
};
2211-
let class_code = self.compile_class_body(name, body, type_params, firstlineno)?;
2212-
self.ctx = prev_ctx;
2199+
// Step 2: Compile class body (always done, whether generic or not)
2200+
let prev_ctx = self.ctx;
2201+
self.ctx = CompileContext {
2202+
func: FunctionContext::NoFunction,
2203+
in_class: true,
2204+
loop_data: None,
2205+
};
2206+
let class_code = self.compile_class_body(name, body, type_params, firstlineno)?;
2207+
self.ctx = prev_ctx;
22132208

2214-
// Back in type params scope, create .generic_base
2209+
// Step 3: Generate the rest of the code for the call
2210+
if is_generic {
2211+
// Still in type params scope
2212+
let dot_type_params = self.name(".type_params");
2213+
let dot_generic_base = self.name(".generic_base");
2214+
2215+
// Create .generic_base
22152216
emit!(self, Instruction::LoadNameAny(dot_type_params));
22162217
emit!(
22172218
self,
22182219
Instruction::CallIntrinsic1 {
22192220
func: bytecode::IntrinsicFunction1::SubscriptGeneric
22202221
}
22212222
);
2222-
let dot_generic_base = self.name(".generic_base");
22232223
emit!(self, Instruction::StoreLocal(dot_generic_base));
22242224

2225-
// Generate the class creation code (still in type params scope)
2225+
// Generate class creation code
22262226
emit!(self, Instruction::LoadBuildClass);
22272227

2228-
// Set up the class function
2228+
// Set up the class function with type params
22292229
let mut func_flags = bytecode::MakeFunctionFlags::empty();
2230-
2231-
// Load .type_params for the class function
22322230
emit!(self, Instruction::LoadNameAny(dot_type_params));
22332231
func_flags |= bytecode::MakeFunctionFlags::TYPE_PARAMS;
22342232

@@ -2240,12 +2238,10 @@ impl Compiler<'_> {
22402238
code: Box::new(class_code),
22412239
});
22422240
self.emit_load_const(ConstantData::Str { value: name.into() });
2243-
22442241
emit!(self, Instruction::MakeFunction(func_flags));
2245-
22462242
self.emit_load_const(ConstantData::Str { value: name.into() });
22472243

2248-
// Compile bases with .generic_base appended
2244+
// Compile original bases
22492245
let base_count = if let Some(arguments) = arguments {
22502246
for arg in &arguments.args {
22512247
self.compile_expression(arg)?;
@@ -2258,7 +2254,7 @@ impl Compiler<'_> {
22582254
// Load .generic_base as the last base
22592255
emit!(self, Instruction::LoadNameAny(dot_generic_base));
22602256

2261-
let nargs = 2 + base_count as u32 + 1; // function, name, bases..., generic_base
2257+
let nargs = 2 + u32::try_from(base_count).expect("too many base classes") + 1; // function, name, bases..., generic_base
22622258

22632259
// Handle keyword arguments
22642260
if let Some(arguments) = arguments
@@ -2272,11 +2268,12 @@ impl Compiler<'_> {
22722268
}
22732269
self.compile_expression(&keyword.value)?;
22742270
}
2275-
22762271
emit!(
22772272
self,
22782273
Instruction::CallFunctionKeyword {
2279-
nargs: nargs + arguments.keywords.len() as u32
2274+
nargs: nargs
2275+
+ u32::try_from(arguments.keywords.len())
2276+
.expect("too many keyword arguments")
22802277
}
22812278
);
22822279
} else {
@@ -2286,52 +2283,38 @@ impl Compiler<'_> {
22862283
// Return the created class
22872284
self.emit_return_value();
22882285

2289-
// Exit type params scope and get the code object
2286+
// Exit type params scope and wrap in function
22902287
let type_params_code = self.exit_scope();
22912288

2292-
// Now execute the type params function
2289+
// Execute the type params function
22932290
if self.build_closure(&type_params_code) {
22942291
// Should not need closure
22952292
}
22962293
self.emit_load_const(ConstantData::Code {
22972294
code: Box::new(type_params_code),
22982295
});
22992296
self.emit_load_const(ConstantData::Str {
2300-
value: type_params_name.into(),
2297+
value: format!("<generic parameters of {name}>").into(),
23012298
});
23022299
emit!(
23032300
self,
23042301
Instruction::MakeFunction(bytecode::MakeFunctionFlags::empty())
23052302
);
2306-
23072303
emit!(self, Instruction::CallFunctionPositional { nargs: 0 });
23082304
} else {
2309-
// Traditional class without type params
2310-
let prev_ctx = self.ctx;
2311-
self.ctx = CompileContext {
2312-
func: FunctionContext::NoFunction,
2313-
in_class: true,
2314-
loop_data: None,
2315-
};
2316-
2317-
let code = self.compile_class_body(name, body, type_params, firstlineno)?;
2318-
self.ctx = prev_ctx;
2319-
2305+
// Non-generic class: standard path
23202306
emit!(self, Instruction::LoadBuildClass);
23212307

23222308
let mut func_flags = bytecode::MakeFunctionFlags::empty();
2323-
2324-
if self.build_closure(&code) {
2309+
if self.build_closure(&class_code) {
23252310
func_flags |= bytecode::MakeFunctionFlags::CLOSURE;
23262311
}
23272312

23282313
self.emit_load_const(ConstantData::Code {
2329-
code: Box::new(code),
2314+
code: Box::new(class_code),
23302315
});
23312316
self.emit_load_const(ConstantData::Str { value: name.into() });
2332-
23332317
emit!(self, Instruction::MakeFunction(func_flags));
2334-
23352318
self.emit_load_const(ConstantData::Str { value: name.into() });
23362319

23372320
let call = if let Some(arguments) = arguments {
@@ -2342,6 +2325,7 @@ impl Compiler<'_> {
23422325
self.compile_normal_call(call);
23432326
}
23442327

2328+
// Step 4: Apply decorators and store (common to both paths)
23452329
self.apply_decorators(decorator_list);
23462330
self.store_name(name)
23472331
}

0 commit comments

Comments
 (0)