@@ -3305,16 +3305,23 @@ impl Compiler {
33053305 if num_typeparam_args > 0 {
33063306 // Stack: [arg1, ..., argN, closure]
33073307 // 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
3308+ match num_typeparam_args {
3309+ 1 => {
3310+ // Stack: [arg1, closure]
3311+ emit ! ( self , Instruction :: Swap { index: 2 } ) ; // [closure, arg1]
3312+ emit ! ( self , Instruction :: PushNull ) ; // [closure, arg1, NULL]
3313+ emit ! ( self , Instruction :: Swap { index: 2 } ) ; // [closure, NULL, arg1]
33133314 }
3314- ) ;
3315- // Stack: [closure, argN, ..., arg1]
3316- emit ! ( self , Instruction :: PushNull ) ;
3317- // Stack: [closure, argN, ..., arg1, NULL]
3315+ 2 => {
3316+ // Stack: [arg1, arg2, closure]
3317+ emit ! ( self , Instruction :: Swap { index: 3 } ) ; // [closure, arg2, arg1]
3318+ emit ! ( self , Instruction :: Swap { index: 2 } ) ; // [closure, arg1, arg2]
3319+ emit ! ( self , Instruction :: PushNull ) ; // [closure, arg1, arg2, NULL]
3320+ emit ! ( self , Instruction :: Swap { index: 3 } ) ; // [closure, NULL, arg2, arg1]
3321+ emit ! ( self , Instruction :: Swap { index: 2 } ) ; // [closure, NULL, arg1, arg2]
3322+ }
3323+ _ => unreachable ! ( "only defaults and kwdefaults are supported" ) ,
3324+ }
33183325 emit ! (
33193326 self ,
33203327 Instruction :: Call {
@@ -3325,7 +3332,6 @@ impl Compiler {
33253332 // Stack: [closure]
33263333 emit ! ( self , Instruction :: PushNull ) ;
33273334 // Stack: [closure, NULL]
3328- // Call pops: args (0), then self_or_null (NULL), then callable (closure)
33293335 emit ! ( self , Instruction :: Call { nargs: 0 } ) ;
33303336 }
33313337 }
@@ -3705,49 +3711,91 @@ impl Compiler {
37053711 self . make_closure ( class_code, func_flags) ?;
37063712 self . emit_load_const ( ConstantData :: Str { value : name. into ( ) } ) ;
37073713
3708- // Compile original bases
3709- let base_count = if let Some ( arguments) = arguments {
3710- for arg in & arguments. args {
3711- self . compile_expression ( arg) ?;
3714+ // Compile bases and call __build_class__
3715+ // Check for starred bases or **kwargs
3716+ let has_starred = arguments
3717+ . is_some_and ( |args| args. args . iter ( ) . any ( |arg| matches ! ( arg, Expr :: Starred ( _) ) ) ) ;
3718+ let has_double_star =
3719+ arguments. is_some_and ( |args| args. keywords . iter ( ) . any ( |kw| kw. arg . is_none ( ) ) ) ;
3720+
3721+ if has_starred || has_double_star {
3722+ // Use CallFunctionEx for *bases or **kwargs
3723+ // Stack has: [__build_class__, NULL, class_func, name]
3724+ // Need to build: args tuple = (class_func, name, *bases, .generic_base)
3725+
3726+ // Compile bases with gather_elements (handles starred)
3727+ let ( size, unpack) = if let Some ( arguments) = arguments {
3728+ self . gather_elements ( 2 , & arguments. args ) ? // 2 = class_func + name already on stack
3729+ } else {
3730+ // Just class_func and name (no bases)
3731+ ( 2 , false )
3732+ } ;
3733+
3734+ // Add .generic_base as final base
3735+ emit ! ( self , Instruction :: LoadName ( dot_generic_base) ) ;
3736+
3737+ // Build args tuple
3738+ if unpack {
3739+ // Starred: gather_elements produced tuples on stack
3740+ emit ! ( self , Instruction :: BuildTuple { size: 1 } ) ; // (.generic_base,)
3741+ emit ! ( self , Instruction :: BuildTupleFromTuples { size: size + 1 } ) ;
3742+ } else {
3743+ // No starred: individual elements on stack
3744+ // size includes class_func + name + bases count, +1 for .generic_base
3745+ emit ! ( self , Instruction :: BuildTuple { size: size + 1 } ) ;
3746+ }
3747+
3748+ // Build kwargs if needed
3749+ let has_kwargs = arguments. is_some_and ( |args| !args. keywords . is_empty ( ) ) ;
3750+ if has_kwargs {
3751+ self . compile_keywords ( & arguments. unwrap ( ) . keywords ) ?;
37123752 }
3713- arguments . args . len ( )
3753+ emit ! ( self , Instruction :: CallFunctionEx { has_kwargs } ) ;
37143754 } else {
3715- 0
3716- } ;
3755+ // Simple case: no starred bases, no **kwargs
3756+ // Compile bases normally
3757+ let base_count = if let Some ( arguments) = arguments {
3758+ for arg in & arguments. args {
3759+ self . compile_expression ( arg) ?;
3760+ }
3761+ arguments. args . len ( )
3762+ } else {
3763+ 0
3764+ } ;
37173765
3718- // Load .generic_base as the last base
3719- emit ! ( self , Instruction :: LoadName ( dot_generic_base) ) ;
3766+ // Load .generic_base as the last base
3767+ emit ! ( self , Instruction :: LoadName ( dot_generic_base) ) ;
37203768
3721- let nargs = 2 + u32:: try_from ( base_count) . expect ( "too many base classes" ) + 1 ; // function, name, bases..., generic_base
3769+ let nargs = 2 + u32:: try_from ( base_count) . expect ( "too many base classes" ) + 1 ;
37223770
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 ( ) ,
3771+ // Handle keyword arguments (no **kwargs here)
3772+ if let Some ( arguments) = arguments
3773+ && !arguments. keywords . is_empty ( )
3774+ {
3775+ let mut kwarg_names = vec ! [ ] ;
3776+ for keyword in & arguments. keywords {
3777+ let name = keyword. arg . as_ref ( ) . expect (
3778+ "keyword argument name must be set (no **kwargs in this branch)" ,
3779+ ) ;
3780+ kwarg_names. push ( ConstantData :: Str {
3781+ value : name. as_str ( ) . into ( ) ,
3782+ } ) ;
3783+ self . compile_expression ( & keyword. value ) ?;
3784+ }
3785+ self . emit_load_const ( ConstantData :: Tuple {
3786+ elements : kwarg_names,
37353787 } ) ;
3736- self . compile_expression ( & keyword. value ) ?;
3788+ emit ! (
3789+ self ,
3790+ Instruction :: CallKw {
3791+ nargs: nargs
3792+ + u32 :: try_from( arguments. keywords. len( ) )
3793+ . expect( "too many keyword arguments" )
3794+ }
3795+ ) ;
3796+ } else {
3797+ emit ! ( self , Instruction :: Call { nargs } ) ;
37373798 }
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 } ) ;
37513799 }
37523800
37533801 // Return the created class
0 commit comments