py/objtype: Handle NotImplemented return from binary special methods.
NotImplemented means "try other fallbacks (like calling __rop__ instead of __op__) and if nothing works, raise TypeError". As MicroPython doesn't implement any fallbacks, signal to raise TypeError right away.
This commit is contained in:
parent
8388ec4e35
commit
784909ce16
1
py/obj.h
1
py/obj.h
@ -616,6 +616,7 @@ extern const mp_obj_type_t mp_type_ZeroDivisionError;
|
|||||||
#define mp_const_true (MP_OBJ_FROM_PTR(&mp_const_true_obj))
|
#define mp_const_true (MP_OBJ_FROM_PTR(&mp_const_true_obj))
|
||||||
#define mp_const_empty_bytes (MP_OBJ_FROM_PTR(&mp_const_empty_bytes_obj))
|
#define mp_const_empty_bytes (MP_OBJ_FROM_PTR(&mp_const_empty_bytes_obj))
|
||||||
#define mp_const_empty_tuple (MP_OBJ_FROM_PTR(&mp_const_empty_tuple_obj))
|
#define mp_const_empty_tuple (MP_OBJ_FROM_PTR(&mp_const_empty_tuple_obj))
|
||||||
|
#define mp_const_notimplemented (MP_OBJ_FROM_PTR(&mp_const_notimplemented_obj))
|
||||||
extern const struct _mp_obj_none_t mp_const_none_obj;
|
extern const struct _mp_obj_none_t mp_const_none_obj;
|
||||||
extern const struct _mp_obj_bool_t mp_const_false_obj;
|
extern const struct _mp_obj_bool_t mp_const_false_obj;
|
||||||
extern const struct _mp_obj_bool_t mp_const_true_obj;
|
extern const struct _mp_obj_bool_t mp_const_true_obj;
|
||||||
|
18
py/objtype.c
18
py/objtype.c
@ -471,14 +471,28 @@ STATIC mp_obj_t instance_binary_op(mp_binary_op_t op, mp_obj_t lhs_in, mp_obj_t
|
|||||||
.is_type = false,
|
.is_type = false,
|
||||||
};
|
};
|
||||||
mp_obj_class_lookup(&lookup, lhs->base.type);
|
mp_obj_class_lookup(&lookup, lhs->base.type);
|
||||||
|
|
||||||
|
mp_obj_t res;
|
||||||
if (dest[0] == MP_OBJ_SENTINEL) {
|
if (dest[0] == MP_OBJ_SENTINEL) {
|
||||||
return mp_binary_op(op, lhs->subobj[0], rhs_in);
|
res = mp_binary_op(op, lhs->subobj[0], rhs_in);
|
||||||
} else if (dest[0] != MP_OBJ_NULL) {
|
} else if (dest[0] != MP_OBJ_NULL) {
|
||||||
dest[2] = rhs_in;
|
dest[2] = rhs_in;
|
||||||
return mp_call_method_n_kw(1, 0, dest);
|
res = mp_call_method_n_kw(1, 0, dest);
|
||||||
} else {
|
} else {
|
||||||
return MP_OBJ_NULL; // op not supported
|
return MP_OBJ_NULL; // op not supported
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if MICROPY_PY_BUILTINS_NOTIMPLEMENTED
|
||||||
|
// NotImplemented means "try other fallbacks (like calling __rop__
|
||||||
|
// instead of __op__) and if nothing works, raise TypeError". As
|
||||||
|
// MicroPython doesn't implement any fallbacks, signal to raise
|
||||||
|
// TypeError right away.
|
||||||
|
if (res == mp_const_notimplemented) {
|
||||||
|
return MP_OBJ_NULL; // op not supported
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
STATIC void mp_obj_instance_load_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) {
|
STATIC void mp_obj_instance_load_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) {
|
||||||
|
50
tests/basics/class_notimpl.py
Normal file
50
tests/basics/class_notimpl.py
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
# Test that returning of NotImplemented from binary op methods leads to
|
||||||
|
# TypeError.
|
||||||
|
try:
|
||||||
|
NotImplemented
|
||||||
|
except NameError:
|
||||||
|
print("SKIP")
|
||||||
|
raise SystemExit
|
||||||
|
|
||||||
|
class C:
|
||||||
|
def __init__(self, value):
|
||||||
|
self.value = value
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return "C(%s)" % self.value
|
||||||
|
|
||||||
|
def __add__(self, rhs):
|
||||||
|
print(self, '+', rhs)
|
||||||
|
return NotImplemented
|
||||||
|
|
||||||
|
def __sub__(self, rhs):
|
||||||
|
print(self, '-', rhs)
|
||||||
|
return NotImplemented
|
||||||
|
|
||||||
|
def __lt__(self, rhs):
|
||||||
|
print(self, '<', rhs)
|
||||||
|
return NotImplemented
|
||||||
|
|
||||||
|
def __neg__(self):
|
||||||
|
print('-', self)
|
||||||
|
return NotImplemented
|
||||||
|
|
||||||
|
c = C(0)
|
||||||
|
|
||||||
|
try:
|
||||||
|
c + 1
|
||||||
|
except TypeError:
|
||||||
|
print("TypeError")
|
||||||
|
|
||||||
|
try:
|
||||||
|
c - 2
|
||||||
|
except TypeError:
|
||||||
|
print("TypeError")
|
||||||
|
|
||||||
|
try:
|
||||||
|
c < 1
|
||||||
|
except TypeError:
|
||||||
|
print("TypeError")
|
||||||
|
|
||||||
|
# NotImplemented isn't handled specially in unary methods
|
||||||
|
print(-c)
|
Loading…
Reference in New Issue
Block a user