Skip to content

Commit 8c097df

Browse files
committed
fix again
1 parent 29d2d88 commit 8c097df

File tree

3 files changed

+112
-66
lines changed

3 files changed

+112
-66
lines changed

Lib/_opcode_metadata.py

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -132,9 +132,6 @@
132132
'BUILD_SET_FROM_TUPLES': 122,
133133
'BUILD_TUPLE_FROM_ITER': 123,
134134
'BUILD_TUPLE_FROM_TUPLES': 124,
135-
'CALL_METHOD_POSITIONAL': 125,
136-
'CALL_METHOD_KEYWORD': 126,
137-
'CALL_METHOD_EX': 127,
138135
'CONTINUE': 128,
139136
'JUMP_IF_FALSE_OR_POP': 129,
140137
'JUMP_IF_TRUE_OR_POP': 130,
@@ -146,7 +143,7 @@
146143
'RESUME': 149,
147144
'JUMP': 252,
148145
'LOAD_CLOSURE': 253,
149-
'LOAD_METHOD': 254,
146+
'LOAD_ATTR_METHOD': 254,
150147
'POP_BLOCK': 255,
151148
}
152149

crates/codegen/src/compile.rs

Lines changed: 110 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -1028,13 +1028,16 @@ impl Compiler {
10281028
if preserve_tos {
10291029
emit!(self, Instruction::Swap { index: 2 });
10301030
}
1031+
// Stack after swap: [..., return_value, __exit__] or [..., __exit__]
10311032

1032-
// Call __exit__(None, None, None) - compiler_call_exit_with_nones
1033-
// Stack: [..., __exit__] or [..., return_value, __exit__]
1033+
// Call __exit__(None, None, None)
1034+
// Call protocol: [callable, self_or_null, arg1, arg2, arg3]
10341035
emit!(self, Instruction::PushNull);
1036+
// Stack: [..., __exit__, NULL]
10351037
self.emit_load_const(ConstantData::None);
10361038
self.emit_load_const(ConstantData::None);
10371039
self.emit_load_const(ConstantData::None);
1040+
// Stack: [..., __exit__, NULL, None, None, None]
10381041
emit!(self, Instruction::Call { nargs: 3 });
10391042

10401043
// For async with, await the result
@@ -2088,6 +2091,8 @@ impl Compiler {
20882091
Ok(())
20892092
}
20902093

2094+
/// Push decorators onto the stack in source order.
2095+
/// For @dec1 @dec2 def foo(): stack becomes [dec1, NULL, dec2, NULL]
20912096
fn prepare_decorators(&mut self, decorator_list: &[Decorator]) -> CompileResult<()> {
20922097
for decorator in decorator_list {
20932098
self.compile_expression(&decorator.expression)?;
@@ -2096,8 +2101,11 @@ impl Compiler {
20962101
Ok(())
20972102
}
20982103

2104+
/// Apply decorators in reverse order (LIFO from stack).
2105+
/// Stack [dec1, NULL, dec2, NULL, func] -> dec2(func) -> dec1(dec2(func))
2106+
/// The forward loop works because each Call pops from TOS, naturally
2107+
/// applying decorators bottom-up (innermost first).
20992108
fn apply_decorators(&mut self, decorator_list: &[Decorator]) {
2100-
// Apply decorators - each pops [decorator, NULL, arg] and pushes result
21012109
for _ in decorator_list {
21022110
emit!(self, Instruction::Call { nargs: 1 });
21032111
}
@@ -3300,21 +3308,29 @@ impl Compiler {
33003308
// Make closure for type params code
33013309
self.make_closure(type_params_code, bytecode::MakeFunctionFlags::empty())?;
33023310

3303-
// Call the closure
3304-
// Call expects stack: [callable, self_or_null, arg1, ..., argN]
3311+
// Call the type params closure with defaults/kwdefaults as arguments.
3312+
// Call protocol: [callable, self_or_null, arg1, ..., argN]
3313+
// We need to reorder: [args..., closure] -> [closure, NULL, args...]
3314+
// Using Swap operations to move closure down and insert NULL.
3315+
// Note: num_typeparam_args is at most 2 (defaults tuple, kwdefaults dict).
33053316
if num_typeparam_args > 0 {
3306-
// Stack: [arg1, ..., argN, closure]
3307-
// Need: [closure, NULL, arg1, ..., argN]
3308-
let reverse_amount = (num_typeparam_args + 1) as u32;
3309-
emit!(
3310-
self,
3311-
Instruction::Reverse {
3312-
amount: reverse_amount
3317+
match num_typeparam_args {
3318+
1 => {
3319+
// Stack: [arg1, closure]
3320+
emit!(self, Instruction::Swap { index: 2 }); // [closure, arg1]
3321+
emit!(self, Instruction::PushNull); // [closure, arg1, NULL]
3322+
emit!(self, Instruction::Swap { index: 2 }); // [closure, NULL, arg1]
33133323
}
3314-
);
3315-
// Stack: [closure, argN, ..., arg1]
3316-
emit!(self, Instruction::PushNull);
3317-
// Stack: [closure, argN, ..., arg1, NULL]
3324+
2 => {
3325+
// Stack: [arg1, arg2, closure]
3326+
emit!(self, Instruction::Swap { index: 3 }); // [closure, arg2, arg1]
3327+
emit!(self, Instruction::Swap { index: 2 }); // [closure, arg1, arg2]
3328+
emit!(self, Instruction::PushNull); // [closure, arg1, arg2, NULL]
3329+
emit!(self, Instruction::Swap { index: 3 }); // [closure, NULL, arg2, arg1]
3330+
emit!(self, Instruction::Swap { index: 2 }); // [closure, NULL, arg1, arg2]
3331+
}
3332+
_ => unreachable!("only defaults and kwdefaults are supported"),
3333+
}
33183334
emit!(
33193335
self,
33203336
Instruction::Call {
@@ -3325,7 +3341,6 @@ impl Compiler {
33253341
// Stack: [closure]
33263342
emit!(self, Instruction::PushNull);
33273343
// Stack: [closure, NULL]
3328-
// Call pops: args (0), then self_or_null (NULL), then callable (closure)
33293344
emit!(self, Instruction::Call { nargs: 0 });
33303345
}
33313346
}
@@ -3705,49 +3720,91 @@ impl Compiler {
37053720
self.make_closure(class_code, func_flags)?;
37063721
self.emit_load_const(ConstantData::Str { value: name.into() });
37073722

3708-
// Compile original bases
3709-
let base_count = if let Some(arguments) = arguments {
3710-
for arg in &arguments.args {
3711-
self.compile_expression(arg)?;
3723+
// Compile bases and call __build_class__
3724+
// Check for starred bases or **kwargs
3725+
let has_starred = arguments
3726+
.is_some_and(|args| args.args.iter().any(|arg| matches!(arg, Expr::Starred(_))));
3727+
let has_double_star =
3728+
arguments.is_some_and(|args| args.keywords.iter().any(|kw| kw.arg.is_none()));
3729+
3730+
if has_starred || has_double_star {
3731+
// Use CallFunctionEx for *bases or **kwargs
3732+
// Stack has: [__build_class__, NULL, class_func, name]
3733+
// Need to build: args tuple = (class_func, name, *bases, .generic_base)
3734+
3735+
// Compile bases with gather_elements (handles starred)
3736+
let (size, unpack) = if let Some(arguments) = arguments {
3737+
self.gather_elements(2, &arguments.args)? // 2 = class_func + name already on stack
3738+
} else {
3739+
// Just class_func and name (no bases)
3740+
(2, false)
3741+
};
3742+
3743+
// Add .generic_base as final base
3744+
emit!(self, Instruction::LoadName(dot_generic_base));
3745+
3746+
// Build args tuple
3747+
if unpack {
3748+
// Starred: gather_elements produced tuples on stack
3749+
emit!(self, Instruction::BuildTuple { size: 1 }); // (.generic_base,)
3750+
emit!(self, Instruction::BuildTupleFromTuples { size: size + 1 });
3751+
} else {
3752+
// No starred: individual elements on stack
3753+
// size includes class_func + name + bases count, +1 for .generic_base
3754+
emit!(self, Instruction::BuildTuple { size: size + 1 });
3755+
}
3756+
3757+
// Build kwargs if needed
3758+
let has_kwargs = arguments.is_some_and(|args| !args.keywords.is_empty());
3759+
if has_kwargs {
3760+
self.compile_keywords(&arguments.unwrap().keywords)?;
37123761
}
3713-
arguments.args.len()
3762+
emit!(self, Instruction::CallFunctionEx { has_kwargs });
37143763
} else {
3715-
0
3716-
};
3764+
// Simple case: no starred bases, no **kwargs
3765+
// Compile bases normally
3766+
let base_count = if let Some(arguments) = arguments {
3767+
for arg in &arguments.args {
3768+
self.compile_expression(arg)?;
3769+
}
3770+
arguments.args.len()
3771+
} else {
3772+
0
3773+
};
37173774

3718-
// Load .generic_base as the last base
3719-
emit!(self, Instruction::LoadName(dot_generic_base));
3775+
// Load .generic_base as the last base
3776+
emit!(self, Instruction::LoadName(dot_generic_base));
37203777

3721-
let nargs = 2 + u32::try_from(base_count).expect("too many base classes") + 1; // function, name, bases..., generic_base
3778+
let nargs = 2 + u32::try_from(base_count).expect("too many base classes") + 1;
37223779

3723-
// Handle keyword arguments
3724-
if let Some(arguments) = arguments
3725-
&& !arguments.keywords.is_empty()
3726-
{
3727-
let mut kwarg_names = vec![];
3728-
for keyword in &arguments.keywords {
3729-
let name = keyword
3730-
.arg
3731-
.as_ref()
3732-
.expect("keyword argument name must be set");
3733-
kwarg_names.push(ConstantData::Str {
3734-
value: name.as_str().into(),
3780+
// Handle keyword arguments (no **kwargs here)
3781+
if let Some(arguments) = arguments
3782+
&& !arguments.keywords.is_empty()
3783+
{
3784+
let mut kwarg_names = vec![];
3785+
for keyword in &arguments.keywords {
3786+
let name = keyword.arg.as_ref().expect(
3787+
"keyword argument name must be set (no **kwargs in this branch)",
3788+
);
3789+
kwarg_names.push(ConstantData::Str {
3790+
value: name.as_str().into(),
3791+
});
3792+
self.compile_expression(&keyword.value)?;
3793+
}
3794+
self.emit_load_const(ConstantData::Tuple {
3795+
elements: kwarg_names,
37353796
});
3736-
self.compile_expression(&keyword.value)?;
3797+
emit!(
3798+
self,
3799+
Instruction::CallKw {
3800+
nargs: nargs
3801+
+ u32::try_from(arguments.keywords.len())
3802+
.expect("too many keyword arguments")
3803+
}
3804+
);
3805+
} else {
3806+
emit!(self, Instruction::Call { nargs });
37373807
}
3738-
self.emit_load_const(ConstantData::Tuple {
3739-
elements: kwarg_names,
3740-
});
3741-
emit!(
3742-
self,
3743-
Instruction::CallKw {
3744-
nargs: nargs
3745-
+ u32::try_from(arguments.keywords.len())
3746-
.expect("too many keyword arguments")
3747-
}
3748-
);
3749-
} else {
3750-
emit!(self, Instruction::Call { nargs });
37513808
}
37523809

37533810
// Return the created class

crates/compiler-core/src/bytecode.rs

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -921,15 +921,6 @@ pub enum Instruction {
921921
BuildTupleFromTuples {
922922
size: Arg<u32>,
923923
} = 124,
924-
CallMethodPositional {
925-
nargs: Arg<u32>,
926-
} = 125,
927-
CallMethodKeyword {
928-
nargs: Arg<u32>,
929-
} = 126,
930-
CallMethodEx {
931-
has_kwargs: Arg<bool>,
932-
} = 127,
933924
Continue {
934925
target: Arg<Label>,
935926
} = 128,
@@ -2062,6 +2053,7 @@ impl Instruction {
20622053
PopJumpIfTrue { target } => w!(POP_JUMP_IF_TRUE, target),
20632054
PopTop => w!(POP_TOP),
20642055
PushExcInfo => w!(PUSH_EXC_INFO),
2056+
PushNull => w!(PUSH_NULL),
20652057
RaiseVarargs { kind } => w!(RAISE_VARARGS, ?kind),
20662058
Reraise { depth } => w!(RERAISE, depth),
20672059
Resume { arg } => w!(RESUME, arg),

0 commit comments

Comments
 (0)