py/runtime: Add MP_BINARY_OP_CONTAINS as reverse of MP_BINARY_OP_IN.

Before this patch MP_BINARY_OP_IN had two meanings: coming from bytecode it
meant that the args needed to be swapped, but coming from within the
runtime meant that the args were already in the correct order.  This lead
to some confusion in the code and comments stating how args were reversed.
It also lead to 2 bugs: 1) containment for a subclass of a native type
didn't work; 2) the expression "{True} in True" would illegally succeed and
return True.  In both of these cases it was because the args to
MP_BINARY_OP_IN ended up being reversed twice.

To fix these things this patch introduces MP_BINARY_OP_CONTAINS which
corresponds exactly to the __contains__ special method, and this is the
operator that built-in types should implement.  MP_BINARY_OP_IN is now only
emitted by the compiler and is converted to MP_BINARY_OP_CONTAINS by
swapping the arguments.
This commit is contained in:
Damien George
2017-11-24 13:04:24 +11:00
parent 5b2f62aff3
commit 5e34a113ea
11 changed files with 34 additions and 36 deletions

View File

@@ -461,7 +461,7 @@ STATIC mp_obj_t set_binary_op(mp_binary_op_t op, mp_obj_t lhs, mp_obj_t rhs) {
#else
bool update = true;
#endif
if (op != MP_BINARY_OP_IN && !is_set_or_frozenset(rhs)) {
if (op != MP_BINARY_OP_CONTAINS && !is_set_or_frozenset(rhs)) {
// For all ops except containment the RHS must be a set/frozenset
return MP_OBJ_NULL;
}
@@ -507,7 +507,7 @@ STATIC mp_obj_t set_binary_op(mp_binary_op_t op, mp_obj_t lhs, mp_obj_t rhs) {
return set_issubset(lhs, rhs);
case MP_BINARY_OP_MORE_EQUAL:
return set_issuperset(lhs, rhs);
case MP_BINARY_OP_IN: {
case MP_BINARY_OP_CONTAINS: {
mp_obj_set_t *o = MP_OBJ_TO_PTR(lhs);
mp_obj_t elem = mp_set_lookup(&o->set, rhs, MP_MAP_LOOKUP);
return mp_obj_new_bool(elem != MP_OBJ_NULL);