@@ -1037,10 +1037,11 @@ impl Compiler {
10371037
10381038 // Call __exit__(None, None, None) - compiler_call_exit_with_nones
10391039 // Stack: [..., __exit__] or [..., return_value, __exit__]
1040+ emit ! ( self , Instruction :: PushNull ) ;
10401041 self . emit_load_const ( ConstantData :: None ) ;
10411042 self . emit_load_const ( ConstantData :: None ) ;
10421043 self . emit_load_const ( ConstantData :: None ) ;
1043- emit ! ( self , Instruction :: CallFunctionPositional { nargs: 3 } ) ;
1044+ emit ! ( self , Instruction :: Call { nargs: 3 } ) ;
10441045
10451046 // For async with, await the result
10461047 if matches ! ( info. fb_type, FBlockType :: AsyncWith ) {
@@ -1875,13 +1876,14 @@ impl Compiler {
18751876
18761877 let assertion_error = self . name ( "AssertionError" ) ;
18771878 emit ! ( self , Instruction :: LoadGlobal ( assertion_error) ) ;
1879+ emit ! ( self , Instruction :: PushNull ) ;
18781880 match msg {
18791881 Some ( e) => {
18801882 self . compile_expression ( e) ?;
1881- emit ! ( self , Instruction :: CallFunctionPositional { nargs: 1 } ) ;
1883+ emit ! ( self , Instruction :: Call { nargs: 1 } ) ;
18821884 }
18831885 None => {
1884- emit ! ( self , Instruction :: CallFunctionPositional { nargs: 0 } ) ;
1886+ emit ! ( self , Instruction :: Call { nargs: 0 } ) ;
18851887 }
18861888 }
18871889 emit ! (
@@ -2095,14 +2097,16 @@ impl Compiler {
20952097 fn prepare_decorators ( & mut self , decorator_list : & [ Decorator ] ) -> CompileResult < ( ) > {
20962098 for decorator in decorator_list {
20972099 self . compile_expression ( & decorator. expression ) ?;
2100+ // PUSH_NULL for self_or_null slot (decorator is not a method call)
2101+ emit ! ( self , Instruction :: PushNull ) ;
20982102 }
20992103 Ok ( ( ) )
21002104 }
21012105
21022106 fn apply_decorators ( & mut self , decorator_list : & [ Decorator ] ) {
2103- // Apply decorators:
2107+ // Apply decorators - each pops [decorator, NULL, arg] and pushes result
21042108 for _ in decorator_list {
2105- emit ! ( self , Instruction :: CallFunctionPositional { nargs: 1 } ) ;
2109+ emit ! ( self , Instruction :: Call { nargs: 1 } ) ;
21062110 }
21072111 }
21082112
@@ -2142,9 +2146,10 @@ impl Compiler {
21422146
21432147 // Create type params function with closure
21442148 self . make_closure ( code, bytecode:: MakeFunctionFlags :: empty ( ) ) ?;
2149+ emit ! ( self , Instruction :: PushNull ) ;
21452150
21462151 // Call the function immediately
2147- emit ! ( self , Instruction :: CallFunctionPositional { nargs: 0 } ) ;
2152+ emit ! ( self , Instruction :: Call { nargs: 0 } ) ;
21482153
21492154 Ok ( ( ) )
21502155 }
@@ -3224,11 +3229,6 @@ impl Compiler {
32243229 num_typeparam_args += 1 ;
32253230 }
32263231
3227- // SWAP if we have both
3228- if num_typeparam_args == 2 {
3229- emit ! ( self , Instruction :: Swap { index: 2 } ) ;
3230- }
3231-
32323232 // Enter type params scope
32333233 let type_params_name = format ! ( "<generic parameters of {name}>" ) ;
32343234 self . push_output (
@@ -3308,22 +3308,39 @@ impl Compiler {
33083308 self . make_closure ( type_params_code, bytecode:: MakeFunctionFlags :: empty ( ) ) ?;
33093309
33103310 // Call the closure
3311+ // Call expects stack: [callable, self_or_null, arg1, ..., argN]
33113312 if num_typeparam_args > 0 {
3313+ // Stack: [arg1, ..., argN, closure]
3314+ // Need: [closure, NULL, arg1, ..., argN]
3315+ let swap_depth = ( num_typeparam_args + 1 ) as u32 ;
3316+ emit ! ( self , Instruction :: Swap { index: swap_depth } ) ;
3317+ // Stack: [closure, ..., argN, arg1]
3318+ emit ! ( self , Instruction :: PushNull ) ;
3319+ // Stack: [closure, ..., argN, arg1, NULL]
3320+ emit ! ( self , Instruction :: Swap { index: swap_depth } ) ;
3321+ // Stack: [closure, NULL, ..., argN, arg1]
3322+ // For N>1, need to reverse args back to original order
3323+ if num_typeparam_args > 1 {
3324+ emit ! (
3325+ self ,
3326+ Instruction :: Reverse {
3327+ amount: num_typeparam_args as u32
3328+ }
3329+ ) ;
3330+ }
3331+ // Stack: [closure, NULL, arg1, ..., argN]
33123332 emit ! (
33133333 self ,
3314- Instruction :: Swap {
3315- index: ( num_typeparam_args + 1 ) as u32
3316- }
3317- ) ;
3318- emit ! (
3319- self ,
3320- Instruction :: CallFunctionPositional {
3334+ Instruction :: Call {
33213335 nargs: num_typeparam_args as u32
33223336 }
33233337 ) ;
33243338 } else {
3325- // No arguments, just call the closure
3326- emit ! ( self , Instruction :: CallFunctionPositional { nargs: 0 } ) ;
3339+ // Stack: [closure]
3340+ emit ! ( self , Instruction :: PushNull ) ;
3341+ // Stack: [closure, NULL] - already correct layout
3342+ // Call pops: args (0), then self_or_null (NULL), then callable (closure)
3343+ emit ! ( self , Instruction :: Call { nargs: 0 } ) ;
33273344 }
33283345 }
33293346
@@ -3691,6 +3708,7 @@ impl Compiler {
36913708
36923709 // Generate class creation code
36933710 emit ! ( self , Instruction :: LoadBuildClass ) ;
3711+ emit ! ( self , Instruction :: PushNull ) ;
36943712
36953713 // Set up the class function with type params
36963714 let mut func_flags = bytecode:: MakeFunctionFlags :: empty ( ) ;
@@ -3720,24 +3738,30 @@ impl Compiler {
37203738 if let Some ( arguments) = arguments
37213739 && !arguments. keywords . is_empty ( )
37223740 {
3741+ let mut kwarg_names = vec ! [ ] ;
37233742 for keyword in & arguments. keywords {
37243743 if let Some ( name) = & keyword. arg {
3725- self . emit_load_const ( ConstantData :: Str {
3744+ kwarg_names . push ( ConstantData :: Str {
37263745 value : name. as_str ( ) . into ( ) ,
37273746 } ) ;
3747+ } else {
3748+ panic ! ( "keyword argument name must be set" ) ;
37283749 }
37293750 self . compile_expression ( & keyword. value ) ?;
37303751 }
3752+ self . emit_load_const ( ConstantData :: Tuple {
3753+ elements : kwarg_names,
3754+ } ) ;
37313755 emit ! (
37323756 self ,
3733- Instruction :: CallFunctionKeyword {
3757+ Instruction :: CallKw {
37343758 nargs: nargs
37353759 + u32 :: try_from( arguments. keywords. len( ) )
37363760 . expect( "too many keyword arguments" )
37373761 }
37383762 ) ;
37393763 } else {
3740- emit ! ( self , Instruction :: CallFunctionPositional { nargs } ) ;
3764+ emit ! ( self , Instruction :: Call { nargs } ) ;
37413765 }
37423766
37433767 // Return the created class
@@ -3748,10 +3772,12 @@ impl Compiler {
37483772
37493773 // Execute the type params function
37503774 self . make_closure ( type_params_code, bytecode:: MakeFunctionFlags :: empty ( ) ) ?;
3751- emit ! ( self , Instruction :: CallFunctionPositional { nargs: 0 } ) ;
3775+ emit ! ( self , Instruction :: PushNull ) ;
3776+ emit ! ( self , Instruction :: Call { nargs: 0 } ) ;
37523777 } else {
37533778 // Non-generic class: standard path
37543779 emit ! ( self , Instruction :: LoadBuildClass ) ;
3780+ emit ! ( self , Instruction :: PushNull ) ;
37553781
37563782 // Create class function with closure
37573783 self . make_closure ( class_code, bytecode:: MakeFunctionFlags :: empty ( ) ) ?;
@@ -3762,7 +3788,7 @@ impl Compiler {
37623788 } else {
37633789 CallType :: Positional { nargs : 2 }
37643790 } ;
3765- self . compile_normal_call ( call) ;
3791+ self . compile_call_with_self ( call) ;
37663792 }
37673793
37683794 // Step 4: Apply decorators and store (common to both paths)
@@ -3912,10 +3938,11 @@ impl Compiler {
39123938 // Stack: [..., __exit__]
39133939 // Call __exit__(None, None, None)
39143940 self . set_source_range ( with_range) ;
3941+ emit ! ( self , Instruction :: PushNull ) ;
39153942 self . emit_load_const ( ConstantData :: None ) ;
39163943 self . emit_load_const ( ConstantData :: None ) ;
39173944 self . emit_load_const ( ConstantData :: None ) ;
3918- emit ! ( self , Instruction :: CallFunctionPositional { nargs: 3 } ) ;
3945+ emit ! ( self , Instruction :: Call { nargs: 3 } ) ;
39193946 if is_async {
39203947 emit ! ( self , Instruction :: GetAwaitable ) ;
39213948 self . emit_load_const ( ConstantData :: None ) ;
@@ -6088,41 +6115,33 @@ impl Compiler {
60886115
60896116 fn compile_call ( & mut self , func : & Expr , args : & Arguments ) -> CompileResult < ( ) > {
60906117 // Method call: obj → LOAD_ATTR_METHOD → [method, self_or_null] → args → CALL_WITH_SELF
6091- // Regular call: func → args → CALL
6118+ // Regular call: func → PUSH_NULL → args → CALL_WITH_SELF
60926119 if let Expr :: Attribute ( ExprAttribute { value, attr, .. } ) = & func {
60936120 // Method call: compile object, then LOAD_ATTR_METHOD
60946121 // LOAD_ATTR_METHOD pushes [method, self_or_null] on stack
60956122 self . compile_expression ( value) ?;
60966123 let idx = self . name ( attr. as_str ( ) ) ;
60976124 emit ! ( self , Instruction :: LoadAttrMethod { idx } ) ;
6098- // Compile args, then use CallWithSelf which handles self_or_null
6125+ // Compile args, then use Call which handles self_or_null
60996126 let call = self . compile_call_inner ( 0 , args) ?;
61006127 self . compile_call_with_self ( call) ;
61016128 } else {
6102- // Regular call: just compile function and args
6129+ // Regular call: push func, then NULL for self_or_null slot
6130+ // Stack layout: [func, NULL, args...] - same as method call [func, self, args...]
61036131 self . compile_expression ( func) ?;
6132+ emit ! ( self , Instruction :: PushNull ) ;
61046133 let call = self . compile_call_inner ( 0 , args) ?;
6105- self . compile_normal_call ( call) ;
6134+ self . compile_call_with_self ( call) ;
61066135 }
61076136 Ok ( ( ) )
61086137 }
61096138
61106139 fn compile_call_with_self ( & mut self , ty : CallType ) {
61116140 match ty {
61126141 CallType :: Positional { nargs } => {
6113- emit ! ( self , Instruction :: CallWithSelf { nargs } )
6114- }
6115- CallType :: Keyword { nargs } => emit ! ( self , Instruction :: CallWithSelfKw { nargs } ) ,
6116- CallType :: Ex { has_kwargs } => emit ! ( self , Instruction :: CallWithSelfEx { has_kwargs } ) ,
6117- }
6118- }
6119-
6120- fn compile_normal_call ( & mut self , ty : CallType ) {
6121- match ty {
6122- CallType :: Positional { nargs } => {
6123- emit ! ( self , Instruction :: CallFunctionPositional { nargs } )
6142+ emit ! ( self , Instruction :: Call { nargs } )
61246143 }
6125- CallType :: Keyword { nargs } => emit ! ( self , Instruction :: CallFunctionKeyword { nargs } ) ,
6144+ CallType :: Keyword { nargs } => emit ! ( self , Instruction :: CallKw { nargs } ) ,
61266145 CallType :: Ex { has_kwargs } => emit ! ( self , Instruction :: CallFunctionEx { has_kwargs } ) ,
61276146 }
61286147 }
@@ -6412,6 +6431,7 @@ impl Compiler {
64126431
64136432 // Create comprehension function with closure
64146433 self . make_closure ( code, bytecode:: MakeFunctionFlags :: empty ( ) ) ?;
6434+ emit ! ( self , Instruction :: PushNull ) ;
64156435
64166436 // Evaluate iterated item:
64176437 self . compile_expression ( & generators[ 0 ] . iter ) ?;
@@ -6425,7 +6445,7 @@ impl Compiler {
64256445 } ;
64266446
64276447 // Call just created <listcomp> function:
6428- emit ! ( self , Instruction :: CallFunctionPositional { nargs: 1 } ) ;
6448+ emit ! ( self , Instruction :: Call { nargs: 1 } ) ;
64296449 if is_async_list_set_dict_comprehension {
64306450 emit ! ( self , Instruction :: GetAwaitable ) ;
64316451 self . emit_load_const ( ConstantData :: None ) ;
@@ -6841,10 +6861,11 @@ impl Compiler {
68416861 match action {
68426862 UnwindAction :: With { is_async } => {
68436863 // compiler_call_exit_with_nones
6864+ emit ! ( self , Instruction :: PushNull ) ;
68446865 self . emit_load_const ( ConstantData :: None ) ;
68456866 self . emit_load_const ( ConstantData :: None ) ;
68466867 self . emit_load_const ( ConstantData :: None ) ;
6847- emit ! ( self , Instruction :: CallFunctionPositional { nargs: 3 } ) ;
6868+ emit ! ( self , Instruction :: Call { nargs: 3 } ) ;
68486869
68496870 if is_async {
68506871 emit ! ( self , Instruction :: GetAwaitable ) ;
0 commit comments