@@ -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