diff --git a/py/obj.h b/py/obj.h index eac2b89ea810d..40c6c4e2ffd2e 100644 --- a/py/obj.h +++ b/py/obj.h @@ -516,6 +516,9 @@ typedef mp_obj_t (*mp_fun_3_t)(mp_obj_t, mp_obj_t, mp_obj_t); typedef mp_obj_t (*mp_fun_var_t)(size_t n, const mp_obj_t *); // mp_fun_kw_t takes mp_map_t* (and not const mp_map_t*) to ease passing // this arg to mp_map_lookup(). +// Note that the mp_obj_t* array will contain all arguments, positional and keyword, with the keyword ones +// starting at offset n, like: arg0 arg1 ... arg key0 value0 key1 value1 ..., and the mp_map_t* gets those +// same keyword arguments but as a map for convenience; see fun_builtin_var_call. typedef mp_obj_t (*mp_fun_kw_t)(size_t n, const mp_obj_t *, mp_map_t *); // Flags for type behaviour (mp_obj_type_t.flags) diff --git a/py/objfun.c b/py/objfun.c index 8279605e9874a..c0c6045c44ccd 100644 --- a/py/objfun.c +++ b/py/objfun.c @@ -107,7 +107,9 @@ static mp_obj_t fun_builtin_var_call(mp_obj_t self_in, size_t n_args, size_t n_k if (self->sig & 1) { // function allows keywords - // we create a map directly from the given args array + // we create a map directly from the given args array; self->fun.kw does still expect args to have + // both positional and keyword arguments, ordered + // arg0 arg1 ... arg key0 value0 key1 value1 ... key value mp_map_t kw_args; mp_map_init_fixed_table(&kw_args, n_kw, args + n_args); diff --git a/py/objtype.c b/py/objtype.c index 16ff5310dac6f..847216982a469 100644 --- a/py/objtype.c +++ b/py/objtype.c @@ -85,14 +85,14 @@ static int instance_count_native_bases(const mp_obj_type_t *type, const mp_obj_t // This wrapper function allows a subclass of a native type to call the // __init__() method (corresponding to type->make_new) of the native type. -static mp_obj_t native_base_init_wrapper(size_t n_args, const mp_obj_t *args) { +static mp_obj_t native_base_init_wrapper(size_t n_args, const mp_obj_t *args, mp_map_t *kw_args) { mp_obj_instance_t *self = MP_OBJ_TO_PTR(args[0]); const mp_obj_type_t *native_base = NULL; instance_count_native_bases(self->base.type, &native_base); - self->subobj[0] = MP_OBJ_TYPE_GET_SLOT(native_base, make_new)(native_base, n_args - 1, 0, args + 1); + self->subobj[0] = MP_OBJ_TYPE_GET_SLOT(native_base, make_new)(native_base, n_args - 1, kw_args->used, args + 1); return mp_const_none; } -static MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(native_base_init_wrapper_obj, 1, MP_OBJ_FUN_ARGS_MAX, native_base_init_wrapper); +static MP_DEFINE_CONST_FUN_OBJ_KW(native_base_init_wrapper_obj, 1, native_base_init_wrapper); #if !MICROPY_CPYTHON_COMPAT static diff --git a/tests/basics/subclass_native_init.py b/tests/basics/subclass_native_init.py index 38d2f23ac3814..64167fa037e0c 100644 --- a/tests/basics/subclass_native_init.py +++ b/tests/basics/subclass_native_init.py @@ -6,6 +6,35 @@ def __init__(self, a, b): super().__init__([a, b]) print(L(2, 3)) +# with keyword arguments, with star arguments and without because those use different C calls +class D(dict): + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) +print(D()) +print(D([('a', 1)])) +print(D([('a', 1)], a=2, b=3)) +print(D(a=2, b=3)) + +class D(dict): + def __init__(self): + super().__init__() +print(D()) + +class D(dict): + def __init__(self): + super().__init__([]) +print(D()) + +class D(dict): + def __init__(self): + super().__init__(a=1) +print(D()) + +class D(dict): + def __init__(self): + super().__init__([], a=1) +print(D()) + # inherits implicitly from object class A: def __init__(self):