@@ -932,6 +932,21 @@ mod builtins {
932932 ) )
933933 } ) ?;
934934
935+ // For PEP 695 classes, set .type_params in namespace before calling the function
936+ let function_obj: PyObjectRef = function. clone ( ) . into ( ) ;
937+ if let Ok ( type_params) = function_obj. get_attr ( identifier ! ( vm, __type_params__) , vm) {
938+ if let Ok ( type_params_tuple) = type_params. clone ( ) . downcast :: < PyTuple > ( ) {
939+ if !type_params_tuple. is_empty ( ) {
940+ // Set .type_params in namespace so the compiler-generated code can use it
941+ namespace. as_object ( ) . set_item (
942+ vm. ctx . intern_str ( ".type_params" ) ,
943+ type_params,
944+ vm,
945+ ) ?;
946+ }
947+ }
948+ }
949+
935950 let classcell = function. invoke_with_locals ( ( ) . into ( ) , Some ( namespace. clone ( ) ) , vm) ?;
936951 let classcell = <Option < PyCellRef > >:: try_from_object ( vm, classcell) ?;
937952
@@ -943,52 +958,15 @@ mod builtins {
943958 ) ?;
944959 }
945960
946- // Check if we need to set __parameters__ for PEP 695 classes
947- let function_obj: PyObjectRef = function. clone ( ) . into ( ) ;
948- let has_type_params =
949- if let Ok ( type_params) = function_obj. get_attr ( identifier ! ( vm, __type_params__) , vm) {
950- if let Ok ( type_params_tuple) = type_params. downcast :: < PyTuple > ( ) {
951- !type_params_tuple. is_empty ( )
952- } else {
953- false
954- }
955- } else {
956- false
957- } ;
958-
959- let needs_parameters = if has_type_params {
960- if let Ok ( bases_tuple) = bases. clone ( ) . downcast :: < PyTuple > ( ) {
961- bases_tuple. iter ( ) . any ( |base| {
962- if let Ok ( base_name) = base. get_attr ( identifier ! ( vm, __name__) , vm) {
963- if let Ok ( name_str) = base_name. downcast :: < PyStr > ( ) {
964- let name = name_str. as_str ( ) ;
965- return name == "Protocol" || name == "Generic" ;
966- }
967- }
968- false
969- } )
970- } else {
971- false
972- }
973- } else {
974- false
975- } ;
961+ // Remove .type_params from namespace before creating the class (CPython compatibility)
962+ namespace
963+ . as_object ( )
964+ . del_item ( vm. ctx . intern_str ( ".type_params" ) , vm)
965+ . ok ( ) ;
976966
977967 let args = FuncArgs :: new ( vec ! [ name_obj. into( ) , bases, namespace. into( ) ] , kwargs) ;
978968 let class = metaclass. call ( args, vm) ?;
979969
980- // Set __type_params__ on the class if the function has type params
981- if has_type_params {
982- if let Ok ( type_params) = function_obj. get_attr ( identifier ! ( vm, __type_params__) , vm) {
983- class. set_attr ( identifier ! ( vm, __type_params__) , type_params. clone ( ) , vm) ?;
984-
985- if needs_parameters {
986- // Set __parameters__ to the same value as __type_params__
987- class. set_attr ( identifier ! ( vm, __parameters__) , type_params, vm) ?;
988- }
989- }
990- }
991-
992970 if let Some ( ref classcell) = classcell {
993971 let classcell = classcell. get ( ) . ok_or_else ( || {
994972 vm. new_type_error ( format ! (
@@ -1003,6 +981,26 @@ mod builtins {
1003981 }
1004982 }
1005983
984+ // For PEP 695 classes, set __parameters__ from __type_params__ (CPython compatibility)
985+ if let Ok ( type_params) = class. get_attr ( identifier ! ( vm, __type_params__) , vm) {
986+ if let Ok ( type_params_tuple) = type_params. clone ( ) . downcast :: < PyTuple > ( ) {
987+ if !type_params_tuple. is_empty ( ) {
988+ // Extract TypeVar/ParamSpec/TypeVarTuple objects from the tuple
989+ let mut parameters = Vec :: new ( ) ;
990+ for param in type_params_tuple. iter ( ) {
991+ // Check if this is a TypeVar, ParamSpec, or TypeVarTuple
992+ if param. get_attr ( identifier ! ( vm, __name__) , vm) . is_ok ( ) {
993+ parameters. push ( param. clone ( ) ) ;
994+ }
995+ }
996+ if !parameters. is_empty ( ) {
997+ let parameters_tuple = PyTuple :: new_ref ( parameters, & vm. ctx ) ;
998+ class. set_attr ( identifier ! ( vm, __parameters__) , parameters_tuple, vm) ?;
999+ }
1000+ }
1001+ }
1002+ }
1003+
10061004 Ok ( class)
10071005 }
10081006}
0 commit comments