diff --git a/py/obj.c b/py/obj.c index e98dbae6cf..0c91e8f6d8 100644 --- a/py/obj.c +++ b/py/obj.c @@ -81,9 +81,16 @@ machine_int_t mp_obj_hash(mp_obj_t o_in) { return mp_obj_str_get_hash(o_in); } else if (MP_OBJ_IS_TYPE(o_in, &none_type)) { return (machine_int_t)o_in; + } else if (MP_OBJ_IS_TYPE(o_in, &fun_native_type) || MP_OBJ_IS_TYPE(o_in, &fun_bc_type)) { + return (machine_int_t)o_in; + } else if (MP_OBJ_IS_TYPE(o_in, &tuple_type)) { + return mp_obj_tuple_hash(o_in); + + // TODO hash class and instances + // TODO delegate to __hash__ method if it exists + } else { - assert(0); - return 0; + nlr_jump(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "unhashable type: '%s'", mp_obj_get_type_str(o_in))); } } diff --git a/py/obj.h b/py/obj.h index dd80b3f021..1daa943447 100644 --- a/py/obj.h +++ b/py/obj.h @@ -330,6 +330,7 @@ mp_obj_t mp_obj_complex_binary_op(int op, mp_float_t lhs_real, mp_float_t lhs_im extern const mp_obj_type_t tuple_type; void mp_obj_tuple_get(mp_obj_t self_in, uint *len, mp_obj_t **items); void mp_obj_tuple_del(mp_obj_t self_in); +machine_int_t mp_obj_tuple_hash(mp_obj_t self_in); // list extern const mp_obj_type_t list_type; diff --git a/py/objtuple.c b/py/objtuple.c index 83d1f21cea..3378b4ec1c 100644 --- a/py/objtuple.c +++ b/py/objtuple.c @@ -218,6 +218,17 @@ void mp_obj_tuple_del(mp_obj_t self_in) { m_del_var(mp_obj_tuple_t, mp_obj_t, self->len, self); } +machine_int_t mp_obj_tuple_hash(mp_obj_t self_in) { + assert(MP_OBJ_IS_TYPE(self_in, &tuple_type)); + mp_obj_tuple_t *self = self_in; + // start hash with pointer to empty tuple, to make it fairly unique + machine_int_t hash = (machine_int_t)mp_const_empty_tuple; + for (uint i = 0; i < self->len; i++) { + hash += mp_obj_hash(self->items[i]); + } + return hash; +} + /******************************************************************************/ /* tuple iterator */