4747static mp_obj_t mp_obj_new_type (qstr name , mp_obj_t bases_tuple , mp_obj_t locals_dict , const mp_obj_type_t * metaclass );
4848static mp_obj_t mp_obj_is_subclass (mp_obj_t object , mp_obj_t classinfo );
4949static mp_obj_t static_class_method_make_new (const mp_obj_type_t * self_in , size_t n_args , size_t n_kw , const mp_obj_t * args );
50+ static mp_obj_t type___new__ (size_t n_args , const mp_obj_t * args );
51+ static MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN (type___new___obj , 1 , 4 , type___new__ ) ;
5052
5153/******************************************************************************/
5254// instance object
@@ -1032,36 +1034,27 @@ static mp_obj_t type_make_new(const mp_obj_type_t *type_in, size_t n_args, size_
10321034 case 1 :
10331035 return MP_OBJ_FROM_PTR (mp_obj_get_type (args [0 ]));
10341036
1035- case 3 : {
1037+ case 3 :
10361038 // args[0] = name
10371039 // args[1] = bases tuple
10381040 // args[2] = locals dict
10391041
1040- // Check if the metaclass has a custom __new__ method
1041- // Use proper method lookup to check inheritance chain
1042- mp_obj_t dest [2 ] = {MP_OBJ_NULL , MP_OBJ_NULL };
1043- struct class_lookup_data lookup = {
1044- .obj = NULL ,
1045- .attr = MP_QSTR___new__ ,
1046- .slot_offset = 0 ,
1047- .dest = dest ,
1048- .is_type = true,
1049- };
1050- mp_obj_class_lookup (& lookup , type_in );
1051- if (dest [0 ] != MP_OBJ_NULL ) {
1052- // Found custom __new__, unwrap if it's a staticmethod
1053- mp_obj_t new_fn = dest [0 ];
1054- if (mp_obj_is_type (new_fn , & mp_type_staticmethod )) {
1055- new_fn = ((mp_obj_static_class_method_t * )MP_OBJ_TO_PTR (new_fn ))-> fun ;
1042+ // Check if metaclass has custom __new__ (not inherited from type)
1043+ if (type_in != & mp_type_type ) {
1044+ mp_obj_t dest [2 ] = {MP_OBJ_NULL , MP_OBJ_NULL };
1045+ mp_load_method_maybe (MP_OBJ_FROM_PTR (type_in ), MP_QSTR___new__ , dest );
1046+ if (dest [0 ] != MP_OBJ_NULL && dest [0 ] != MP_OBJ_FROM_PTR (& type___new___obj )) {
1047+ // Found custom __new__, call it with (metaclass, name, bases, dict)
1048+ mp_obj_t new_args [4 ] = {MP_OBJ_FROM_PTR (type_in ), args [0 ], args [1 ], args [2 ]};
1049+ return mp_call_function_n_kw (dest [0 ], 4 , 0 , new_args );
10561050 }
1057- // Call it with (metaclass, name, bases, dict)
1058- mp_obj_t new_args [4 ] = {MP_OBJ_FROM_PTR (type_in ), args [0 ], args [1 ], args [2 ]};
1059- return mp_call_function_n_kw (new_fn , 4 , 0 , new_args );
10601051 }
10611052
1062- // No custom __new__, use default behavior
1063- return mp_obj_new_type (mp_obj_str_get_qstr (args [0 ]), args [1 ], args [2 ], type_in );
1064- }
1053+ // No custom __new__, use default type.__new__
1054+ {
1055+ mp_obj_t new_args [4 ] = {MP_OBJ_FROM_PTR (type_in ), args [0 ], args [1 ], args [2 ]};
1056+ return type___new__ (4 , new_args );
1057+ }
10651058
10661059 default :
10671060 mp_raise_TypeError (MP_ERROR_TEXT ("type takes 1 or 3 arguments" ));
@@ -1074,34 +1067,23 @@ static mp_obj_t type_call(mp_obj_t self_in, size_t n_args, size_t n_kw, const mp
10741067 mp_obj_type_t * self = MP_OBJ_TO_PTR (self_in );
10751068
10761069 // Check if the metaclass has a custom __call__ method
1077- // If it does, use that instead of the default make_new behavior
10781070 const mp_obj_type_t * metaclass = self -> base .type ;
10791071 if (metaclass != & mp_type_type ) {
1080- // Custom metaclass, check for __call__ method
10811072 mp_obj_t dest [2 ] = {MP_OBJ_NULL , MP_OBJ_NULL };
1082- struct class_lookup_data lookup = {
1083- .obj = NULL ,
1084- .attr = MP_QSTR___call__ ,
1085- .slot_offset = 0 ,
1086- .dest = dest ,
1087- .is_type = true,
1088- };
1089- mp_obj_class_lookup (& lookup , metaclass );
1073+ mp_load_method_maybe (MP_OBJ_FROM_PTR (metaclass ), MP_QSTR___call__ , dest );
10901074 if (dest [0 ] != MP_OBJ_NULL ) {
1091- // Found __call__ on metaclass, use it
1092- // dest[0] contains the function, call it with cls as first argument
1075+ // Found custom __call__, call it with (cls, *args, **kwargs)
10931076 mp_obj_t * new_args ;
1094- mp_obj_t stack_args [8 ]; // Stack allocation for small arg counts
1077+ mp_obj_t stack_args [8 ];
10951078
1096- if (n_args < 8 ) { // Use all 8 slots: up to 7 args + cls = 8 total
1079+ if (n_args < 8 ) {
10971080 new_args = stack_args ;
10981081 } else {
10991082 new_args = m_new (mp_obj_t , n_args + 1 );
11001083 }
11011084
1102- new_args [0 ] = self_in ; // cls argument
1085+ new_args [0 ] = self_in ;
11031086 memcpy (new_args + 1 , args , sizeof (mp_obj_t ) * n_args );
1104- // Call the function directly (not as a method) to avoid recursion
11051087 mp_obj_t result = mp_call_function_n_kw (dest [0 ], n_args + 1 , n_kw , new_args );
11061088
11071089 if (n_args >= 8 ) {
@@ -1112,6 +1094,7 @@ static mp_obj_t type_call(mp_obj_t self_in, size_t n_args, size_t n_kw, const mp
11121094 }
11131095 }
11141096
1097+ // No custom __call__, use default make_new behavior
11151098 if (!MP_OBJ_TYPE_HAS_SLOT (self , make_new )) {
11161099 #if MICROPY_ERROR_REPORTING <= MICROPY_ERROR_REPORTING_TERSE
11171100 mp_raise_TypeError (MP_ERROR_TEXT ("can't create instance" ));
@@ -1120,11 +1103,7 @@ static mp_obj_t type_call(mp_obj_t self_in, size_t n_args, size_t n_kw, const mp
11201103 #endif
11211104 }
11221105
1123- // make new instance
1124- mp_obj_t o = MP_OBJ_TYPE_GET_SLOT (self , make_new )(self , n_args , n_kw , args );
1125-
1126- // return new instance
1127- return o ;
1106+ return MP_OBJ_TYPE_GET_SLOT (self , make_new )(self , n_args , n_kw , args );
11281107}
11291108
11301109// Minimal type.__new__ for metaclass support
@@ -1150,7 +1129,6 @@ static mp_obj_t type___new__(size_t n_args, const mp_obj_t *args) {
11501129 MP_ERROR_TEXT ("type.__new__() takes 1, 2 or 4 arguments (%d given)" ), n_args );
11511130 }
11521131}
1153- static MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN (type___new___obj , 1 , 4 , type___new__ ) ;
11541132
11551133// type.__init__(cls, name, bases, dict) - does nothing, exists for metaclass super() calls
11561134static mp_obj_t type___init__ (size_t n_args , const mp_obj_t * args ) {
0 commit comments