py: Change MP_UNARY_OP_INT to MP_UNARY_OP_INT_MAYBE.

To be consistent with MP_UNARY_OP_INT_FLOAT and MP_UNARY_OP_INT_COMPLEX,
and allow int() to first check if a type supports __int__ before trying
other things (as per CPython).

Signed-off-by: Damien George <damien@micropython.org>
This commit is contained in:
Damien George 2023-05-25 10:57:08 +10:00
parent 3ae78e803b
commit 48ffd6596e
11 changed files with 50 additions and 39 deletions

View File

@ -582,7 +582,7 @@ STATIC mp_obj_t uctypes_struct_subscr(mp_obj_t self_in, mp_obj_t index_in, mp_ob
STATIC mp_obj_t uctypes_struct_unary_op(mp_unary_op_t op, mp_obj_t self_in) { STATIC mp_obj_t uctypes_struct_unary_op(mp_unary_op_t op, mp_obj_t self_in) {
mp_obj_uctypes_struct_t *self = MP_OBJ_TO_PTR(self_in); mp_obj_uctypes_struct_t *self = MP_OBJ_TO_PTR(self_in);
switch (op) { switch (op) {
case MP_UNARY_OP_INT: case MP_UNARY_OP_INT_MAYBE:
if (mp_obj_is_type(self->desc, &mp_type_tuple)) { if (mp_obj_is_type(self->desc, &mp_type_tuple)) {
mp_obj_tuple_t *t = MP_OBJ_TO_PTR(self->desc); mp_obj_tuple_t *t = MP_OBJ_TO_PTR(self->desc);
mp_int_t offset = MP_OBJ_SMALL_INT_VALUE(t->items[0]); mp_int_t offset = MP_OBJ_SMALL_INT_VALUE(t->items[0]);

View File

@ -298,18 +298,11 @@ mp_int_t mp_obj_get_int(mp_const_obj_t arg) {
// This function essentially performs implicit type conversion to int // This function essentially performs implicit type conversion to int
// Note that Python does NOT provide implicit type conversion from // Note that Python does NOT provide implicit type conversion from
// float to int in the core expression language, try some_list[1.0]. // float to int in the core expression language, try some_list[1.0].
if (arg == mp_const_false) { mp_int_t val;
return 0; if (!mp_obj_get_int_maybe(arg, &val)) {
} else if (arg == mp_const_true) { mp_raise_TypeError_int_conversion(arg);
return 1;
} else if (mp_obj_is_small_int(arg)) {
return MP_OBJ_SMALL_INT_VALUE(arg);
} else if (mp_obj_is_exact_type(arg, &mp_type_int)) {
return mp_obj_int_get_checked(arg);
} else {
mp_obj_t res = mp_unary_op(MP_UNARY_OP_INT, (mp_obj_t)arg);
return mp_obj_int_get_checked(res);
} }
return val;
} }
mp_int_t mp_obj_get_int_truncated(mp_const_obj_t arg) { mp_int_t mp_obj_get_int_truncated(mp_const_obj_t arg) {

View File

@ -48,10 +48,10 @@ STATIC mp_obj_t mp_obj_int_make_new(const mp_obj_type_t *type_in, size_t n_args,
case 0: case 0:
return MP_OBJ_NEW_SMALL_INT(0); return MP_OBJ_NEW_SMALL_INT(0);
case 1: case 1: {
if (mp_obj_is_int(args[0])) { mp_obj_t o = mp_unary_op(MP_UNARY_OP_INT_MAYBE, args[0]);
// already an int (small or long), just return it if (o != MP_OBJ_NULL) {
return args[0]; return o;
} else if (mp_obj_is_str_or_bytes(args[0])) { } else if (mp_obj_is_str_or_bytes(args[0])) {
// a string, parse it // a string, parse it
size_t l; size_t l;
@ -62,8 +62,9 @@ STATIC mp_obj_t mp_obj_int_make_new(const mp_obj_type_t *type_in, size_t n_args,
return mp_obj_new_int_from_float(mp_obj_float_get(args[0])); return mp_obj_new_int_from_float(mp_obj_float_get(args[0]));
#endif #endif
} else { } else {
return mp_unary_op(MP_UNARY_OP_INT, args[0]); mp_raise_TypeError_int_conversion(args[0]);
} }
}
case 2: case 2:
default: { default: {

View File

@ -119,6 +119,8 @@ mp_obj_t mp_obj_int_unary_op(mp_unary_op_t op, mp_obj_t o_in) {
self->val = -self->val; self->val = -self->val;
return MP_OBJ_FROM_PTR(self); return MP_OBJ_FROM_PTR(self);
} }
case MP_UNARY_OP_INT_MAYBE:
return o_in;
default: default:
return MP_OBJ_NULL; // op not supported return MP_OBJ_NULL; // op not supported
} }

View File

@ -165,6 +165,8 @@ mp_obj_t mp_obj_int_unary_op(mp_unary_op_t op, mp_obj_t o_in) {
mpz_abs_inpl(&self2->mpz, &self->mpz); mpz_abs_inpl(&self2->mpz, &self->mpz);
return MP_OBJ_FROM_PTR(self2); return MP_OBJ_FROM_PTR(self2);
} }
case MP_UNARY_OP_INT_MAYBE:
return o_in;
default: default:
return MP_OBJ_NULL; // op not supported return MP_OBJ_NULL; // op not supported
} }

View File

@ -374,7 +374,7 @@ const byte mp_unary_op_method_name[MP_UNARY_OP_NUM_RUNTIME] = {
[MP_UNARY_OP_BOOL] = MP_QSTR___bool__, [MP_UNARY_OP_BOOL] = MP_QSTR___bool__,
[MP_UNARY_OP_LEN] = MP_QSTR___len__, [MP_UNARY_OP_LEN] = MP_QSTR___len__,
[MP_UNARY_OP_HASH] = MP_QSTR___hash__, [MP_UNARY_OP_HASH] = MP_QSTR___hash__,
[MP_UNARY_OP_INT] = MP_QSTR___int__, [MP_UNARY_OP_INT_MAYBE] = MP_QSTR___int__,
#if MICROPY_PY_ALL_SPECIAL_METHODS #if MICROPY_PY_ALL_SPECIAL_METHODS
[MP_UNARY_OP_POSITIVE] = MP_QSTR___pos__, [MP_UNARY_OP_POSITIVE] = MP_QSTR___pos__,
[MP_UNARY_OP_NEGATIVE] = MP_QSTR___neg__, [MP_UNARY_OP_NEGATIVE] = MP_QSTR___neg__,
@ -432,7 +432,7 @@ STATIC mp_obj_t instance_unary_op(mp_unary_op_t op, mp_obj_t self_in) {
// __hash__ must return a small int // __hash__ must return a small int
val = MP_OBJ_NEW_SMALL_INT(mp_obj_get_int_truncated(val)); val = MP_OBJ_NEW_SMALL_INT(mp_obj_get_int_truncated(val));
break; break;
case MP_UNARY_OP_INT: case MP_UNARY_OP_INT_MAYBE:
// Must return int // Must return int
if (!mp_obj_is_int(val)) { if (!mp_obj_is_int(val)) {
mp_raise_TypeError(NULL); mp_raise_TypeError(NULL);

View File

@ -277,7 +277,7 @@ mp_obj_t mp_unary_op(mp_unary_op_t op, mp_obj_t arg) {
case MP_UNARY_OP_HASH: case MP_UNARY_OP_HASH:
return arg; return arg;
case MP_UNARY_OP_POSITIVE: case MP_UNARY_OP_POSITIVE:
case MP_UNARY_OP_INT: case MP_UNARY_OP_INT_MAYBE:
return arg; return arg;
case MP_UNARY_OP_NEGATIVE: case MP_UNARY_OP_NEGATIVE:
// check for overflow // check for overflow
@ -324,32 +324,23 @@ mp_obj_t mp_unary_op(mp_unary_op_t op, mp_obj_t arg) {
// if arg==mp_const_none. // if arg==mp_const_none.
return mp_const_true; return mp_const_true;
} }
#if MICROPY_PY_BUILTINS_FLOAT if (op == MP_UNARY_OP_INT_MAYBE
if (op == MP_UNARY_OP_FLOAT_MAYBE #if MICROPY_PY_BUILTINS_FLOAT
|| op == MP_UNARY_OP_FLOAT_MAYBE
#if MICROPY_PY_BUILTINS_COMPLEX #if MICROPY_PY_BUILTINS_COMPLEX
|| op == MP_UNARY_OP_COMPLEX_MAYBE || op == MP_UNARY_OP_COMPLEX_MAYBE
#endif #endif
#endif
) { ) {
// These operators may return MP_OBJ_NULL if they are not supported by the type.
return MP_OBJ_NULL; return MP_OBJ_NULL;
} }
#endif
// With MP_UNARY_OP_INT, mp_unary_op() becomes a fallback for mp_obj_get_int().
// In this case provide a more focused error message to not confuse, e.g. chr(1.0)
#if MICROPY_ERROR_REPORTING <= MICROPY_ERROR_REPORTING_TERSE #if MICROPY_ERROR_REPORTING <= MICROPY_ERROR_REPORTING_TERSE
if (op == MP_UNARY_OP_INT) { mp_raise_TypeError(MP_ERROR_TEXT("unsupported type for operator"));
mp_raise_TypeError(MP_ERROR_TEXT("can't convert to int"));
} else {
mp_raise_TypeError(MP_ERROR_TEXT("unsupported type for operator"));
}
#else #else
if (op == MP_UNARY_OP_INT) { mp_raise_msg_varg(&mp_type_TypeError,
mp_raise_msg_varg(&mp_type_TypeError, MP_ERROR_TEXT("unsupported type for %q: '%s'"),
MP_ERROR_TEXT("can't convert %s to int"), mp_obj_get_type_str(arg)); mp_unary_op_method_name[op], mp_obj_get_type_str(arg));
} else {
mp_raise_msg_varg(&mp_type_TypeError,
MP_ERROR_TEXT("unsupported type for %q: '%s'"),
mp_unary_op_method_name[op], mp_obj_get_type_str(arg));
}
#endif #endif
} }
} }
@ -1700,6 +1691,16 @@ NORETURN void mp_raise_StopIteration(mp_obj_t arg) {
} }
} }
NORETURN void mp_raise_TypeError_int_conversion(mp_const_obj_t arg) {
#if MICROPY_ERROR_REPORTING <= MICROPY_ERROR_REPORTING_TERSE
(void)arg;
mp_raise_TypeError(MP_ERROR_TEXT("can't convert to int"));
#else
mp_raise_msg_varg(&mp_type_TypeError,
MP_ERROR_TEXT("can't convert %s to int"), mp_obj_get_type_str(arg));
#endif
}
NORETURN void mp_raise_OSError(int errno_) { NORETURN void mp_raise_OSError(int errno_) {
mp_raise_type_arg(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(errno_)); mp_raise_type_arg(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(errno_));
} }

View File

@ -198,6 +198,7 @@ NORETURN void mp_raise_NotImplementedError(mp_rom_error_text_t msg);
NORETURN void mp_raise_type_arg(const mp_obj_type_t *exc_type, mp_obj_t arg); NORETURN void mp_raise_type_arg(const mp_obj_type_t *exc_type, mp_obj_t arg);
NORETURN void mp_raise_StopIteration(mp_obj_t arg); NORETURN void mp_raise_StopIteration(mp_obj_t arg);
NORETURN void mp_raise_TypeError_int_conversion(mp_const_obj_t arg);
NORETURN void mp_raise_OSError(int errno_); NORETURN void mp_raise_OSError(int errno_);
NORETURN void mp_raise_OSError_with_filename(int errno_, const char *filename); NORETURN void mp_raise_OSError_with_filename(int errno_, const char *filename);
NORETURN void mp_raise_recursion_depth(void); NORETURN void mp_raise_recursion_depth(void);

View File

@ -75,7 +75,7 @@ typedef enum {
MP_UNARY_OP_LEN, // __len__ MP_UNARY_OP_LEN, // __len__
MP_UNARY_OP_HASH, // __hash__; must return a small int MP_UNARY_OP_HASH, // __hash__; must return a small int
MP_UNARY_OP_ABS, // __abs__ MP_UNARY_OP_ABS, // __abs__
MP_UNARY_OP_INT, // __int__ MP_UNARY_OP_INT_MAYBE, // __int__; must return MP_OBJ_NULL, or an object satisfying mp_obj_is_int()
MP_UNARY_OP_FLOAT_MAYBE, // __float__ MP_UNARY_OP_FLOAT_MAYBE, // __float__
MP_UNARY_OP_COMPLEX_MAYBE, // __complex__ MP_UNARY_OP_COMPLEX_MAYBE, // __complex__
MP_UNARY_OP_SIZEOF, // for sys.getsizeof() MP_UNARY_OP_SIZEOF, // for sys.getsizeof()

View File

@ -10,6 +10,9 @@ print(y)
print('%#X' % (x - x)) # print prefix print('%#X' % (x - x)) # print prefix
print('{:#,}'.format(x)) # print with commas print('{:#,}'.format(x)) # print with commas
# construction
print(int(x))
# addition # addition
print(x + 1) print(x + 1)
print(x + y) print(x + y)

View File

@ -0,0 +1,8 @@
# Test class special methods, that use a bigint.
class A:
def __int__(self):
return 1 << 100
print(int(A()))