@@ -974,6 +974,48 @@ static bool check_for_special_accessors(mp_obj_t key, mp_obj_t value) {
974
974
}
975
975
#endif
976
976
977
+ #if MICROPY_PY_DESCRIPTORS
978
+ static void run_set_name_hooks (mp_map_t * locals_map_orig , mp_obj_t owner ) {
979
+ // copy the dict so we can iterate safely even while __set_name__ potentially modifies the original
980
+ mp_map_t locals_map = * locals_map_orig ;
981
+ locals_map .table = mp_local_alloc (locals_map .alloc * sizeof (mp_map_elem_t ));
982
+ memcpy (locals_map .table , locals_map_orig -> table , locals_map .alloc * sizeof (mp_map_elem_t ));
983
+
984
+ #if MICROPY_ENABLE_PYSTACK
985
+ nlr_buf_t nlr ;
986
+ if (nlr_push (& nlr ) == 0 )
987
+ // Note: on !MICROPY_ENABLE_PYSTACK ports, `mp_local_alloc` is just `alloca` and `mp_local_free` is a no-op.
988
+ // Therefore we don't need to set an exception trap; the exception handler implicitly frees as it unwinds the stack.
989
+ #endif
990
+ {
991
+ // use the copy to call __set_name__ on each
992
+ for (size_t i = 0 ; i < locals_map .alloc ; i ++ ) {
993
+ if (mp_map_slot_is_filled (& locals_map , i )) {
994
+ mp_map_elem_t * elem = & (locals_map .table [i ]);
995
+ mp_obj_t set_name_method [4 ];
996
+ mp_load_method_maybe (elem -> value , MP_QSTR___set_name__ , set_name_method );
997
+ if (set_name_method [1 ] != MP_OBJ_NULL ) {
998
+ set_name_method [2 ] = owner ;
999
+ set_name_method [3 ] = elem -> key ;
1000
+ mp_call_method_n_kw (2 , 0 , set_name_method );
1001
+ }
1002
+ }
1003
+ }
1004
+
1005
+ #if MICROPY_ENABLE_PYSTACK
1006
+ nlr_pop ();
1007
+ #endif
1008
+ mp_local_free (locals_map .table );
1009
+ }
1010
+ #if MICROPY_ENABLE_PYSTACK
1011
+ else {
1012
+ mp_local_free (locals_map .table );
1013
+ nlr_raise (nlr .ret_val ); // TODO cpython raises a RuntimeError in this situation
1014
+ }
1015
+ #endif
1016
+ }
1017
+ #endif
1018
+
977
1019
static void type_print (const mp_print_t * print , mp_obj_t self_in , mp_print_kind_t kind ) {
978
1020
(void )kind ;
979
1021
mp_obj_type_t * self = MP_OBJ_TO_PTR (self_in );
@@ -1242,20 +1284,7 @@ mp_obj_t mp_obj_new_type(qstr name, mp_obj_t bases_tuple, mp_obj_t locals_dict)
1242
1284
}
1243
1285
1244
1286
#if MICROPY_PY_DESCRIPTORS
1245
- // call __set_name__ on all entries (especially descriptors)
1246
- for (size_t i = 0 ; i < locals_map -> alloc ; i ++ ) {
1247
- if (mp_map_slot_is_filled (locals_map , i )) {
1248
- elem = & (locals_map -> table [i ]);
1249
-
1250
- mp_obj_t set_name_method [4 ];
1251
- mp_load_method_maybe (elem -> value , MP_QSTR___set_name__ , set_name_method );
1252
- if (set_name_method [1 ] != MP_OBJ_NULL ) {
1253
- set_name_method [2 ] = MP_OBJ_FROM_PTR (o );
1254
- set_name_method [3 ] = elem -> key ;
1255
- mp_call_method_n_kw (2 , 0 , set_name_method );
1256
- }
1257
- }
1258
- }
1287
+ run_set_name_hooks (locals_map , MP_OBJ_FROM_PTR (o ));
1259
1288
#endif
1260
1289
1261
1290
return MP_OBJ_FROM_PTR (o );
0 commit comments