From 144ad010b2e15ab492374c29a958025b2dcdd642 Mon Sep 17 00:00:00 2001 From: 97littleleaf11 <97littleleaf11@gmail.com> Date: Fri, 16 Apr 2021 17:06:10 +0800 Subject: [PATCH 1/5] Add PyDictObject --- mypyc/ir/rtypes.py | 11 ++++++++++- mypyc/irbuild/ll_builder.py | 7 ++++--- 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/mypyc/ir/rtypes.py b/mypyc/ir/rtypes.py index 2490da6fe51f..86e6ab5c2bcf 100644 --- a/mypyc/ir/rtypes.py +++ b/mypyc/ir/rtypes.py @@ -801,5 +801,14 @@ def deserialize(cls, data: JsonDict, ctx: 'DeserMaps') -> 'RArray': PyListObject = RStruct( name='PyListObject', names=['ob_base', 'ob_item', 'allocated'], - types=[PyObject, pointer_rprimitive, c_pyssize_t_rprimitive] + types=[PyVarObject, pointer_rprimitive, c_pyssize_t_rprimitive] +) + +# ma_keys: PyDictKeysObject* +# ma_values: PyObject** +PyDictObject = RStruct( + name='PyDictObject', + names=['ob_base', 'ma_used', 'ma_version_tag', 'ma_keys', 'ma_values'], + types=[PyObject, c_pyssize_t_rprimitive, uint64_rprimitive, pointer_rprimitive, + pointer_rprimitive] ) diff --git a/mypyc/irbuild/ll_builder.py b/mypyc/irbuild/ll_builder.py index 0a0a9df050f3..24a768a743bb 100644 --- a/mypyc/irbuild/ll_builder.py +++ b/mypyc/irbuild/ll_builder.py @@ -32,7 +32,7 @@ is_list_rprimitive, is_tuple_rprimitive, is_dict_rprimitive, is_set_rprimitive, PySetObject, none_rprimitive, RTuple, is_bool_rprimitive, is_str_rprimitive, c_int_rprimitive, pointer_rprimitive, PyObject, PyListObject, bit_rprimitive, is_bit_rprimitive, - object_pointer_rprimitive, c_size_t_rprimitive + object_pointer_rprimitive, c_size_t_rprimitive, PyDictObject ) from mypyc.ir.func_ir import FuncDecl, FuncSignature from mypyc.ir.class_ir import ClassIR, all_concrete_classes @@ -51,7 +51,7 @@ list_tuple_op, new_tuple_op, new_tuple_with_length_op ) from mypyc.primitives.dict_ops import ( - dict_update_in_display_op, dict_new_op, dict_build_op, dict_size_op + dict_update_in_display_op, dict_new_op, dict_build_op ) from mypyc.primitives.generic_ops import ( py_getattr_op, py_call_op, py_call_with_kwargs_op, py_method_call_op, @@ -1098,7 +1098,8 @@ def builtin_len(self, val: Value, line: int, return self.int_op(short_int_rprimitive, size_value, offset, IntOp.LEFT_SHIFT, line) elif is_dict_rprimitive(typ): - size_value = self.call_c(dict_size_op, [val], line) + elem_address = self.add(GetElementPtr(val, PyDictObject, 'ma_used')) + size_value = self.add(LoadMem(c_pyssize_t_rprimitive, elem_address)) if use_pyssize_t: return size_value offset = Integer(1, c_pyssize_t_rprimitive, line) From d6137302e5721aba6f3caf6deb8bb6de6aa808ee Mon Sep 17 00:00:00 2001 From: 97littleleaf11 <97littleleaf11@gmail.com> Date: Fri, 16 Apr 2021 17:55:05 +0800 Subject: [PATCH 2/5] Add tests --- mypyc/irbuild/ll_builder.py | 5 +- mypyc/test-data/irbuild-dict.test | 224 +++++++++++++++++------------- mypyc/test-data/run-dicts.test | 23 +++ 3 files changed, 154 insertions(+), 98 deletions(-) diff --git a/mypyc/irbuild/ll_builder.py b/mypyc/irbuild/ll_builder.py index 24a768a743bb..9011c539fa7d 100644 --- a/mypyc/irbuild/ll_builder.py +++ b/mypyc/irbuild/ll_builder.py @@ -32,7 +32,7 @@ is_list_rprimitive, is_tuple_rprimitive, is_dict_rprimitive, is_set_rprimitive, PySetObject, none_rprimitive, RTuple, is_bool_rprimitive, is_str_rprimitive, c_int_rprimitive, pointer_rprimitive, PyObject, PyListObject, bit_rprimitive, is_bit_rprimitive, - object_pointer_rprimitive, c_size_t_rprimitive, PyDictObject + object_pointer_rprimitive, c_size_t_rprimitive, PyDictObject, dict_rprimitive ) from mypyc.ir.func_ir import FuncDecl, FuncSignature from mypyc.ir.class_ir import ClassIR, all_concrete_classes @@ -960,7 +960,8 @@ def add_bool_branch(self, value: Value, true: BasicBlock, false: BasicBlock) -> return elif is_same_type(value.type, str_rprimitive): value = self.call_c(str_check_if_true, [value], value.line) - elif is_same_type(value.type, list_rprimitive): + elif (is_same_type(value.type, list_rprimitive) + or is_same_type(value.type, dict_rprimitive)): length = self.builtin_len(value, value.line) zero = Integer(0) value = self.binary_op(length, zero, '!=', value.line) diff --git a/mypyc/test-data/irbuild-dict.test b/mypyc/test-data/irbuild-dict.test index da08ed79d5bd..d58d538e2af0 100644 --- a/mypyc/test-data/irbuild-dict.test +++ b/mypyc/test-data/irbuild-dict.test @@ -138,42 +138,44 @@ def increment(d: Dict[str, int]) -> Dict[str, int]: def increment(d): d :: dict r0 :: short_int - r1 :: native_int - r2 :: short_int - r3 :: object - r4 :: tuple[bool, int, object] - r5 :: int - r6 :: bool - r7 :: object - r8, k :: str - r9, r10, r11 :: object - r12 :: int32 - r13, r14, r15 :: bit + r1 :: ptr + r2 :: native_int + r3 :: short_int + r4 :: object + r5 :: tuple[bool, int, object] + r6 :: int + r7 :: bool + r8 :: object + r9, k :: str + r10, r11, r12 :: object + r13 :: int32 + r14, r15, r16 :: bit L0: r0 = 0 - r1 = PyDict_Size(d) - r2 = r1 << 1 - r3 = CPyDict_GetKeysIter(d) + r1 = get_element_ptr d ma_used :: PyDictObject + r2 = load_mem r1 :: native_int* + r3 = r2 << 1 + r4 = CPyDict_GetKeysIter(d) L1: - r4 = CPyDict_NextKey(r3, r0) - r5 = r4[1] - r0 = r5 - r6 = r4[0] - if r6 goto L2 else goto L4 :: bool + r5 = CPyDict_NextKey(r4, r0) + r6 = r5[1] + r0 = r6 + r7 = r5[0] + if r7 goto L2 else goto L4 :: bool L2: - r7 = r4[2] - r8 = cast(str, r7) - k = r8 - r9 = CPyDict_GetItem(d, k) - r10 = box(short_int, 2) - r11 = PyNumber_InPlaceAdd(r9, r10) - r12 = CPyDict_SetItem(d, k, r11) - r13 = r12 >= 0 :: signed + r8 = r5[2] + r9 = cast(str, r8) + k = r9 + r10 = CPyDict_GetItem(d, k) + r11 = box(short_int, 2) + r12 = PyNumber_InPlaceAdd(r10, r11) + r13 = CPyDict_SetItem(d, k, r12) + r14 = r13 >= 0 :: signed L3: - r14 = CPyDict_CheckSize(d, r2) + r15 = CPyDict_CheckSize(d, r3) goto L1 L4: - r15 = CPy_NoErrOccured() + r16 = CPy_NoErrOccured() L5: return d @@ -216,89 +218,93 @@ def print_dict_methods(d1: Dict[int, int], d2: Dict[int, int]) -> None: def print_dict_methods(d1, d2): d1, d2 :: dict r0 :: short_int - r1 :: native_int - r2 :: short_int - r3 :: object - r4 :: tuple[bool, int, object] - r5 :: int - r6 :: bool - r7 :: object - r8, v :: int - r9 :: object - r10 :: int32 - r11 :: bit - r12 :: bool - r13, r14 :: bit - r15 :: short_int - r16 :: native_int - r17 :: short_int - r18 :: object - r19 :: tuple[bool, int, object, object] - r20 :: int - r21 :: bool - r22, r23 :: object - r24, r25, k :: int - r26, r27, r28, r29, r30 :: object - r31 :: int32 - r32, r33, r34 :: bit + r1 :: ptr + r2 :: native_int + r3 :: short_int + r4 :: object + r5 :: tuple[bool, int, object] + r6 :: int + r7 :: bool + r8 :: object + r9, v :: int + r10 :: object + r11 :: int32 + r12 :: bit + r13 :: bool + r14, r15 :: bit + r16 :: short_int + r17 :: ptr + r18 :: native_int + r19 :: short_int + r20 :: object + r21 :: tuple[bool, int, object, object] + r22 :: int + r23 :: bool + r24, r25 :: object + r26, r27, k :: int + r28, r29, r30, r31, r32 :: object + r33 :: int32 + r34, r35, r36 :: bit L0: r0 = 0 - r1 = PyDict_Size(d1) - r2 = r1 << 1 - r3 = CPyDict_GetValuesIter(d1) + r1 = get_element_ptr d1 ma_used :: PyDictObject + r2 = load_mem r1 :: native_int* + r3 = r2 << 1 + r4 = CPyDict_GetValuesIter(d1) L1: - r4 = CPyDict_NextValue(r3, r0) - r5 = r4[1] - r0 = r5 - r6 = r4[0] - if r6 goto L2 else goto L6 :: bool + r5 = CPyDict_NextValue(r4, r0) + r6 = r5[1] + r0 = r6 + r7 = r5[0] + if r7 goto L2 else goto L6 :: bool L2: - r7 = r4[2] - r8 = unbox(int, r7) - v = r8 - r9 = box(int, v) - r10 = PyDict_Contains(d2, r9) - r11 = r10 >= 0 :: signed - r12 = truncate r10: int32 to builtins.bool - if r12 goto L3 else goto L4 :: bool + r8 = r5[2] + r9 = unbox(int, r8) + v = r9 + r10 = box(int, v) + r11 = PyDict_Contains(d2, r10) + r12 = r11 >= 0 :: signed + r13 = truncate r11: int32 to builtins.bool + if r13 goto L3 else goto L4 :: bool L3: return 1 L4: L5: - r13 = CPyDict_CheckSize(d1, r2) + r14 = CPyDict_CheckSize(d1, r3) goto L1 L6: - r14 = CPy_NoErrOccured() + r15 = CPy_NoErrOccured() L7: - r15 = 0 - r16 = PyDict_Size(d2) - r17 = r16 << 1 - r18 = CPyDict_GetItemsIter(d2) + r16 = 0 + r17 = get_element_ptr d2 ma_used :: PyDictObject + r18 = load_mem r17 :: native_int* + r19 = r18 << 1 + r20 = CPyDict_GetItemsIter(d2) L8: - r19 = CPyDict_NextItem(r18, r15) - r20 = r19[1] - r15 = r20 - r21 = r19[0] - if r21 goto L9 else goto L11 :: bool + r21 = CPyDict_NextItem(r20, r16) + r22 = r21[1] + r16 = r22 + r23 = r21[0] + if r23 goto L9 else goto L11 :: bool L9: - r22 = r19[2] - r23 = r19[3] - r24 = unbox(int, r22) - r25 = unbox(int, r23) - k = r24 - v = r25 - r26 = box(int, k) - r27 = CPyDict_GetItem(d2, r26) - r28 = box(int, v) - r29 = PyNumber_InPlaceAdd(r27, r28) - r30 = box(int, k) - r31 = CPyDict_SetItem(d2, r30, r29) - r32 = r31 >= 0 :: signed + r24 = r21[2] + r25 = r21[3] + r26 = unbox(int, r24) + r27 = unbox(int, r25) + k = r26 + v = r27 + r28 = box(int, k) + r29 = CPyDict_GetItem(d2, r28) + r30 = box(int, v) + r31 = PyNumber_InPlaceAdd(r29, r30) + r32 = box(int, k) + r33 = CPyDict_SetItem(d2, r32, r31) + r34 = r33 >= 0 :: signed L10: - r33 = CPyDict_CheckSize(d2, r17) + r35 = CPyDict_CheckSize(d2, r19) goto L8 L11: - r34 = CPy_NoErrOccured() + r36 = CPy_NoErrOccured() L12: return 1 @@ -350,3 +356,29 @@ L0: r1 = 'b' r2 = CPyDict_SetDefault(d, r0, r1) return r2 + +[case testDictToBool] +def is_true(x: dict) -> bool: + if x: + return True + else: + return False +[out] +def is_true(x): + x :: dict + r0 :: ptr + r1 :: native_int + r2 :: short_int + r3 :: bit +L0: + r0 = get_element_ptr x ma_used :: PyDictObject + r1 = load_mem r0 :: native_int* + r2 = r1 << 1 + r3 = r2 != 0 + if r3 goto L1 else goto L2 :: bool +L1: + return 1 +L2: + return 0 +L3: + unreachable diff --git a/mypyc/test-data/run-dicts.test b/mypyc/test-data/run-dicts.test index 89188e09b1f1..49deb0854483 100644 --- a/mypyc/test-data/run-dicts.test +++ b/mypyc/test-data/run-dicts.test @@ -253,3 +253,26 @@ def test_dict_subclass_setdefault() -> None: assert d.setdefault('a') == 1 assert d.setdefault('e') == None assert d.setdefault('e', 100) == 110 + +[case testDictToBool] +from typing import Dict, List + +def is_true(x: dict) -> bool: + if x: + return True + else: + return False + +def is_false(x: dict) -> bool: + if not x: + return True + else: + return False + +def test_dict_to_bool() -> None: + assert is_false({}) + assert not is_true({}) + tmp_list: List[Dict] = [{2: bool}, {'a': 'b'}] + for x in tmp_list: + assert is_true(x) + assert not is_false(x) From addd4c0795805fa033dfa8ab6ba955ed7f15e84a Mon Sep 17 00:00:00 2001 From: 97littleleaf11 <97littleleaf11@gmail.com> Date: Fri, 16 Apr 2021 20:51:27 +0800 Subject: [PATCH 3/5] Fix IR test --- mypyc/test-data/irbuild-set.test | 58 +++++----- mypyc/test-data/irbuild-statements.test | 134 ++++++++++++------------ mypyc/test-data/refcount.test | 66 ++++++------ 3 files changed, 133 insertions(+), 125 deletions(-) diff --git a/mypyc/test-data/irbuild-set.test b/mypyc/test-data/irbuild-set.test index aab70ecd0e76..ca03dc429fd9 100644 --- a/mypyc/test-data/irbuild-set.test +++ b/mypyc/test-data/irbuild-set.test @@ -170,17 +170,18 @@ def test3(): r6, tmp_dict :: dict r7 :: set r8 :: short_int - r9 :: native_int - r10 :: short_int - r11 :: object - r12 :: tuple[bool, int, object] - r13 :: int - r14 :: bool - r15 :: object - r16, x, r17 :: int - r18 :: object - r19 :: int32 - r20, r21, r22 :: bit + r9 :: ptr + r10 :: native_int + r11 :: short_int + r12 :: object + r13 :: tuple[bool, int, object] + r14 :: int + r15 :: bool + r16 :: object + r17, x, r18 :: int + r19 :: object + r20 :: int32 + r21, r22, r23 :: bit c :: set L0: r0 = '1' @@ -193,28 +194,29 @@ L0: tmp_dict = r6 r7 = PySet_New(0) r8 = 0 - r9 = PyDict_Size(tmp_dict) - r10 = r9 << 1 - r11 = CPyDict_GetKeysIter(tmp_dict) + r9 = get_element_ptr tmp_dict ma_used :: PyDictObject + r10 = load_mem r9 :: native_int* + r11 = r10 << 1 + r12 = CPyDict_GetKeysIter(tmp_dict) L1: - r12 = CPyDict_NextKey(r11, r8) - r13 = r12[1] - r8 = r13 - r14 = r12[0] - if r14 goto L2 else goto L4 :: bool + r13 = CPyDict_NextKey(r12, r8) + r14 = r13[1] + r8 = r14 + r15 = r13[0] + if r15 goto L2 else goto L4 :: bool L2: - r15 = r12[2] - r16 = unbox(int, r15) - x = r16 - r17 = f(x) - r18 = box(int, r17) - r19 = PySet_Add(r7, r18) - r20 = r19 >= 0 :: signed + r16 = r13[2] + r17 = unbox(int, r16) + x = r17 + r18 = f(x) + r19 = box(int, r18) + r20 = PySet_Add(r7, r19) + r21 = r20 >= 0 :: signed L3: - r21 = CPyDict_CheckSize(tmp_dict, r10) + r22 = CPyDict_CheckSize(tmp_dict, r11) goto L1 L4: - r22 = CPy_NoErrOccured() + r23 = CPy_NoErrOccured() L5: c = r7 return 1 diff --git a/mypyc/test-data/irbuild-statements.test b/mypyc/test-data/irbuild-statements.test index e5e47c05877a..bb7b72d7d32d 100644 --- a/mypyc/test-data/irbuild-statements.test +++ b/mypyc/test-data/irbuild-statements.test @@ -339,40 +339,42 @@ def f(d: Dict[int, int]) -> None: def f(d): d :: dict r0 :: short_int - r1 :: native_int - r2 :: short_int - r3 :: object - r4 :: tuple[bool, int, object] - r5 :: int - r6 :: bool - r7 :: object - r8, key :: int - r9, r10 :: object - r11 :: int - r12, r13 :: bit + r1 :: ptr + r2 :: native_int + r3 :: short_int + r4 :: object + r5 :: tuple[bool, int, object] + r6 :: int + r7 :: bool + r8 :: object + r9, key :: int + r10, r11 :: object + r12 :: int + r13, r14 :: bit L0: r0 = 0 - r1 = PyDict_Size(d) - r2 = r1 << 1 - r3 = CPyDict_GetKeysIter(d) + r1 = get_element_ptr d ma_used :: PyDictObject + r2 = load_mem r1 :: native_int* + r3 = r2 << 1 + r4 = CPyDict_GetKeysIter(d) L1: - r4 = CPyDict_NextKey(r3, r0) - r5 = r4[1] - r0 = r5 - r6 = r4[0] - if r6 goto L2 else goto L4 :: bool + r5 = CPyDict_NextKey(r4, r0) + r6 = r5[1] + r0 = r6 + r7 = r5[0] + if r7 goto L2 else goto L4 :: bool L2: - r7 = r4[2] - r8 = unbox(int, r7) - key = r8 - r9 = box(int, key) - r10 = CPyDict_GetItem(d, r9) - r11 = unbox(int, r10) + r8 = r5[2] + r9 = unbox(int, r8) + key = r9 + r10 = box(int, key) + r11 = CPyDict_GetItem(d, r10) + r12 = unbox(int, r11) L3: - r12 = CPyDict_CheckSize(d, r2) + r13 = CPyDict_CheckSize(d, r3) goto L1 L4: - r13 = CPy_NoErrOccured() + r14 = CPy_NoErrOccured() L5: return 1 @@ -391,55 +393,57 @@ def sum_over_even_values(d): d :: dict s :: int r0 :: short_int - r1 :: native_int - r2 :: short_int - r3 :: object - r4 :: tuple[bool, int, object] - r5 :: int - r6 :: bool - r7 :: object - r8, key :: int - r9, r10 :: object - r11, r12 :: int - r13 :: bit - r14, r15 :: object - r16, r17 :: int - r18, r19 :: bit + r1 :: ptr + r2 :: native_int + r3 :: short_int + r4 :: object + r5 :: tuple[bool, int, object] + r6 :: int + r7 :: bool + r8 :: object + r9, key :: int + r10, r11 :: object + r12, r13 :: int + r14 :: bit + r15, r16 :: object + r17, r18 :: int + r19, r20 :: bit L0: s = 0 r0 = 0 - r1 = PyDict_Size(d) - r2 = r1 << 1 - r3 = CPyDict_GetKeysIter(d) + r1 = get_element_ptr d ma_used :: PyDictObject + r2 = load_mem r1 :: native_int* + r3 = r2 << 1 + r4 = CPyDict_GetKeysIter(d) L1: - r4 = CPyDict_NextKey(r3, r0) - r5 = r4[1] - r0 = r5 - r6 = r4[0] - if r6 goto L2 else goto L6 :: bool + r5 = CPyDict_NextKey(r4, r0) + r6 = r5[1] + r0 = r6 + r7 = r5[0] + if r7 goto L2 else goto L6 :: bool L2: - r7 = r4[2] - r8 = unbox(int, r7) - key = r8 - r9 = box(int, key) - r10 = CPyDict_GetItem(d, r9) - r11 = unbox(int, r10) - r12 = CPyTagged_Remainder(r11, 4) - r13 = r12 != 0 - if r13 goto L3 else goto L4 :: bool + r8 = r5[2] + r9 = unbox(int, r8) + key = r9 + r10 = box(int, key) + r11 = CPyDict_GetItem(d, r10) + r12 = unbox(int, r11) + r13 = CPyTagged_Remainder(r12, 4) + r14 = r13 != 0 + if r14 goto L3 else goto L4 :: bool L3: goto L5 L4: - r14 = box(int, key) - r15 = CPyDict_GetItem(d, r14) - r16 = unbox(int, r15) - r17 = CPyTagged_Add(s, r16) - s = r17 + r15 = box(int, key) + r16 = CPyDict_GetItem(d, r15) + r17 = unbox(int, r16) + r18 = CPyTagged_Add(s, r17) + s = r18 L5: - r18 = CPyDict_CheckSize(d, r2) + r19 = CPyDict_CheckSize(d, r3) goto L1 L6: - r19 = CPy_NoErrOccured() + r20 = CPy_NoErrOccured() L7: return s diff --git a/mypyc/test-data/refcount.test b/mypyc/test-data/refcount.test index f487600ad877..90475b48207f 100644 --- a/mypyc/test-data/refcount.test +++ b/mypyc/test-data/refcount.test @@ -721,50 +721,52 @@ def f(d: Dict[int, int]) -> None: def f(d): d :: dict r0 :: short_int - r1 :: native_int - r2 :: short_int - r3 :: object - r4 :: tuple[bool, int, object] - r5 :: int - r6 :: bool - r7 :: object - r8, key :: int - r9, r10 :: object - r11 :: int - r12, r13 :: bit + r1 :: ptr + r2 :: native_int + r3 :: short_int + r4 :: object + r5 :: tuple[bool, int, object] + r6 :: int + r7 :: bool + r8 :: object + r9, key :: int + r10, r11 :: object + r12 :: int + r13, r14 :: bit L0: r0 = 0 - r1 = PyDict_Size(d) - r2 = r1 << 1 - r3 = CPyDict_GetKeysIter(d) + r1 = get_element_ptr d ma_used :: PyDictObject + r2 = load_mem r1 :: native_int* + r3 = r2 << 1 + r4 = CPyDict_GetKeysIter(d) L1: - r4 = CPyDict_NextKey(r3, r0) - r5 = r4[1] - r0 = r5 - r6 = r4[0] - if r6 goto L2 else goto L6 :: bool + r5 = CPyDict_NextKey(r4, r0) + r6 = r5[1] + r0 = r6 + r7 = r5[0] + if r7 goto L2 else goto L6 :: bool L2: - r7 = r4[2] - dec_ref r4 - r8 = unbox(int, r7) - dec_ref r7 - key = r8 - r9 = box(int, key) - r10 = CPyDict_GetItem(d, r9) - dec_ref r9 - r11 = unbox(int, r10) + r8 = r5[2] + dec_ref r5 + r9 = unbox(int, r8) + dec_ref r8 + key = r9 + r10 = box(int, key) + r11 = CPyDict_GetItem(d, r10) dec_ref r10 - dec_ref r11 :: int + r12 = unbox(int, r11) + dec_ref r11 + dec_ref r12 :: int L3: - r12 = CPyDict_CheckSize(d, r2) + r13 = CPyDict_CheckSize(d, r3) goto L1 L4: - r13 = CPy_NoErrOccured() + r14 = CPy_NoErrOccured() L5: return 1 L6: - dec_ref r3 dec_ref r4 + dec_ref r5 goto L4 [case testBorrowRefs] From fe04d8bca1d98271721b5c92236b3d05ab6095bf Mon Sep 17 00:00:00 2001 From: 97littleleaf11 <97littleleaf11@gmail.com> Date: Thu, 22 Apr 2021 21:12:53 +0800 Subject: [PATCH 4/5] Revert changes --- mypyc/ir/rtypes.py | 11 +- mypyc/irbuild/ll_builder.py | 10 +- mypyc/test-data/irbuild-dict.test | 224 ++++++++++-------------- mypyc/test-data/irbuild-set.test | 58 +++--- mypyc/test-data/irbuild-statements.test | 134 +++++++------- mypyc/test-data/refcount.test | 66 ++++--- mypyc/test-data/run-dicts.test | 23 --- 7 files changed, 226 insertions(+), 300 deletions(-) diff --git a/mypyc/ir/rtypes.py b/mypyc/ir/rtypes.py index 86e6ab5c2bcf..2490da6fe51f 100644 --- a/mypyc/ir/rtypes.py +++ b/mypyc/ir/rtypes.py @@ -801,14 +801,5 @@ def deserialize(cls, data: JsonDict, ctx: 'DeserMaps') -> 'RArray': PyListObject = RStruct( name='PyListObject', names=['ob_base', 'ob_item', 'allocated'], - types=[PyVarObject, pointer_rprimitive, c_pyssize_t_rprimitive] -) - -# ma_keys: PyDictKeysObject* -# ma_values: PyObject** -PyDictObject = RStruct( - name='PyDictObject', - names=['ob_base', 'ma_used', 'ma_version_tag', 'ma_keys', 'ma_values'], - types=[PyObject, c_pyssize_t_rprimitive, uint64_rprimitive, pointer_rprimitive, - pointer_rprimitive] + types=[PyObject, pointer_rprimitive, c_pyssize_t_rprimitive] ) diff --git a/mypyc/irbuild/ll_builder.py b/mypyc/irbuild/ll_builder.py index 9011c539fa7d..0a0a9df050f3 100644 --- a/mypyc/irbuild/ll_builder.py +++ b/mypyc/irbuild/ll_builder.py @@ -32,7 +32,7 @@ is_list_rprimitive, is_tuple_rprimitive, is_dict_rprimitive, is_set_rprimitive, PySetObject, none_rprimitive, RTuple, is_bool_rprimitive, is_str_rprimitive, c_int_rprimitive, pointer_rprimitive, PyObject, PyListObject, bit_rprimitive, is_bit_rprimitive, - object_pointer_rprimitive, c_size_t_rprimitive, PyDictObject, dict_rprimitive + object_pointer_rprimitive, c_size_t_rprimitive ) from mypyc.ir.func_ir import FuncDecl, FuncSignature from mypyc.ir.class_ir import ClassIR, all_concrete_classes @@ -51,7 +51,7 @@ list_tuple_op, new_tuple_op, new_tuple_with_length_op ) from mypyc.primitives.dict_ops import ( - dict_update_in_display_op, dict_new_op, dict_build_op + dict_update_in_display_op, dict_new_op, dict_build_op, dict_size_op ) from mypyc.primitives.generic_ops import ( py_getattr_op, py_call_op, py_call_with_kwargs_op, py_method_call_op, @@ -960,8 +960,7 @@ def add_bool_branch(self, value: Value, true: BasicBlock, false: BasicBlock) -> return elif is_same_type(value.type, str_rprimitive): value = self.call_c(str_check_if_true, [value], value.line) - elif (is_same_type(value.type, list_rprimitive) - or is_same_type(value.type, dict_rprimitive)): + elif is_same_type(value.type, list_rprimitive): length = self.builtin_len(value, value.line) zero = Integer(0) value = self.binary_op(length, zero, '!=', value.line) @@ -1099,8 +1098,7 @@ def builtin_len(self, val: Value, line: int, return self.int_op(short_int_rprimitive, size_value, offset, IntOp.LEFT_SHIFT, line) elif is_dict_rprimitive(typ): - elem_address = self.add(GetElementPtr(val, PyDictObject, 'ma_used')) - size_value = self.add(LoadMem(c_pyssize_t_rprimitive, elem_address)) + size_value = self.call_c(dict_size_op, [val], line) if use_pyssize_t: return size_value offset = Integer(1, c_pyssize_t_rprimitive, line) diff --git a/mypyc/test-data/irbuild-dict.test b/mypyc/test-data/irbuild-dict.test index d58d538e2af0..da08ed79d5bd 100644 --- a/mypyc/test-data/irbuild-dict.test +++ b/mypyc/test-data/irbuild-dict.test @@ -138,44 +138,42 @@ def increment(d: Dict[str, int]) -> Dict[str, int]: def increment(d): d :: dict r0 :: short_int - r1 :: ptr - r2 :: native_int - r3 :: short_int - r4 :: object - r5 :: tuple[bool, int, object] - r6 :: int - r7 :: bool - r8 :: object - r9, k :: str - r10, r11, r12 :: object - r13 :: int32 - r14, r15, r16 :: bit + r1 :: native_int + r2 :: short_int + r3 :: object + r4 :: tuple[bool, int, object] + r5 :: int + r6 :: bool + r7 :: object + r8, k :: str + r9, r10, r11 :: object + r12 :: int32 + r13, r14, r15 :: bit L0: r0 = 0 - r1 = get_element_ptr d ma_used :: PyDictObject - r2 = load_mem r1 :: native_int* - r3 = r2 << 1 - r4 = CPyDict_GetKeysIter(d) + r1 = PyDict_Size(d) + r2 = r1 << 1 + r3 = CPyDict_GetKeysIter(d) L1: - r5 = CPyDict_NextKey(r4, r0) - r6 = r5[1] - r0 = r6 - r7 = r5[0] - if r7 goto L2 else goto L4 :: bool + r4 = CPyDict_NextKey(r3, r0) + r5 = r4[1] + r0 = r5 + r6 = r4[0] + if r6 goto L2 else goto L4 :: bool L2: - r8 = r5[2] - r9 = cast(str, r8) - k = r9 - r10 = CPyDict_GetItem(d, k) - r11 = box(short_int, 2) - r12 = PyNumber_InPlaceAdd(r10, r11) - r13 = CPyDict_SetItem(d, k, r12) - r14 = r13 >= 0 :: signed + r7 = r4[2] + r8 = cast(str, r7) + k = r8 + r9 = CPyDict_GetItem(d, k) + r10 = box(short_int, 2) + r11 = PyNumber_InPlaceAdd(r9, r10) + r12 = CPyDict_SetItem(d, k, r11) + r13 = r12 >= 0 :: signed L3: - r15 = CPyDict_CheckSize(d, r3) + r14 = CPyDict_CheckSize(d, r2) goto L1 L4: - r16 = CPy_NoErrOccured() + r15 = CPy_NoErrOccured() L5: return d @@ -218,93 +216,89 @@ def print_dict_methods(d1: Dict[int, int], d2: Dict[int, int]) -> None: def print_dict_methods(d1, d2): d1, d2 :: dict r0 :: short_int - r1 :: ptr - r2 :: native_int - r3 :: short_int - r4 :: object - r5 :: tuple[bool, int, object] - r6 :: int - r7 :: bool - r8 :: object - r9, v :: int - r10 :: object - r11 :: int32 - r12 :: bit - r13 :: bool - r14, r15 :: bit - r16 :: short_int - r17 :: ptr - r18 :: native_int - r19 :: short_int - r20 :: object - r21 :: tuple[bool, int, object, object] - r22 :: int - r23 :: bool - r24, r25 :: object - r26, r27, k :: int - r28, r29, r30, r31, r32 :: object - r33 :: int32 - r34, r35, r36 :: bit + r1 :: native_int + r2 :: short_int + r3 :: object + r4 :: tuple[bool, int, object] + r5 :: int + r6 :: bool + r7 :: object + r8, v :: int + r9 :: object + r10 :: int32 + r11 :: bit + r12 :: bool + r13, r14 :: bit + r15 :: short_int + r16 :: native_int + r17 :: short_int + r18 :: object + r19 :: tuple[bool, int, object, object] + r20 :: int + r21 :: bool + r22, r23 :: object + r24, r25, k :: int + r26, r27, r28, r29, r30 :: object + r31 :: int32 + r32, r33, r34 :: bit L0: r0 = 0 - r1 = get_element_ptr d1 ma_used :: PyDictObject - r2 = load_mem r1 :: native_int* - r3 = r2 << 1 - r4 = CPyDict_GetValuesIter(d1) + r1 = PyDict_Size(d1) + r2 = r1 << 1 + r3 = CPyDict_GetValuesIter(d1) L1: - r5 = CPyDict_NextValue(r4, r0) - r6 = r5[1] - r0 = r6 - r7 = r5[0] - if r7 goto L2 else goto L6 :: bool + r4 = CPyDict_NextValue(r3, r0) + r5 = r4[1] + r0 = r5 + r6 = r4[0] + if r6 goto L2 else goto L6 :: bool L2: - r8 = r5[2] - r9 = unbox(int, r8) - v = r9 - r10 = box(int, v) - r11 = PyDict_Contains(d2, r10) - r12 = r11 >= 0 :: signed - r13 = truncate r11: int32 to builtins.bool - if r13 goto L3 else goto L4 :: bool + r7 = r4[2] + r8 = unbox(int, r7) + v = r8 + r9 = box(int, v) + r10 = PyDict_Contains(d2, r9) + r11 = r10 >= 0 :: signed + r12 = truncate r10: int32 to builtins.bool + if r12 goto L3 else goto L4 :: bool L3: return 1 L4: L5: - r14 = CPyDict_CheckSize(d1, r3) + r13 = CPyDict_CheckSize(d1, r2) goto L1 L6: - r15 = CPy_NoErrOccured() + r14 = CPy_NoErrOccured() L7: - r16 = 0 - r17 = get_element_ptr d2 ma_used :: PyDictObject - r18 = load_mem r17 :: native_int* - r19 = r18 << 1 - r20 = CPyDict_GetItemsIter(d2) + r15 = 0 + r16 = PyDict_Size(d2) + r17 = r16 << 1 + r18 = CPyDict_GetItemsIter(d2) L8: - r21 = CPyDict_NextItem(r20, r16) - r22 = r21[1] - r16 = r22 - r23 = r21[0] - if r23 goto L9 else goto L11 :: bool + r19 = CPyDict_NextItem(r18, r15) + r20 = r19[1] + r15 = r20 + r21 = r19[0] + if r21 goto L9 else goto L11 :: bool L9: - r24 = r21[2] - r25 = r21[3] - r26 = unbox(int, r24) - r27 = unbox(int, r25) - k = r26 - v = r27 - r28 = box(int, k) - r29 = CPyDict_GetItem(d2, r28) - r30 = box(int, v) - r31 = PyNumber_InPlaceAdd(r29, r30) - r32 = box(int, k) - r33 = CPyDict_SetItem(d2, r32, r31) - r34 = r33 >= 0 :: signed + r22 = r19[2] + r23 = r19[3] + r24 = unbox(int, r22) + r25 = unbox(int, r23) + k = r24 + v = r25 + r26 = box(int, k) + r27 = CPyDict_GetItem(d2, r26) + r28 = box(int, v) + r29 = PyNumber_InPlaceAdd(r27, r28) + r30 = box(int, k) + r31 = CPyDict_SetItem(d2, r30, r29) + r32 = r31 >= 0 :: signed L10: - r35 = CPyDict_CheckSize(d2, r19) + r33 = CPyDict_CheckSize(d2, r17) goto L8 L11: - r36 = CPy_NoErrOccured() + r34 = CPy_NoErrOccured() L12: return 1 @@ -356,29 +350,3 @@ L0: r1 = 'b' r2 = CPyDict_SetDefault(d, r0, r1) return r2 - -[case testDictToBool] -def is_true(x: dict) -> bool: - if x: - return True - else: - return False -[out] -def is_true(x): - x :: dict - r0 :: ptr - r1 :: native_int - r2 :: short_int - r3 :: bit -L0: - r0 = get_element_ptr x ma_used :: PyDictObject - r1 = load_mem r0 :: native_int* - r2 = r1 << 1 - r3 = r2 != 0 - if r3 goto L1 else goto L2 :: bool -L1: - return 1 -L2: - return 0 -L3: - unreachable diff --git a/mypyc/test-data/irbuild-set.test b/mypyc/test-data/irbuild-set.test index ca03dc429fd9..aab70ecd0e76 100644 --- a/mypyc/test-data/irbuild-set.test +++ b/mypyc/test-data/irbuild-set.test @@ -170,18 +170,17 @@ def test3(): r6, tmp_dict :: dict r7 :: set r8 :: short_int - r9 :: ptr - r10 :: native_int - r11 :: short_int - r12 :: object - r13 :: tuple[bool, int, object] - r14 :: int - r15 :: bool - r16 :: object - r17, x, r18 :: int - r19 :: object - r20 :: int32 - r21, r22, r23 :: bit + r9 :: native_int + r10 :: short_int + r11 :: object + r12 :: tuple[bool, int, object] + r13 :: int + r14 :: bool + r15 :: object + r16, x, r17 :: int + r18 :: object + r19 :: int32 + r20, r21, r22 :: bit c :: set L0: r0 = '1' @@ -194,29 +193,28 @@ L0: tmp_dict = r6 r7 = PySet_New(0) r8 = 0 - r9 = get_element_ptr tmp_dict ma_used :: PyDictObject - r10 = load_mem r9 :: native_int* - r11 = r10 << 1 - r12 = CPyDict_GetKeysIter(tmp_dict) + r9 = PyDict_Size(tmp_dict) + r10 = r9 << 1 + r11 = CPyDict_GetKeysIter(tmp_dict) L1: - r13 = CPyDict_NextKey(r12, r8) - r14 = r13[1] - r8 = r14 - r15 = r13[0] - if r15 goto L2 else goto L4 :: bool + r12 = CPyDict_NextKey(r11, r8) + r13 = r12[1] + r8 = r13 + r14 = r12[0] + if r14 goto L2 else goto L4 :: bool L2: - r16 = r13[2] - r17 = unbox(int, r16) - x = r17 - r18 = f(x) - r19 = box(int, r18) - r20 = PySet_Add(r7, r19) - r21 = r20 >= 0 :: signed + r15 = r12[2] + r16 = unbox(int, r15) + x = r16 + r17 = f(x) + r18 = box(int, r17) + r19 = PySet_Add(r7, r18) + r20 = r19 >= 0 :: signed L3: - r22 = CPyDict_CheckSize(tmp_dict, r11) + r21 = CPyDict_CheckSize(tmp_dict, r10) goto L1 L4: - r23 = CPy_NoErrOccured() + r22 = CPy_NoErrOccured() L5: c = r7 return 1 diff --git a/mypyc/test-data/irbuild-statements.test b/mypyc/test-data/irbuild-statements.test index bb7b72d7d32d..e5e47c05877a 100644 --- a/mypyc/test-data/irbuild-statements.test +++ b/mypyc/test-data/irbuild-statements.test @@ -339,42 +339,40 @@ def f(d: Dict[int, int]) -> None: def f(d): d :: dict r0 :: short_int - r1 :: ptr - r2 :: native_int - r3 :: short_int - r4 :: object - r5 :: tuple[bool, int, object] - r6 :: int - r7 :: bool - r8 :: object - r9, key :: int - r10, r11 :: object - r12 :: int - r13, r14 :: bit + r1 :: native_int + r2 :: short_int + r3 :: object + r4 :: tuple[bool, int, object] + r5 :: int + r6 :: bool + r7 :: object + r8, key :: int + r9, r10 :: object + r11 :: int + r12, r13 :: bit L0: r0 = 0 - r1 = get_element_ptr d ma_used :: PyDictObject - r2 = load_mem r1 :: native_int* - r3 = r2 << 1 - r4 = CPyDict_GetKeysIter(d) + r1 = PyDict_Size(d) + r2 = r1 << 1 + r3 = CPyDict_GetKeysIter(d) L1: - r5 = CPyDict_NextKey(r4, r0) - r6 = r5[1] - r0 = r6 - r7 = r5[0] - if r7 goto L2 else goto L4 :: bool + r4 = CPyDict_NextKey(r3, r0) + r5 = r4[1] + r0 = r5 + r6 = r4[0] + if r6 goto L2 else goto L4 :: bool L2: - r8 = r5[2] - r9 = unbox(int, r8) - key = r9 - r10 = box(int, key) - r11 = CPyDict_GetItem(d, r10) - r12 = unbox(int, r11) + r7 = r4[2] + r8 = unbox(int, r7) + key = r8 + r9 = box(int, key) + r10 = CPyDict_GetItem(d, r9) + r11 = unbox(int, r10) L3: - r13 = CPyDict_CheckSize(d, r3) + r12 = CPyDict_CheckSize(d, r2) goto L1 L4: - r14 = CPy_NoErrOccured() + r13 = CPy_NoErrOccured() L5: return 1 @@ -393,57 +391,55 @@ def sum_over_even_values(d): d :: dict s :: int r0 :: short_int - r1 :: ptr - r2 :: native_int - r3 :: short_int - r4 :: object - r5 :: tuple[bool, int, object] - r6 :: int - r7 :: bool - r8 :: object - r9, key :: int - r10, r11 :: object - r12, r13 :: int - r14 :: bit - r15, r16 :: object - r17, r18 :: int - r19, r20 :: bit + r1 :: native_int + r2 :: short_int + r3 :: object + r4 :: tuple[bool, int, object] + r5 :: int + r6 :: bool + r7 :: object + r8, key :: int + r9, r10 :: object + r11, r12 :: int + r13 :: bit + r14, r15 :: object + r16, r17 :: int + r18, r19 :: bit L0: s = 0 r0 = 0 - r1 = get_element_ptr d ma_used :: PyDictObject - r2 = load_mem r1 :: native_int* - r3 = r2 << 1 - r4 = CPyDict_GetKeysIter(d) + r1 = PyDict_Size(d) + r2 = r1 << 1 + r3 = CPyDict_GetKeysIter(d) L1: - r5 = CPyDict_NextKey(r4, r0) - r6 = r5[1] - r0 = r6 - r7 = r5[0] - if r7 goto L2 else goto L6 :: bool + r4 = CPyDict_NextKey(r3, r0) + r5 = r4[1] + r0 = r5 + r6 = r4[0] + if r6 goto L2 else goto L6 :: bool L2: - r8 = r5[2] - r9 = unbox(int, r8) - key = r9 - r10 = box(int, key) - r11 = CPyDict_GetItem(d, r10) - r12 = unbox(int, r11) - r13 = CPyTagged_Remainder(r12, 4) - r14 = r13 != 0 - if r14 goto L3 else goto L4 :: bool + r7 = r4[2] + r8 = unbox(int, r7) + key = r8 + r9 = box(int, key) + r10 = CPyDict_GetItem(d, r9) + r11 = unbox(int, r10) + r12 = CPyTagged_Remainder(r11, 4) + r13 = r12 != 0 + if r13 goto L3 else goto L4 :: bool L3: goto L5 L4: - r15 = box(int, key) - r16 = CPyDict_GetItem(d, r15) - r17 = unbox(int, r16) - r18 = CPyTagged_Add(s, r17) - s = r18 + r14 = box(int, key) + r15 = CPyDict_GetItem(d, r14) + r16 = unbox(int, r15) + r17 = CPyTagged_Add(s, r16) + s = r17 L5: - r19 = CPyDict_CheckSize(d, r3) + r18 = CPyDict_CheckSize(d, r2) goto L1 L6: - r20 = CPy_NoErrOccured() + r19 = CPy_NoErrOccured() L7: return s diff --git a/mypyc/test-data/refcount.test b/mypyc/test-data/refcount.test index 90475b48207f..f487600ad877 100644 --- a/mypyc/test-data/refcount.test +++ b/mypyc/test-data/refcount.test @@ -721,52 +721,50 @@ def f(d: Dict[int, int]) -> None: def f(d): d :: dict r0 :: short_int - r1 :: ptr - r2 :: native_int - r3 :: short_int - r4 :: object - r5 :: tuple[bool, int, object] - r6 :: int - r7 :: bool - r8 :: object - r9, key :: int - r10, r11 :: object - r12 :: int - r13, r14 :: bit + r1 :: native_int + r2 :: short_int + r3 :: object + r4 :: tuple[bool, int, object] + r5 :: int + r6 :: bool + r7 :: object + r8, key :: int + r9, r10 :: object + r11 :: int + r12, r13 :: bit L0: r0 = 0 - r1 = get_element_ptr d ma_used :: PyDictObject - r2 = load_mem r1 :: native_int* - r3 = r2 << 1 - r4 = CPyDict_GetKeysIter(d) + r1 = PyDict_Size(d) + r2 = r1 << 1 + r3 = CPyDict_GetKeysIter(d) L1: - r5 = CPyDict_NextKey(r4, r0) - r6 = r5[1] - r0 = r6 - r7 = r5[0] - if r7 goto L2 else goto L6 :: bool + r4 = CPyDict_NextKey(r3, r0) + r5 = r4[1] + r0 = r5 + r6 = r4[0] + if r6 goto L2 else goto L6 :: bool L2: - r8 = r5[2] - dec_ref r5 - r9 = unbox(int, r8) - dec_ref r8 - key = r9 - r10 = box(int, key) - r11 = CPyDict_GetItem(d, r10) + r7 = r4[2] + dec_ref r4 + r8 = unbox(int, r7) + dec_ref r7 + key = r8 + r9 = box(int, key) + r10 = CPyDict_GetItem(d, r9) + dec_ref r9 + r11 = unbox(int, r10) dec_ref r10 - r12 = unbox(int, r11) - dec_ref r11 - dec_ref r12 :: int + dec_ref r11 :: int L3: - r13 = CPyDict_CheckSize(d, r3) + r12 = CPyDict_CheckSize(d, r2) goto L1 L4: - r14 = CPy_NoErrOccured() + r13 = CPy_NoErrOccured() L5: return 1 L6: + dec_ref r3 dec_ref r4 - dec_ref r5 goto L4 [case testBorrowRefs] diff --git a/mypyc/test-data/run-dicts.test b/mypyc/test-data/run-dicts.test index 49deb0854483..89188e09b1f1 100644 --- a/mypyc/test-data/run-dicts.test +++ b/mypyc/test-data/run-dicts.test @@ -253,26 +253,3 @@ def test_dict_subclass_setdefault() -> None: assert d.setdefault('a') == 1 assert d.setdefault('e') == None assert d.setdefault('e', 100) == 110 - -[case testDictToBool] -from typing import Dict, List - -def is_true(x: dict) -> bool: - if x: - return True - else: - return False - -def is_false(x: dict) -> bool: - if not x: - return True - else: - return False - -def test_dict_to_bool() -> None: - assert is_false({}) - assert not is_true({}) - tmp_list: List[Dict] = [{2: bool}, {'a': 'b'}] - for x in tmp_list: - assert is_true(x) - assert not is_false(x) From 754f37bcc35d3981e461dd5a2bcd855d60fd5291 Mon Sep 17 00:00:00 2001 From: 97littleleaf11 <97littleleaf11@gmail.com> Date: Thu, 22 Apr 2021 21:18:02 +0800 Subject: [PATCH 5/5] Support dict true test --- mypyc/irbuild/ll_builder.py | 5 +++-- mypyc/test-data/run-dicts.test | 23 +++++++++++++++++++++++ 2 files changed, 26 insertions(+), 2 deletions(-) diff --git a/mypyc/irbuild/ll_builder.py b/mypyc/irbuild/ll_builder.py index 0a0a9df050f3..94f1dcbfff8f 100644 --- a/mypyc/irbuild/ll_builder.py +++ b/mypyc/irbuild/ll_builder.py @@ -32,7 +32,7 @@ is_list_rprimitive, is_tuple_rprimitive, is_dict_rprimitive, is_set_rprimitive, PySetObject, none_rprimitive, RTuple, is_bool_rprimitive, is_str_rprimitive, c_int_rprimitive, pointer_rprimitive, PyObject, PyListObject, bit_rprimitive, is_bit_rprimitive, - object_pointer_rprimitive, c_size_t_rprimitive + object_pointer_rprimitive, c_size_t_rprimitive, dict_rprimitive ) from mypyc.ir.func_ir import FuncDecl, FuncSignature from mypyc.ir.class_ir import ClassIR, all_concrete_classes @@ -960,7 +960,8 @@ def add_bool_branch(self, value: Value, true: BasicBlock, false: BasicBlock) -> return elif is_same_type(value.type, str_rprimitive): value = self.call_c(str_check_if_true, [value], value.line) - elif is_same_type(value.type, list_rprimitive): + elif (is_same_type(value.type, list_rprimitive) + or is_same_type(value.type, dict_rprimitive)): length = self.builtin_len(value, value.line) zero = Integer(0) value = self.binary_op(length, zero, '!=', value.line) diff --git a/mypyc/test-data/run-dicts.test b/mypyc/test-data/run-dicts.test index 89188e09b1f1..49deb0854483 100644 --- a/mypyc/test-data/run-dicts.test +++ b/mypyc/test-data/run-dicts.test @@ -253,3 +253,26 @@ def test_dict_subclass_setdefault() -> None: assert d.setdefault('a') == 1 assert d.setdefault('e') == None assert d.setdefault('e', 100) == 110 + +[case testDictToBool] +from typing import Dict, List + +def is_true(x: dict) -> bool: + if x: + return True + else: + return False + +def is_false(x: dict) -> bool: + if not x: + return True + else: + return False + +def test_dict_to_bool() -> None: + assert is_false({}) + assert not is_true({}) + tmp_list: List[Dict] = [{2: bool}, {'a': 'b'}] + for x in tmp_list: + assert is_true(x) + assert not is_false(x)