@@ -2173,103 +2173,97 @@ impl Compiler<'_> {
2173
2173
) -> CompileResult < ( ) > {
2174
2174
self . prepare_decorators ( decorator_list) ?;
2175
2175
2176
- let prev_ctx = self . ctx ;
2177
- self . ctx = CompileContext {
2178
- func : FunctionContext :: NoFunction ,
2179
- in_class : true ,
2180
- loop_data : None ,
2181
- } ;
2176
+ let has_type_params = type_params. is_some ( ) ;
2177
+ let firstlineno = self . get_source_line_number ( ) . get ( ) . to_u32 ( ) ;
2178
+
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) ;
2188
+ self . push_output (
2189
+ bytecode:: CodeFlags :: IS_OPTIMIZED | bytecode:: CodeFlags :: NEW_LOCALS ,
2190
+ 0 ,
2191
+ 0 ,
2192
+ 0 ,
2193
+ type_params_name. clone ( ) ,
2194
+ ) ;
2195
+
2196
+ // Set private name for name mangling
2197
+ self . code_stack . last_mut ( ) . unwrap ( ) . private = Some ( name. to_owned ( ) ) ;
2182
2198
2183
- // If there are type params, we need to push a special symbol table just for them
2184
- if let Some ( type_params) = type_params {
2185
- self . push_symbol_table ( ) ;
2186
- // Save current private name to restore later
2187
- let saved_private = self . code_stack . last ( ) . and_then ( |info| info. private . clone ( ) ) ;
2188
2199
// Compile type parameters and store as .type_params
2189
- self . compile_type_params ( type_params) ?;
2190
- // Restore private name after type param scope
2191
- if let Some ( private) = saved_private {
2192
- self . code_stack . last_mut ( ) . unwrap ( ) . private = Some ( private) ;
2193
- }
2200
+ self . compile_type_params ( type_params. unwrap ( ) ) ?;
2194
2201
let dot_type_params = self . name ( ".type_params" ) ;
2195
2202
emit ! ( self , Instruction :: StoreLocal ( dot_type_params) ) ;
2196
2203
2197
- // Create .generic_base in the type params scope (like CPython)
2198
- // Load .type_params
2199
- emit ! ( self , Instruction :: LoadNameAny ( dot_type_params) ) ;
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;
2200
2213
2201
- // Call INTRINSIC_SUBSCRIPT_GENERIC to create Generic[*type_params]
2214
+ // Back in type params scope, create .generic_base
2215
+ emit ! ( self , Instruction :: LoadNameAny ( dot_type_params) ) ;
2202
2216
emit ! (
2203
2217
self ,
2204
2218
Instruction :: CallIntrinsic1 {
2205
2219
func: bytecode:: IntrinsicFunction1 :: SubscriptGeneric
2206
2220
}
2207
2221
) ;
2208
-
2209
- // Store as .generic_base in the type params scope
2210
2222
let dot_generic_base = self . name ( ".generic_base" ) ;
2211
2223
emit ! ( self , Instruction :: StoreLocal ( dot_generic_base) ) ;
2212
- }
2213
-
2214
- // Compile the class body into a code object
2215
- let firstlineno = self . get_source_line_number ( ) . get ( ) . to_u32 ( ) ;
2216
- let code = self . compile_class_body ( name, body, type_params, firstlineno) ?;
2217
- self . ctx = prev_ctx;
2218
2224
2219
- emit ! ( self , Instruction :: LoadBuildClass ) ;
2225
+ // Generate the class creation code (still in type params scope)
2226
+ emit ! ( self , Instruction :: LoadBuildClass ) ;
2220
2227
2221
- let mut func_flags = bytecode:: MakeFunctionFlags :: empty ( ) ;
2228
+ // Set up the class function
2229
+ let mut func_flags = bytecode:: MakeFunctionFlags :: empty ( ) ;
2222
2230
2223
- // Prepare generic type parameters:
2224
- if type_params. is_some ( ) {
2225
- // Load .type_params from the type params scope
2226
- let dot_type_params = self . name ( ".type_params" ) ;
2231
+ // Load .type_params for the class function
2227
2232
emit ! ( self , Instruction :: LoadNameAny ( dot_type_params) ) ;
2228
2233
func_flags |= bytecode:: MakeFunctionFlags :: TYPE_PARAMS ;
2229
- }
2230
2234
2231
- if self . build_closure ( & code) {
2232
- func_flags |= bytecode:: MakeFunctionFlags :: CLOSURE ;
2233
- }
2234
-
2235
- self . emit_load_const ( ConstantData :: Code {
2236
- code : Box :: new ( code) ,
2237
- } ) ;
2238
- self . emit_load_const ( ConstantData :: Str { value : name. into ( ) } ) ;
2235
+ if self . build_closure ( & class_code) {
2236
+ func_flags |= bytecode:: MakeFunctionFlags :: CLOSURE ;
2237
+ }
2239
2238
2240
- // Turn code object into function object:
2241
- emit ! ( self , Instruction :: MakeFunction ( func_flags) ) ;
2239
+ self . emit_load_const ( ConstantData :: Code {
2240
+ code : Box :: new ( class_code) ,
2241
+ } ) ;
2242
+ self . emit_load_const ( ConstantData :: Str { value : name. into ( ) } ) ;
2242
2243
2243
- self . emit_load_const ( ConstantData :: Str { value : name . into ( ) } ) ;
2244
+ emit ! ( self , Instruction :: MakeFunction ( func_flags ) ) ;
2244
2245
2245
- // For PEP 695 classes: handle Generic base creation
2246
- if type_params. is_some ( ) {
2247
- // Stack currently: [function, class_name]
2246
+ self . emit_load_const ( ConstantData :: Str { value : name. into ( ) } ) ;
2248
2247
2249
- // Compile the original bases (if any)
2250
- if let Some ( arguments) = arguments {
2251
- // Compile all the positional arguments (bases)
2248
+ // Compile bases with .generic_base appended
2249
+ let base_count = if let Some ( arguments) = arguments {
2252
2250
for arg in & arguments. args {
2253
2251
self . compile_expression ( arg) ?;
2254
2252
}
2255
- }
2253
+ arguments. args . len ( )
2254
+ } else {
2255
+ 0
2256
+ } ;
2256
2257
2257
- // Load .generic_base from the type params scope
2258
- let dot_generic_base = self . name ( ".generic_base" ) ;
2258
+ // Load .generic_base as the last base
2259
2259
emit ! ( self , Instruction :: LoadNameAny ( dot_generic_base) ) ;
2260
2260
2261
- // Calculate total number of positional args
2262
- let nargs = if let Some ( arguments) = arguments {
2263
- 2 + arguments. args . len ( ) as u32 + 1 // function, name, bases..., generic_base
2264
- } else {
2265
- 3 // function, name, generic_base
2266
- } ;
2261
+ let nargs = 2 + base_count as u32 + 1 ; // function, name, bases..., generic_base
2267
2262
2268
- // Handle keyword arguments if any
2263
+ // Handle keyword arguments
2269
2264
if let Some ( arguments) = arguments
2270
2265
&& !arguments. keywords . is_empty ( )
2271
2266
{
2272
- // Compile keyword arguments
2273
2267
for keyword in & arguments. keywords {
2274
2268
if let Some ( name) = & keyword. arg {
2275
2269
self . emit_load_const ( ConstantData :: Str {
@@ -2288,8 +2282,58 @@ impl Compiler<'_> {
2288
2282
} else {
2289
2283
emit ! ( self , Instruction :: CallFunctionPositional { nargs } ) ;
2290
2284
}
2285
+
2286
+ // Return the created class
2287
+ self . emit_return_value ( ) ;
2288
+
2289
+ // Exit type params scope and get the code object
2290
+ let type_params_code = self . exit_scope ( ) ;
2291
+
2292
+ // Now execute the type params function
2293
+ if self . build_closure ( & type_params_code) {
2294
+ // Should not need closure
2295
+ }
2296
+ self . emit_load_const ( ConstantData :: Code {
2297
+ code : Box :: new ( type_params_code) ,
2298
+ } ) ;
2299
+ self . emit_load_const ( ConstantData :: Str {
2300
+ value : type_params_name. into ( ) ,
2301
+ } ) ;
2302
+ emit ! (
2303
+ self ,
2304
+ Instruction :: MakeFunction ( bytecode:: MakeFunctionFlags :: empty( ) )
2305
+ ) ;
2306
+
2307
+ emit ! ( self , Instruction :: CallFunctionPositional { nargs: 0 } ) ;
2291
2308
} else {
2292
- // No type params, normal compilation
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
+
2320
+ emit ! ( self , Instruction :: LoadBuildClass ) ;
2321
+
2322
+ let mut func_flags = bytecode:: MakeFunctionFlags :: empty ( ) ;
2323
+
2324
+ if self . build_closure ( & code) {
2325
+ func_flags |= bytecode:: MakeFunctionFlags :: CLOSURE ;
2326
+ }
2327
+
2328
+ self . emit_load_const ( ConstantData :: Code {
2329
+ code : Box :: new ( code) ,
2330
+ } ) ;
2331
+ self . emit_load_const ( ConstantData :: Str { value : name. into ( ) } ) ;
2332
+
2333
+ emit ! ( self , Instruction :: MakeFunction ( func_flags) ) ;
2334
+
2335
+ self . emit_load_const ( ConstantData :: Str { value : name. into ( ) } ) ;
2336
+
2293
2337
let call = if let Some ( arguments) = arguments {
2294
2338
self . compile_call_inner ( 2 , arguments) ?
2295
2339
} else {
@@ -2298,13 +2342,7 @@ impl Compiler<'_> {
2298
2342
self . compile_normal_call ( call) ;
2299
2343
}
2300
2344
2301
- // Pop the special type params symbol table
2302
- if type_params. is_some ( ) {
2303
- self . pop_symbol_table ( ) ;
2304
- }
2305
-
2306
2345
self . apply_decorators ( decorator_list) ;
2307
-
2308
2346
self . store_name ( name)
2309
2347
}
2310
2348
0 commit comments