From 4e39ff221abff9d1d7d7fc654da67a89a7543112 Mon Sep 17 00:00:00 2001 From: Jim Mussared Date: Thu, 20 Feb 2020 22:30:49 +1100 Subject: [PATCH] py/runtime: Fix bool unary op for subclasses of native types. Previously a subclass of a type that didn't implement unary_op, or didn't handle MP_UNARY_OP_BOOL, would raise TypeError on bool conversion. Fixes #5677. --- py/runtime.c | 6 ++++++ tests/basics/unary_op.py | 7 +++++++ 2 files changed, 13 insertions(+) diff --git a/py/runtime.c b/py/runtime.c index 19686c310b..27e5bc13eb 100644 --- a/py/runtime.c +++ b/py/runtime.c @@ -284,6 +284,12 @@ mp_obj_t mp_unary_op(mp_unary_op_t op, mp_obj_t arg) { return result; } } + if (op == MP_UNARY_OP_BOOL) { + // Type doesn't have unary_op (or didn't handle MP_UNARY_OP_BOOL), + // so is implicitly True as this code path is impossible to reach + // if arg==mp_const_none. + return mp_const_true; + } // 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 diff --git a/tests/basics/unary_op.py b/tests/basics/unary_op.py index bd78a20d0d..2239e2b206 100644 --- a/tests/basics/unary_op.py +++ b/tests/basics/unary_op.py @@ -23,5 +23,12 @@ print(not A()) # check user instances derived from builtins class B(int): pass print(not B()) +print(True if B() else False) class C(list): pass print(not C()) +print(True if C() else False) +# type doesn't define unary_op +class D(type): pass +d = D("foo", (), {}) +print(not d) +print(True if d else False)