@@ -98,12 +98,6 @@ enum NameUsage {
9898 Delete ,
9999}
100100
101- enum CallType {
102- Positional { nargs : u32 } ,
103- Keyword { nargs : u32 } ,
104- Ex { has_kwargs : bool } ,
105- }
106-
107101fn is_forbidden_name ( name : & str ) -> bool {
108102 // See https://docs.python.org/3/library/constants.html#built-in-constants
109103 const BUILTIN_CONSTANTS : & [ & str ] = & [ "__debug__" ] ;
@@ -1037,10 +1031,11 @@ impl Compiler {
10371031
10381032 // Call __exit__(None, None, None) - compiler_call_exit_with_nones
10391033 // Stack: [..., __exit__] or [..., return_value, __exit__]
1034+ emit ! ( self , Instruction :: PushNull ) ;
10401035 self . emit_load_const ( ConstantData :: None ) ;
10411036 self . emit_load_const ( ConstantData :: None ) ;
10421037 self . emit_load_const ( ConstantData :: None ) ;
1043- emit ! ( self , Instruction :: CallFunctionPositional { nargs: 3 } ) ;
1038+ emit ! ( self , Instruction :: Call { nargs: 3 } ) ;
10441039
10451040 // For async with, await the result
10461041 if matches ! ( info. fb_type, FBlockType :: AsyncWith ) {
@@ -1875,13 +1870,14 @@ impl Compiler {
18751870
18761871 let assertion_error = self . name ( "AssertionError" ) ;
18771872 emit ! ( self , Instruction :: LoadGlobal ( assertion_error) ) ;
1873+ emit ! ( self , Instruction :: PushNull ) ;
18781874 match msg {
18791875 Some ( e) => {
18801876 self . compile_expression ( e) ?;
1881- emit ! ( self , Instruction :: CallFunctionPositional { nargs: 1 } ) ;
1877+ emit ! ( self , Instruction :: Call { nargs: 1 } ) ;
18821878 }
18831879 None => {
1884- emit ! ( self , Instruction :: CallFunctionPositional { nargs: 0 } ) ;
1880+ emit ! ( self , Instruction :: Call { nargs: 0 } ) ;
18851881 }
18861882 }
18871883 emit ! (
@@ -2095,14 +2091,15 @@ impl Compiler {
20952091 fn prepare_decorators ( & mut self , decorator_list : & [ Decorator ] ) -> CompileResult < ( ) > {
20962092 for decorator in decorator_list {
20972093 self . compile_expression ( & decorator. expression ) ?;
2094+ emit ! ( self , Instruction :: PushNull ) ;
20982095 }
20992096 Ok ( ( ) )
21002097 }
21012098
21022099 fn apply_decorators ( & mut self , decorator_list : & [ Decorator ] ) {
2103- // Apply decorators:
2100+ // Apply decorators - each pops [decorator, NULL, arg] and pushes result
21042101 for _ in decorator_list {
2105- emit ! ( self , Instruction :: CallFunctionPositional { nargs: 1 } ) ;
2102+ emit ! ( self , Instruction :: Call { nargs: 1 } ) ;
21062103 }
21072104 }
21082105
@@ -2142,9 +2139,10 @@ impl Compiler {
21422139
21432140 // Create type params function with closure
21442141 self . make_closure ( code, bytecode:: MakeFunctionFlags :: empty ( ) ) ?;
2142+ emit ! ( self , Instruction :: PushNull ) ;
21452143
21462144 // Call the function immediately
2147- emit ! ( self , Instruction :: CallFunctionPositional { nargs: 0 } ) ;
2145+ emit ! ( self , Instruction :: Call { nargs: 0 } ) ;
21482146
21492147 Ok ( ( ) )
21502148 }
@@ -3224,11 +3222,6 @@ impl Compiler {
32243222 num_typeparam_args += 1 ;
32253223 }
32263224
3227- // SWAP if we have both
3228- if num_typeparam_args == 2 {
3229- emit ! ( self , Instruction :: Swap { index: 2 } ) ;
3230- }
3231-
32323225 // Enter type params scope
32333226 let type_params_name = format ! ( "<generic parameters of {name}>" ) ;
32343227 self . push_output (
@@ -3308,22 +3301,39 @@ impl Compiler {
33083301 self . make_closure ( type_params_code, bytecode:: MakeFunctionFlags :: empty ( ) ) ?;
33093302
33103303 // Call the closure
3304+ // Call expects stack: [callable, self_or_null, arg1, ..., argN]
33113305 if num_typeparam_args > 0 {
3306+ // Stack: [arg1, ..., argN, closure]
3307+ // Need: [closure, NULL, arg1, ..., argN]
3308+ let swap_depth = ( num_typeparam_args + 1 ) as u32 ;
3309+ emit ! ( self , Instruction :: Swap { index: swap_depth } ) ;
3310+ // Stack: [closure, ..., argN, arg1]
3311+ emit ! ( self , Instruction :: PushNull ) ;
3312+ // Stack: [closure, ..., argN, arg1, NULL]
3313+ emit ! ( self , Instruction :: Swap { index: swap_depth } ) ;
3314+ // Stack: [closure, NULL, ..., argN, arg1]
3315+ // For N>1, need to reverse args back to original order
3316+ if num_typeparam_args > 1 {
3317+ emit ! (
3318+ self ,
3319+ Instruction :: Reverse {
3320+ amount: num_typeparam_args as u32
3321+ }
3322+ ) ;
3323+ }
3324+ // Stack: [closure, NULL, arg1, ..., argN]
33123325 emit ! (
33133326 self ,
3314- Instruction :: Swap {
3315- index: ( num_typeparam_args + 1 ) as u32
3316- }
3317- ) ;
3318- emit ! (
3319- self ,
3320- Instruction :: CallFunctionPositional {
3327+ Instruction :: Call {
33213328 nargs: num_typeparam_args as u32
33223329 }
33233330 ) ;
33243331 } else {
3325- // No arguments, just call the closure
3326- emit ! ( self , Instruction :: CallFunctionPositional { nargs: 0 } ) ;
3332+ // Stack: [closure]
3333+ emit ! ( self , Instruction :: PushNull ) ;
3334+ // Stack: [closure, NULL]
3335+ // Call pops: args (0), then self_or_null (NULL), then callable (closure)
3336+ emit ! ( self , Instruction :: Call { nargs: 0 } ) ;
33273337 }
33283338 }
33293339
@@ -3691,6 +3701,7 @@ impl Compiler {
36913701
36923702 // Generate class creation code
36933703 emit ! ( self , Instruction :: LoadBuildClass ) ;
3704+ emit ! ( self , Instruction :: PushNull ) ;
36943705
36953706 // Set up the class function with type params
36963707 let mut func_flags = bytecode:: MakeFunctionFlags :: empty ( ) ;
@@ -3720,24 +3731,30 @@ impl Compiler {
37203731 if let Some ( arguments) = arguments
37213732 && !arguments. keywords . is_empty ( )
37223733 {
3734+ let mut kwarg_names = vec ! [ ] ;
37233735 for keyword in & arguments. keywords {
37243736 if let Some ( name) = & keyword. arg {
3725- self . emit_load_const ( ConstantData :: Str {
3737+ kwarg_names . push ( ConstantData :: Str {
37263738 value : name. as_str ( ) . into ( ) ,
37273739 } ) ;
3740+ } else {
3741+ panic ! ( "keyword argument name must be set" ) ;
37283742 }
37293743 self . compile_expression ( & keyword. value ) ?;
37303744 }
3745+ self . emit_load_const ( ConstantData :: Tuple {
3746+ elements : kwarg_names,
3747+ } ) ;
37313748 emit ! (
37323749 self ,
3733- Instruction :: CallFunctionKeyword {
3750+ Instruction :: CallKw {
37343751 nargs: nargs
37353752 + u32 :: try_from( arguments. keywords. len( ) )
37363753 . expect( "too many keyword arguments" )
37373754 }
37383755 ) ;
37393756 } else {
3740- emit ! ( self , Instruction :: CallFunctionPositional { nargs } ) ;
3757+ emit ! ( self , Instruction :: Call { nargs } ) ;
37413758 }
37423759
37433760 // Return the created class
@@ -3748,21 +3765,22 @@ impl Compiler {
37483765
37493766 // Execute the type params function
37503767 self . make_closure ( type_params_code, bytecode:: MakeFunctionFlags :: empty ( ) ) ?;
3751- emit ! ( self , Instruction :: CallFunctionPositional { nargs: 0 } ) ;
3768+ emit ! ( self , Instruction :: PushNull ) ;
3769+ emit ! ( self , Instruction :: Call { nargs: 0 } ) ;
37523770 } else {
37533771 // Non-generic class: standard path
37543772 emit ! ( self , Instruction :: LoadBuildClass ) ;
3773+ emit ! ( self , Instruction :: PushNull ) ;
37553774
37563775 // Create class function with closure
37573776 self . make_closure ( class_code, bytecode:: MakeFunctionFlags :: empty ( ) ) ?;
37583777 self . emit_load_const ( ConstantData :: Str { value : name. into ( ) } ) ;
37593778
3760- let call = if let Some ( arguments) = arguments {
3761- self . compile_call_inner ( 2 , arguments) ?
3779+ if let Some ( arguments) = arguments {
3780+ self . compile_call_helper ( 2 , arguments) ?;
37623781 } else {
3763- CallType :: Positional { nargs : 2 }
3764- } ;
3765- self . compile_normal_call ( call) ;
3782+ emit ! ( self , Instruction :: Call { nargs: 2 } ) ;
3783+ }
37663784 }
37673785
37683786 // Step 4: Apply decorators and store (common to both paths)
@@ -3912,10 +3930,11 @@ impl Compiler {
39123930 // Stack: [..., __exit__]
39133931 // Call __exit__(None, None, None)
39143932 self . set_source_range ( with_range) ;
3933+ emit ! ( self , Instruction :: PushNull ) ;
39153934 self . emit_load_const ( ConstantData :: None ) ;
39163935 self . emit_load_const ( ConstantData :: None ) ;
39173936 self . emit_load_const ( ConstantData :: None ) ;
3918- emit ! ( self , Instruction :: CallFunctionPositional { nargs: 3 } ) ;
3937+ emit ! ( self , Instruction :: Call { nargs: 3 } ) ;
39193938 if is_async {
39203939 emit ! ( self , Instruction :: GetAwaitable ) ;
39213940 self . emit_load_const ( ConstantData :: None ) ;
@@ -6087,51 +6106,32 @@ impl Compiler {
60876106 }
60886107
60896108 fn compile_call ( & mut self , func : & Expr , args : & Arguments ) -> CompileResult < ( ) > {
6090- // Method call: obj → LOAD_ATTR_METHOD → [method, self_or_null] → args → CALL_WITH_SELF
6091- // Regular call: func → args → CALL
6109+ // Method call: obj → LOAD_ATTR_METHOD → [method, self_or_null] → args → CALL
6110+ // Regular call: func → PUSH_NULL → args → CALL
60926111 if let Expr :: Attribute ( ExprAttribute { value, attr, .. } ) = & func {
60936112 // Method call: compile object, then LOAD_ATTR_METHOD
60946113 // LOAD_ATTR_METHOD pushes [method, self_or_null] on stack
60956114 self . compile_expression ( value) ?;
60966115 let idx = self . name ( attr. as_str ( ) ) ;
60976116 emit ! ( self , Instruction :: LoadAttrMethod { idx } ) ;
6098- // Compile args, then use CallWithSelf which handles self_or_null
6099- let call = self . compile_call_inner ( 0 , args) ?;
6100- self . compile_call_with_self ( call) ;
6117+ self . compile_call_helper ( 0 , args) ?;
61016118 } else {
6102- // Regular call: just compile function and args
6119+ // Regular call: push func, then NULL for self_or_null slot
6120+ // Stack layout: [func, NULL, args...] - same as method call [func, self, args...]
61036121 self . compile_expression ( func) ?;
6104- let call = self . compile_call_inner ( 0 , args ) ? ;
6105- self . compile_normal_call ( call ) ;
6122+ emit ! ( self , Instruction :: PushNull ) ;
6123+ self . compile_call_helper ( 0 , args ) ? ;
61066124 }
61076125 Ok ( ( ) )
61086126 }
61096127
6110- fn compile_call_with_self ( & mut self , ty : CallType ) {
6111- match ty {
6112- 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 } )
6124- }
6125- CallType :: Keyword { nargs } => emit ! ( self , Instruction :: CallFunctionKeyword { nargs } ) ,
6126- CallType :: Ex { has_kwargs } => emit ! ( self , Instruction :: CallFunctionEx { has_kwargs } ) ,
6127- }
6128- }
6129-
6130- fn compile_call_inner (
6128+ /// Compile call arguments and emit the appropriate CALL instruction.
6129+ /// This is shared between compiler_call and compiler_class.
6130+ fn compile_call_helper (
61316131 & mut self ,
61326132 additional_positional : u32 ,
61336133 arguments : & Arguments ,
6134- ) -> CompileResult < CallType > {
6134+ ) -> CompileResult < ( ) > {
61356135 let count = u32:: try_from ( arguments. len ( ) ) . unwrap ( ) + additional_positional;
61366136
61376137 // Normal arguments:
@@ -6144,7 +6144,7 @@ impl Compiler {
61446144 }
61456145 }
61466146
6147- let call = if unpack || has_double_star {
6147+ if unpack || has_double_star {
61486148 // Create a tuple with positional args:
61496149 if unpack {
61506150 emit ! ( self , Instruction :: BuildTupleFromTuples { size } ) ;
@@ -6157,7 +6157,7 @@ impl Compiler {
61576157 if has_kwargs {
61586158 self . compile_keywords ( & arguments. keywords ) ?;
61596159 }
6160- CallType :: Ex { has_kwargs }
6160+ emit ! ( self , Instruction :: CallFunctionEx { has_kwargs } ) ;
61616161 } else if !arguments. keywords . is_empty ( ) {
61626162 let mut kwarg_names = vec ! [ ] ;
61636163 for keyword in & arguments. keywords {
@@ -6175,12 +6175,12 @@ impl Compiler {
61756175 self . emit_load_const ( ConstantData :: Tuple {
61766176 elements : kwarg_names,
61776177 } ) ;
6178- CallType :: Keyword { nargs : count }
6178+ emit ! ( self , Instruction :: CallKw { nargs: count } ) ;
61796179 } else {
6180- CallType :: Positional { nargs : count }
6181- } ;
6180+ emit ! ( self , Instruction :: Call { nargs: count } ) ;
6181+ }
61826182
6183- Ok ( call )
6183+ Ok ( ( ) )
61846184 }
61856185
61866186 // Given a vector of expr / star expr generate code which gives either
@@ -6412,6 +6412,7 @@ impl Compiler {
64126412
64136413 // Create comprehension function with closure
64146414 self . make_closure ( code, bytecode:: MakeFunctionFlags :: empty ( ) ) ?;
6415+ emit ! ( self , Instruction :: PushNull ) ;
64156416
64166417 // Evaluate iterated item:
64176418 self . compile_expression ( & generators[ 0 ] . iter ) ?;
@@ -6425,7 +6426,7 @@ impl Compiler {
64256426 } ;
64266427
64276428 // Call just created <listcomp> function:
6428- emit ! ( self , Instruction :: CallFunctionPositional { nargs: 1 } ) ;
6429+ emit ! ( self , Instruction :: Call { nargs: 1 } ) ;
64296430 if is_async_list_set_dict_comprehension {
64306431 emit ! ( self , Instruction :: GetAwaitable ) ;
64316432 self . emit_load_const ( ConstantData :: None ) ;
@@ -6841,10 +6842,11 @@ impl Compiler {
68416842 match action {
68426843 UnwindAction :: With { is_async } => {
68436844 // compiler_call_exit_with_nones
6845+ emit ! ( self , Instruction :: PushNull ) ;
68446846 self . emit_load_const ( ConstantData :: None ) ;
68456847 self . emit_load_const ( ConstantData :: None ) ;
68466848 self . emit_load_const ( ConstantData :: None ) ;
6847- emit ! ( self , Instruction :: CallFunctionPositional { nargs: 3 } ) ;
6849+ emit ! ( self , Instruction :: Call { nargs: 3 } ) ;
68486850
68496851 if is_async {
68506852 emit ! ( self , Instruction :: GetAwaitable ) ;
0 commit comments