From 2db5a2ad703faedafcda092938bde12d9d52d6f3 Mon Sep 17 00:00:00 2001 From: BobTheBuidler <70677534+BobTheBuidler@users.noreply.github.com> Date: Fri, 12 Sep 2025 23:48:52 +0000 Subject: [PATCH 01/11] [mypyc] feat: exact_dict_rprimitive --- mypyc/ir/rtypes.py | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/mypyc/ir/rtypes.py b/mypyc/ir/rtypes.py index 34824a59cd5c..6ae26b5dedf9 100644 --- a/mypyc/ir/rtypes.py +++ b/mypyc/ir/rtypes.py @@ -487,8 +487,13 @@ def __hash__(self) -> int: "builtins.list", is_unboxed=False, is_refcounted=True, may_be_immortal=False ) -# Python dict object (or an instance of a subclass of dict). +# Python dict object. +exact_dict_rprimitive: Final = RPrimitive( + "builtins.dict[exact]", is_unboxed=False, is_refcounted=True) +) + dict_rprimitive: Final = RPrimitive("builtins.dict", is_unboxed=False, is_refcounted=True) +# An instance of a subclass of dict. # Python set object (or an instance of a subclass of set). set_rprimitive: Final = RPrimitive("builtins.set", is_unboxed=False, is_refcounted=True) @@ -608,7 +613,14 @@ def is_list_rprimitive(rtype: RType) -> TypeGuard[RPrimitive]: def is_dict_rprimitive(rtype: RType) -> TypeGuard[RPrimitive]: - return isinstance(rtype, RPrimitive) and rtype.name == "builtins.dict" + return isinstance(rtype, RPrimitive) and rtype.name in ( + "builtins.dict", + "builtins.dict[exact]", + ) + + +def is_exact_dict_rprimitive(rtype: RType) -> TypeGuard[RPrimitive]: + return isinstance(rtype, RPrimitive) and rtype.name == "builtins.dict[exact]" def is_set_rprimitive(rtype: RType) -> TypeGuard[RPrimitive]: From f43c0728e6a880aa1ecd38ed8414bcad747a739e Mon Sep 17 00:00:00 2001 From: BobTheBuidler <70677534+BobTheBuidler@users.noreply.github.com> Date: Fri, 12 Sep 2025 23:48:52 +0000 Subject: [PATCH 02/11] Update rt_subtype.py --- mypyc/rt_subtype.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/mypyc/rt_subtype.py b/mypyc/rt_subtype.py index 004e56ed75bc..01619158a954 100644 --- a/mypyc/rt_subtype.py +++ b/mypyc/rt_subtype.py @@ -27,6 +27,8 @@ RVoid, is_bit_rprimitive, is_bool_rprimitive, + is_dict_rprimitive, + is_exact_dict_rprimitive, is_int_rprimitive, is_short_int_rprimitive, ) @@ -58,6 +60,8 @@ def visit_rprimitive(self, left: RPrimitive) -> bool: return True if is_bit_rprimitive(left) and is_bool_rprimitive(self.right): return True + if is_exact_dict_rprimitive(left) and is_dict_rprimitive(self.right): + return True return left is self.right def visit_rtuple(self, left: RTuple) -> bool: From 3942c6289a2e123b8e0519faa84b0626fd6c65ad Mon Sep 17 00:00:00 2001 From: BobTheBuidler <70677534+BobTheBuidler@users.noreply.github.com> Date: Fri, 12 Sep 2025 23:48:52 +0000 Subject: [PATCH 03/11] Update subtype.py --- mypyc/subtype.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/mypyc/subtype.py b/mypyc/subtype.py index 726a48d7a01d..6ad4dcb1d19e 100644 --- a/mypyc/subtype.py +++ b/mypyc/subtype.py @@ -1,3 +1,4 @@ + """Subtype check for RTypes.""" from __future__ import annotations @@ -14,6 +15,8 @@ RVoid, is_bit_rprimitive, is_bool_rprimitive, + is_dict_rprimitive, + is_exact_dict_rprimitive, is_fixed_width_rtype, is_int_rprimitive, is_object_rprimitive, @@ -67,6 +70,9 @@ def visit_rprimitive(self, left: RPrimitive) -> bool: elif is_fixed_width_rtype(left): if is_int_rprimitive(right): return True + elif is_exact_dict_rprimitive(left): + if is_dict_rprimitive(right): + return True return left is right def visit_rtuple(self, left: RTuple) -> bool: From 11768a9301000cd13358e8ba06b88f649a06c369 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Fri, 12 Sep 2025 23:48:52 +0000 Subject: [PATCH 04/11] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- mypyc/subtype.py | 1 - 1 file changed, 1 deletion(-) diff --git a/mypyc/subtype.py b/mypyc/subtype.py index 6ad4dcb1d19e..6feb4b83b5cf 100644 --- a/mypyc/subtype.py +++ b/mypyc/subtype.py @@ -1,4 +1,3 @@ - """Subtype check for RTypes.""" from __future__ import annotations From 555d83aab0d659e68f594930ded92e458c9b7631 Mon Sep 17 00:00:00 2001 From: BobTheBuidler <70677534+BobTheBuidler@users.noreply.github.com> Date: Fri, 12 Sep 2025 23:48:52 +0000 Subject: [PATCH 05/11] Update ircheck.py --- mypyc/analysis/ircheck.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/mypyc/analysis/ircheck.py b/mypyc/analysis/ircheck.py index 6980c9cee419..0af0c4b0ec28 100644 --- a/mypyc/analysis/ircheck.py +++ b/mypyc/analysis/ircheck.py @@ -197,7 +197,10 @@ def can_coerce_to(src: RType, dest: RType) -> bool: if isinstance(src, RPrimitive): # If either src or dest is a disjoint type, then they must both be. if src.name in disjoint_types and dest.name in disjoint_types: - return src.name == dest.name + return src.name == dest.name or ( + src.name in ("builtins.dict", "builtins.dict[exact]") + and dest.name in ("builtins.dict", "builtins.dict[exact]") + ) return src.size == dest.size if isinstance(src, RInstance): return is_object_rprimitive(dest) From 665e2e6bcf0a5928e0df10aad70114409cb80fd7 Mon Sep 17 00:00:00 2001 From: BobTheBuidler <70677534+BobTheBuidler@users.noreply.github.com> Date: Fri, 12 Sep 2025 23:48:52 +0000 Subject: [PATCH 06/11] Update rtypes.py --- mypyc/ir/rtypes.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mypyc/ir/rtypes.py b/mypyc/ir/rtypes.py index 6ae26b5dedf9..e5db2211d859 100644 --- a/mypyc/ir/rtypes.py +++ b/mypyc/ir/rtypes.py @@ -492,8 +492,8 @@ def __hash__(self) -> int: "builtins.dict[exact]", is_unboxed=False, is_refcounted=True) ) -dict_rprimitive: Final = RPrimitive("builtins.dict", is_unboxed=False, is_refcounted=True) # An instance of a subclass of dict. +dict_rprimitive: Final = RPrimitive("builtins.dict", is_unboxed=False, is_refcounted=True) # Python set object (or an instance of a subclass of set). set_rprimitive: Final = RPrimitive("builtins.set", is_unboxed=False, is_refcounted=True) From 0e7ef8dce648e33cfa68e2daa178f026f3a2e960 Mon Sep 17 00:00:00 2001 From: BobTheBuidler <70677534+BobTheBuidler@users.noreply.github.com> Date: Fri, 12 Sep 2025 23:48:52 +0000 Subject: [PATCH 07/11] Update rtypes.py --- mypyc/ir/rtypes.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mypyc/ir/rtypes.py b/mypyc/ir/rtypes.py index e5db2211d859..7cb3d59e2ea9 100644 --- a/mypyc/ir/rtypes.py +++ b/mypyc/ir/rtypes.py @@ -489,7 +489,7 @@ def __hash__(self) -> int: # Python dict object. exact_dict_rprimitive: Final = RPrimitive( - "builtins.dict[exact]", is_unboxed=False, is_refcounted=True) + "builtins.dict[exact]", is_unboxed=False, is_refcounted=True ) # An instance of a subclass of dict. From 3aca0f3cd68815c9175daac2990ac11191c106a9 Mon Sep 17 00:00:00 2001 From: BobTheBuidler <70677534+BobTheBuidler@users.noreply.github.com> Date: Mon, 18 Aug 2025 17:10:36 -0400 Subject: [PATCH 08/11] Update misc_ops.py --- mypyc/primitives/misc_ops.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/mypyc/primitives/misc_ops.py b/mypyc/primitives/misc_ops.py index 8e6e450c64dc..63a48b6e2906 100644 --- a/mypyc/primitives/misc_ops.py +++ b/mypyc/primitives/misc_ops.py @@ -13,6 +13,7 @@ c_pyssize_t_rprimitive, cstring_rprimitive, dict_rprimitive, + exact_dict_rprimitive, float_rprimitive, int_rprimitive, none_rprimitive, @@ -161,7 +162,7 @@ # Get the sys.modules dictionary get_module_dict_op = custom_op( arg_types=[], - return_type=dict_rprimitive, + return_type=exact_dict_rprimitive, c_function_name="PyImport_GetModuleDict", error_kind=ERR_NEVER, is_borrowed=True, From 328a11db21ce472b15d6d9d2e7987e33a5ba2737 Mon Sep 17 00:00:00 2001 From: BobTheBuidler <70677534+BobTheBuidler@users.noreply.github.com> Date: Tue, 19 Aug 2025 10:58:33 -0400 Subject: [PATCH 09/11] update IR --- mypyc/test-data/irbuild-basic.test | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/mypyc/test-data/irbuild-basic.test b/mypyc/test-data/irbuild-basic.test index 612f3266fd79..340d1c230031 100644 --- a/mypyc/test-data/irbuild-basic.test +++ b/mypyc/test-data/irbuild-basic.test @@ -3290,7 +3290,7 @@ def root(): r4 :: str r5 :: object r6 :: str - r7 :: dict + r7 :: dict[exact] r8 :: str r9 :: object r10 :: i32 @@ -3301,7 +3301,7 @@ def root(): r16 :: str r17 :: object r18 :: str - r19 :: dict + r19 :: dict[exact] r20 :: str r21 :: object r22 :: i32 @@ -3347,12 +3347,12 @@ def submodule(): r4 :: str r5 :: object r6 :: str - r7 :: dict + r7 :: dict[exact] r8 :: str r9 :: object r10 :: i32 r11 :: bit - r12 :: dict + r12 :: dict[exact] r13 :: str r14 :: object r15 :: str From 67323589c6d7770be11edbb8959b1b8a11b40996 Mon Sep 17 00:00:00 2001 From: BobTheBuidler Date: Fri, 3 Oct 2025 21:21:09 +0000 Subject: [PATCH 10/11] [mypyc] feat: use exact_dict_rprimitive for star2 arg rtype --- mypyc/irbuild/mapper.py | 3 ++- mypyc/primitives/misc_ops.py | 9 +++++++++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/mypyc/irbuild/mapper.py b/mypyc/irbuild/mapper.py index 05aa0e45c569..0ebc5eb62738 100644 --- a/mypyc/irbuild/mapper.py +++ b/mypyc/irbuild/mapper.py @@ -33,6 +33,7 @@ bool_rprimitive, bytes_rprimitive, dict_rprimitive, + exact_dict_rprimitive, float_rprimitive, frozenset_rprimitive, int16_rprimitive, @@ -169,7 +170,7 @@ def get_arg_rtype(self, typ: Type, kind: ArgKind) -> RType: if kind == ARG_STAR: return tuple_rprimitive elif kind == ARG_STAR2: - return dict_rprimitive + return exact_dict_rprimitive else: return self.type_to_rtype(typ) diff --git a/mypyc/primitives/misc_ops.py b/mypyc/primitives/misc_ops.py index 63a48b6e2906..bb92f0807aa0 100644 --- a/mypyc/primitives/misc_ops.py +++ b/mypyc/primitives/misc_ops.py @@ -189,6 +189,15 @@ priority=0, ) +# bool(dict) +dict_is_true_op = function_op( + name="builtins.bool", + arg_types=[exact_dict_rprimitive], + return_type=bit_rprimitive, + c_function_name="CPyDict_IsTrue", + error_kind=ERR_NEVER, +) + # bool(obj) with unboxed result bool_op = function_op( name="builtins.bool", From 280e5a39d0ae0f2654c2dea0837e4826e349dd36 Mon Sep 17 00:00:00 2001 From: BobTheBuidler <70677534+BobTheBuidler@users.noreply.github.com> Date: Fri, 3 Oct 2025 17:52:29 -0400 Subject: [PATCH 11/11] Update misc_ops.py --- mypyc/primitives/misc_ops.py | 9 --------- 1 file changed, 9 deletions(-) diff --git a/mypyc/primitives/misc_ops.py b/mypyc/primitives/misc_ops.py index bb92f0807aa0..63a48b6e2906 100644 --- a/mypyc/primitives/misc_ops.py +++ b/mypyc/primitives/misc_ops.py @@ -189,15 +189,6 @@ priority=0, ) -# bool(dict) -dict_is_true_op = function_op( - name="builtins.bool", - arg_types=[exact_dict_rprimitive], - return_type=bit_rprimitive, - c_function_name="CPyDict_IsTrue", - error_kind=ERR_NEVER, -) - # bool(obj) with unboxed result bool_op = function_op( name="builtins.bool",