py/runtime: If inplace binop fails then try corresponding normal binop.
The code that handles inplace-operator to normal-binary-operator fallback is moved in this commit from py/objtype.c to py/runtime.c, making it apply to all types, not just user classes. Signed-off-by: Damien George <damien@micropython.org>
This commit is contained in:
parent
4b57330465
commit
ea7031faff
13
py/objtype.c
13
py/objtype.c
|
@ -534,7 +534,6 @@ STATIC mp_obj_t instance_binary_op(mp_binary_op_t op, mp_obj_t lhs_in, mp_obj_t
|
||||||
// Note: For ducktyping, CPython does not look in the instance members or use
|
// Note: For ducktyping, CPython does not look in the instance members or use
|
||||||
// __getattr__ or __getattribute__. It only looks in the class dictionary.
|
// __getattr__ or __getattribute__. It only looks in the class dictionary.
|
||||||
mp_obj_instance_t *lhs = MP_OBJ_TO_PTR(lhs_in);
|
mp_obj_instance_t *lhs = MP_OBJ_TO_PTR(lhs_in);
|
||||||
retry:;
|
|
||||||
qstr op_name = mp_binary_op_method_name[op];
|
qstr op_name = mp_binary_op_method_name[op];
|
||||||
/* Still try to lookup native slot
|
/* Still try to lookup native slot
|
||||||
if (op_name == 0) {
|
if (op_name == 0) {
|
||||||
|
@ -559,22 +558,12 @@ retry:;
|
||||||
res = mp_call_method_n_kw(1, 0, dest);
|
res = mp_call_method_n_kw(1, 0, dest);
|
||||||
res = op == MP_BINARY_OP_CONTAINS ? mp_obj_new_bool(mp_obj_is_true(res)) : res;
|
res = op == MP_BINARY_OP_CONTAINS ? mp_obj_new_bool(mp_obj_is_true(res)) : res;
|
||||||
} else {
|
} else {
|
||||||
// If this was an inplace method, fallback to normal method
|
|
||||||
// https://docs.python.org/3/reference/datamodel.html#object.__iadd__ :
|
|
||||||
// "If a specific method is not defined, the augmented assignment
|
|
||||||
// falls back to the normal methods."
|
|
||||||
if (op >= MP_BINARY_OP_INPLACE_OR && op <= MP_BINARY_OP_INPLACE_POWER) {
|
|
||||||
op -= MP_BINARY_OP_INPLACE_OR - MP_BINARY_OP_OR;
|
|
||||||
goto retry;
|
|
||||||
}
|
|
||||||
return MP_OBJ_NULL; // op not supported
|
return MP_OBJ_NULL; // op not supported
|
||||||
}
|
}
|
||||||
|
|
||||||
#if MICROPY_PY_BUILTINS_NOTIMPLEMENTED
|
#if MICROPY_PY_BUILTINS_NOTIMPLEMENTED
|
||||||
// NotImplemented means "try other fallbacks (like calling __rop__
|
// NotImplemented means "try other fallbacks (like calling __rop__
|
||||||
// instead of __op__) and if nothing works, raise TypeError". As
|
// instead of __op__) and if nothing works, raise TypeError".
|
||||||
// MicroPython doesn't implement any fallbacks, signal to raise
|
|
||||||
// TypeError right away.
|
|
||||||
if (res == mp_const_notimplemented) {
|
if (res == mp_const_notimplemented) {
|
||||||
return MP_OBJ_NULL; // op not supported
|
return MP_OBJ_NULL; // op not supported
|
||||||
}
|
}
|
||||||
|
|
|
@ -625,6 +625,15 @@ generic_binary_op:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If this was an inplace method, fallback to the corresponding normal method.
|
||||||
|
// https://docs.python.org/3/reference/datamodel.html#object.__iadd__ :
|
||||||
|
// "If a specific method is not defined, the augmented assignment falls back
|
||||||
|
// to the normal methods."
|
||||||
|
if (op >= MP_BINARY_OP_INPLACE_OR && op <= MP_BINARY_OP_INPLACE_POWER) {
|
||||||
|
op += MP_BINARY_OP_OR - MP_BINARY_OP_INPLACE_OR;
|
||||||
|
goto generic_binary_op;
|
||||||
|
}
|
||||||
|
|
||||||
#if MICROPY_PY_REVERSE_SPECIAL_METHODS
|
#if MICROPY_PY_REVERSE_SPECIAL_METHODS
|
||||||
if (op >= MP_BINARY_OP_OR && op <= MP_BINARY_OP_POWER) {
|
if (op >= MP_BINARY_OP_OR && op <= MP_BINARY_OP_POWER) {
|
||||||
mp_obj_t t = rhs;
|
mp_obj_t t = rhs;
|
||||||
|
|
|
@ -46,3 +46,8 @@ print("a" | B("b"))
|
||||||
print("a" + B("b"))
|
print("a" + B("b"))
|
||||||
print("a" * B("b"))
|
print("a" * B("b"))
|
||||||
print("a" / B("b"))
|
print("a" / B("b"))
|
||||||
|
|
||||||
|
x = "a"; x |= B("b"); print(x)
|
||||||
|
x = "a"; x += B("b"); print(x)
|
||||||
|
x = "a"; x *= B("b"); print(x)
|
||||||
|
x = "a"; x /= B("b"); print(x)
|
||||||
|
|
|
@ -11,6 +11,16 @@ a = [1, 2, 3]
|
||||||
c = a * 3
|
c = a * 3
|
||||||
print(a, c)
|
print(a, c)
|
||||||
|
|
||||||
|
# check inplace multiplication
|
||||||
|
a = [4, 5, 6]
|
||||||
|
a *= 3
|
||||||
|
print(a)
|
||||||
|
|
||||||
|
# check reverse inplace multiplication
|
||||||
|
a = 3
|
||||||
|
a *= [7, 8, 9]
|
||||||
|
print(a)
|
||||||
|
|
||||||
# unsupported type on RHS
|
# unsupported type on RHS
|
||||||
try:
|
try:
|
||||||
[] * None
|
[] * None
|
||||||
|
|
|
@ -10,3 +10,13 @@ for i in (-4, -2, 0, 2, 4):
|
||||||
a = '123'
|
a = '123'
|
||||||
c = a * 3
|
c = a * 3
|
||||||
print(a, c)
|
print(a, c)
|
||||||
|
|
||||||
|
# check inplace multiplication
|
||||||
|
a = '456'
|
||||||
|
a *= 3
|
||||||
|
print(a)
|
||||||
|
|
||||||
|
# check reverse inplace multiplication
|
||||||
|
a = 3
|
||||||
|
a *= '789'
|
||||||
|
print(a)
|
||||||
|
|
Loading…
Reference in New Issue