From 009c38727a47315c46a36d65dc982a15540fd4b7 Mon Sep 17 00:00:00 2001 From: BobTheBuidler Date: Mon, 4 Aug 2025 02:01:35 +0000 Subject: [PATCH 01/43] feat: true dict rprimitive --- mypyc/annotate.py | 2 +- mypyc/ir/rtypes.py | 18 +- mypyc/irbuild/builder.py | 12 +- mypyc/irbuild/classdef.py | 4 +- mypyc/irbuild/expression.py | 4 +- mypyc/irbuild/for_helpers.py | 54 ++++- mypyc/irbuild/function.py | 17 +- mypyc/irbuild/ll_builder.py | 37 ++- mypyc/irbuild/mapper.py | 5 +- mypyc/irbuild/match.py | 4 +- mypyc/irbuild/prepare.py | 4 +- mypyc/irbuild/specialize.py | 24 +- mypyc/lib-rt/CPy.h | 30 +++ mypyc/lib-rt/dict_ops.c | 122 ++++++++-- mypyc/primitives/bytes_ops.py | 3 +- mypyc/primitives/dict_ops.py | 251 +++++++++++++++++++- mypyc/primitives/misc_ops.py | 12 +- mypyc/test-data/irbuild-basic.test | 199 ++++++++-------- mypyc/test-data/irbuild-bool.test | 16 +- mypyc/test-data/irbuild-classes.test | 30 +-- mypyc/test-data/irbuild-dict.test | 159 +++++++------ mypyc/test-data/irbuild-generics.test | 40 ++-- mypyc/test-data/irbuild-match.test | 88 +++---- mypyc/test-data/irbuild-set.test | 76 +++--- mypyc/test-data/irbuild-singledispatch.test | 20 +- mypyc/test-data/irbuild-statements.test | 46 ++-- mypyc/test-data/run-dicts.test | 10 +- 27 files changed, 899 insertions(+), 388 deletions(-) diff --git a/mypyc/annotate.py b/mypyc/annotate.py index bc282fc3ea6c..f6aa0f006151 100644 --- a/mypyc/annotate.py +++ b/mypyc/annotate.py @@ -216,7 +216,7 @@ def function_annotations(func_ir: FuncIR, tree: MypyFile) -> dict[int, list[Anno ann = "Dynamic method call." elif name in op_hints: ann = op_hints[name] - elif name in ("CPyDict_GetItem", "CPyDict_SetItem"): + elif name in ("CPyDict_GetItemUnsafe", "PyDict_SetItem"): if ( isinstance(op.args[0], LoadStatic) and isinstance(op.args[1], LoadLiteral) diff --git a/mypyc/ir/rtypes.py b/mypyc/ir/rtypes.py index 34824a59cd5c..68d4b11b2221 100644 --- a/mypyc/ir/rtypes.py +++ b/mypyc/ir/rtypes.py @@ -487,8 +487,15 @@ 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. +true_dict_rprimitive: Final = RPrimitive( + "builtins.dict[confirmed]", is_unboxed=False, is_refcounted=True +) +"""A primitive for dicts that are confirmed to be actual instances of builtins.dict, not a subclass.""" + +# An instance of a subclass of dict. dict_rprimitive: Final = RPrimitive("builtins.dict", is_unboxed=False, is_refcounted=True) +"""A primitive that represents instances of builtins.dict or subclasses 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 +615,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[confirmed]", + ) + + +def is_true_dict_rprimitive(rtype: RType) -> TypeGuard[RPrimitive]: + return isinstance(rtype, RPrimitive) and rtype.name == "builtins.dict[confirmed]" def is_set_rprimitive(rtype: RType) -> TypeGuard[RPrimitive]: diff --git a/mypyc/irbuild/builder.py b/mypyc/irbuild/builder.py index 4f2f539118d7..23dbd9c38723 100644 --- a/mypyc/irbuild/builder.py +++ b/mypyc/irbuild/builder.py @@ -93,7 +93,6 @@ bitmap_rprimitive, bytes_rprimitive, c_pyssize_t_rprimitive, - dict_rprimitive, int_rprimitive, is_float_rprimitive, is_list_rprimitive, @@ -104,6 +103,7 @@ none_rprimitive, object_rprimitive, str_rprimitive, + true_dict_rprimitive, ) from mypyc.irbuild.context import FuncInfo, ImplicitClass from mypyc.irbuild.ll_builder import LowLevelIRBuilder @@ -125,7 +125,7 @@ ) from mypyc.irbuild.util import bytes_from_str, is_constant from mypyc.options import CompilerOptions -from mypyc.primitives.dict_ops import dict_get_item_op, dict_set_item_op +from mypyc.primitives.dict_ops import dict_set_item_op, true_dict_get_item_op from mypyc.primitives.generic_ops import iter_op, next_op, py_setattr_op from mypyc.primitives.list_ops import list_get_item_unsafe_op, list_pop_last, to_list from mypyc.primitives.misc_ops import check_unpack_count_op, get_module_dict_op, import_op @@ -436,6 +436,8 @@ def add_to_non_ext_dict( ) -> None: # Add an attribute entry into the class dict of a non-extension class. key_unicode = self.load_str(key) + # must use `dict_set_item_op` instead of `true_dict_set_item_op` because + # it breaks enums, and probably other stuff, if we take the fast path. self.primitive_op(dict_set_item_op, [non_ext.dict, key_unicode, val], line) # It's important that accessing class dictionary items from multiple threads @@ -471,7 +473,7 @@ def get_module(self, module: str, line: int) -> Value: # Python 3.7 has a nice 'PyImport_GetModule' function that we can't use :( mod_dict = self.call_c(get_module_dict_op, [], line) # Get module object from modules dict. - return self.primitive_op(dict_get_item_op, [mod_dict, self.load_str(module)], line) + return self.primitive_op(true_dict_get_item_op, [mod_dict, self.load_str(module)], line) def get_module_attr(self, module: str, attr: str, line: int) -> Value: """Look up an attribute of a module without storing it in the local namespace. @@ -1388,10 +1390,10 @@ def load_global(self, expr: NameExpr) -> Value: def load_global_str(self, name: str, line: int) -> Value: _globals = self.load_globals_dict() reg = self.load_str(name) - return self.primitive_op(dict_get_item_op, [_globals, reg], line) + return self.primitive_op(true_dict_get_item_op, [_globals, reg], line) def load_globals_dict(self) -> Value: - return self.add(LoadStatic(dict_rprimitive, "globals", self.module_name)) + return self.add(LoadStatic(true_dict_rprimitive, "globals", self.module_name)) def load_module_attr_by_fullname(self, fullname: str, line: int) -> Value: module, _, name = fullname.rpartition(".") diff --git a/mypyc/irbuild/classdef.py b/mypyc/irbuild/classdef.py index 324b44b95dc4..f36f3971b40b 100644 --- a/mypyc/irbuild/classdef.py +++ b/mypyc/irbuild/classdef.py @@ -50,11 +50,11 @@ from mypyc.ir.rtypes import ( RType, bool_rprimitive, - dict_rprimitive, is_none_rprimitive, is_object_rprimitive, is_optional_type, object_rprimitive, + true_dict_rprimitive, ) from mypyc.irbuild.builder import IRBuilder, create_type_params from mypyc.irbuild.function import ( @@ -611,7 +611,7 @@ def setup_non_ext_dict( py_hasattr_op, [metaclass, builder.load_str("__prepare__")], cdef.line ) - non_ext_dict = Register(dict_rprimitive) + non_ext_dict = Register(true_dict_rprimitive) true_block, false_block, exit_block = BasicBlock(), BasicBlock(), BasicBlock() builder.add_bool_branch(has_prepare, true_block, false_block) diff --git a/mypyc/irbuild/expression.py b/mypyc/irbuild/expression.py index 4409b1acff26..ffb64765005b 100644 --- a/mypyc/irbuild/expression.py +++ b/mypyc/irbuild/expression.py @@ -100,7 +100,7 @@ ) from mypyc.irbuild.specialize import apply_function_specialization, apply_method_specialization from mypyc.primitives.bytes_ops import bytes_slice_op -from mypyc.primitives.dict_ops import dict_get_item_op, dict_new_op, exact_dict_set_item_op +from mypyc.primitives.dict_ops import dict_new_op, exact_dict_set_item_op from mypyc.primitives.generic_ops import iter_op, name_op from mypyc.primitives.list_ops import list_append_op, list_extend_op, list_slice_op from mypyc.primitives.misc_ops import ellipsis_op, get_module_dict_op, new_slice_op, type_op @@ -186,7 +186,7 @@ def transform_name_expr(builder: IRBuilder, expr: NameExpr) -> Value: # instead load the module separately on each access. mod_dict = builder.call_c(get_module_dict_op, [], expr.line) obj = builder.primitive_op( - dict_get_item_op, [mod_dict, builder.load_str(expr.node.fullname)], expr.line + true_dict_get_item_op, [mod_dict, builder.load_str(expr.node.fullname)], expr.line ) return obj else: diff --git a/mypyc/irbuild/for_helpers.py b/mypyc/irbuild/for_helpers.py index 5edee6cb4df4..088370313f79 100644 --- a/mypyc/irbuild/for_helpers.py +++ b/mypyc/irbuild/for_helpers.py @@ -58,6 +58,7 @@ is_sequence_rprimitive, is_short_int_rprimitive, is_str_rprimitive, + is_true_dict_rprimitive, is_tuple_rprimitive, object_pointer_rprimitive, object_rprimitive, @@ -75,6 +76,11 @@ dict_next_key_op, dict_next_value_op, dict_value_iter_op, + true_dict_check_size_op, + true_dict_iter_fast_path_op, + true_dict_next_item_op, + true_dict_next_key_op, + true_dict_next_value_op, ) from mypyc.primitives.exc_ops import no_err_occurred_op, propagate_if_error_op from mypyc.primitives.generic_ops import aiter_op, anext_op, iter_op, next_op @@ -424,8 +430,10 @@ def make_for_loop_generator( # Special case "for k in ". expr_reg = builder.accept(expr) target_type = builder.get_dict_key_type(expr) - - for_dict = ForDictionaryKeys(builder, index, body_block, loop_exit, line, nested) + for_loop_cls = ( + ForTrueDictionaryKeys if is_true_dict_rprimitive(rtyp) else ForDictionaryKeys + ) + for_dict = for_loop_cls(builder, index, body_block, loop_exit, line, nested) for_dict.init(expr_reg, target_type) return for_dict @@ -507,13 +515,22 @@ def make_for_loop_generator( for_dict_type: type[ForGenerator] | None = None if expr.callee.name == "keys": target_type = builder.get_dict_key_type(expr.callee.expr) - for_dict_type = ForDictionaryKeys + if is_true_dict_rprimitive(rtype): + for_dict_type = ForTrueDictionaryKeys + else: + for_dict_type = ForDictionaryKeys elif expr.callee.name == "values": target_type = builder.get_dict_value_type(expr.callee.expr) - for_dict_type = ForDictionaryValues + if is_true_dict_rprimitive(rtype): + for_dict_type = ForTrueDictionaryValues + else: + for_dict_type = ForDictionaryValues else: target_type = builder.get_dict_item_type(expr.callee.expr) - for_dict_type = ForDictionaryItems + if is_true_dict_rprimitive(rtype): + for_dict_type = ForTrueDictionaryItems + else: + for_dict_type = ForDictionaryItems for_dict_gen = for_dict_type(builder, index, body_block, loop_exit, line, nested) for_dict_gen.init(expr_reg, target_type) return for_dict_gen @@ -898,6 +915,7 @@ class ForDictionaryCommon(ForGenerator): dict_next_op: ClassVar[CFunctionDescription] dict_iter_op: ClassVar[CFunctionDescription] + dict_size_op: ClassVar[CFunctionDescription] = dict_check_size_op def need_cleanup(self) -> bool: # Technically, a dict subclass can raise an unrelated exception @@ -944,7 +962,7 @@ def gen_step(self) -> None: line = self.line # Technically, we don't need a new primitive for this, but it is simpler. builder.call_c( - dict_check_size_op, + self.dict_size_op, [builder.read(self.expr_target, line), builder.read(self.size, line)], line, ) @@ -1022,6 +1040,30 @@ def begin_body(self) -> None: builder.assign(target, rvalue, line) +class ForTrueDictionaryKeys(ForDictionaryKeys): + """Generate optimized IR for a for loop over dictionary items without type checks.""" + + dict_next_op = true_dict_next_key_op + dict_iter_op = true_dict_iter_fast_path_op + dict_size_op = true_dict_check_size_op + + +class ForTrueDictionaryValues(ForDictionaryValues): + """Generate optimized IR for a for loop over dictionary items without type checks.""" + + dict_next_op = true_dict_next_value_op + dict_iter_op = true_dict_iter_fast_path_op + dict_size_op = true_dict_check_size_op + + +class ForTrueDictionaryItems(ForDictionaryItems): + """Generate optimized IR for a for loop over dictionary items without type checks.""" + + dict_next_op = true_dict_next_item_op + dict_iter_op = true_dict_iter_fast_path_op + dict_size_op = true_dict_check_size_op + + class ForRange(ForGenerator): """Generate optimized IR for a for loop over an integer range.""" diff --git a/mypyc/irbuild/function.py b/mypyc/irbuild/function.py index f0fc424aea54..db229224e04e 100644 --- a/mypyc/irbuild/function.py +++ b/mypyc/irbuild/function.py @@ -56,9 +56,9 @@ from mypyc.ir.rtypes import ( RInstance, bool_rprimitive, - dict_rprimitive, int_rprimitive, object_rprimitive, + true_dict_rprimitive, ) from mypyc.irbuild.builder import IRBuilder, calculate_arg_defaults, gen_arg_defaults from mypyc.irbuild.callable_class import ( @@ -77,7 +77,6 @@ from mypyc.irbuild.generator import gen_generator_func, gen_generator_func_body from mypyc.irbuild.targets import AssignmentTarget from mypyc.primitives.dict_ops import ( - dict_get_method_with_none, dict_new_op, exact_dict_set_item_op, ) @@ -814,10 +813,12 @@ def generate_singledispatch_dispatch_function( arg_type = builder.builder.get_type_of_obj(arg_info.args[0], line) dispatch_cache = builder.builder.get_attr( - dispatch_func_obj, "dispatch_cache", dict_rprimitive, line + dispatch_func_obj, "dispatch_cache", true_dict_rprimitive, line ) call_find_impl, use_cache, call_func = BasicBlock(), BasicBlock(), BasicBlock() - get_result = builder.primitive_op(dict_get_method_with_none, [dispatch_cache, arg_type], line) + get_result = builder.primitive_op( + true_dict_get_method_with_none, [dispatch_cache, arg_type], line + ) is_not_none = builder.translate_is_op(get_result, builder.none_object(), "is not", line) impl_to_use = Register(object_rprimitive) builder.add_bool_branch(is_not_none, use_cache, call_find_impl) @@ -894,8 +895,8 @@ def gen_dispatch_func_ir( """ builder.enter(FuncInfo(fitem, dispatch_name)) setup_callable_class(builder) - builder.fn_info.callable_class.ir.attributes["registry"] = dict_rprimitive - builder.fn_info.callable_class.ir.attributes["dispatch_cache"] = dict_rprimitive + builder.fn_info.callable_class.ir.attributes["registry"] = true_dict_rprimitive + builder.fn_info.callable_class.ir.attributes["dispatch_cache"] = true_dict_rprimitive builder.fn_info.callable_class.ir.has_dict = True builder.fn_info.callable_class.ir.needs_getseters = True generate_singledispatch_callable_class_ctor(builder) @@ -958,7 +959,7 @@ def add_register_method_to_callable_class(builder: IRBuilder, fn_info: FuncInfo) def load_singledispatch_registry(builder: IRBuilder, dispatch_func_obj: Value, line: int) -> Value: - return builder.builder.get_attr(dispatch_func_obj, "registry", dict_rprimitive, line) + return builder.builder.get_attr(dispatch_func_obj, "registry", true_dict_rprimitive, line) def singledispatch_main_func_name(orig_name: str) -> str: @@ -1009,7 +1010,7 @@ def maybe_insert_into_registry_dict(builder: IRBuilder, fitem: FuncDef) -> None: loaded_type = load_type(builder, typ, None, line) builder.call_c(exact_dict_set_item_op, [registry, loaded_type, to_insert], line) dispatch_cache = builder.builder.get_attr( - dispatch_func_obj, "dispatch_cache", dict_rprimitive, line + dispatch_func_obj, "dispatch_cache", true_dict_rprimitive, line ) builder.gen_method_call(dispatch_cache, "clear", [], None, line) diff --git a/mypyc/irbuild/ll_builder.py b/mypyc/irbuild/ll_builder.py index 4b85c13892c1..8cf69937a159 100644 --- a/mypyc/irbuild/ll_builder.py +++ b/mypyc/irbuild/ll_builder.py @@ -94,6 +94,7 @@ c_pyssize_t_rprimitive, c_size_t_rprimitive, check_native_int_range, + dict_rprimitive, float_rprimitive, int_rprimitive, is_bool_or_bit_rprimitive, @@ -114,8 +115,10 @@ is_short_int_rprimitive, is_str_rprimitive, is_tagged, + is_true_dict_rprimitive, is_tuple_rprimitive, is_uint8_rprimitive, + list_rprimitive, none_rprimitive, object_pointer_rprimitive, object_rprimitive, @@ -123,6 +126,8 @@ pointer_rprimitive, short_int_rprimitive, str_rprimitive, + true_dict_rprimitive, + tuple_rprimitive, ) from mypyc.irbuild.util import concrete_arg_kind from mypyc.options import CompilerOptions @@ -134,6 +139,9 @@ dict_new_op, dict_ssize_t_size_op, dict_update_in_display_op, + true_dict_copy_op, + true_dict_ssize_t_size_op, + true_dict_update_op, ) from mypyc.primitives.exc_ops import err_occurred_op, keep_propagating_op from mypyc.primitives.float_ops import copysign_op, int_to_float_op @@ -168,6 +176,7 @@ bool_op, buf_init_item, debug_print_op, + dict_is_true_op, fast_isinstance_op, none_object_op, not_implemented_op, @@ -852,8 +861,11 @@ def _construct_varargs( ) star2_result = self._create_dict(star2_keys, star2_values, line) - - self.call_c(dict_update_in_display_op, [star2_result, value], line=line) + if is_true_dict_rprimitive(value): + op = true_dict_update_op + else: + op = dict_update_in_display_op + self.call_c(op, [star2_result, value], line=line) else: nullable = kind.is_optional() maybe_pos = kind.is_positional() and has_star @@ -1815,9 +1827,18 @@ def make_dict(self, key_value_pairs: Sequence[DictEntry], line: int) -> Value: else: # **value if result is None: + if len(key_value_pairs) == 1 and is_true_dict_rprimitive(value): + # fast path for cases like `my_func(**dict(zip(iterable, other)))` and similar + return self.call_c(true_dict_copy_op, [value], line=line) + result = self._create_dict(keys, values, line) - self.call_c(dict_update_in_display_op, [result, value], line=line) + if is_true_dict_rprimitive(value): + op = true_dict_update_op + else: + op = dict_update_in_display_op + + self.call_c(op, [result, value], line=line) if result is None: result = self._create_dict(keys, values, line) @@ -1921,10 +1942,10 @@ def bool_value(self, value: Value) -> Value: result = self.add(ComparisonOp(value, zero, ComparisonOp.NEQ)) elif is_str_rprimitive(value.type): result = self.call_c(str_check_if_true, [value], value.line) - elif ( - is_list_rprimitive(value.type) - or is_dict_rprimitive(value.type) - or is_tuple_rprimitive(value.type) + elif is_same_type(value.type, true_dict_rprimitive): + result = self.call_c(dict_is_true_op, [value], line=value.line) + elif is_same_type(value.type, list_rprimitive) or is_same_type( + value.type, dict_rprimitive of is_same_type(value.type, tuple_rprimitive) ): length = self.builtin_len(value, value.line) zero = Integer(0) @@ -2428,6 +2449,8 @@ def builtin_len(self, val: Value, line: int, use_pyssize_t: bool = False) -> Val elem_address = self.add(GetElementPtr(val, PySetObject, "used")) size_value = self.load_mem(elem_address, c_pyssize_t_rprimitive) self.add(KeepAlive([val])) + elif is_true_dict_rprimitive(typ): + size_value = self.call_c(true_dict_ssize_t_size_op, [val], line) elif is_dict_rprimitive(typ): size_value = self.call_c(dict_ssize_t_size_op, [val], line) elif is_str_rprimitive(typ): diff --git a/mypyc/irbuild/mapper.py b/mypyc/irbuild/mapper.py index 05aa0e45c569..f308998c9549 100644 --- a/mypyc/irbuild/mapper.py +++ b/mypyc/irbuild/mapper.py @@ -45,6 +45,7 @@ range_rprimitive, set_rprimitive, str_rprimitive, + true_dict_rprimitive, tuple_rprimitive, uint8_rprimitive, ) @@ -154,7 +155,7 @@ def type_to_rtype(self, typ: Type | None) -> RType: elif isinstance(typ, Overloaded): return object_rprimitive elif isinstance(typ, TypedDictType): - return dict_rprimitive + return true_dict_rprimitive elif isinstance(typ, LiteralType): return self.type_to_rtype(typ.fallback) elif isinstance(typ, (UninhabitedType, UnboundType)): @@ -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 true_dict_rprimitive else: return self.type_to_rtype(typ) diff --git a/mypyc/irbuild/match.py b/mypyc/irbuild/match.py index c2ca9cfd32ff..17866ea8c2c6 100644 --- a/mypyc/irbuild/match.py +++ b/mypyc/irbuild/match.py @@ -22,9 +22,9 @@ from mypyc.irbuild.builder import IRBuilder from mypyc.primitives.dict_ops import ( dict_copy, - dict_del_item, mapping_has_key, supports_mapping_protocol, + true_dict_del_item, ) from mypyc.primitives.generic_ops import generic_ssize_t_len_op from mypyc.primitives.list_ops import ( @@ -239,7 +239,7 @@ def visit_mapping_pattern(self, pattern: MappingPattern) -> None: self.builder.assign(target, rest, pattern.rest.line) for i, key_name in enumerate(keys): - self.builder.call_c(dict_del_item, [rest, key_name], pattern.keys[i].line) + self.builder.call_c(true_dict_del_item, [rest, key_name], pattern.keys[i].line) self.builder.goto(self.code_block) diff --git a/mypyc/irbuild/prepare.py b/mypyc/irbuild/prepare.py index 61e3e5b95cf4..978de86f9343 100644 --- a/mypyc/irbuild/prepare.py +++ b/mypyc/irbuild/prepare.py @@ -54,10 +54,10 @@ from mypyc.ir.rtypes import ( RInstance, RType, - dict_rprimitive, none_rprimitive, object_pointer_rprimitive, object_rprimitive, + true_dict_rprimitive, tuple_rprimitive, ) from mypyc.irbuild.mapper import Mapper @@ -626,7 +626,7 @@ def prepare_init_method(cdef: ClassDef, ir: ClassIR, module_name: str, mapper: M [ init_sig.args[0], RuntimeArg("args", tuple_rprimitive, ARG_STAR), - RuntimeArg("kwargs", dict_rprimitive, ARG_STAR2), + RuntimeArg("kwargs", true_dict_rprimitive, ARG_STAR2), ], init_sig.ret_type, ) diff --git a/mypyc/irbuild/specialize.py b/mypyc/irbuild/specialize.py index 0880c62bc7a5..18b51a23b783 100644 --- a/mypyc/irbuild/specialize.py +++ b/mypyc/irbuild/specialize.py @@ -66,10 +66,12 @@ is_int64_rprimitive, is_int_rprimitive, is_list_rprimitive, + is_true_dict_rprimitive, is_uint8_rprimitive, list_rprimitive, set_rprimitive, str_rprimitive, + true_dict_rprimitive, uint8_rprimitive, ) from mypyc.irbuild.builder import IRBuilder @@ -92,6 +94,9 @@ dict_setdefault_spec_init_op, dict_values_op, isinstance_dict, + true_dict_items_op, + true_dict_keys_op, + true_dict_values_op, ) from mypyc.primitives.float_ops import isinstance_float from mypyc.primitives.int_ops import isinstance_int @@ -254,11 +259,22 @@ def dict_methods_fast_path(builder: IRBuilder, expr: CallExpr, callee: RefExpr) # so the corresponding helpers in CPy.h fallback to (inlined) # generic logic. if attr == "keys": - return builder.call_c(dict_keys_op, [obj], expr.line) + if is_true_dict_rprimitive(rtype): + op = true_dict_keys_op + else: + op = dict_keys_op elif attr == "values": - return builder.call_c(dict_values_op, [obj], expr.line) + if is_true_dict_rprimitive(rtype): + op = true_dict_values_op + else: + op = dict_values_op else: - return builder.call_c(dict_items_op, [obj], expr.line) + if is_true_dict_rprimitive(rtype): + op = true_dict_items_op + else: + op = dict_items_op + + return builder.call_c(op, [obj], expr.line) @specialize_function("builtins.list") @@ -367,6 +383,7 @@ def faster_min_max(builder: IRBuilder, expr: CallExpr, callee: RefExpr) -> Value @specialize_function("join", str_rprimitive) @specialize_function("extend", list_rprimitive) @specialize_function("update", dict_rprimitive) +@specialize_function("update", true_dict_rprimitive) @specialize_function("update", set_rprimitive) def translate_safe_generator_call( builder: IRBuilder, expr: CallExpr, callee: RefExpr @@ -608,6 +625,7 @@ def translate_isinstance(builder: IRBuilder, expr: CallExpr, callee: RefExpr) -> @specialize_function("setdefault", dict_rprimitive) +@specialize_function("setdefault", true_dict_rprimitive) def translate_dict_setdefault(builder: IRBuilder, expr: CallExpr, callee: RefExpr) -> Value | None: """Special case for 'dict.setdefault' which would only construct default empty collection when needed. diff --git a/mypyc/lib-rt/CPy.h b/mypyc/lib-rt/CPy.h index 5dec7509ac7b..2e49d67fa5b2 100644 --- a/mypyc/lib-rt/CPy.h +++ b/mypyc/lib-rt/CPy.h @@ -711,6 +711,17 @@ tuple_T3CIO CPyDict_NextValue(PyObject *dict_or_iter, CPyTagged offset); tuple_T4CIOO CPyDict_NextItem(PyObject *dict_or_iter, CPyTagged offset); int CPyMapping_Check(PyObject *obj); +// Unsafe dict operations (assume PyDict_CheckExact(dict) is always true) +int CPyDict_UpdateFromAnyUnsafe(PyObject *dict, PyObject *stuff); +PyObject *CPyDict_GetItemUnsafe(PyObject *dict, PyObject *key); +tuple_T3CIO CPyDict_NextKeyUnsafe(PyObject *dict_or_iter, CPyTagged offset); +tuple_T3CIO CPyDict_NextValueUnsafe(PyObject *dict_or_iter, CPyTagged offset); +tuple_T4CIOO CPyDict_NextItemUnsafe(PyObject *dict_or_iter, CPyTagged offset); +PyObject *CPyDict_KeysViewUnsafe(PyObject *dict); +PyObject *CPyDict_ValuesViewUnsafe(PyObject *dict); +PyObject *CPyDict_ItemsViewUnsafe(PyObject *dict); +PyObject *_CPyDict_GetIterUnsafe(PyObject *dict); + // Check that dictionary didn't change size during iteration. static inline char CPyDict_CheckSize(PyObject *dict, Py_ssize_t size) { if (!PyDict_CheckExact(dict)) { @@ -725,6 +736,25 @@ static inline char CPyDict_CheckSize(PyObject *dict, Py_ssize_t size) { return 1; } +// Unsafe because it assumes dict is actually a dict. +static inline char CPyDict_CheckSizeUnsafe(PyObject *dict, Py_ssize_t size) { + Py_ssize_t dict_size = PyDict_Size(dict); + if (size != dict_size) { + PyErr_SetString(PyExc_RuntimeError, "dictionary changed size during iteration"); + return 0; + } + return 1; +} + + +static inline char CPyDict_IsTrue(PyObject *dict) { + Py_ssize_t size = PyDict_Size(dict); + if (size != 0) { + return 1; + } + return 0; +} + // Str operations diff --git a/mypyc/lib-rt/dict_ops.c b/mypyc/lib-rt/dict_ops.c index b102aba57307..547e8c779c32 100644 --- a/mypyc/lib-rt/dict_ops.c +++ b/mypyc/lib-rt/dict_ops.c @@ -15,15 +15,7 @@ // some indirections. PyObject *CPyDict_GetItem(PyObject *dict, PyObject *key) { if (PyDict_CheckExact(dict)) { - PyObject *res = PyDict_GetItemWithError(dict, key); - if (!res) { - if (!PyErr_Occurred()) { - PyErr_SetObject(PyExc_KeyError, key); - } - } else { - Py_INCREF(res); - } - return res; + return CPyDict_GetItemUnsafe(dict, key); } else { return PyObject_GetItem(dict, key); } @@ -169,12 +161,7 @@ int CPyDict_Update(PyObject *dict, PyObject *stuff) { int CPyDict_UpdateFromAny(PyObject *dict, PyObject *stuff) { if (PyDict_CheckExact(dict)) { // Argh this sucks - _Py_IDENTIFIER(keys); - if (PyDict_Check(stuff) || _CPyObject_HasAttrId(stuff, &PyId_keys)) { - return PyDict_Update(dict, stuff); - } else { - return PyDict_MergeFromSeq2(dict, stuff, 1); - } + return CPyDict_UpdateFromAnyUnsafe(dict, stuff); } else { return CPyDict_UpdateGeneral(dict, stuff); } @@ -348,9 +335,7 @@ PyObject *CPyDict_GetKeysIter(PyObject *dict) { PyObject *CPyDict_GetItemsIter(PyObject *dict) { if (PyDict_CheckExact(dict)) { - // Return dict itself to indicate we can use fast path instead. - Py_INCREF(dict); - return dict; + return _CPyDict_GetIterUnsafe(dict); } _Py_IDENTIFIER(items); PyObject *name = _PyUnicode_FromId(&PyId_items); /* borrowed */ @@ -485,7 +470,108 @@ tuple_T4CIOO CPyDict_NextItem(PyObject *dict_or_iter, CPyTagged offset) { Py_INCREF(ret.f3); return ret; } +tuple_T3CIO CPyDict_NextKeyUnsafe(PyObject *dict_or_iter, CPyTagged offset) { + tuple_T3CIO ret; + Py_ssize_t py_offset = CPyTagged_AsSsize_t(offset); + PyObject *dummy; + + ret.f0 = PyDict_Next(dict_or_iter, &py_offset, &ret.f2, &dummy); + if (ret.f0) { + ret.f1 = CPyTagged_FromSsize_t(py_offset); + } else { + // Set key to None, so mypyc can manage refcounts. + ret.f1 = 0; + ret.f2 = Py_None; + } + // PyDict_Next() returns borrowed references. + Py_INCREF(ret.f2); + return ret; +} + +tuple_T3CIO CPyDict_NextValueUnsafe(PyObject *dict_or_iter, CPyTagged offset) { + tuple_T3CIO ret; + Py_ssize_t py_offset = CPyTagged_AsSsize_t(offset); + PyObject *dummy; + + ret.f0 = PyDict_Next(dict_or_iter, &py_offset, &dummy, &ret.f2); + if (ret.f0) { + ret.f1 = CPyTagged_FromSsize_t(py_offset); + } else { + // Set value to None, so mypyc can manage refcounts. + ret.f1 = 0; + ret.f2 = Py_None; + } + // PyDict_Next() returns borrowed references. + Py_INCREF(ret.f2); + return ret; +} + +tuple_T4CIOO CPyDict_NextItemUnsafe(PyObject *dict_or_iter, CPyTagged offset) { + tuple_T4CIOO ret; + Py_ssize_t py_offset = CPyTagged_AsSsize_t(offset); + + ret.f0 = PyDict_Next(dict_or_iter, &py_offset, &ret.f2, &ret.f3); + if (ret.f0) { + ret.f1 = CPyTagged_FromSsize_t(py_offset); + } else { + // Set key and value to None, so mypyc can manage refcounts. + ret.f1 = 0; + ret.f2 = Py_None; + ret.f3 = Py_None; + } + // PyDict_Next() returns borrowed references. + Py_INCREF(ret.f2); + Py_INCREF(ret.f3); + return ret; +} int CPyMapping_Check(PyObject *obj) { return Py_TYPE(obj)->tp_flags & Py_TPFLAGS_MAPPING; } + +// ======================= +// Unsafe dict operations +// ======================= + +// Unsafe: assumes dict is a true dict (PyDict_CheckExact(dict) is always true) + +int CPyDict_UpdateFromAnyUnsafe(PyObject *dict, PyObject *stuff) { + // Argh this sucks + _Py_IDENTIFIER(keys); + if (PyDict_Check(stuff) || _CPyObject_HasAttrId(stuff, &PyId_keys)) { + return PyDict_Update(dict, stuff); + } else { + return PyDict_MergeFromSeq2(dict, stuff, 1); + } +} + +PyObject *CPyDict_GetItemUnsafe(PyObject *dict, PyObject *key) { + // No type check, direct call + PyObject *res = PyDict_GetItemWithError(dict, key); + if (!res) { + if (!PyErr_Occurred()) { + PyErr_SetObject(PyExc_KeyError, key); + } + } else { + Py_INCREF(res); + } + return res; +} + +PyObject *_CPyDict_GetIterUnsafe(PyObject *dict) { + // No type check, no-op to prepare for fast path. Returns dict to pass directly to fast path for further handling. + Py_INCREF(dict); + return dict; +} + +PyObject *CPyDict_KeysViewUnsafe(PyObject *dict) { + return _CPyDictView_New(dict, &PyDictKeys_Type); +} + +PyObject *CPyDict_ValuesViewUnsafe(PyObject *dict) { + return _CPyDictView_New(dict, &PyDictValues_Type); +} + +PyObject *CPyDict_ItemsViewUnsafe(PyObject *dict) { + return _CPyDictView_New(dict, &PyDictItems_Type); +} diff --git a/mypyc/primitives/bytes_ops.py b/mypyc/primitives/bytes_ops.py index c88e89d1a2ba..c218ad006737 100644 --- a/mypyc/primitives/bytes_ops.py +++ b/mypyc/primitives/bytes_ops.py @@ -14,6 +14,7 @@ list_rprimitive, object_rprimitive, str_rprimitive, + true_dict_rprimitive, ) from mypyc.primitives.registry import ( ERR_NEG_INT, @@ -30,7 +31,7 @@ # bytes(obj) function_op( name="builtins.bytes", - arg_types=[RUnion([list_rprimitive, dict_rprimitive, str_rprimitive])], + arg_types=[RUnion([list_rprimitive, dict_rprimitive, true_dict_rprimitive, str_rprimitive])], return_type=bytes_rprimitive, c_function_name="PyBytes_FromObject", error_kind=ERR_MAGIC, diff --git a/mypyc/primitives/dict_ops.py b/mypyc/primitives/dict_ops.py index f98bcc8ac2ec..7b4e32157247 100644 --- a/mypyc/primitives/dict_ops.py +++ b/mypyc/primitives/dict_ops.py @@ -14,6 +14,7 @@ int_rprimitive, list_rprimitive, object_rprimitive, + true_dict_rprimitive, ) from mypyc.primitives.registry import ( ERR_NEG_INT, @@ -31,14 +32,17 @@ function_op( name="builtins.dict", arg_types=[], - return_type=dict_rprimitive, + return_type=true_dict_rprimitive, c_function_name="PyDict_New", error_kind=ERR_MAGIC, ) # Construct an empty dictionary. dict_new_op = custom_op( - arg_types=[], return_type=dict_rprimitive, c_function_name="PyDict_New", error_kind=ERR_MAGIC + arg_types=[], + return_type=true_dict_rprimitive, + c_function_name="PyDict_New", + error_kind=ERR_MAGIC, ) # Construct a dictionary from keys and values. @@ -46,7 +50,7 @@ # Variable arguments are (key1, value1, ..., keyN, valueN). dict_build_op = custom_op( arg_types=[c_pyssize_t_rprimitive], - return_type=dict_rprimitive, + return_type=true_dict_rprimitive, c_function_name="CPyDict_Build", error_kind=ERR_MAGIC, var_arg_type=object_rprimitive, @@ -54,6 +58,15 @@ # Construct a dictionary from another dictionary. dict_copy_op = function_op( + name="builtins.dict", + arg_types=[true_dict_rprimitive], + return_type=true_dict_rprimitive, + c_function_name="PyDict_Copy", + error_kind=ERR_MAGIC, + priority=2, +) + +function_op( name="builtins.dict", arg_types=[dict_rprimitive], return_type=dict_rprimitive, @@ -66,7 +79,7 @@ dict_copy = function_op( name="builtins.dict", arg_types=[object_rprimitive], - return_type=dict_rprimitive, + return_type=true_dict_rprimitive, c_function_name="CPyDict_FromAny", error_kind=ERR_MAGIC, ) @@ -81,6 +94,15 @@ ) # dict[key] +true_dict_get_item_op = method_op( + name="__getitem__", + arg_types=[true_dict_rprimitive, object_rprimitive], + return_type=object_rprimitive, + c_function_name="CPyDict_GetItemUnsafe", + error_kind=ERR_MAGIC, +) + +# dictsubclass[key] dict_get_item_op = method_op( name="__getitem__", arg_types=[dict_rprimitive, object_rprimitive], @@ -90,6 +112,15 @@ ) # dict[key] = value +true_dict_set_item_op = method_op( + name="__setitem__", + arg_types=[true_dict_rprimitive, object_rprimitive, object_rprimitive], + return_type=c_int_rprimitive, + c_function_name="PyDict_SetItem", + error_kind=ERR_NEG_INT, +) + +# dictsubclass[key] = value dict_set_item_op = method_op( name="__setitem__", arg_types=[dict_rprimitive, object_rprimitive, object_rprimitive], @@ -108,6 +139,17 @@ ) # key in dict +binary_op( + name="in", + arg_types=[object_rprimitive, true_dict_rprimitive], + return_type=c_int_rprimitive, + c_function_name="PyDict_Contains", + error_kind=ERR_NEG_INT, + truncated_type=bool_rprimitive, + ordering=[1, 0], +) + +# key in dict or dict subclass binary_op( name="in", arg_types=[object_rprimitive, dict_rprimitive], @@ -119,6 +161,36 @@ ) # dict1.update(dict2) +true_dict_update_op = method_op( + name="update", + arg_types=[true_dict_rprimitive, true_dict_rprimitive], + return_type=c_int_rprimitive, + c_function_name="PyDict_Update", + error_kind=ERR_NEG_INT, + priority=2, +) + +# dictorsubclass.update(dict) +dict_update_from_true_dict_op = method_op( + name="update", + arg_types=[dict_rprimitive, true_dict_rprimitive], + return_type=c_int_rprimitive, + c_function_name="CPyDict_Update", + error_kind=ERR_NEG_INT, + priority=2, +) + +# dict.update(dictsubclass) +true_dict_update_from_dict_op = method_op( + name="update", + arg_types=[true_dict_rprimitive, dict_rprimitive], + return_type=c_int_rprimitive, + c_function_name="PyDict_Update", + error_kind=ERR_NEG_INT, + priority=2, +) + +# dictsubclass1.update(dictsubclass2) dict_update_op = method_op( name="update", arg_types=[dict_rprimitive, dict_rprimitive], @@ -138,6 +210,15 @@ ) # dict.update(obj) +method_op( + name="update", + arg_types=[true_dict_rprimitive, object_rprimitive], + return_type=c_int_rprimitive, + c_function_name="CPyDict_UpdateFromAnyUnsafe", + error_kind=ERR_NEG_INT, +) + +# dictorsubclass.update(obj) method_op( name="update", arg_types=[dict_rprimitive, object_rprimitive], @@ -147,6 +228,15 @@ ) # dict.get(key, default) +method_op( + name="get", + arg_types=[true_dict_rprimitive, object_rprimitive, object_rprimitive], + return_type=object_rprimitive, + c_function_name="CPyDict_Get", + error_kind=ERR_MAGIC, +) + +# dictorsubclass.get(key, default) method_op( name="get", arg_types=[dict_rprimitive, object_rprimitive, object_rprimitive], @@ -156,6 +246,15 @@ ) # dict.get(key) +true_dict_get_method_with_none = method_op( + name="get", + arg_types=[true_dict_rprimitive, object_rprimitive], + return_type=object_rprimitive, + c_function_name="CPyDict_GetWithNone", + error_kind=ERR_MAGIC, +) + +# dictorsubclass.get(key) dict_get_method_with_none = method_op( name="get", arg_types=[dict_rprimitive, object_rprimitive], @@ -165,6 +264,15 @@ ) # dict.setdefault(key, default) +true_dict_setdefault_op = method_op( + name="setdefault", + arg_types=[true_dict_rprimitive, object_rprimitive, object_rprimitive], + return_type=object_rprimitive, + c_function_name="PyDict_SetDefault", + error_kind=ERR_MAGIC, +) + +# dictorsubclass.setdefault(key, default) dict_setdefault_op = method_op( name="setdefault", arg_types=[dict_rprimitive, object_rprimitive, object_rprimitive], @@ -174,6 +282,15 @@ ) # dict.setdefault(key) +method_op( + name="setdefault", + arg_types=[true_dict_rprimitive, object_rprimitive], + return_type=object_rprimitive, + c_function_name="CPyDict_SetDefaultWithNone", + error_kind=ERR_MAGIC, +) + +# dictorsubclass.setdefault(key) method_op( name="setdefault", arg_types=[dict_rprimitive, object_rprimitive], @@ -194,6 +311,15 @@ ) # dict.keys() +method_op( + name="keys", + arg_types=[true_dict_rprimitive], + return_type=object_rprimitive, + c_function_name="CPyDict_KeysViewUnsafe", + error_kind=ERR_MAGIC, +) + +# dictorsubclass.keys() method_op( name="keys", arg_types=[dict_rprimitive], @@ -203,6 +329,15 @@ ) # dict.values() +method_op( + name="values", + arg_types=[true_dict_rprimitive], + return_type=object_rprimitive, + c_function_name="CPyDict_ValuesViewUnsafe", + error_kind=ERR_MAGIC, +) + +# dictorsubclass.values() method_op( name="values", arg_types=[dict_rprimitive], @@ -212,6 +347,15 @@ ) # dict.items() +method_op( + name="items", + arg_types=[true_dict_rprimitive], + return_type=object_rprimitive, + c_function_name="CPyDict_ItemsViewUnsafe", + error_kind=ERR_MAGIC, +) + +# dictorsubclass.items() method_op( name="items", arg_types=[dict_rprimitive], @@ -221,6 +365,15 @@ ) # dict.clear() +method_op( + name="clear", + arg_types=[true_dict_rprimitive], + return_type=bit_rprimitive, + c_function_name="PyDict_Clear", + error_kind=ERR_FALSE, +) + +# dictsubclass.clear() method_op( name="clear", arg_types=[dict_rprimitive], @@ -230,6 +383,15 @@ ) # dict.copy() +true_dict_copy_op = method_op( + name="copy", + arg_types=[true_dict_rprimitive], + return_type=true_dict_rprimitive, + c_function_name="PyDict_Copy", + error_kind=ERR_MAGIC, +) + +# dictsubclass.copy() method_op( name="copy", arg_types=[dict_rprimitive], @@ -239,30 +401,62 @@ ) # list(dict.keys()) +true_dict_keys_op = custom_op( + arg_types=[true_dict_rprimitive], + return_type=list_rprimitive, + c_function_name="PyDict_Keys", + error_kind=ERR_MAGIC, +) + +# list(dictorsubclass.keys()) dict_keys_op = custom_op( arg_types=[dict_rprimitive], return_type=list_rprimitive, - c_function_name="CPyDict_Keys", + c_function_name="PyDict_Keys", error_kind=ERR_MAGIC, ) # list(dict.values()) +true_dict_values_op = custom_op( + arg_types=[true_dict_rprimitive], + return_type=list_rprimitive, + c_function_name="PyDict_Values", + error_kind=ERR_MAGIC, +) + +# list(dictorsubclass.values()) dict_values_op = custom_op( arg_types=[dict_rprimitive], return_type=list_rprimitive, - c_function_name="CPyDict_Values", + c_function_name="PyDict_Values", error_kind=ERR_MAGIC, ) # list(dict.items()) +true_dict_items_op = custom_op( + arg_types=[true_dict_rprimitive], + return_type=list_rprimitive, + c_function_name="PyDict_Items", + error_kind=ERR_MAGIC, +) + +# list(dictorsubclass.items()) dict_items_op = custom_op( arg_types=[dict_rprimitive], return_type=list_rprimitive, - c_function_name="CPyDict_Items", + c_function_name="PyDict_Items", error_kind=ERR_MAGIC, ) # PyDict_Next() fast iteration +true_dict_iter_fast_path_op = custom_op( + arg_types=[true_dict_rprimitive], + return_type=true_dict_rprimitive, + c_function_name="_CPyDict_GetIterUnsafe", + error_kind=ERR_MAGIC, +) + +# PyDict_Next() fast iteration for subclass dict_key_iter_op = custom_op( arg_types=[dict_rprimitive], return_type=object_rprimitive, @@ -305,7 +499,36 @@ error_kind=ERR_NEVER, ) +true_dict_next_key_op = custom_op( + arg_types=[object_rprimitive, int_rprimitive], + return_type=dict_next_rtuple_single, + c_function_name="CPyDict_NextKeyUnsafe", + error_kind=ERR_NEVER, +) + +true_dict_next_value_op = custom_op( + arg_types=[object_rprimitive, int_rprimitive], + return_type=dict_next_rtuple_single, + c_function_name="CPyDict_NextValueUnsafe", + error_kind=ERR_NEVER, +) + +true_dict_next_item_op = custom_op( + arg_types=[true_dict_rprimitive, int_rprimitive], + return_type=dict_next_rtuple_pair, + c_function_name="CPyDict_NextItemUnsafe", + error_kind=ERR_NEVER, +) + # check that len(dict) == const during iteration +true_dict_check_size_op = custom_op( + arg_types=[true_dict_rprimitive, c_pyssize_t_rprimitive], + return_type=bit_rprimitive, + c_function_name="CPyDict_CheckSizeUnsafe", + error_kind=ERR_FALSE, +) + +# check that len(dictorsubclass) == const during iteration dict_check_size_op = custom_op( arg_types=[dict_rprimitive, c_pyssize_t_rprimitive], return_type=bit_rprimitive, @@ -313,6 +536,13 @@ error_kind=ERR_FALSE, ) +true_dict_ssize_t_size_op = custom_op( + arg_types=[true_dict_rprimitive], + return_type=c_pyssize_t_rprimitive, + c_function_name="PyDict_Size", + error_kind=ERR_NEVER, +) + dict_ssize_t_size_op = custom_op( arg_types=[dict_rprimitive], return_type=c_pyssize_t_rprimitive, @@ -321,6 +551,13 @@ ) # Delete an item from a dict +true_dict_del_item = custom_op( + arg_types=[true_dict_rprimitive, object_rprimitive], + return_type=c_int_rprimitive, + c_function_name="PyDict_DelItem", + error_kind=ERR_NEG_INT, +) + dict_del_item = custom_op( arg_types=[object_rprimitive, object_rprimitive], return_type=c_int_rprimitive, diff --git a/mypyc/primitives/misc_ops.py b/mypyc/primitives/misc_ops.py index 8e6e450c64dc..83ddf5466c8b 100644 --- a/mypyc/primitives/misc_ops.py +++ b/mypyc/primitives/misc_ops.py @@ -20,6 +20,7 @@ object_rprimitive, pointer_rprimitive, str_rprimitive, + true_dict_rprimitive, uint8_rprimitive, void_rtype, ) @@ -161,7 +162,7 @@ # Get the sys.modules dictionary get_module_dict_op = custom_op( arg_types=[], - return_type=dict_rprimitive, + return_type=true_dict_rprimitive, c_function_name="PyImport_GetModuleDict", error_kind=ERR_NEVER, is_borrowed=True, @@ -188,6 +189,15 @@ priority=0, ) +# bool(dict) +dict_is_true_op = function_op( + name="builtins.bool", + arg_types=[true_dict_rprimitive], + return_type=bit_rprimitive, + c_function_name="CPyDict_IsTrue", + error_kind=ERR_FALSE, +) + # bool(obj) with unboxed result bool_op = function_op( name="builtins.bool", diff --git a/mypyc/test-data/irbuild-basic.test b/mypyc/test-data/irbuild-basic.test index 612f3266fd79..6957933af372 100644 --- a/mypyc/test-data/irbuild-basic.test +++ b/mypyc/test-data/irbuild-basic.test @@ -526,11 +526,11 @@ def __top_level__(): r11 :: native_int[4] r12 :: c_ptr r13 :: object - r14 :: dict + r14 :: dict[confirmed] r15, r16 :: str r17 :: bit r18 :: str - r19 :: dict + r19 :: dict[confirmed] r20 :: str r21 :: i32 r22 :: bit @@ -540,7 +540,7 @@ def __top_level__(): r26 :: native_int[1] r27 :: c_ptr r28 :: object - r29 :: dict + r29 :: dict[confirmed] r30, r31 :: str r32 :: bit r33 :: object @@ -572,7 +572,7 @@ L2: r18 = 'filler' r19 = __main__.globals :: static r20 = '_' - r21 = CPyDict_SetItem(r19, r20, r18) + r21 = PyDict_SetItem(r19, r20, r18) r22 = r21 >= 0 :: signed r23 = load_address single :: module r24 = [r23] @@ -604,25 +604,25 @@ def h() -> int: [out] def f(x): x :: int - r0 :: dict + r0 :: dict[confirmed] r1 :: str r2, r3 :: object r4 :: object[1] r5 :: object_ptr r6 :: object r7 :: int - r8 :: dict + r8 :: dict[confirmed] r9 :: str r10, r11 :: object r12, r13 :: int - r14 :: dict + r14 :: dict[confirmed] r15 :: str r16, r17 :: object r18, r19 :: int L0: r0 = __main__.globals :: static r1 = 'g' - r2 = CPyDict_GetItem(r0, r1) + r2 = CPyDict_GetItemUnsafe(r0, r1) r3 = box(int, x) r4 = [r3] r5 = load_address r4 @@ -631,13 +631,13 @@ L0: r7 = unbox(int, r6) r8 = __main__.globals :: static r9 = 'h' - r10 = CPyDict_GetItem(r8, r9) + r10 = CPyDict_GetItemUnsafe(r8, r9) r11 = PyObject_Vectorcall(r10, 0, 0, 0) r12 = unbox(int, r11) r13 = CPyTagged_Add(r7, r12) r14 = __main__.globals :: static r15 = 'two' - r16 = CPyDict_GetItem(r14, r15) + r16 = CPyDict_GetItemUnsafe(r14, r15) r17 = PyObject_Vectorcall(r16, 0, 0, 0) r18 = unbox(int, r17) r19 = CPyTagged_Add(r13, r18) @@ -648,10 +648,10 @@ def __top_level__(): r3 :: str r4, r5 :: object r6 :: str - r7 :: dict + r7 :: dict[confirmed] r8, r9, r10 :: object r11 :: str - r12 :: dict + r12 :: dict[confirmed] r13 :: object L0: r0 = builtins :: module @@ -1137,7 +1137,7 @@ L0: return r0 def call_python_function(x): x :: int - r0 :: dict + r0 :: dict[confirmed] r1 :: str r2, r3 :: object r4 :: object[1] @@ -1147,7 +1147,7 @@ def call_python_function(x): L0: r0 = __main__.globals :: static r1 = 'f' - r2 = CPyDict_GetItem(r0, r1) + r2 = CPyDict_GetItemUnsafe(r0, r1) r3 = box(int, x) r4 = [r3] r5 = load_address r4 @@ -1159,13 +1159,13 @@ def return_float(): L0: return 5.0 def return_callable_type(): - r0 :: dict + r0 :: dict[confirmed] r1 :: str r2 :: object L0: r0 = __main__.globals :: static r1 = 'return_float' - r2 = CPyDict_GetItem(r0, r1) + r2 = CPyDict_GetItemUnsafe(r0, r1) return r2 def call_callable_type(): r0, f, r1 :: object @@ -1423,7 +1423,7 @@ def f() -> None: print(x) [out] def f(): - r0 :: dict + r0 :: dict[confirmed] r1 :: str r2 :: object r3 :: int @@ -1436,7 +1436,7 @@ def f(): L0: r0 = __main__.globals :: static r1 = 'x' - r2 = CPyDict_GetItem(r0, r1) + r2 = CPyDict_GetItemUnsafe(r0, r1) r3 = unbox(int, r2) r4 = builtins :: module r5 = 'print' @@ -1452,12 +1452,12 @@ def __top_level__(): r2 :: bit r3 :: str r4 :: object - r5 :: dict + r5 :: dict[confirmed] r6 :: str r7 :: object r8 :: i32 r9 :: bit - r10 :: dict + r10 :: dict[confirmed] r11 :: str r12 :: object r13 :: int @@ -1480,11 +1480,11 @@ L2: r5 = __main__.globals :: static r6 = 'x' r7 = object 1 - r8 = CPyDict_SetItem(r5, r6, r7) + r8 = PyDict_SetItem(r5, r6, r7) r9 = r8 >= 0 :: signed r10 = __main__.globals :: static r11 = 'x' - r12 = CPyDict_GetItem(r10, r11) + r12 = CPyDict_GetItemUnsafe(r10, r11) r13 = unbox(int, r12) r14 = builtins :: module r15 = 'print' @@ -1672,7 +1672,7 @@ L0: return r0 def g(): r0 :: tuple[int, int, int] - r1 :: dict + r1 :: dict[confirmed] r2 :: str r3, r4, r5 :: object r6 :: tuple[int, int, int] @@ -1687,7 +1687,7 @@ L0: return r6 def h(): r0 :: tuple[int, int] - r1 :: dict + r1 :: dict[confirmed] r2 :: str r3 :: object r4 :: list @@ -1701,7 +1701,7 @@ L0: r0 = (4, 6) r1 = __main__.globals :: static r2 = 'f' - r3 = CPyDict_GetItem(r1, r2) + r3 = CPyDict_GetItemUnsafe(r1, r2) r4 = PyList_New(1) r5 = object 1 r6 = list_items r4 @@ -1758,33 +1758,38 @@ L0: def h(): r0, r1 :: str r2, r3 :: object - r4, r5 :: dict - r6 :: str - r7 :: object - r8 :: dict - r9 :: i32 - r10 :: bit - r11 :: object - r12 :: tuple + r4 :: dict[confirmed] + r5 :: dict + r6 :: dict[confirmed] + r7 :: str + r8 :: object + r9 :: dict[confirmed] + r10 :: dict + r11 :: i32 + r12 :: bit r13 :: object - r14 :: tuple[int, int, int] + r14 :: tuple + r15 :: object + r16 :: tuple[int, int, int] L0: r0 = 'b' r1 = 'c' r2 = object 2 r3 = object 3 r4 = CPyDict_Build(2, r0, r2, r1, r3) - r5 = __main__.globals :: static - r6 = 'f' - r7 = CPyDict_GetItem(r5, r6) - r8 = PyDict_New() - r9 = CPyDict_UpdateInDisplay(r8, r4) - r10 = r9 >= 0 :: signed - r11 = object 1 - r12 = PyTuple_Pack(1, r11) - r13 = PyObject_Call(r7, r12, r8) - r14 = unbox(tuple[int, int, int], r13) - return r14 + r5 = cast(dict, r4) + r6 = __main__.globals :: static + r7 = 'f' + r8 = CPyDict_GetItemUnsafe(r6, r7) + r9 = PyDict_New() + r10 = cast(dict, r9) + r11 = CPyDict_UpdateInDisplay(r10, r5) + r12 = r11 >= 0 :: signed + r13 = object 1 + r14 = PyTuple_Pack(1, r13) + r15 = PyObject_Call(r8, r14, r9) + r16 = unbox(tuple[int, int, int], r15) + return r16 [case testFunctionCallWithDefaultArgs] def f(x: int, y: int = 3, z: str = "test") -> None: @@ -1931,7 +1936,7 @@ def f() -> Dict[int, int]: return {x: x*x for x in [1,2,3] if x != 2 if x != 3} [out] def f(): - r0 :: dict + r0 :: dict[confirmed] r1 :: list r2, r3, r4 :: object r5 :: ptr @@ -1945,6 +1950,7 @@ def f(): r16 :: i32 r17 :: bit r18 :: native_int + r19 :: dict L0: r0 = PyDict_New() r1 = PyList_New(3) @@ -1985,7 +1991,8 @@ L7: r6 = r18 goto L1 L8: - return r0 + r19 = cast(dict, r0) + return r19 [case testLoopsMultipleAssign] from typing import List, Tuple @@ -2149,7 +2156,7 @@ def __top_level__(): r3 :: str r4, r5 :: object r6 :: str - r7 :: dict + r7 :: dict[confirmed] r8 :: object r9, r10 :: str r11 :: object @@ -2161,53 +2168,53 @@ def __top_level__(): r17 :: object r18 :: tuple[object, object] r19 :: object - r20 :: dict + r20 :: dict[confirmed] r21 :: str r22 :: object r23 :: object[2] r24 :: object_ptr r25 :: object - r26 :: dict + r26 :: dict[confirmed] r27 :: str r28 :: i32 r29 :: bit r30 :: str - r31 :: dict + r31 :: dict[confirmed] r32 :: str r33, r34 :: object r35 :: object[2] r36 :: object_ptr r37 :: object r38 :: tuple - r39 :: dict + r39 :: dict[confirmed] r40 :: str r41 :: i32 r42 :: bit - r43 :: dict + r43 :: dict[confirmed] r44 :: str r45, r46, r47 :: object - r48 :: dict + r48 :: dict[confirmed] r49 :: str r50 :: i32 r51 :: bit r52 :: str - r53 :: dict + r53 :: dict[confirmed] r54 :: str r55 :: object - r56 :: dict + r56 :: dict[confirmed] r57 :: str r58 :: object r59 :: object[2] r60 :: object_ptr r61 :: object - r62 :: dict + r62 :: dict[confirmed] r63 :: str r64 :: i32 r65 :: bit r66 :: list r67, r68, r69 :: object r70 :: ptr - r71 :: dict + r71 :: dict[confirmed] r72 :: str r73 :: i32 r74 :: bit @@ -2239,19 +2246,19 @@ L2: r19 = box(tuple[object, object], r18) r20 = __main__.globals :: static r21 = 'NamedTuple' - r22 = CPyDict_GetItem(r20, r21) + r22 = CPyDict_GetItemUnsafe(r20, r21) r23 = [r9, r19] r24 = load_address r23 r25 = PyObject_Vectorcall(r22, r24, 2, 0) keep_alive r9, r19 r26 = __main__.globals :: static r27 = 'Lol' - r28 = CPyDict_SetItem(r26, r27, r25) + r28 = PyDict_SetItem(r26, r27, r25) r29 = r28 >= 0 :: signed r30 = '' r31 = __main__.globals :: static r32 = 'Lol' - r33 = CPyDict_GetItem(r31, r32) + r33 = CPyDict_GetItemUnsafe(r31, r32) r34 = object 1 r35 = [r34, r30] r36 = load_address r35 @@ -2260,31 +2267,31 @@ L2: r38 = cast(tuple, r37) r39 = __main__.globals :: static r40 = 'x' - r41 = CPyDict_SetItem(r39, r40, r38) + r41 = PyDict_SetItem(r39, r40, r38) r42 = r41 >= 0 :: signed r43 = __main__.globals :: static r44 = 'List' - r45 = CPyDict_GetItem(r43, r44) + r45 = CPyDict_GetItemUnsafe(r43, r44) r46 = load_address PyLong_Type r47 = PyObject_GetItem(r45, r46) r48 = __main__.globals :: static r49 = 'Foo' - r50 = CPyDict_SetItem(r48, r49, r47) + r50 = PyDict_SetItem(r48, r49, r47) r51 = r50 >= 0 :: signed r52 = 'Bar' r53 = __main__.globals :: static r54 = 'Foo' - r55 = CPyDict_GetItem(r53, r54) + r55 = CPyDict_GetItemUnsafe(r53, r54) r56 = __main__.globals :: static r57 = 'NewType' - r58 = CPyDict_GetItem(r56, r57) + r58 = CPyDict_GetItemUnsafe(r56, r57) r59 = [r52, r55] r60 = load_address r59 r61 = PyObject_Vectorcall(r58, r60, 2, 0) keep_alive r52, r55 r62 = __main__.globals :: static r63 = 'Bar' - r64 = CPyDict_SetItem(r62, r63, r61) + r64 = PyDict_SetItem(r62, r63, r61) r65 = r64 >= 0 :: signed r66 = PyList_New(3) r67 = object 1 @@ -2297,7 +2304,7 @@ L2: keep_alive r66 r71 = __main__.globals :: static r72 = 'y' - r73 = CPyDict_SetItem(r71, r72, r66) + r73 = PyDict_SetItem(r71, r72, r66) r74 = r73 >= 0 :: signed return 1 @@ -2581,19 +2588,19 @@ def c(): r0 :: __main__.c_env r1 :: __main__.d_c_obj r2 :: bool - r3 :: dict + r3 :: dict[confirmed] r4 :: str r5 :: object r6 :: object[1] r7 :: object_ptr r8 :: object - r9 :: dict + r9 :: dict[confirmed] r10 :: str r11 :: object r12 :: object[1] r13 :: object_ptr r14, d :: object - r15 :: dict + r15 :: dict[confirmed] r16 :: str r17 :: i32 r18 :: bit @@ -2610,14 +2617,14 @@ L0: r1.__mypyc_env__ = r0; r2 = is_error r3 = __main__.globals :: static r4 = 'b' - r5 = CPyDict_GetItem(r3, r4) + r5 = CPyDict_GetItemUnsafe(r3, r4) r6 = [r1] r7 = load_address r6 r8 = PyObject_Vectorcall(r5, r7, 1, 0) keep_alive r1 r9 = __main__.globals :: static r10 = 'a' - r11 = CPyDict_GetItem(r9, r10) + r11 = CPyDict_GetItemUnsafe(r9, r10) r12 = [r8] r13 = load_address r12 r14 = PyObject_Vectorcall(r11, r13, 1, 0) @@ -2643,24 +2650,24 @@ def __top_level__(): r3 :: str r4, r5 :: object r6 :: str - r7 :: dict + r7 :: dict[confirmed] r8 :: object - r9 :: dict + r9 :: dict[confirmed] r10 :: str r11 :: object - r12 :: dict + r12 :: dict[confirmed] r13 :: str r14 :: object r15 :: object[1] r16 :: object_ptr r17 :: object - r18 :: dict + r18 :: dict[confirmed] r19 :: str r20 :: object r21 :: object[1] r22 :: object_ptr r23 :: object - r24 :: dict + r24 :: dict[confirmed] r25 :: str r26 :: i32 r27 :: bit @@ -2681,17 +2688,17 @@ L2: typing = r8 :: module r9 = __main__.globals :: static r10 = 'c' - r11 = CPyDict_GetItem(r9, r10) + r11 = CPyDict_GetItemUnsafe(r9, r10) r12 = __main__.globals :: static r13 = 'b' - r14 = CPyDict_GetItem(r12, r13) + r14 = CPyDict_GetItemUnsafe(r12, r13) r15 = [r11] r16 = load_address r15 r17 = PyObject_Vectorcall(r14, r16, 1, 0) keep_alive r11 r18 = __main__.globals :: static r19 = 'a' - r20 = CPyDict_GetItem(r18, r19) + r20 = CPyDict_GetItemUnsafe(r18, r19) r21 = [r17] r22 = load_address r21 r23 = PyObject_Vectorcall(r20, r22, 1, 0) @@ -2784,7 +2791,7 @@ def __top_level__(): r3 :: str r4, r5 :: object r6 :: str - r7 :: dict + r7 :: dict[confirmed] r8 :: object L0: r0 = builtins :: module @@ -3284,24 +3291,24 @@ x = 1 [file p/m.py] [out] def root(): - r0 :: dict + r0 :: dict[confirmed] r1, r2 :: object r3 :: bit r4 :: str r5 :: object r6 :: str - r7 :: dict + r7 :: dict[confirmed] r8 :: str r9 :: object r10 :: i32 r11 :: bit - r12 :: dict + r12 :: dict[confirmed] r13, r14 :: object r15 :: bit r16 :: str r17 :: object r18 :: str - r19 :: dict + r19 :: dict[confirmed] r20 :: str r21 :: object r22 :: i32 @@ -3320,8 +3327,8 @@ L2: r6 = 'dataclasses' r7 = PyImport_GetModuleDict() r8 = 'dataclasses' - r9 = CPyDict_GetItem(r7, r8) - r10 = CPyDict_SetItem(r0, r6, r9) + r9 = CPyDict_GetItemUnsafe(r7, r8) + r10 = PyDict_SetItem(r0, r6, r9) r11 = r10 >= 0 :: signed r12 = __main__.globals :: static r13 = enum :: module @@ -3336,23 +3343,23 @@ L4: r18 = 'enum' r19 = PyImport_GetModuleDict() r20 = 'enum' - r21 = CPyDict_GetItem(r19, r20) - r22 = CPyDict_SetItem(r12, r18, r21) + r21 = CPyDict_GetItemUnsafe(r19, r20) + r22 = PyDict_SetItem(r12, r18, r21) r23 = r22 >= 0 :: signed return 1 def submodule(): - r0 :: dict + r0 :: dict[confirmed] r1, r2 :: object r3 :: bit r4 :: str r5 :: object r6 :: str - r7 :: dict + r7 :: dict[confirmed] r8 :: str r9 :: object r10 :: i32 r11 :: bit - r12 :: dict + r12 :: dict[confirmed] r13 :: str r14 :: object r15 :: str @@ -3372,12 +3379,12 @@ L2: r6 = 'p' r7 = PyImport_GetModuleDict() r8 = 'p' - r9 = CPyDict_GetItem(r7, r8) - r10 = CPyDict_SetItem(r0, r6, r9) + r9 = CPyDict_GetItemUnsafe(r7, r8) + r10 = PyDict_SetItem(r0, r6, r9) r11 = r10 >= 0 :: signed r12 = PyImport_GetModuleDict() r13 = 'p' - r14 = CPyDict_GetItem(r12, r13) + r14 = CPyDict_GetItemUnsafe(r12, r13) r15 = 'x' r16 = CPyObject_GetAttr(r14, r15) r17 = unbox(int, r16) diff --git a/mypyc/test-data/irbuild-bool.test b/mypyc/test-data/irbuild-bool.test index 5eac6d8db24f..fa209186b09c 100644 --- a/mypyc/test-data/irbuild-bool.test +++ b/mypyc/test-data/irbuild-bool.test @@ -59,13 +59,17 @@ L0: return r1 [case testConversionToBool] -from typing import List, Optional +from typing import List, Optional, TypedDict class C: pass class D: def __bool__(self) -> bool: return True +class E(TypedDict): + a: str + b: int + def list_to_bool(l: List[str]) -> bool: return bool(l) @@ -80,6 +84,10 @@ def optional_truthy_to_bool(o: Optional[C]) -> bool: def optional_maybe_falsey_to_bool(o: Optional[D]) -> bool: return bool(o) + +def typeddict_to_bool(o: E) -> bool: + return bool(o) +[typing fixtures/typing-full.pyi] [out] def D.__bool__(self): self :: __main__.D @@ -139,6 +147,12 @@ L2: r4 = 0 L3: return r4 +def typeddict_to_bool(o): + o :: dict[confirmed] + r0 :: bit +L0: + r0 = CPyDict_IsTrue(o) + return r0 [case testBoolComparisons] def eq(x: bool, y: bool) -> bool: diff --git a/mypyc/test-data/irbuild-classes.test b/mypyc/test-data/irbuild-classes.test index 78ca7b68cefb..cdc467008929 100644 --- a/mypyc/test-data/irbuild-classes.test +++ b/mypyc/test-data/irbuild-classes.test @@ -201,19 +201,19 @@ def __top_level__(): r3 :: str r4, r5 :: object r6 :: str - r7 :: dict + r7 :: dict[confirmed] r8, r9 :: object r10 :: str - r11 :: dict + r11 :: dict[confirmed] r12 :: object r13 :: str - r14 :: dict + r14 :: dict[confirmed] r15 :: str r16 :: object r17 :: object[1] r18 :: object_ptr r19 :: object - r20 :: dict + r20 :: dict[confirmed] r21 :: str r22 :: i32 r23 :: bit @@ -225,7 +225,7 @@ def __top_level__(): r30 :: tuple r31 :: i32 r32 :: bit - r33 :: dict + r33 :: dict[confirmed] r34 :: str r35 :: i32 r36 :: bit @@ -236,15 +236,15 @@ def __top_level__(): r42 :: tuple r43 :: i32 r44 :: bit - r45 :: dict + r45 :: dict[confirmed] r46 :: str r47 :: i32 r48 :: bit r49, r50 :: object - r51 :: dict + r51 :: dict[confirmed] r52 :: str r53 :: object - r54 :: dict + r54 :: dict[confirmed] r55 :: str r56, r57 :: object r58 :: tuple @@ -255,7 +255,7 @@ def __top_level__(): r65 :: tuple r66 :: i32 r67 :: bit - r68 :: dict + r68 :: dict[confirmed] r69 :: str r70 :: i32 r71 :: bit @@ -282,14 +282,14 @@ L2: r13 = 'T' r14 = __main__.globals :: static r15 = 'TypeVar' - r16 = CPyDict_GetItem(r14, r15) + r16 = CPyDict_GetItemUnsafe(r14, r15) r17 = [r13] r18 = load_address r17 r19 = PyObject_Vectorcall(r16, r18, 1, 0) keep_alive r13 r20 = __main__.globals :: static r21 = 'T' - r22 = CPyDict_SetItem(r20, r21, r19) + r22 = PyDict_SetItem(r20, r21, r19) r23 = r22 >= 0 :: signed r24 = :: object r25 = '__main__' @@ -322,10 +322,10 @@ L2: r50 = __main__.S :: type r51 = __main__.globals :: static r52 = 'Generic' - r53 = CPyDict_GetItem(r51, r52) + r53 = CPyDict_GetItemUnsafe(r51, r52) r54 = __main__.globals :: static r55 = 'T' - r56 = CPyDict_GetItem(r54, r55) + r56 = CPyDict_GetItemUnsafe(r54, r55) r57 = PyObject_GetItem(r53, r56) r58 = PyTuple_Pack(3, r49, r50, r57) r59 = '__main__' @@ -1064,7 +1064,7 @@ L0: return 1 def B.__mypyc_defaults_setup(__mypyc_self__): __mypyc_self__ :: __main__.B - r0 :: dict + r0 :: dict[confirmed] r1 :: str r2 :: object r3 :: str @@ -1073,7 +1073,7 @@ L0: __mypyc_self__.x = 20 r0 = __main__.globals :: static r1 = 'LOL' - r2 = CPyDict_GetItem(r0, r1) + r2 = CPyDict_GetItemUnsafe(r0, r1) r3 = cast(str, r2) __mypyc_self__.y = r3 r4 = box(None, 1) diff --git a/mypyc/test-data/irbuild-dict.test b/mypyc/test-data/irbuild-dict.test index e0c014f07813..1233ee02bd3b 100644 --- a/mypyc/test-data/irbuild-dict.test +++ b/mypyc/test-data/irbuild-dict.test @@ -36,10 +36,12 @@ def f() -> None: d = {} # type: Dict[bool, int] [out] def f(): - r0, d :: dict + r0 :: dict[confirmed] + r1, d :: dict L0: r0 = PyDict_New() - d = r0 + r1 = cast(dict, r0) + d = r1 return 1 [case testNewEmptyDictViaFunc] @@ -49,10 +51,12 @@ def f() -> None: [out] def f(): - r0, d :: dict + r0 :: dict[confirmed] + r1, d :: dict L0: r0 = PyDict_New() - d = r0 + r1 = cast(dict, r0) + d = r1 return 1 [case testNewDictWithValues] @@ -63,13 +67,15 @@ def f(x): x :: object r0 :: str r1, r2 :: object - r3, d :: dict + r3 :: dict[confirmed] + r4, d :: dict L0: r0 = '' r1 = object 1 r2 = object 2 r3 = CPyDict_Build(2, r1, r2, r0, x) - d = r3 + r4 = cast(dict, r3) + d = r4 return 1 [case testInDict] @@ -198,22 +204,26 @@ def f(x, y): y :: dict r0 :: str r1 :: object - r2 :: dict - r3 :: i32 - r4 :: bit - r5 :: object - r6 :: i32 - r7 :: bit + r2 :: dict[confirmed] + r3 :: dict + r4 :: i32 + r5 :: bit + r6 :: object + r7 :: i32 + r8 :: bit + r9 :: dict L0: r0 = 'z' r1 = object 2 r2 = CPyDict_Build(1, x, r1) - r3 = CPyDict_UpdateInDisplay(r2, y) - r4 = r3 >= 0 :: signed - r5 = object 3 - r6 = CPyDict_SetItem(r2, r0, r5) - r7 = r6 >= 0 :: signed - return r2 + r3 = cast(dict, r2) + r4 = CPyDict_UpdateInDisplay(r3, y) + r5 = r4 >= 0 :: signed + r6 = object 3 + r7 = PyDict_SetItem(r2, r0, r6) + r8 = r7 >= 0 :: signed + r9 = cast(dict, r2) + return r9 [case testDictIterationMethods] from typing import Dict, TypedDict, Union @@ -323,66 +333,69 @@ L11: L12: return 1 def union_of_dicts(d): - d, r0, new :: dict - r1 :: short_int - r2 :: native_int - r3 :: object - r4 :: tuple[bool, short_int, object, object] - r5 :: short_int - r6 :: bool - r7, r8 :: object - r9 :: str - r10 :: union[int, str] + d :: dict + r0 :: dict[confirmed] + r1, new :: dict + r2 :: short_int + r3 :: native_int + r4 :: object + r5 :: tuple[bool, short_int, object, object] + r6 :: short_int + r7 :: bool + r8, r9 :: object + r10 :: str + r11 :: union[int, str] k :: str v :: union[int, str] - r11 :: object - r12 :: object[1] - r13 :: object_ptr - r14 :: object - r15 :: int - r16 :: object - r17 :: i32 - r18, r19, r20 :: bit + r12 :: object + r13 :: object[1] + r14 :: object_ptr + r15 :: object + r16 :: int + r17 :: object + r18 :: i32 + r19, r20, r21 :: bit L0: r0 = PyDict_New() - new = r0 - r1 = 0 - r2 = PyDict_Size(d) - r3 = CPyDict_GetItemsIter(d) + r1 = cast(dict, r0) + new = r1 + r2 = 0 + r3 = PyDict_Size(d) + r4 = CPyDict_GetItemsIter(d) L1: - r4 = CPyDict_NextItem(r3, r1) - r5 = r4[1] - r1 = r5 - r6 = r4[0] - if r6 goto L2 else goto L4 :: bool + r5 = CPyDict_NextItem(r4, r2) + r6 = r5[1] + r2 = r6 + r7 = r5[0] + if r7 goto L2 else goto L4 :: bool L2: - r7 = r4[2] - r8 = r4[3] - r9 = cast(str, r7) - r10 = cast(union[int, str], r8) - k = r9 - v = r10 - r11 = load_address PyLong_Type - r12 = [v] - r13 = load_address r12 - r14 = PyObject_Vectorcall(r11, r13, 1, 0) + r8 = r5[2] + r9 = r5[3] + r10 = cast(str, r8) + r11 = cast(union[int, str], r9) + k = r10 + v = r11 + r12 = load_address PyLong_Type + r13 = [v] + r14 = load_address r13 + r15 = PyObject_Vectorcall(r12, r14, 1, 0) keep_alive v - r15 = unbox(int, r14) - r16 = box(int, r15) - r17 = CPyDict_SetItem(new, k, r16) - r18 = r17 >= 0 :: signed + r16 = unbox(int, r15) + r17 = box(int, r16) + r18 = CPyDict_SetItem(new, k, r17) + r19 = r18 >= 0 :: signed L3: - r19 = CPyDict_CheckSize(d, r2) + r20 = CPyDict_CheckSize(d, r3) goto L1 L4: - r20 = CPy_NoErrOccurred() + r21 = CPy_NoErrOccurred() L5: return 1 def typeddict(d): - d :: dict + d :: dict[confirmed] r0 :: short_int r1 :: native_int - r2 :: object + r2 :: dict[confirmed] r3 :: tuple[bool, short_int, object, object] r4 :: short_int r5 :: bool @@ -396,9 +409,9 @@ def typeddict(d): L0: r0 = 0 r1 = PyDict_Size(d) - r2 = CPyDict_GetItemsIter(d) + r2 = _CPyDict_GetIterUnsafe(d) L1: - r3 = CPyDict_NextItem(r2, r0) + r3 = CPyDict_NextItemUnsafe(r2, r0) r4 = r3[1] r0 = r4 r5 = r3[0] @@ -416,7 +429,7 @@ L3: name = v L4: L5: - r11 = CPyDict_CheckSize(d, r1) + r11 = CPyDict_CheckSizeUnsafe(d, r1) goto L1 L6: r12 = CPy_NoErrOccurred() @@ -547,8 +560,9 @@ def f4(d, flag): r1 :: object r2, r3 :: str r4 :: object - r5 :: dict - r6, r7 :: object + r5 :: dict[confirmed] + r6 :: dict + r7, r8 :: object L0: if flag goto L1 else goto L2 :: bool L1: @@ -560,8 +574,9 @@ L2: r3 = 'c' r4 = object 1 r5 = CPyDict_Build(1, r3, r4) - r6 = CPyDict_SetDefault(d, r2, r5) - return r6 -L3: - r7 = box(None, 1) + r6 = cast(dict, r5) + r7 = CPyDict_SetDefault(d, r2, r6) return r7 +L3: + r8 = box(None, 1) + return r8 diff --git a/mypyc/test-data/irbuild-generics.test b/mypyc/test-data/irbuild-generics.test index 9ec29182e89b..04d9729c246b 100644 --- a/mypyc/test-data/irbuild-generics.test +++ b/mypyc/test-data/irbuild-generics.test @@ -246,7 +246,7 @@ def fn_mapping(m): r35, x_3 :: str r36 :: i32 r37, r38, r39 :: bit - r40 :: dict + r40 :: dict[confirmed] r41 :: short_int r42 :: native_int r43 :: object @@ -391,7 +391,7 @@ def fn_union(m): r34, x_3 :: str r35 :: i32 r36, r37, r38 :: bit - r39 :: dict + r39 :: dict[confirmed] r40 :: short_int r41 :: native_int r42 :: object @@ -499,11 +499,11 @@ L19: L20: return 1 def fn_typeddict(t): - t :: dict + t :: dict[confirmed] r0 :: list r1 :: short_int r2 :: native_int - r3 :: object + r3 :: dict[confirmed] r4 :: tuple[bool, short_int, object] r5 :: short_int r6 :: bool @@ -514,7 +514,7 @@ def fn_typeddict(t): r13 :: list r14 :: short_int r15 :: native_int - r16 :: object + r16 :: dict[confirmed] r17 :: tuple[bool, short_int, object] r18 :: short_int r19 :: bool @@ -524,7 +524,7 @@ def fn_typeddict(t): r25 :: set r26 :: short_int r27 :: native_int - r28 :: object + r28 :: dict[confirmed] r29 :: tuple[bool, short_int, object] r30 :: short_int r31 :: bool @@ -532,10 +532,10 @@ def fn_typeddict(t): r33, x_3 :: str r34 :: i32 r35, r36, r37 :: bit - r38 :: dict + r38 :: dict[confirmed] r39 :: short_int r40 :: native_int - r41 :: object + r41 :: dict[confirmed] r42 :: tuple[bool, short_int, object, object] r43 :: short_int r44 :: bool @@ -548,9 +548,9 @@ L0: r0 = PyList_New(0) r1 = 0 r2 = PyDict_Size(t) - r3 = CPyDict_GetKeysIter(t) + r3 = _CPyDict_GetIterUnsafe(t) L1: - r4 = CPyDict_NextKey(r3, r1) + r4 = CPyDict_NextKeyUnsafe(r3, r1) r5 = r4[1] r1 = r5 r6 = r4[0] @@ -562,7 +562,7 @@ L2: r9 = PyList_Append(r0, x) r10 = r9 >= 0 :: signed L3: - r11 = CPyDict_CheckSize(t, r2) + r11 = CPyDict_CheckSizeUnsafe(t, r2) goto L1 L4: r12 = CPy_NoErrOccurred() @@ -570,9 +570,9 @@ L5: r13 = PyList_New(0) r14 = 0 r15 = PyDict_Size(t) - r16 = CPyDict_GetValuesIter(t) + r16 = _CPyDict_GetIterUnsafe(t) L6: - r17 = CPyDict_NextValue(r16, r14) + r17 = CPyDict_NextValueUnsafe(r16, r14) r18 = r17[1] r14 = r18 r19 = r17[0] @@ -583,7 +583,7 @@ L7: r21 = PyList_Append(r13, x_2) r22 = r21 >= 0 :: signed L8: - r23 = CPyDict_CheckSize(t, r15) + r23 = CPyDict_CheckSizeUnsafe(t, r15) goto L6 L9: r24 = CPy_NoErrOccurred() @@ -591,9 +591,9 @@ L10: r25 = PySet_New(0) r26 = 0 r27 = PyDict_Size(t) - r28 = CPyDict_GetKeysIter(t) + r28 = _CPyDict_GetIterUnsafe(t) L11: - r29 = CPyDict_NextKey(r28, r26) + r29 = CPyDict_NextKeyUnsafe(r28, r26) r30 = r29[1] r26 = r30 r31 = r29[0] @@ -605,7 +605,7 @@ L12: r34 = PySet_Add(r25, x_3) r35 = r34 >= 0 :: signed L13: - r36 = CPyDict_CheckSize(t, r27) + r36 = CPyDict_CheckSizeUnsafe(t, r27) goto L11 L14: r37 = CPy_NoErrOccurred() @@ -613,9 +613,9 @@ L15: r38 = PyDict_New() r39 = 0 r40 = PyDict_Size(t) - r41 = CPyDict_GetItemsIter(t) + r41 = _CPyDict_GetIterUnsafe(t) L16: - r42 = CPyDict_NextItem(r41, r39) + r42 = CPyDict_NextItemUnsafe(r41, r39) r43 = r42[1] r39 = r43 r44 = r42[0] @@ -629,7 +629,7 @@ L17: r48 = PyDict_SetItem(r38, k, v) r49 = r48 >= 0 :: signed L18: - r50 = CPyDict_CheckSize(t, r40) + r50 = CPyDict_CheckSizeUnsafe(t, r40) goto L16 L19: r51 = CPy_NoErrOccurred() diff --git a/mypyc/test-data/irbuild-match.test b/mypyc/test-data/irbuild-match.test index 28aff3dcfc45..48b2605d3d88 100644 --- a/mypyc/test-data/irbuild-match.test +++ b/mypyc/test-data/irbuild-match.test @@ -1089,35 +1089,37 @@ def f(x): x :: object r0 :: i32 r1 :: bit - r2, rest :: dict - r3 :: str - r4 :: object - r5 :: str - r6 :: object - r7 :: object[1] - r8 :: object_ptr - r9, r10 :: object + r2 :: dict[confirmed] + r3, rest :: dict + r4 :: str + r5 :: object + r6 :: str + r7 :: object + r8 :: object[1] + r9 :: object_ptr + r10, r11 :: object L0: r0 = CPyMapping_Check(x) r1 = r0 != 0 if r1 goto L1 else goto L3 :: bool L1: r2 = CPyDict_FromAny(x) - rest = r2 + r3 = cast(dict, r2) + rest = r3 L2: - r3 = 'matched' - r4 = builtins :: module - r5 = 'print' - r6 = CPyObject_GetAttr(r4, r5) - r7 = [r3] - r8 = load_address r7 - r9 = PyObject_Vectorcall(r6, r8, 1, 0) - keep_alive r3 + r4 = 'matched' + r5 = builtins :: module + r6 = 'print' + r7 = CPyObject_GetAttr(r5, r6) + r8 = [r4] + r9 = load_address r8 + r10 = PyObject_Vectorcall(r7, r9, 1, 0) + keep_alive r4 goto L4 L3: L4: - r10 = box(None, 1) - return r10 + r11 = box(None, 1) + return r11 [case testMatchMappingPatternWithRestPopKeys_python3_10] def f(x): match x: @@ -1137,16 +1139,17 @@ def f(x): r8 :: i32 r9 :: bit r10 :: bool - r11, rest :: dict - r12 :: i32 - r13 :: bit - r14 :: str - r15 :: object - r16 :: str - r17 :: object - r18 :: object[1] - r19 :: object_ptr - r20, r21 :: object + r11 :: dict[confirmed] + r12, rest :: dict + r13 :: i32 + r14 :: bit + r15 :: str + r16 :: object + r17 :: str + r18 :: object + r19 :: object[1] + r20 :: object_ptr + r21, r22 :: object L0: r0 = CPyMapping_Check(x) r1 = r0 != 0 @@ -1166,23 +1169,24 @@ L2: if r10 goto L3 else goto L5 :: bool L3: r11 = CPyDict_FromAny(x) - rest = r11 - r12 = PyDict_DelItem(r11, r2) - r13 = r12 >= 0 :: signed + r12 = cast(dict, r11) + rest = r12 + r13 = PyDict_DelItem(r11, r2) + r14 = r13 >= 0 :: signed L4: - r14 = 'matched' - r15 = builtins :: module - r16 = 'print' - r17 = CPyObject_GetAttr(r15, r16) - r18 = [r14] - r19 = load_address r18 - r20 = PyObject_Vectorcall(r17, r19, 1, 0) - keep_alive r14 + r15 = 'matched' + r16 = builtins :: module + r17 = 'print' + r18 = CPyObject_GetAttr(r16, r17) + r19 = [r15] + r20 = load_address r19 + r21 = PyObject_Vectorcall(r18, r20, 1, 0) + keep_alive r15 goto L6 L5: L6: - r21 = box(None, 1) - return r21 + r22 = box(None, 1) + return r22 [case testMatchEmptySequencePattern_python3_10] def f(x): match x: diff --git a/mypyc/test-data/irbuild-set.test b/mypyc/test-data/irbuild-set.test index 5586a2bf4cfb..8b2e716ea0ce 100644 --- a/mypyc/test-data/irbuild-set.test +++ b/mypyc/test-data/irbuild-set.test @@ -161,19 +161,20 @@ L5: def test3(): r0, r1, r2 :: str r3, r4, r5 :: object - r6, tmp_dict :: dict - r7 :: set - r8 :: short_int - r9 :: native_int - r10 :: object - r11 :: tuple[bool, short_int, object] - r12 :: short_int - r13 :: bool - r14 :: object - r15, x, r16 :: int - r17 :: object - r18 :: i32 - r19, r20, r21 :: bit + r6 :: dict[confirmed] + r7, tmp_dict :: dict + r8 :: set + r9 :: short_int + r10 :: native_int + r11 :: object + r12 :: tuple[bool, short_int, object] + r13 :: short_int + r14 :: bool + r15 :: object + r16, x, r17 :: int + r18 :: object + r19 :: i32 + r20, r21, r22 :: bit c :: set L0: r0 = '1' @@ -183,32 +184,33 @@ L0: r4 = object 3 r5 = object 5 r6 = CPyDict_Build(3, r3, r0, r4, r1, r5, r2) - tmp_dict = r6 - r7 = PySet_New(0) - r8 = 0 - r9 = PyDict_Size(tmp_dict) - r10 = CPyDict_GetKeysIter(tmp_dict) + r7 = cast(dict, r6) + tmp_dict = r7 + r8 = PySet_New(0) + r9 = 0 + r10 = PyDict_Size(tmp_dict) + r11 = CPyDict_GetKeysIter(tmp_dict) L1: - r11 = CPyDict_NextKey(r10, r8) - r12 = r11[1] - r8 = r12 - r13 = r11[0] - if r13 goto L2 else goto L4 :: bool + r12 = CPyDict_NextKey(r11, r9) + r13 = r12[1] + r9 = r13 + r14 = r12[0] + if r14 goto L2 else goto L4 :: bool L2: - r14 = r11[2] - r15 = unbox(int, r14) - x = r15 - r16 = f(x) - r17 = box(int, r16) - r18 = PySet_Add(r7, r17) - r19 = r18 >= 0 :: signed + r15 = r12[2] + r16 = unbox(int, r15) + x = r16 + r17 = f(x) + r18 = box(int, r17) + r19 = PySet_Add(r8, r18) + r20 = r19 >= 0 :: signed L3: - r20 = CPyDict_CheckSize(tmp_dict, r9) + r21 = CPyDict_CheckSize(tmp_dict, r10) goto L1 L4: - r21 = CPy_NoErrOccurred() + r22 = CPy_NoErrOccurred() L5: - c = r7 + c = r8 return 1 def test4(): r0 :: set @@ -646,7 +648,7 @@ L0: return r3 def not_precomputed_non_final_name(i): i :: int - r0 :: dict + r0 :: dict[confirmed] r1 :: str r2 :: object r3 :: int @@ -661,7 +663,7 @@ def not_precomputed_non_final_name(i): L0: r0 = __main__.globals :: static r1 = 'non_const' - r2 = CPyDict_GetItem(r0, r1) + r2 = CPyDict_GetItemUnsafe(r0, r1) r3 = unbox(int, r2) r4 = PySet_New(0) r5 = box(int, r3) @@ -766,7 +768,7 @@ L4: L5: return 1 def not_precomputed(): - r0 :: dict + r0 :: dict[confirmed] r1 :: str r2 :: object r3 :: int @@ -780,7 +782,7 @@ def not_precomputed(): L0: r0 = __main__.globals :: static r1 = 'non_const' - r2 = CPyDict_GetItem(r0, r1) + r2 = CPyDict_GetItemUnsafe(r0, r1) r3 = unbox(int, r2) r4 = PySet_New(0) r5 = box(int, r3) diff --git a/mypyc/test-data/irbuild-singledispatch.test b/mypyc/test-data/irbuild-singledispatch.test index 1060ee63c57d..a3df1c363ade 100644 --- a/mypyc/test-data/irbuild-singledispatch.test +++ b/mypyc/test-data/irbuild-singledispatch.test @@ -14,7 +14,7 @@ L0: return 0 def f_obj.__init__(__mypyc_self__): __mypyc_self__ :: __main__.f_obj - r0, r1 :: dict + r0, r1 :: dict[confirmed] r2 :: str r3 :: i32 r4 :: bit @@ -31,13 +31,13 @@ def f_obj.__call__(__mypyc_self__, arg): arg :: object r0 :: ptr r1 :: object - r2 :: dict + r2 :: dict[confirmed] r3, r4 :: object r5 :: bit r6, r7 :: object r8 :: str r9 :: object - r10 :: dict + r10 :: dict[confirmed] r11 :: object[2] r12 :: object_ptr r13 :: object @@ -124,14 +124,14 @@ L0: return r0 def f(arg): arg :: object - r0 :: dict + r0 :: dict[confirmed] r1 :: str r2 :: object r3 :: bool L0: r0 = __main__.globals :: static r1 = 'f' - r2 = CPyDict_GetItem(r0, r1) + r2 = CPyDict_GetItemUnsafe(r0, r1) r3 = f_obj.__call__(r2, arg) return r3 def g(arg): @@ -155,7 +155,7 @@ L0: return 1 def f_obj.__init__(__mypyc_self__): __mypyc_self__ :: __main__.f_obj - r0, r1 :: dict + r0, r1 :: dict[confirmed] r2 :: str r3 :: i32 r4 :: bit @@ -172,13 +172,13 @@ def f_obj.__call__(__mypyc_self__, x): x :: object r0 :: ptr r1 :: object - r2 :: dict + r2 :: dict[confirmed] r3, r4 :: object r5 :: bit r6, r7 :: object r8 :: str r9 :: object - r10 :: dict + r10 :: dict[confirmed] r11 :: object[2] r12 :: object_ptr r13 :: object @@ -255,14 +255,14 @@ L0: return r0 def f(x): x :: object - r0 :: dict + r0 :: dict[confirmed] r1 :: str r2 :: object r3 :: None L0: r0 = __main__.globals :: static r1 = 'f' - r2 = CPyDict_GetItem(r0, r1) + r2 = CPyDict_GetItemUnsafe(r0, r1) r3 = f_obj.__call__(r2, x) return r3 def test(): diff --git a/mypyc/test-data/irbuild-statements.test b/mypyc/test-data/irbuild-statements.test index 48b8e0e318b8..fd5e93fc6c42 100644 --- a/mypyc/test-data/irbuild-statements.test +++ b/mypyc/test-data/irbuild-statements.test @@ -759,30 +759,33 @@ def delDictMultiple() -> None: def delDict(): r0, r1 :: str r2, r3 :: object - r4, d :: dict - r5 :: str - r6 :: i32 - r7 :: bit + r4 :: dict[confirmed] + r5, d :: dict + r6 :: str + r7 :: i32 + r8 :: bit L0: r0 = 'one' r1 = 'two' r2 = object 1 r3 = object 2 r4 = CPyDict_Build(2, r0, r2, r1, r3) - d = r4 - r5 = 'one' - r6 = PyObject_DelItem(d, r5) - r7 = r6 >= 0 :: signed + r5 = cast(dict, r4) + d = r5 + r6 = 'one' + r7 = PyObject_DelItem(d, r6) + r8 = r7 >= 0 :: signed return 1 def delDictMultiple(): r0, r1, r2, r3 :: str r4, r5, r6, r7 :: object - r8, d :: dict - r9, r10 :: str - r11 :: i32 - r12 :: bit - r13 :: i32 - r14 :: bit + r8 :: dict[confirmed] + r9, d :: dict + r10, r11 :: str + r12 :: i32 + r13 :: bit + r14 :: i32 + r15 :: bit L0: r0 = 'one' r1 = 'two' @@ -793,13 +796,14 @@ L0: r6 = object 3 r7 = object 4 r8 = CPyDict_Build(4, r0, r4, r1, r5, r2, r6, r3, r7) - d = r8 - r9 = 'one' - r10 = 'four' - r11 = PyObject_DelItem(d, r9) - r12 = r11 >= 0 :: signed - r13 = PyObject_DelItem(d, r10) - r14 = r13 >= 0 :: signed + r9 = cast(dict, r8) + d = r9 + r10 = 'one' + r11 = 'four' + r12 = PyObject_DelItem(d, r10) + r13 = r12 >= 0 :: signed + r14 = PyObject_DelItem(d, r11) + r15 = r14 >= 0 :: signed return 1 [case testDelAttribute] diff --git a/mypyc/test-data/run-dicts.test b/mypyc/test-data/run-dicts.test index 2b75b32c906e..c39b9cd03a47 100644 --- a/mypyc/test-data/run-dicts.test +++ b/mypyc/test-data/run-dicts.test @@ -84,13 +84,13 @@ update_dict(d, object.__dict__) assert d == dict(object.__dict__) assert u(10) == 10 -assert get_content({1: 2}) == ([1], [2], [(1, 2)]) +assert get_content({1: 2}) == ([1], [2], [(1, 2)]), get_content({1: 2}) od = OrderedDict([(1, 2), (3, 4)]) -assert get_content(od) == ([1, 3], [2, 4], [(1, 2), (3, 4)]) +assert get_content(od) == ([1, 3], [2, 4], [(1, 2), (3, 4)]), get_content(od) od.move_to_end(1) -assert get_content(od) == ([3, 1], [4, 2], [(3, 4), (1, 2)]) -assert get_content_set({1: 2}) == ({1}, {2}, {(1, 2)}) -assert get_content_set(od) == ({1, 3}, {2, 4}, {(1, 2), (3, 4)}) +assert get_content(od) == ([3, 1], [4, 2], [(3, 4), (1, 2)]), get_content(od) +assert get_content_set({1: 2}) == ({1}, {2}, {(1, 2)}), get_content_set({1: 2}) +assert get_content_set(od) == ({1, 3}, {2, 4}, {(1, 2), (3, 4)}), get_content_set(od) [typing fixtures/typing-full.pyi] From af7cf9d6e6210290eb512ba4fbb514876f1774e7 Mon Sep 17 00:00:00 2001 From: BobTheBuidler Date: Mon, 4 Aug 2025 02:01:35 +0000 Subject: [PATCH 02/43] fix: ordered dict --- mypyc/primitives/dict_ops.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/mypyc/primitives/dict_ops.py b/mypyc/primitives/dict_ops.py index 7b4e32157247..c3059fc4f203 100644 --- a/mypyc/primitives/dict_ops.py +++ b/mypyc/primitives/dict_ops.py @@ -412,7 +412,7 @@ dict_keys_op = custom_op( arg_types=[dict_rprimitive], return_type=list_rprimitive, - c_function_name="PyDict_Keys", + c_function_name="CPyDict_Keys", error_kind=ERR_MAGIC, ) @@ -428,7 +428,7 @@ dict_values_op = custom_op( arg_types=[dict_rprimitive], return_type=list_rprimitive, - c_function_name="PyDict_Values", + c_function_name="CPyDict_Values", error_kind=ERR_MAGIC, ) @@ -444,7 +444,7 @@ dict_items_op = custom_op( arg_types=[dict_rprimitive], return_type=list_rprimitive, - c_function_name="PyDict_Items", + c_function_name="CPyDict_Items", error_kind=ERR_MAGIC, ) From a075a3f7b2ade63ffb5cd7497972d601bd83de88 Mon Sep 17 00:00:00 2001 From: BobTheBuidler Date: Mon, 4 Aug 2025 02:01:35 +0000 Subject: [PATCH 03/43] fix: mypy errs --- mypyc/irbuild/ll_builder.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/mypyc/irbuild/ll_builder.py b/mypyc/irbuild/ll_builder.py index 8cf69937a159..9b1e5067aa24 100644 --- a/mypyc/irbuild/ll_builder.py +++ b/mypyc/irbuild/ll_builder.py @@ -861,7 +861,7 @@ def _construct_varargs( ) star2_result = self._create_dict(star2_keys, star2_values, line) - if is_true_dict_rprimitive(value): + if is_true_dict_rprimitive(value.type): op = true_dict_update_op else: op = dict_update_in_display_op @@ -1827,13 +1827,13 @@ def make_dict(self, key_value_pairs: Sequence[DictEntry], line: int) -> Value: else: # **value if result is None: - if len(key_value_pairs) == 1 and is_true_dict_rprimitive(value): + if len(key_value_pairs) == 1 and is_true_dict_rprimitive(value.type): # fast path for cases like `my_func(**dict(zip(iterable, other)))` and similar return self.call_c(true_dict_copy_op, [value], line=line) result = self._create_dict(keys, values, line) - if is_true_dict_rprimitive(value): + if is_true_dict_rprimitive(value.type): op = true_dict_update_op else: op = dict_update_in_display_op From abc0eb36246ba81d2b06e93388a4ce489b50fcc0 Mon Sep 17 00:00:00 2001 From: BobTheBuidler Date: Mon, 4 Aug 2025 02:01:35 +0000 Subject: [PATCH 04/43] fix: mypy errs --- mypyc/irbuild/ll_builder.py | 6 +++--- mypyc/primitives/dict_ops.py | 9 +++++++++ 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/mypyc/irbuild/ll_builder.py b/mypyc/irbuild/ll_builder.py index 9b1e5067aa24..0d83df7339b8 100644 --- a/mypyc/irbuild/ll_builder.py +++ b/mypyc/irbuild/ll_builder.py @@ -141,7 +141,7 @@ dict_update_in_display_op, true_dict_copy_op, true_dict_ssize_t_size_op, - true_dict_update_op, + true_dict_update_in_display_op, ) from mypyc.primitives.exc_ops import err_occurred_op, keep_propagating_op from mypyc.primitives.float_ops import copysign_op, int_to_float_op @@ -862,7 +862,7 @@ def _construct_varargs( star2_result = self._create_dict(star2_keys, star2_values, line) if is_true_dict_rprimitive(value.type): - op = true_dict_update_op + op = true_dict_update_in_display_op else: op = dict_update_in_display_op self.call_c(op, [star2_result, value], line=line) @@ -1834,7 +1834,7 @@ def make_dict(self, key_value_pairs: Sequence[DictEntry], line: int) -> Value: result = self._create_dict(keys, values, line) if is_true_dict_rprimitive(value.type): - op = true_dict_update_op + op = true_dict_update_in_display_op else: op = dict_update_in_display_op diff --git a/mypyc/primitives/dict_ops.py b/mypyc/primitives/dict_ops.py index c3059fc4f203..4e420522dc77 100644 --- a/mypyc/primitives/dict_ops.py +++ b/mypyc/primitives/dict_ops.py @@ -200,6 +200,15 @@ priority=2, ) +# Operation used for **value in with exact dictionary `value`. +# This is mostly like dict.update(obj), but has customized error handling. +true_dict_update_in_display_op = custom_op( + arg_types=[true_dict_rprimitive, true_dict_rprimitive], + return_type=c_int_rprimitive, + c_function_name="PyDict_Update", + error_kind=ERR_NEG_INT, +) + # Operation used for **value in dict displays. # This is mostly like dict.update(obj), but has customized error handling. dict_update_in_display_op = custom_op( From 94ec27c822fe59f928be3409e16b48b0c55ff7ab Mon Sep 17 00:00:00 2001 From: BobTheBuidler Date: Mon, 4 Aug 2025 02:01:36 +0000 Subject: [PATCH 05/43] fix: mypy errs --- mypyc/primitives/dict_ops.py | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/mypyc/primitives/dict_ops.py b/mypyc/primitives/dict_ops.py index 4e420522dc77..4c0f777cb0fc 100644 --- a/mypyc/primitives/dict_ops.py +++ b/mypyc/primitives/dict_ops.py @@ -392,7 +392,7 @@ ) # dict.copy() -true_dict_copy_op = method_op( +method_op( name="copy", arg_types=[true_dict_rprimitive], return_type=true_dict_rprimitive, @@ -409,6 +409,15 @@ error_kind=ERR_MAGIC, ) +# dict.copy() custom_op +true_dict_copy_op = method_op( + name="copy", + arg_types=[true_dict_rprimitive], + return_type=true_dict_rprimitive, + c_function_name="PyDict_Copy", + error_kind=ERR_MAGIC, +) + # list(dict.keys()) true_dict_keys_op = custom_op( arg_types=[true_dict_rprimitive], From 4eb3611f148f628fb78305451e74405d11e2b8f6 Mon Sep 17 00:00:00 2001 From: BobTheBuidler Date: Mon, 4 Aug 2025 02:01:36 +0000 Subject: [PATCH 06/43] fix: mypy errs --- mypyc/primitives/dict_ops.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/mypyc/primitives/dict_ops.py b/mypyc/primitives/dict_ops.py index 4c0f777cb0fc..af1eba2a9841 100644 --- a/mypyc/primitives/dict_ops.py +++ b/mypyc/primitives/dict_ops.py @@ -410,8 +410,7 @@ ) # dict.copy() custom_op -true_dict_copy_op = method_op( - name="copy", +true_dict_copy_op = custom_op( arg_types=[true_dict_rprimitive], return_type=true_dict_rprimitive, c_function_name="PyDict_Copy", From cd8af87170c349db318e8360c007c487a07cc292 Mon Sep 17 00:00:00 2001 From: BobTheBuidler Date: Mon, 4 Aug 2025 02:01:36 +0000 Subject: [PATCH 07/43] feat: use true_dict_rprimitive for builtins.dict --- mypyc/analysis/ircheck.py | 2 + mypyc/irbuild/mapper.py | 2 + mypyc/test-data/irbuild-basic.test | 55 ++--- mypyc/test-data/irbuild-bytes.test | 2 +- mypyc/test-data/irbuild-dict.test | 298 ++++++++++++------------ mypyc/test-data/irbuild-generics.test | 71 +++--- mypyc/test-data/irbuild-match.test | 90 ++++--- mypyc/test-data/irbuild-set.test | 68 +++--- mypyc/test-data/irbuild-statements.test | 72 +++--- mypyc/test-data/refcount.test | 12 +- 10 files changed, 327 insertions(+), 345 deletions(-) diff --git a/mypyc/analysis/ircheck.py b/mypyc/analysis/ircheck.py index 6980c9cee419..1e57183eb7cd 100644 --- a/mypyc/analysis/ircheck.py +++ b/mypyc/analysis/ircheck.py @@ -71,6 +71,7 @@ range_rprimitive, set_rprimitive, str_rprimitive, + true_dict_rprimitive, tuple_rprimitive, ) @@ -177,6 +178,7 @@ def check_op_sources_valid(fn: FuncIR) -> list[FnError]: int_rprimitive.name, bytes_rprimitive.name, str_rprimitive.name, + true_dict_rprimitive.name, dict_rprimitive.name, list_rprimitive.name, set_rprimitive.name, diff --git a/mypyc/irbuild/mapper.py b/mypyc/irbuild/mapper.py index f308998c9549..d079d3a88f24 100644 --- a/mypyc/irbuild/mapper.py +++ b/mypyc/irbuild/mapper.py @@ -94,6 +94,8 @@ def type_to_rtype(self, typ: Type | None) -> RType: # Dict subclasses are at least somewhat common and we # specifically support them, so make sure that dict operations # get optimized on them. + elif typ.type.fullname == "builtins.dict": + return true_dict_rprimitive elif any(cls.fullname == "builtins.dict" for cls in typ.type.mro): return dict_rprimitive elif typ.type.fullname == "builtins.set": diff --git a/mypyc/test-data/irbuild-basic.test b/mypyc/test-data/irbuild-basic.test index 6957933af372..0da2238a7e59 100644 --- a/mypyc/test-data/irbuild-basic.test +++ b/mypyc/test-data/irbuild-basic.test @@ -966,10 +966,10 @@ def f(o, p, n, b, t, s, a, l, d): s :: tuple[int, int] a :: __main__.A l :: list - d :: dict + d :: dict[confirmed] r0 :: object l2 :: list - d2 :: dict + d2 :: dict[confirmed] L0: o = o p = p @@ -1758,38 +1758,33 @@ L0: def h(): r0, r1 :: str r2, r3 :: object - r4 :: dict[confirmed] - r5 :: dict - r6 :: dict[confirmed] - r7 :: str - r8 :: object - r9 :: dict[confirmed] - r10 :: dict - r11 :: i32 - r12 :: bit + r4, r5 :: dict[confirmed] + r6 :: str + r7 :: object + r8 :: dict[confirmed] + r9 :: i32 + r10 :: bit + r11 :: object + r12 :: tuple r13 :: object - r14 :: tuple - r15 :: object - r16 :: tuple[int, int, int] + r14 :: tuple[int, int, int] L0: r0 = 'b' r1 = 'c' r2 = object 2 r3 = object 3 r4 = CPyDict_Build(2, r0, r2, r1, r3) - r5 = cast(dict, r4) - r6 = __main__.globals :: static - r7 = 'f' - r8 = CPyDict_GetItemUnsafe(r6, r7) - r9 = PyDict_New() - r10 = cast(dict, r9) - r11 = CPyDict_UpdateInDisplay(r10, r5) - r12 = r11 >= 0 :: signed - r13 = object 1 - r14 = PyTuple_Pack(1, r13) - r15 = PyObject_Call(r8, r14, r9) - r16 = unbox(tuple[int, int, int], r15) - return r16 + r5 = __main__.globals :: static + r6 = 'f' + r7 = CPyDict_GetItemUnsafe(r5, r6) + r8 = PyDict_New() + r9 = PyDict_Update(r8, r4) + r10 = r9 >= 0 :: signed + r11 = object 1 + r12 = PyTuple_Pack(1, r11) + r13 = PyObject_Call(r7, r12, r8) + r14 = unbox(tuple[int, int, int], r13) + return r14 [case testFunctionCallWithDefaultArgs] def f(x: int, y: int = 3, z: str = "test") -> None: @@ -1950,7 +1945,6 @@ def f(): r16 :: i32 r17 :: bit r18 :: native_int - r19 :: dict L0: r0 = PyDict_New() r1 = PyList_New(3) @@ -1991,8 +1985,7 @@ L7: r6 = r18 goto L1 L8: - r19 = cast(dict, r0) - return r19 + return r0 [case testLoopsMultipleAssign] from typing import List, Tuple @@ -3257,7 +3250,7 @@ L0: r1 = PySequence_List(r0) return r1 def h(x): - x :: dict + x :: dict[confirmed] r0 :: list L0: r0 = PySequence_List(x) diff --git a/mypyc/test-data/irbuild-bytes.test b/mypyc/test-data/irbuild-bytes.test index 8cfefe03ae22..f0d72cd0d160 100644 --- a/mypyc/test-data/irbuild-bytes.test +++ b/mypyc/test-data/irbuild-bytes.test @@ -9,7 +9,7 @@ def f(num: int, l: list, d: dict, s: str) -> None: def f(num, l, d, s): num :: int l :: list - d :: dict + d :: dict[confirmed] s :: str r0, r1 :: object r2, b1 :: bytes diff --git a/mypyc/test-data/irbuild-dict.test b/mypyc/test-data/irbuild-dict.test index 1233ee02bd3b..8cf2477ce38a 100644 --- a/mypyc/test-data/irbuild-dict.test +++ b/mypyc/test-data/irbuild-dict.test @@ -4,12 +4,12 @@ def f(d: Dict[int, bool]) -> bool: return d[0] [out] def f(d): - d :: dict + d :: dict[confirmed] r0, r1 :: object r2 :: bool L0: r0 = object 0 - r1 = CPyDict_GetItem(d, r0) + r1 = CPyDict_GetItemUnsafe(d, r0) r2 = unbox(bool, r1) return r2 @@ -19,14 +19,14 @@ def f(d: Dict[int, bool]) -> None: d[0] = False [out] def f(d): - d :: dict + d :: dict[confirmed] r0, r1 :: object r2 :: i32 r3 :: bit L0: r0 = object 0 r1 = box(bool, 0) - r2 = CPyDict_SetItem(d, r0, r1) + r2 = PyDict_SetItem(d, r0, r1) r3 = r2 >= 0 :: signed return 1 @@ -36,12 +36,10 @@ def f() -> None: d = {} # type: Dict[bool, int] [out] def f(): - r0 :: dict[confirmed] - r1, d :: dict + r0, d :: dict[confirmed] L0: r0 = PyDict_New() - r1 = cast(dict, r0) - d = r1 + d = r0 return 1 [case testNewEmptyDictViaFunc] @@ -51,12 +49,10 @@ def f() -> None: [out] def f(): - r0 :: dict[confirmed] - r1, d :: dict + r0, d :: dict[confirmed] L0: r0 = PyDict_New() - r1 = cast(dict, r0) - d = r1 + d = r0 return 1 [case testNewDictWithValues] @@ -67,15 +63,13 @@ def f(x): x :: object r0 :: str r1, r2 :: object - r3 :: dict[confirmed] - r4, d :: dict + r3, d :: dict[confirmed] L0: r0 = '' r1 = object 1 r2 = object 2 r3 = CPyDict_Build(2, r1, r2, r0, x) - r4 = cast(dict, r3) - d = r4 + d = r3 return 1 [case testInDict] @@ -87,7 +81,7 @@ def f(d: Dict[int, int]) -> bool: return False [out] def f(d): - d :: dict + d :: dict[confirmed] r0 :: object r1 :: i32 r2 :: bit @@ -114,7 +108,7 @@ def f(d: Dict[int, int]) -> bool: return False [out] def f(d): - d :: dict + d :: dict[confirmed] r0 :: object r1 :: i32 r2 :: bit @@ -139,11 +133,11 @@ def f(a: Dict[int, int], b: Dict[int, int]) -> None: a.update(b) [out] def f(a, b): - a, b :: dict + a, b :: dict[confirmed] r0 :: i32 r1 :: bit L0: - r0 = CPyDict_Update(a, b) + r0 = PyDict_Update(a, b) r1 = r0 >= 0 :: signed return 1 @@ -155,10 +149,10 @@ def increment(d: Dict[str, int]) -> Dict[str, int]: return d [out] def increment(d): - d :: dict + d :: dict[confirmed] r0 :: short_int r1 :: native_int - r2 :: object + r2 :: dict[confirmed] r3 :: tuple[bool, short_int, object] r4 :: short_int r5 :: bool @@ -170,9 +164,9 @@ def increment(d): L0: r0 = 0 r1 = PyDict_Size(d) - r2 = CPyDict_GetKeysIter(d) + r2 = _CPyDict_GetIterUnsafe(d) L1: - r3 = CPyDict_NextKey(r2, r0) + r3 = CPyDict_NextKeyUnsafe(r2, r0) r4 = r3[1] r0 = r4 r5 = r3[0] @@ -181,13 +175,13 @@ L2: r6 = r3[2] r7 = cast(str, r6) k = r7 - r8 = CPyDict_GetItem(d, k) + r8 = CPyDict_GetItemUnsafe(d, k) r9 = object 1 r10 = PyNumber_InPlaceAdd(r8, r9) - r11 = CPyDict_SetItem(d, k, r10) + r11 = PyDict_SetItem(d, k, r10) r12 = r11 >= 0 :: signed L3: - r13 = CPyDict_CheckSize(d, r1) + r13 = CPyDict_CheckSizeUnsafe(d, r1) goto L1 L4: r14 = CPy_NoErrOccurred() @@ -201,29 +195,25 @@ def f(x: str, y: Dict[str, int]) -> Dict[str, int]: [out] def f(x, y): x :: str - y :: dict + y :: dict[confirmed] r0 :: str r1 :: object r2 :: dict[confirmed] - r3 :: dict - r4 :: i32 - r5 :: bit - r6 :: object - r7 :: i32 - r8 :: bit - r9 :: dict + r3 :: i32 + r4 :: bit + r5 :: object + r6 :: i32 + r7 :: bit L0: r0 = 'z' r1 = object 2 r2 = CPyDict_Build(1, x, r1) - r3 = cast(dict, r2) - r4 = CPyDict_UpdateInDisplay(r3, y) - r5 = r4 >= 0 :: signed - r6 = object 3 - r7 = PyDict_SetItem(r2, r0, r6) - r8 = r7 >= 0 :: signed - r9 = cast(dict, r2) - return r9 + r3 = PyDict_Update(r2, y) + r4 = r3 >= 0 :: signed + r5 = object 3 + r6 = PyDict_SetItem(r2, r0, r5) + r7 = r6 >= 0 :: signed + return r2 [case testDictIterationMethods] from typing import Dict, TypedDict, Union @@ -249,10 +239,10 @@ def typeddict(d: Person) -> None: [typing fixtures/typing-full.pyi] [out] def print_dict_methods(d1, d2): - d1, d2 :: dict + d1, d2 :: dict[confirmed] r0 :: short_int r1 :: native_int - r2 :: object + r2 :: dict[confirmed] r3 :: tuple[bool, short_int, object] r4 :: short_int r5 :: bool @@ -265,7 +255,7 @@ def print_dict_methods(d1, d2): r12, r13 :: bit r14 :: short_int r15 :: native_int - r16 :: object + r16 :: dict[confirmed] r17 :: tuple[bool, short_int, object, object] r18 :: short_int r19 :: bool @@ -277,9 +267,9 @@ def print_dict_methods(d1, d2): L0: r0 = 0 r1 = PyDict_Size(d1) - r2 = CPyDict_GetValuesIter(d1) + r2 = _CPyDict_GetIterUnsafe(d1) L1: - r3 = CPyDict_NextValue(r2, r0) + r3 = CPyDict_NextValueUnsafe(r2, r0) r4 = r3[1] r0 = r4 r5 = r3[0] @@ -297,16 +287,16 @@ L3: return 1 L4: L5: - r12 = CPyDict_CheckSize(d1, r1) + r12 = CPyDict_CheckSizeUnsafe(d1, r1) goto L1 L6: r13 = CPy_NoErrOccurred() L7: r14 = 0 r15 = PyDict_Size(d2) - r16 = CPyDict_GetItemsIter(d2) + r16 = _CPyDict_GetIterUnsafe(d2) L8: - r17 = CPyDict_NextItem(r16, r14) + r17 = CPyDict_NextItemUnsafe(r16, r14) r18 = r17[1] r14 = r18 r19 = r17[0] @@ -319,76 +309,73 @@ L9: k = r22 v = r23 r24 = box(int, k) - r25 = CPyDict_GetItem(d2, r24) + r25 = CPyDict_GetItemUnsafe(d2, r24) r26 = box(int, v) r27 = PyNumber_InPlaceAdd(r25, r26) r28 = box(int, k) - r29 = CPyDict_SetItem(d2, r28, r27) + r29 = PyDict_SetItem(d2, r28, r27) r30 = r29 >= 0 :: signed L10: - r31 = CPyDict_CheckSize(d2, r15) + r31 = CPyDict_CheckSizeUnsafe(d2, r15) goto L8 L11: r32 = CPy_NoErrOccurred() L12: return 1 def union_of_dicts(d): - d :: dict - r0 :: dict[confirmed] - r1, new :: dict - r2 :: short_int - r3 :: native_int - r4 :: object - r5 :: tuple[bool, short_int, object, object] - r6 :: short_int - r7 :: bool - r8, r9 :: object - r10 :: str - r11 :: union[int, str] + d, r0, new :: dict[confirmed] + r1 :: short_int + r2 :: native_int + r3 :: dict[confirmed] + r4 :: tuple[bool, short_int, object, object] + r5 :: short_int + r6 :: bool + r7, r8 :: object + r9 :: str + r10 :: union[int, str] k :: str v :: union[int, str] - r12 :: object - r13 :: object[1] - r14 :: object_ptr - r15 :: object - r16 :: int - r17 :: object - r18 :: i32 - r19, r20, r21 :: bit + r11 :: object + r12 :: object[1] + r13 :: object_ptr + r14 :: object + r15 :: int + r16 :: object + r17 :: i32 + r18, r19, r20 :: bit L0: r0 = PyDict_New() - r1 = cast(dict, r0) - new = r1 - r2 = 0 - r3 = PyDict_Size(d) - r4 = CPyDict_GetItemsIter(d) + new = r0 + r1 = 0 + r2 = PyDict_Size(d) + r3 = _CPyDict_GetIterUnsafe(d) L1: - r5 = CPyDict_NextItem(r4, r2) - r6 = r5[1] - r2 = r6 - r7 = r5[0] - if r7 goto L2 else goto L4 :: bool + r4 = CPyDict_NextItemUnsafe(r3, r1) + r5 = r4[1] + r1 = r5 + r6 = r4[0] + if r6 goto L2 else goto L4 :: bool L2: - r8 = r5[2] - r9 = r5[3] - r10 = cast(str, r8) - r11 = cast(union[int, str], r9) - k = r10 - v = r11 - r12 = load_address PyLong_Type - r13 = [v] - r14 = load_address r13 - r15 = PyObject_Vectorcall(r12, r14, 1, 0) + r7 = r4[2] + r8 = r4[3] + r9 = cast(str, r7) + r10 = cast(union[int, str], r8) + k = r9 + v = r10 + r11 = load_address PyLong_Type + r12 = [v] + r13 = load_address r12 + r14 = PyObject_Vectorcall(r11, r13, 1, 0) keep_alive v - r16 = unbox(int, r15) - r17 = box(int, r16) - r18 = CPyDict_SetItem(new, k, r17) - r19 = r18 >= 0 :: signed + r15 = unbox(int, r14) + r16 = box(int, r15) + r17 = PyDict_SetItem(new, k, r16) + r18 = r17 >= 0 :: signed L3: - r20 = CPyDict_CheckSize(d, r3) + r19 = CPyDict_CheckSizeUnsafe(d, r2) goto L1 L4: - r21 = CPy_NoErrOccurred() + r20 = CPy_NoErrOccurred() L5: return 1 def typeddict(d): @@ -453,10 +440,10 @@ def f(d: Dict[int, int]) -> None: return d.clear() [out] def f(d): - d :: dict + d :: dict[confirmed] r0 :: bit L0: - r0 = CPyDict_Clear(d) + r0 = PyDict_Clear(d) return 1 [case testDictCopy] @@ -465,9 +452,9 @@ def f(d: Dict[int, int]) -> Dict[int, int]: return d.copy() [out] def f(d): - d, r0 :: dict + d, r0 :: dict[confirmed] L0: - r0 = CPyDict_Copy(d) + r0 = PyDict_Copy(d) return r0 [case testDictSetdefault] @@ -494,89 +481,94 @@ def f4(d: Dict[object, object], flag: bool) -> object: return d.setdefault('a', {'c': 1}) [out] def f(d): - d :: dict + d :: dict[confirmed] r0, r1 :: str r2 :: object L0: r0 = 'a' r1 = 'b' - r2 = CPyDict_SetDefault(d, r0, r1) + r2 = PyDict_SetDefault(d, r0, r1) return r2 def f2(d, flag): - d :: dict + d :: dict[confirmed] flag :: bool r0 :: str - r1 :: object - r2, r3 :: str - r4 :: set - r5, r6 :: object + r1 :: dict + r2 :: object + r3, r4 :: str + r5 :: set + r6, r7 :: object L0: if flag goto L1 else goto L2 :: bool L1: r0 = 'a' - r1 = CPyDict_SetDefaultWithEmptyDatatype(d, r0, 3) - return r1 + r1 = cast(dict, d) + r2 = CPyDict_SetDefaultWithEmptyDatatype(r1, r0, 3) + return r2 L2: - r2 = 'a' - r3 = 'b' - r4 = PySet_New(r3) - r5 = CPyDict_SetDefault(d, r2, r4) - return r5 -L3: - r6 = box(None, 1) + r3 = 'a' + r4 = 'b' + r5 = PySet_New(r4) + r6 = PyDict_SetDefault(d, r3, r5) return r6 +L3: + r7 = box(None, 1) + return r7 def f3(d, flag): - d :: dict + d :: dict[confirmed] flag :: bool r0 :: str - r1 :: object - r2 :: str - r3 :: list - r4 :: object - r5 :: ptr - r6, r7 :: object + r1 :: dict + r2 :: object + r3 :: str + r4 :: list + r5 :: object + r6 :: ptr + r7, r8 :: object L0: if flag goto L1 else goto L2 :: bool L1: r0 = 'a' - r1 = CPyDict_SetDefaultWithEmptyDatatype(d, r0, 1) - return r1 + r1 = cast(dict, d) + r2 = CPyDict_SetDefaultWithEmptyDatatype(r1, r0, 1) + return r2 L2: - r2 = 'a' - r3 = PyList_New(1) - r4 = object 1 - r5 = list_items r3 - buf_init_item r5, 0, r4 - keep_alive r3 - r6 = CPyDict_SetDefault(d, r2, r3) - return r6 -L3: - r7 = box(None, 1) + r3 = 'a' + r4 = PyList_New(1) + r5 = object 1 + r6 = list_items r4 + buf_init_item r6, 0, r5 + keep_alive r4 + r7 = PyDict_SetDefault(d, r3, r4) return r7 +L3: + r8 = box(None, 1) + return r8 def f4(d, flag): - d :: dict + d :: dict[confirmed] flag :: bool r0 :: str - r1 :: object - r2, r3 :: str - r4 :: object - r5 :: dict[confirmed] - r6 :: dict + r1 :: dict + r2 :: object + r3, r4 :: str + r5 :: object + r6 :: dict[confirmed] r7, r8 :: object L0: if flag goto L1 else goto L2 :: bool L1: r0 = 'a' - r1 = CPyDict_SetDefaultWithEmptyDatatype(d, r0, 2) - return r1 + r1 = cast(dict, d) + r2 = CPyDict_SetDefaultWithEmptyDatatype(r1, r0, 2) + return r2 L2: - r2 = 'a' - r3 = 'c' - r4 = object 1 - r5 = CPyDict_Build(1, r3, r4) - r6 = cast(dict, r5) - r7 = CPyDict_SetDefault(d, r2, r6) + r3 = 'a' + r4 = 'c' + r5 = object 1 + r6 = CPyDict_Build(1, r4, r5) + r7 = PyDict_SetDefault(d, r3, r6) return r7 L3: r8 = box(None, 1) return r8 + diff --git a/mypyc/test-data/irbuild-generics.test b/mypyc/test-data/irbuild-generics.test index 04d9729c246b..dd81ebc2b342 100644 --- a/mypyc/test-data/irbuild-generics.test +++ b/mypyc/test-data/irbuild-generics.test @@ -211,11 +211,11 @@ def fn_typeddict(t: T) -> None: [typing fixtures/typing-full.pyi] [out] def fn_mapping(m): - m :: dict + m :: dict[confirmed] r0 :: list r1 :: short_int r2 :: native_int - r3 :: object + r3 :: dict[confirmed] r4 :: tuple[bool, short_int, object] r5 :: short_int r6 :: bool @@ -226,7 +226,7 @@ def fn_mapping(m): r13 :: list r14 :: short_int r15 :: native_int - r16 :: object + r16 :: dict[confirmed] r17 :: tuple[bool, short_int, object] r18 :: short_int r19 :: bool @@ -238,7 +238,7 @@ def fn_mapping(m): r27 :: set r28 :: short_int r29 :: native_int - r30 :: object + r30 :: dict[confirmed] r31 :: tuple[bool, short_int, object] r32 :: short_int r33 :: bool @@ -249,7 +249,7 @@ def fn_mapping(m): r40 :: dict[confirmed] r41 :: short_int r42 :: native_int - r43 :: object + r43 :: dict[confirmed] r44 :: tuple[bool, short_int, object, object] r45 :: short_int r46 :: bool @@ -265,9 +265,9 @@ L0: r0 = PyList_New(0) r1 = 0 r2 = PyDict_Size(m) - r3 = CPyDict_GetKeysIter(m) + r3 = _CPyDict_GetIterUnsafe(m) L1: - r4 = CPyDict_NextKey(r3, r1) + r4 = CPyDict_NextKeyUnsafe(r3, r1) r5 = r4[1] r1 = r5 r6 = r4[0] @@ -279,7 +279,7 @@ L2: r9 = PyList_Append(r0, x) r10 = r9 >= 0 :: signed L3: - r11 = CPyDict_CheckSize(m, r2) + r11 = CPyDict_CheckSizeUnsafe(m, r2) goto L1 L4: r12 = CPy_NoErrOccurred() @@ -287,9 +287,9 @@ L5: r13 = PyList_New(0) r14 = 0 r15 = PyDict_Size(m) - r16 = CPyDict_GetValuesIter(m) + r16 = _CPyDict_GetIterUnsafe(m) L6: - r17 = CPyDict_NextValue(r16, r14) + r17 = CPyDict_NextValueUnsafe(r16, r14) r18 = r17[1] r14 = r18 r19 = r17[0] @@ -302,7 +302,7 @@ L7: r23 = PyList_Append(r13, r22) r24 = r23 >= 0 :: signed L8: - r25 = CPyDict_CheckSize(m, r15) + r25 = CPyDict_CheckSizeUnsafe(m, r15) goto L6 L9: r26 = CPy_NoErrOccurred() @@ -310,9 +310,9 @@ L10: r27 = PySet_New(0) r28 = 0 r29 = PyDict_Size(m) - r30 = CPyDict_GetKeysIter(m) + r30 = _CPyDict_GetIterUnsafe(m) L11: - r31 = CPyDict_NextKey(r30, r28) + r31 = CPyDict_NextKeyUnsafe(r30, r28) r32 = r31[1] r28 = r32 r33 = r31[0] @@ -324,7 +324,7 @@ L12: r36 = PySet_Add(r27, x_3) r37 = r36 >= 0 :: signed L13: - r38 = CPyDict_CheckSize(m, r29) + r38 = CPyDict_CheckSizeUnsafe(m, r29) goto L11 L14: r39 = CPy_NoErrOccurred() @@ -332,9 +332,9 @@ L15: r40 = PyDict_New() r41 = 0 r42 = PyDict_Size(m) - r43 = CPyDict_GetItemsIter(m) + r43 = _CPyDict_GetIterUnsafe(m) L16: - r44 = CPyDict_NextItem(r43, r41) + r44 = CPyDict_NextItemUnsafe(r43, r41) r45 = r44[1] r41 = r45 r46 = r44[0] @@ -350,18 +350,18 @@ L17: r52 = PyDict_SetItem(r40, k, r51) r53 = r52 >= 0 :: signed L18: - r54 = CPyDict_CheckSize(m, r42) + r54 = CPyDict_CheckSizeUnsafe(m, r42) goto L16 L19: r55 = CPy_NoErrOccurred() L20: return 1 def fn_union(m): - m :: dict + m :: dict[confirmed] r0 :: list r1 :: short_int r2 :: native_int - r3 :: object + r3 :: dict[confirmed] r4 :: tuple[bool, short_int, object] r5 :: short_int r6 :: bool @@ -372,7 +372,7 @@ def fn_union(m): r13 :: list r14 :: short_int r15 :: native_int - r16 :: object + r16 :: dict[confirmed] r17 :: tuple[bool, short_int, object] r18 :: short_int r19 :: bool @@ -383,7 +383,7 @@ def fn_union(m): r26 :: set r27 :: short_int r28 :: native_int - r29 :: object + r29 :: dict[confirmed] r30 :: tuple[bool, short_int, object] r31 :: short_int r32 :: bool @@ -394,7 +394,7 @@ def fn_union(m): r39 :: dict[confirmed] r40 :: short_int r41 :: native_int - r42 :: object + r42 :: dict[confirmed] r43 :: tuple[bool, short_int, object, object] r44 :: short_int r45 :: bool @@ -409,9 +409,9 @@ L0: r0 = PyList_New(0) r1 = 0 r2 = PyDict_Size(m) - r3 = CPyDict_GetKeysIter(m) + r3 = _CPyDict_GetIterUnsafe(m) L1: - r4 = CPyDict_NextKey(r3, r1) + r4 = CPyDict_NextKeyUnsafe(r3, r1) r5 = r4[1] r1 = r5 r6 = r4[0] @@ -423,7 +423,7 @@ L2: r9 = PyList_Append(r0, x) r10 = r9 >= 0 :: signed L3: - r11 = CPyDict_CheckSize(m, r2) + r11 = CPyDict_CheckSizeUnsafe(m, r2) goto L1 L4: r12 = CPy_NoErrOccurred() @@ -431,9 +431,9 @@ L5: r13 = PyList_New(0) r14 = 0 r15 = PyDict_Size(m) - r16 = CPyDict_GetValuesIter(m) + r16 = _CPyDict_GetIterUnsafe(m) L6: - r17 = CPyDict_NextValue(r16, r14) + r17 = CPyDict_NextValueUnsafe(r16, r14) r18 = r17[1] r14 = r18 r19 = r17[0] @@ -445,7 +445,7 @@ L7: r22 = PyList_Append(r13, x_2) r23 = r22 >= 0 :: signed L8: - r24 = CPyDict_CheckSize(m, r15) + r24 = CPyDict_CheckSizeUnsafe(m, r15) goto L6 L9: r25 = CPy_NoErrOccurred() @@ -453,9 +453,9 @@ L10: r26 = PySet_New(0) r27 = 0 r28 = PyDict_Size(m) - r29 = CPyDict_GetKeysIter(m) + r29 = _CPyDict_GetIterUnsafe(m) L11: - r30 = CPyDict_NextKey(r29, r27) + r30 = CPyDict_NextKeyUnsafe(r29, r27) r31 = r30[1] r27 = r31 r32 = r30[0] @@ -467,7 +467,7 @@ L12: r35 = PySet_Add(r26, x_3) r36 = r35 >= 0 :: signed L13: - r37 = CPyDict_CheckSize(m, r28) + r37 = CPyDict_CheckSizeUnsafe(m, r28) goto L11 L14: r38 = CPy_NoErrOccurred() @@ -475,9 +475,9 @@ L15: r39 = PyDict_New() r40 = 0 r41 = PyDict_Size(m) - r42 = CPyDict_GetItemsIter(m) + r42 = _CPyDict_GetIterUnsafe(m) L16: - r43 = CPyDict_NextItem(r42, r40) + r43 = CPyDict_NextItemUnsafe(r42, r40) r44 = r43[1] r40 = r44 r45 = r43[0] @@ -492,7 +492,7 @@ L17: r50 = PyDict_SetItem(r39, k, v) r51 = r50 >= 0 :: signed L18: - r52 = CPyDict_CheckSize(m, r41) + r52 = CPyDict_CheckSizeUnsafe(m, r41) goto L16 L19: r53 = CPy_NoErrOccurred() @@ -674,7 +674,7 @@ L2: def inner_deco_obj.__call__(__mypyc_self__, args, kwargs): __mypyc_self__ :: __main__.inner_deco_obj args :: tuple - kwargs :: dict + kwargs :: dict[confirmed] r0 :: __main__.deco_env r1 :: native_int r2 :: list @@ -773,3 +773,4 @@ def f(x): x :: int L0: return x + diff --git a/mypyc/test-data/irbuild-match.test b/mypyc/test-data/irbuild-match.test index 48b2605d3d88..164828b433fc 100644 --- a/mypyc/test-data/irbuild-match.test +++ b/mypyc/test-data/irbuild-match.test @@ -1089,37 +1089,36 @@ def f(x): x :: object r0 :: i32 r1 :: bit - r2 :: dict[confirmed] - r3, rest :: dict - r4 :: str - r5 :: object - r6 :: str - r7 :: object - r8 :: object[1] - r9 :: object_ptr - r10, r11 :: object + r2, rest :: dict[confirmed] + r3 :: str + r4 :: object + r5 :: str + r6 :: object + r7 :: object[1] + r8 :: object_ptr + r9, r10 :: object L0: r0 = CPyMapping_Check(x) r1 = r0 != 0 if r1 goto L1 else goto L3 :: bool L1: r2 = CPyDict_FromAny(x) - r3 = cast(dict, r2) - rest = r3 + rest = r2 L2: - r4 = 'matched' - r5 = builtins :: module - r6 = 'print' - r7 = CPyObject_GetAttr(r5, r6) - r8 = [r4] - r9 = load_address r8 - r10 = PyObject_Vectorcall(r7, r9, 1, 0) - keep_alive r4 + r3 = 'matched' + r4 = builtins :: module + r5 = 'print' + r6 = CPyObject_GetAttr(r4, r5) + r7 = [r3] + r8 = load_address r7 + r9 = PyObject_Vectorcall(r6, r8, 1, 0) + keep_alive r3 goto L4 L3: L4: - r11 = box(None, 1) - return r11 + r10 = box(None, 1) + return r10 + [case testMatchMappingPatternWithRestPopKeys_python3_10] def f(x): match x: @@ -1139,17 +1138,16 @@ def f(x): r8 :: i32 r9 :: bit r10 :: bool - r11 :: dict[confirmed] - r12, rest :: dict - r13 :: i32 - r14 :: bit - r15 :: str - r16 :: object - r17 :: str - r18 :: object - r19 :: object[1] - r20 :: object_ptr - r21, r22 :: object + r11, rest :: dict[confirmed] + r12 :: i32 + r13 :: bit + r14 :: str + r15 :: object + r16 :: str + r17 :: object + r18 :: object[1] + r19 :: object_ptr + r20, r21 :: object L0: r0 = CPyMapping_Check(x) r1 = r0 != 0 @@ -1169,24 +1167,24 @@ L2: if r10 goto L3 else goto L5 :: bool L3: r11 = CPyDict_FromAny(x) - r12 = cast(dict, r11) - rest = r12 - r13 = PyDict_DelItem(r11, r2) - r14 = r13 >= 0 :: signed + rest = r11 + r12 = PyDict_DelItem(r11, r2) + r13 = r12 >= 0 :: signed L4: - r15 = 'matched' - r16 = builtins :: module - r17 = 'print' - r18 = CPyObject_GetAttr(r16, r17) - r19 = [r15] - r20 = load_address r19 - r21 = PyObject_Vectorcall(r18, r20, 1, 0) - keep_alive r15 + r14 = 'matched' + r15 = builtins :: module + r16 = 'print' + r17 = CPyObject_GetAttr(r15, r16) + r18 = [r14] + r19 = load_address r18 + r20 = PyObject_Vectorcall(r17, r19, 1, 0) + keep_alive r14 goto L6 L5: L6: - r22 = box(None, 1) - return r22 + r21 = box(None, 1) + return r21 + [case testMatchEmptySequencePattern_python3_10] def f(x): match x: diff --git a/mypyc/test-data/irbuild-set.test b/mypyc/test-data/irbuild-set.test index 8b2e716ea0ce..79a225175482 100644 --- a/mypyc/test-data/irbuild-set.test +++ b/mypyc/test-data/irbuild-set.test @@ -161,20 +161,19 @@ L5: def test3(): r0, r1, r2 :: str r3, r4, r5 :: object - r6 :: dict[confirmed] - r7, tmp_dict :: dict - r8 :: set - r9 :: short_int - r10 :: native_int - r11 :: object - r12 :: tuple[bool, short_int, object] - r13 :: short_int - r14 :: bool - r15 :: object - r16, x, r17 :: int - r18 :: object - r19 :: i32 - r20, r21, r22 :: bit + r6, tmp_dict :: dict[confirmed] + r7 :: set + r8 :: short_int + r9 :: native_int + r10 :: dict[confirmed] + r11 :: tuple[bool, short_int, object] + r12 :: short_int + r13 :: bool + r14 :: object + r15, x, r16 :: int + r17 :: object + r18 :: i32 + r19, r20, r21 :: bit c :: set L0: r0 = '1' @@ -184,33 +183,32 @@ L0: r4 = object 3 r5 = object 5 r6 = CPyDict_Build(3, r3, r0, r4, r1, r5, r2) - r7 = cast(dict, r6) - tmp_dict = r7 - r8 = PySet_New(0) - r9 = 0 - r10 = PyDict_Size(tmp_dict) - r11 = CPyDict_GetKeysIter(tmp_dict) + tmp_dict = r6 + r7 = PySet_New(0) + r8 = 0 + r9 = PyDict_Size(tmp_dict) + r10 = _CPyDict_GetIterUnsafe(tmp_dict) L1: - r12 = CPyDict_NextKey(r11, r9) - r13 = r12[1] - r9 = r13 - r14 = r12[0] - if r14 goto L2 else goto L4 :: bool + r11 = CPyDict_NextKeyUnsafe(r10, r8) + r12 = r11[1] + r8 = r12 + r13 = r11[0] + if r13 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(r8, r18) - r20 = r19 >= 0 :: signed + r14 = r11[2] + r15 = unbox(int, r14) + x = r15 + r16 = f(x) + r17 = box(int, r16) + r18 = PySet_Add(r7, r17) + r19 = r18 >= 0 :: signed L3: - r21 = CPyDict_CheckSize(tmp_dict, r10) + r20 = CPyDict_CheckSizeUnsafe(tmp_dict, r9) goto L1 L4: - r22 = CPy_NoErrOccurred() + r21 = CPy_NoErrOccurred() L5: - c = r8 + c = r7 return 1 def test4(): r0 :: set diff --git a/mypyc/test-data/irbuild-statements.test b/mypyc/test-data/irbuild-statements.test index fd5e93fc6c42..392f4457c72c 100644 --- a/mypyc/test-data/irbuild-statements.test +++ b/mypyc/test-data/irbuild-statements.test @@ -263,10 +263,10 @@ def f(d: Dict[int, int]) -> None: d[key] [out] def f(d): - d :: dict + d :: dict[confirmed] r0 :: short_int r1 :: native_int - r2 :: object + r2 :: dict[confirmed] r3 :: tuple[bool, short_int, object] r4 :: short_int r5 :: bool @@ -278,9 +278,9 @@ def f(d): L0: r0 = 0 r1 = PyDict_Size(d) - r2 = CPyDict_GetKeysIter(d) + r2 = _CPyDict_GetIterUnsafe(d) L1: - r3 = CPyDict_NextKey(r2, r0) + r3 = CPyDict_NextKeyUnsafe(r2, r0) r4 = r3[1] r0 = r4 r5 = r3[0] @@ -290,10 +290,10 @@ L2: r7 = unbox(int, r6) key = r7 r8 = box(int, key) - r9 = CPyDict_GetItem(d, r8) + r9 = CPyDict_GetItemUnsafe(d, r8) r10 = unbox(int, r9) L3: - r11 = CPyDict_CheckSize(d, r1) + r11 = CPyDict_CheckSizeUnsafe(d, r1) goto L1 L4: r12 = CPy_NoErrOccurred() @@ -312,11 +312,11 @@ def sum_over_even_values(d: Dict[int, int]) -> int: return s [out] def sum_over_even_values(d): - d :: dict + d :: dict[confirmed] s :: int r0 :: short_int r1 :: native_int - r2 :: object + r2 :: dict[confirmed] r3 :: tuple[bool, short_int, object] r4 :: short_int r5 :: bool @@ -332,9 +332,9 @@ L0: s = 0 r0 = 0 r1 = PyDict_Size(d) - r2 = CPyDict_GetKeysIter(d) + r2 = _CPyDict_GetIterUnsafe(d) L1: - r3 = CPyDict_NextKey(r2, r0) + r3 = CPyDict_NextKeyUnsafe(r2, r0) r4 = r3[1] r0 = r4 r5 = r3[0] @@ -344,7 +344,7 @@ L2: r7 = unbox(int, r6) key = r7 r8 = box(int, key) - r9 = CPyDict_GetItem(d, r8) + r9 = CPyDict_GetItemUnsafe(d, r8) r10 = unbox(int, r9) r11 = CPyTagged_Remainder(r10, 4) r12 = r11 != 0 @@ -353,12 +353,12 @@ L3: goto L5 L4: r13 = box(int, key) - r14 = CPyDict_GetItem(d, r13) + r14 = CPyDict_GetItemUnsafe(d, r13) r15 = unbox(int, r14) r16 = CPyTagged_Add(s, r15) s = r16 L5: - r17 = CPyDict_CheckSize(d, r1) + r17 = CPyDict_CheckSizeUnsafe(d, r1) goto L1 L6: r18 = CPy_NoErrOccurred() @@ -759,33 +759,30 @@ def delDictMultiple() -> None: def delDict(): r0, r1 :: str r2, r3 :: object - r4 :: dict[confirmed] - r5, d :: dict - r6 :: str - r7 :: i32 - r8 :: bit + r4, d :: dict[confirmed] + r5 :: str + r6 :: i32 + r7 :: bit L0: r0 = 'one' r1 = 'two' r2 = object 1 r3 = object 2 r4 = CPyDict_Build(2, r0, r2, r1, r3) - r5 = cast(dict, r4) - d = r5 - r6 = 'one' - r7 = PyObject_DelItem(d, r6) - r8 = r7 >= 0 :: signed + d = r4 + r5 = 'one' + r6 = PyObject_DelItem(d, r5) + r7 = r6 >= 0 :: signed return 1 def delDictMultiple(): r0, r1, r2, r3 :: str r4, r5, r6, r7 :: object - r8 :: dict[confirmed] - r9, d :: dict - r10, r11 :: str - r12 :: i32 - r13 :: bit - r14 :: i32 - r15 :: bit + r8, d :: dict[confirmed] + r9, r10 :: str + r11 :: i32 + r12 :: bit + r13 :: i32 + r14 :: bit L0: r0 = 'one' r1 = 'two' @@ -796,14 +793,13 @@ L0: r6 = object 3 r7 = object 4 r8 = CPyDict_Build(4, r0, r4, r1, r5, r2, r6, r3, r7) - r9 = cast(dict, r8) - d = r9 - r10 = 'one' - r11 = 'four' - r12 = PyObject_DelItem(d, r10) - r13 = r12 >= 0 :: signed - r14 = PyObject_DelItem(d, r11) - r15 = r14 >= 0 :: signed + d = r8 + r9 = 'one' + r10 = 'four' + r11 = PyObject_DelItem(d, r9) + r12 = r11 >= 0 :: signed + r13 = PyObject_DelItem(d, r10) + r14 = r13 >= 0 :: signed return 1 [case testDelAttribute] diff --git a/mypyc/test-data/refcount.test b/mypyc/test-data/refcount.test index a71c53041cf7..91b17fc53a4e 100644 --- a/mypyc/test-data/refcount.test +++ b/mypyc/test-data/refcount.test @@ -727,10 +727,10 @@ def f(d: Dict[int, int]) -> None: d[key] [out] def f(d): - d :: dict + d :: dict[confirmed] r0 :: short_int r1 :: native_int - r2 :: object + r2 :: dict[confirmed] r3 :: tuple[bool, short_int, object] r4 :: short_int r5 :: bool @@ -742,9 +742,9 @@ def f(d): L0: r0 = 0 r1 = PyDict_Size(d) - r2 = CPyDict_GetKeysIter(d) + r2 = _CPyDict_GetIterUnsafe(d) L1: - r3 = CPyDict_NextKey(r2, r0) + r3 = CPyDict_NextKeyUnsafe(r2, r0) r4 = r3[1] r0 = r4 r5 = r3[0] @@ -756,13 +756,13 @@ L2: dec_ref r6 key = r7 r8 = box(int, key) - r9 = CPyDict_GetItem(d, r8) + r9 = CPyDict_GetItemUnsafe(d, r8) dec_ref r8 r10 = unbox(int, r9) dec_ref r9 dec_ref r10 :: int L3: - r11 = CPyDict_CheckSize(d, r1) + r11 = CPyDict_CheckSizeUnsafe(d, r1) goto L1 L4: r12 = CPy_NoErrOccurred() From 61db53367f04f22c913ab90df100f60bca10c57d Mon Sep 17 00:00:00 2001 From: BobTheBuidler Date: Mon, 4 Aug 2025 02:01:36 +0000 Subject: [PATCH 08/43] fix: mypy errs --- mypyc/primitives/misc_ops.py | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/mypyc/primitives/misc_ops.py b/mypyc/primitives/misc_ops.py index 83ddf5466c8b..70372803fd8c 100644 --- a/mypyc/primitives/misc_ops.py +++ b/mypyc/primitives/misc_ops.py @@ -190,7 +190,7 @@ ) # bool(dict) -dict_is_true_op = function_op( +function_op( name="builtins.bool", arg_types=[true_dict_rprimitive], return_type=bit_rprimitive, @@ -198,6 +198,14 @@ error_kind=ERR_FALSE, ) +# bool(dict) custom_op +dict_is_true_op = function_op( + arg_types=[true_dict_rprimitive], + return_type=bit_rprimitive, + c_function_name="CPyDict_IsTrue", + error_kind=ERR_FALSE, +) + # bool(obj) with unboxed result bool_op = function_op( name="builtins.bool", From 990b8364c2b360454183eddb57e90dc9ca41ae25 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 4 Aug 2025 02:01:36 +0000 Subject: [PATCH 09/43] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- mypyc/test-data/irbuild-dict.test | 1 - mypyc/test-data/irbuild-generics.test | 1 - 2 files changed, 2 deletions(-) diff --git a/mypyc/test-data/irbuild-dict.test b/mypyc/test-data/irbuild-dict.test index 8cf2477ce38a..ed888ecaa828 100644 --- a/mypyc/test-data/irbuild-dict.test +++ b/mypyc/test-data/irbuild-dict.test @@ -571,4 +571,3 @@ L2: L3: r8 = box(None, 1) return r8 - diff --git a/mypyc/test-data/irbuild-generics.test b/mypyc/test-data/irbuild-generics.test index dd81ebc2b342..8f356e271c2a 100644 --- a/mypyc/test-data/irbuild-generics.test +++ b/mypyc/test-data/irbuild-generics.test @@ -773,4 +773,3 @@ def f(x): x :: int L0: return x - From 6543e4f76877856af74e229fc85c532f0eea56e0 Mon Sep 17 00:00:00 2001 From: BobTheBuidler Date: Mon, 4 Aug 2025 02:01:36 +0000 Subject: [PATCH 10/43] fix: mypy errs --- mypyc/primitives/misc_ops.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mypyc/primitives/misc_ops.py b/mypyc/primitives/misc_ops.py index 70372803fd8c..2ba6ec075793 100644 --- a/mypyc/primitives/misc_ops.py +++ b/mypyc/primitives/misc_ops.py @@ -199,7 +199,7 @@ ) # bool(dict) custom_op -dict_is_true_op = function_op( +dict_is_true_op = custom_op( arg_types=[true_dict_rprimitive], return_type=bit_rprimitive, c_function_name="CPyDict_IsTrue", From 89c4879b71ea6f9bf366151a70eb9b05454605b2 Mon Sep 17 00:00:00 2001 From: BobTheBuidler Date: Mon, 4 Aug 2025 02:01:36 +0000 Subject: [PATCH 11/43] fix: clear ers never --- mypyc/primitives/dict_ops.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mypyc/primitives/dict_ops.py b/mypyc/primitives/dict_ops.py index af1eba2a9841..622d49154d17 100644 --- a/mypyc/primitives/dict_ops.py +++ b/mypyc/primitives/dict_ops.py @@ -379,7 +379,7 @@ arg_types=[true_dict_rprimitive], return_type=bit_rprimitive, c_function_name="PyDict_Clear", - error_kind=ERR_FALSE, + error_kind=ERR_NEVER, ) # dictsubclass.clear() From efc9401be69ebb13f286b3e7d35918dcbd87fc57 Mon Sep 17 00:00:00 2001 From: BobTheBuidler Date: Mon, 4 Aug 2025 02:01:36 +0000 Subject: [PATCH 12/43] fix: err kind --- mypyc/primitives/dict_ops.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mypyc/primitives/dict_ops.py b/mypyc/primitives/dict_ops.py index 622d49154d17..9aace7acc48c 100644 --- a/mypyc/primitives/dict_ops.py +++ b/mypyc/primitives/dict_ops.py @@ -470,7 +470,7 @@ arg_types=[true_dict_rprimitive], return_type=true_dict_rprimitive, c_function_name="_CPyDict_GetIterUnsafe", - error_kind=ERR_MAGIC, + error_kind=ERR_NEVER, ) # PyDict_Next() fast iteration for subclass From c08f8b53d644d14bd4ae308310cfad9b2b2e7a3f Mon Sep 17 00:00:00 2001 From: BobTheBuidler Date: Mon, 4 Aug 2025 02:01:36 +0000 Subject: [PATCH 13/43] fix: err kind --- mypyc/primitives/dict_ops.py | 12 ++++++------ mypyc/primitives/misc_ops.py | 4 ++-- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/mypyc/primitives/dict_ops.py b/mypyc/primitives/dict_ops.py index 9aace7acc48c..5c8f6e9e299f 100644 --- a/mypyc/primitives/dict_ops.py +++ b/mypyc/primitives/dict_ops.py @@ -278,7 +278,7 @@ arg_types=[true_dict_rprimitive, object_rprimitive, object_rprimitive], return_type=object_rprimitive, c_function_name="PyDict_SetDefault", - error_kind=ERR_MAGIC, + error_kind=ERR_NEVER, ) # dictorsubclass.setdefault(key, default) @@ -397,7 +397,7 @@ arg_types=[true_dict_rprimitive], return_type=true_dict_rprimitive, c_function_name="PyDict_Copy", - error_kind=ERR_MAGIC, + error_kind=ERR_NEVER, ) # dictsubclass.copy() @@ -414,7 +414,7 @@ arg_types=[true_dict_rprimitive], return_type=true_dict_rprimitive, c_function_name="PyDict_Copy", - error_kind=ERR_MAGIC, + error_kind=ERR_NEVER, ) # list(dict.keys()) @@ -422,7 +422,7 @@ arg_types=[true_dict_rprimitive], return_type=list_rprimitive, c_function_name="PyDict_Keys", - error_kind=ERR_MAGIC, + error_kind=ERR_NEVER, ) # list(dictorsubclass.keys()) @@ -438,7 +438,7 @@ arg_types=[true_dict_rprimitive], return_type=list_rprimitive, c_function_name="PyDict_Values", - error_kind=ERR_MAGIC, + error_kind=ERR_NEVER, ) # list(dictorsubclass.values()) @@ -454,7 +454,7 @@ arg_types=[true_dict_rprimitive], return_type=list_rprimitive, c_function_name="PyDict_Items", - error_kind=ERR_MAGIC, + error_kind=ERR_NEVER, ) # list(dictorsubclass.items()) diff --git a/mypyc/primitives/misc_ops.py b/mypyc/primitives/misc_ops.py index 2ba6ec075793..df1508f65ea9 100644 --- a/mypyc/primitives/misc_ops.py +++ b/mypyc/primitives/misc_ops.py @@ -195,7 +195,7 @@ arg_types=[true_dict_rprimitive], return_type=bit_rprimitive, c_function_name="CPyDict_IsTrue", - error_kind=ERR_FALSE, + error_kind=ERR_NEVER, ) # bool(dict) custom_op @@ -203,7 +203,7 @@ arg_types=[true_dict_rprimitive], return_type=bit_rprimitive, c_function_name="CPyDict_IsTrue", - error_kind=ERR_FALSE, + error_kind=ERR_NEVER, ) # bool(obj) with unboxed result From b49e66d66516f501cbe79f061ccf81429d84c81f Mon Sep 17 00:00:00 2001 From: BobTheBuidler Date: Mon, 4 Aug 2025 02:01:36 +0000 Subject: [PATCH 14/43] fix: err kind --- mypyc/primitives/dict_ops.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/mypyc/primitives/dict_ops.py b/mypyc/primitives/dict_ops.py index 5c8f6e9e299f..bff19db1a6f6 100644 --- a/mypyc/primitives/dict_ops.py +++ b/mypyc/primitives/dict_ops.py @@ -15,6 +15,7 @@ list_rprimitive, object_rprimitive, true_dict_rprimitive, + void_rtype, ) from mypyc.primitives.registry import ( ERR_NEG_INT, @@ -377,7 +378,7 @@ method_op( name="clear", arg_types=[true_dict_rprimitive], - return_type=bit_rprimitive, + return_type=void_rtype, c_function_name="PyDict_Clear", error_kind=ERR_NEVER, ) From ee47b94bd95d1de52087cf3fcfc6eab91d9c30c7 Mon Sep 17 00:00:00 2001 From: BobTheBuidler Date: Mon, 4 Aug 2025 02:01:36 +0000 Subject: [PATCH 15/43] chore: rename true dict to exact dict --- mypyc/analysis/ircheck.py | 4 +- mypyc/ir/rtypes.py | 10 +-- mypyc/irbuild/builder.py | 4 +- mypyc/irbuild/classdef.py | 4 +- mypyc/irbuild/for_helpers.py | 22 ++--- mypyc/irbuild/function.py | 12 +-- mypyc/irbuild/ll_builder.py | 15 ++-- mypyc/irbuild/mapper.py | 8 +- mypyc/irbuild/prepare.py | 4 +- mypyc/irbuild/specialize.py | 14 +-- mypyc/primitives/bytes_ops.py | 4 +- mypyc/primitives/dict_ops.py | 72 ++++++++-------- mypyc/primitives/misc_ops.py | 8 +- mypyc/test-data/irbuild-basic.test | 96 ++++++++++----------- mypyc/test-data/irbuild-bool.test | 2 +- mypyc/test-data/irbuild-bytes.test | 2 +- mypyc/test-data/irbuild-classes.test | 20 ++--- mypyc/test-data/irbuild-dict.test | 52 +++++------ mypyc/test-data/irbuild-generics.test | 38 ++++---- mypyc/test-data/irbuild-match.test | 4 +- mypyc/test-data/irbuild-set.test | 8 +- mypyc/test-data/irbuild-singledispatch.test | 16 ++-- mypyc/test-data/irbuild-statements.test | 12 +-- mypyc/test-data/refcount.test | 4 +- 24 files changed, 217 insertions(+), 218 deletions(-) diff --git a/mypyc/analysis/ircheck.py b/mypyc/analysis/ircheck.py index 1e57183eb7cd..bcbe15e8e824 100644 --- a/mypyc/analysis/ircheck.py +++ b/mypyc/analysis/ircheck.py @@ -71,7 +71,7 @@ range_rprimitive, set_rprimitive, str_rprimitive, - true_dict_rprimitive, + exact_dict_rprimitive, tuple_rprimitive, ) @@ -178,7 +178,7 @@ def check_op_sources_valid(fn: FuncIR) -> list[FnError]: int_rprimitive.name, bytes_rprimitive.name, str_rprimitive.name, - true_dict_rprimitive.name, + exact_dict_rprimitive.name, dict_rprimitive.name, list_rprimitive.name, set_rprimitive.name, diff --git a/mypyc/ir/rtypes.py b/mypyc/ir/rtypes.py index 68d4b11b2221..82fa5c790a10 100644 --- a/mypyc/ir/rtypes.py +++ b/mypyc/ir/rtypes.py @@ -488,8 +488,8 @@ def __hash__(self) -> int: ) # Python dict object. -true_dict_rprimitive: Final = RPrimitive( - "builtins.dict[confirmed]", is_unboxed=False, is_refcounted=True +exact_dict_rprimitive: Final = RPrimitive( + "builtins.dict[exact]", is_unboxed=False, is_refcounted=True ) """A primitive for dicts that are confirmed to be actual instances of builtins.dict, not a subclass.""" @@ -617,12 +617,12 @@ def is_list_rprimitive(rtype: RType) -> TypeGuard[RPrimitive]: def is_dict_rprimitive(rtype: RType) -> TypeGuard[RPrimitive]: return isinstance(rtype, RPrimitive) and rtype.name in ( "builtins.dict", - "builtins.dict[confirmed]", + "builtins.dict[exact]", ) -def is_true_dict_rprimitive(rtype: RType) -> TypeGuard[RPrimitive]: - return isinstance(rtype, RPrimitive) and rtype.name == "builtins.dict[confirmed]" +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]: diff --git a/mypyc/irbuild/builder.py b/mypyc/irbuild/builder.py index 23dbd9c38723..47154ff20d54 100644 --- a/mypyc/irbuild/builder.py +++ b/mypyc/irbuild/builder.py @@ -103,7 +103,7 @@ none_rprimitive, object_rprimitive, str_rprimitive, - true_dict_rprimitive, + exact_dict_rprimitive, ) from mypyc.irbuild.context import FuncInfo, ImplicitClass from mypyc.irbuild.ll_builder import LowLevelIRBuilder @@ -1393,7 +1393,7 @@ def load_global_str(self, name: str, line: int) -> Value: return self.primitive_op(true_dict_get_item_op, [_globals, reg], line) def load_globals_dict(self) -> Value: - return self.add(LoadStatic(true_dict_rprimitive, "globals", self.module_name)) + return self.add(LoadStatic(exact_dict_rprimitive, "globals", self.module_name)) def load_module_attr_by_fullname(self, fullname: str, line: int) -> Value: module, _, name = fullname.rpartition(".") diff --git a/mypyc/irbuild/classdef.py b/mypyc/irbuild/classdef.py index f36f3971b40b..9db9c258aa61 100644 --- a/mypyc/irbuild/classdef.py +++ b/mypyc/irbuild/classdef.py @@ -54,7 +54,7 @@ is_object_rprimitive, is_optional_type, object_rprimitive, - true_dict_rprimitive, + exact_dict_rprimitive, ) from mypyc.irbuild.builder import IRBuilder, create_type_params from mypyc.irbuild.function import ( @@ -611,7 +611,7 @@ def setup_non_ext_dict( py_hasattr_op, [metaclass, builder.load_str("__prepare__")], cdef.line ) - non_ext_dict = Register(true_dict_rprimitive) + non_ext_dict = Register(exact_dict_rprimitive) true_block, false_block, exit_block = BasicBlock(), BasicBlock(), BasicBlock() builder.add_bool_branch(has_prepare, true_block, false_block) diff --git a/mypyc/irbuild/for_helpers.py b/mypyc/irbuild/for_helpers.py index 088370313f79..178ddca0bfe0 100644 --- a/mypyc/irbuild/for_helpers.py +++ b/mypyc/irbuild/for_helpers.py @@ -58,7 +58,7 @@ is_sequence_rprimitive, is_short_int_rprimitive, is_str_rprimitive, - is_true_dict_rprimitive, + is_exact_dict_rprimitive, is_tuple_rprimitive, object_pointer_rprimitive, object_rprimitive, @@ -431,7 +431,7 @@ def make_for_loop_generator( expr_reg = builder.accept(expr) target_type = builder.get_dict_key_type(expr) for_loop_cls = ( - ForTrueDictionaryKeys if is_true_dict_rprimitive(rtyp) else ForDictionaryKeys + ForExactDictionaryKeys if is_exact_dict_rprimitive(rtyp) else ForDictionaryKeys ) for_dict = for_loop_cls(builder, index, body_block, loop_exit, line, nested) for_dict.init(expr_reg, target_type) @@ -515,20 +515,20 @@ def make_for_loop_generator( for_dict_type: type[ForGenerator] | None = None if expr.callee.name == "keys": target_type = builder.get_dict_key_type(expr.callee.expr) - if is_true_dict_rprimitive(rtype): - for_dict_type = ForTrueDictionaryKeys + if is_exact_dict_rprimitive(rtype): + for_dict_type = ForExactDictionaryKeys else: for_dict_type = ForDictionaryKeys elif expr.callee.name == "values": target_type = builder.get_dict_value_type(expr.callee.expr) - if is_true_dict_rprimitive(rtype): - for_dict_type = ForTrueDictionaryValues + if is_exact_dict_rprimitive(rtype): + for_dict_type = ForExactDictionaryValues else: for_dict_type = ForDictionaryValues else: target_type = builder.get_dict_item_type(expr.callee.expr) - if is_true_dict_rprimitive(rtype): - for_dict_type = ForTrueDictionaryItems + if is_exact_dict_rprimitive(rtype): + for_dict_type = ForExactDictionaryItems else: for_dict_type = ForDictionaryItems for_dict_gen = for_dict_type(builder, index, body_block, loop_exit, line, nested) @@ -1040,7 +1040,7 @@ def begin_body(self) -> None: builder.assign(target, rvalue, line) -class ForTrueDictionaryKeys(ForDictionaryKeys): +class ForExactDictionaryKeys(ForDictionaryKeys): """Generate optimized IR for a for loop over dictionary items without type checks.""" dict_next_op = true_dict_next_key_op @@ -1048,7 +1048,7 @@ class ForTrueDictionaryKeys(ForDictionaryKeys): dict_size_op = true_dict_check_size_op -class ForTrueDictionaryValues(ForDictionaryValues): +class ForExactDictionaryValues(ForDictionaryValues): """Generate optimized IR for a for loop over dictionary items without type checks.""" dict_next_op = true_dict_next_value_op @@ -1056,7 +1056,7 @@ class ForTrueDictionaryValues(ForDictionaryValues): dict_size_op = true_dict_check_size_op -class ForTrueDictionaryItems(ForDictionaryItems): +class ForExactDictionaryItems(ForDictionaryItems): """Generate optimized IR for a for loop over dictionary items without type checks.""" dict_next_op = true_dict_next_item_op diff --git a/mypyc/irbuild/function.py b/mypyc/irbuild/function.py index db229224e04e..f0f78b667a98 100644 --- a/mypyc/irbuild/function.py +++ b/mypyc/irbuild/function.py @@ -58,7 +58,7 @@ bool_rprimitive, int_rprimitive, object_rprimitive, - true_dict_rprimitive, + exact_dict_rprimitive, ) from mypyc.irbuild.builder import IRBuilder, calculate_arg_defaults, gen_arg_defaults from mypyc.irbuild.callable_class import ( @@ -813,7 +813,7 @@ def generate_singledispatch_dispatch_function( arg_type = builder.builder.get_type_of_obj(arg_info.args[0], line) dispatch_cache = builder.builder.get_attr( - dispatch_func_obj, "dispatch_cache", true_dict_rprimitive, line + dispatch_func_obj, "dispatch_cache", exact_dict_rprimitive, line ) call_find_impl, use_cache, call_func = BasicBlock(), BasicBlock(), BasicBlock() get_result = builder.primitive_op( @@ -895,8 +895,8 @@ def gen_dispatch_func_ir( """ builder.enter(FuncInfo(fitem, dispatch_name)) setup_callable_class(builder) - builder.fn_info.callable_class.ir.attributes["registry"] = true_dict_rprimitive - builder.fn_info.callable_class.ir.attributes["dispatch_cache"] = true_dict_rprimitive + builder.fn_info.callable_class.ir.attributes["registry"] = exact_dict_rprimitive + builder.fn_info.callable_class.ir.attributes["dispatch_cache"] = exact_dict_rprimitive builder.fn_info.callable_class.ir.has_dict = True builder.fn_info.callable_class.ir.needs_getseters = True generate_singledispatch_callable_class_ctor(builder) @@ -959,7 +959,7 @@ def add_register_method_to_callable_class(builder: IRBuilder, fn_info: FuncInfo) def load_singledispatch_registry(builder: IRBuilder, dispatch_func_obj: Value, line: int) -> Value: - return builder.builder.get_attr(dispatch_func_obj, "registry", true_dict_rprimitive, line) + return builder.builder.get_attr(dispatch_func_obj, "registry", exact_dict_rprimitive, line) def singledispatch_main_func_name(orig_name: str) -> str: @@ -1010,7 +1010,7 @@ def maybe_insert_into_registry_dict(builder: IRBuilder, fitem: FuncDef) -> None: loaded_type = load_type(builder, typ, None, line) builder.call_c(exact_dict_set_item_op, [registry, loaded_type, to_insert], line) dispatch_cache = builder.builder.get_attr( - dispatch_func_obj, "dispatch_cache", true_dict_rprimitive, line + dispatch_func_obj, "dispatch_cache", exact_dict_rprimitive, line ) builder.gen_method_call(dispatch_cache, "clear", [], None, line) diff --git a/mypyc/irbuild/ll_builder.py b/mypyc/irbuild/ll_builder.py index 0d83df7339b8..3f6e092cf2dd 100644 --- a/mypyc/irbuild/ll_builder.py +++ b/mypyc/irbuild/ll_builder.py @@ -95,6 +95,7 @@ c_size_t_rprimitive, check_native_int_range, dict_rprimitive, + exact_dict_rprimitive, float_rprimitive, int_rprimitive, is_bool_or_bit_rprimitive, @@ -115,7 +116,7 @@ is_short_int_rprimitive, is_str_rprimitive, is_tagged, - is_true_dict_rprimitive, + is_exact_dict_rprimitive, is_tuple_rprimitive, is_uint8_rprimitive, list_rprimitive, @@ -126,8 +127,6 @@ pointer_rprimitive, short_int_rprimitive, str_rprimitive, - true_dict_rprimitive, - tuple_rprimitive, ) from mypyc.irbuild.util import concrete_arg_kind from mypyc.options import CompilerOptions @@ -861,7 +860,7 @@ def _construct_varargs( ) star2_result = self._create_dict(star2_keys, star2_values, line) - if is_true_dict_rprimitive(value.type): + if is_exact_dict_rprimitive(value.type): op = true_dict_update_in_display_op else: op = dict_update_in_display_op @@ -1827,13 +1826,13 @@ def make_dict(self, key_value_pairs: Sequence[DictEntry], line: int) -> Value: else: # **value if result is None: - if len(key_value_pairs) == 1 and is_true_dict_rprimitive(value.type): + if len(key_value_pairs) == 1 and is_exact_dict_rprimitive(value.type): # fast path for cases like `my_func(**dict(zip(iterable, other)))` and similar return self.call_c(true_dict_copy_op, [value], line=line) result = self._create_dict(keys, values, line) - if is_true_dict_rprimitive(value.type): + if is_exact_dict_rprimitive(value.type): op = true_dict_update_in_display_op else: op = dict_update_in_display_op @@ -1942,7 +1941,7 @@ def bool_value(self, value: Value) -> Value: result = self.add(ComparisonOp(value, zero, ComparisonOp.NEQ)) elif is_str_rprimitive(value.type): result = self.call_c(str_check_if_true, [value], value.line) - elif is_same_type(value.type, true_dict_rprimitive): + elif is_same_type(value.type, exact_dict_rprimitive): result = self.call_c(dict_is_true_op, [value], line=value.line) elif is_same_type(value.type, list_rprimitive) or is_same_type( value.type, dict_rprimitive of is_same_type(value.type, tuple_rprimitive) @@ -2449,7 +2448,7 @@ def builtin_len(self, val: Value, line: int, use_pyssize_t: bool = False) -> Val elem_address = self.add(GetElementPtr(val, PySetObject, "used")) size_value = self.load_mem(elem_address, c_pyssize_t_rprimitive) self.add(KeepAlive([val])) - elif is_true_dict_rprimitive(typ): + elif is_exact_dict_rprimitive(typ): size_value = self.call_c(true_dict_ssize_t_size_op, [val], line) elif is_dict_rprimitive(typ): size_value = self.call_c(dict_ssize_t_size_op, [val], line) diff --git a/mypyc/irbuild/mapper.py b/mypyc/irbuild/mapper.py index d079d3a88f24..5d5862a42637 100644 --- a/mypyc/irbuild/mapper.py +++ b/mypyc/irbuild/mapper.py @@ -45,7 +45,7 @@ range_rprimitive, set_rprimitive, str_rprimitive, - true_dict_rprimitive, + exact_dict_rprimitive, tuple_rprimitive, uint8_rprimitive, ) @@ -95,7 +95,7 @@ def type_to_rtype(self, typ: Type | None) -> RType: # specifically support them, so make sure that dict operations # get optimized on them. elif typ.type.fullname == "builtins.dict": - return true_dict_rprimitive + return exact_dict_rprimitive elif any(cls.fullname == "builtins.dict" for cls in typ.type.mro): return dict_rprimitive elif typ.type.fullname == "builtins.set": @@ -157,7 +157,7 @@ def type_to_rtype(self, typ: Type | None) -> RType: elif isinstance(typ, Overloaded): return object_rprimitive elif isinstance(typ, TypedDictType): - return true_dict_rprimitive + return exact_dict_rprimitive elif isinstance(typ, LiteralType): return self.type_to_rtype(typ.fallback) elif isinstance(typ, (UninhabitedType, UnboundType)): @@ -172,7 +172,7 @@ def get_arg_rtype(self, typ: Type, kind: ArgKind) -> RType: if kind == ARG_STAR: return tuple_rprimitive elif kind == ARG_STAR2: - return true_dict_rprimitive + return exact_dict_rprimitive else: return self.type_to_rtype(typ) diff --git a/mypyc/irbuild/prepare.py b/mypyc/irbuild/prepare.py index 978de86f9343..8b2dc500cc31 100644 --- a/mypyc/irbuild/prepare.py +++ b/mypyc/irbuild/prepare.py @@ -57,7 +57,7 @@ none_rprimitive, object_pointer_rprimitive, object_rprimitive, - true_dict_rprimitive, + exact_dict_rprimitive, tuple_rprimitive, ) from mypyc.irbuild.mapper import Mapper @@ -626,7 +626,7 @@ def prepare_init_method(cdef: ClassDef, ir: ClassIR, module_name: str, mapper: M [ init_sig.args[0], RuntimeArg("args", tuple_rprimitive, ARG_STAR), - RuntimeArg("kwargs", true_dict_rprimitive, ARG_STAR2), + RuntimeArg("kwargs", exact_dict_rprimitive, ARG_STAR2), ], init_sig.ret_type, ) diff --git a/mypyc/irbuild/specialize.py b/mypyc/irbuild/specialize.py index 18b51a23b783..0c54b76a8f35 100644 --- a/mypyc/irbuild/specialize.py +++ b/mypyc/irbuild/specialize.py @@ -66,12 +66,12 @@ is_int64_rprimitive, is_int_rprimitive, is_list_rprimitive, - is_true_dict_rprimitive, + is_exact_dict_rprimitive, is_uint8_rprimitive, list_rprimitive, set_rprimitive, str_rprimitive, - true_dict_rprimitive, + exact_dict_rprimitive, uint8_rprimitive, ) from mypyc.irbuild.builder import IRBuilder @@ -259,17 +259,17 @@ def dict_methods_fast_path(builder: IRBuilder, expr: CallExpr, callee: RefExpr) # so the corresponding helpers in CPy.h fallback to (inlined) # generic logic. if attr == "keys": - if is_true_dict_rprimitive(rtype): + if is_exact_dict_rprimitive(rtype): op = true_dict_keys_op else: op = dict_keys_op elif attr == "values": - if is_true_dict_rprimitive(rtype): + if is_exact_dict_rprimitive(rtype): op = true_dict_values_op else: op = dict_values_op else: - if is_true_dict_rprimitive(rtype): + if is_exact_dict_rprimitive(rtype): op = true_dict_items_op else: op = dict_items_op @@ -383,7 +383,7 @@ def faster_min_max(builder: IRBuilder, expr: CallExpr, callee: RefExpr) -> Value @specialize_function("join", str_rprimitive) @specialize_function("extend", list_rprimitive) @specialize_function("update", dict_rprimitive) -@specialize_function("update", true_dict_rprimitive) +@specialize_function("update", exact_dict_rprimitive) @specialize_function("update", set_rprimitive) def translate_safe_generator_call( builder: IRBuilder, expr: CallExpr, callee: RefExpr @@ -625,7 +625,7 @@ def translate_isinstance(builder: IRBuilder, expr: CallExpr, callee: RefExpr) -> @specialize_function("setdefault", dict_rprimitive) -@specialize_function("setdefault", true_dict_rprimitive) +@specialize_function("setdefault", exact_dict_rprimitive) def translate_dict_setdefault(builder: IRBuilder, expr: CallExpr, callee: RefExpr) -> Value | None: """Special case for 'dict.setdefault' which would only construct default empty collection when needed. diff --git a/mypyc/primitives/bytes_ops.py b/mypyc/primitives/bytes_ops.py index c218ad006737..117d842867b7 100644 --- a/mypyc/primitives/bytes_ops.py +++ b/mypyc/primitives/bytes_ops.py @@ -14,7 +14,7 @@ list_rprimitive, object_rprimitive, str_rprimitive, - true_dict_rprimitive, + exact_dict_rprimitive, ) from mypyc.primitives.registry import ( ERR_NEG_INT, @@ -31,7 +31,7 @@ # bytes(obj) function_op( name="builtins.bytes", - arg_types=[RUnion([list_rprimitive, dict_rprimitive, true_dict_rprimitive, str_rprimitive])], + arg_types=[RUnion([list_rprimitive, dict_rprimitive, exact_dict_rprimitive, str_rprimitive])], return_type=bytes_rprimitive, c_function_name="PyBytes_FromObject", error_kind=ERR_MAGIC, diff --git a/mypyc/primitives/dict_ops.py b/mypyc/primitives/dict_ops.py index bff19db1a6f6..bb35a1fba3f3 100644 --- a/mypyc/primitives/dict_ops.py +++ b/mypyc/primitives/dict_ops.py @@ -14,7 +14,7 @@ int_rprimitive, list_rprimitive, object_rprimitive, - true_dict_rprimitive, + exact_dict_rprimitive, void_rtype, ) from mypyc.primitives.registry import ( @@ -33,7 +33,7 @@ function_op( name="builtins.dict", arg_types=[], - return_type=true_dict_rprimitive, + return_type=exact_dict_rprimitive, c_function_name="PyDict_New", error_kind=ERR_MAGIC, ) @@ -41,7 +41,7 @@ # Construct an empty dictionary. dict_new_op = custom_op( arg_types=[], - return_type=true_dict_rprimitive, + return_type=exact_dict_rprimitive, c_function_name="PyDict_New", error_kind=ERR_MAGIC, ) @@ -51,7 +51,7 @@ # Variable arguments are (key1, value1, ..., keyN, valueN). dict_build_op = custom_op( arg_types=[c_pyssize_t_rprimitive], - return_type=true_dict_rprimitive, + return_type=exact_dict_rprimitive, c_function_name="CPyDict_Build", error_kind=ERR_MAGIC, var_arg_type=object_rprimitive, @@ -60,8 +60,8 @@ # Construct a dictionary from another dictionary. dict_copy_op = function_op( name="builtins.dict", - arg_types=[true_dict_rprimitive], - return_type=true_dict_rprimitive, + arg_types=[exact_dict_rprimitive], + return_type=exact_dict_rprimitive, c_function_name="PyDict_Copy", error_kind=ERR_MAGIC, priority=2, @@ -80,7 +80,7 @@ dict_copy = function_op( name="builtins.dict", arg_types=[object_rprimitive], - return_type=true_dict_rprimitive, + return_type=exact_dict_rprimitive, c_function_name="CPyDict_FromAny", error_kind=ERR_MAGIC, ) @@ -97,7 +97,7 @@ # dict[key] true_dict_get_item_op = method_op( name="__getitem__", - arg_types=[true_dict_rprimitive, object_rprimitive], + arg_types=[exact_dict_rprimitive, object_rprimitive], return_type=object_rprimitive, c_function_name="CPyDict_GetItemUnsafe", error_kind=ERR_MAGIC, @@ -115,7 +115,7 @@ # dict[key] = value true_dict_set_item_op = method_op( name="__setitem__", - arg_types=[true_dict_rprimitive, object_rprimitive, object_rprimitive], + arg_types=[exact_dict_rprimitive, object_rprimitive, object_rprimitive], return_type=c_int_rprimitive, c_function_name="PyDict_SetItem", error_kind=ERR_NEG_INT, @@ -142,7 +142,7 @@ # key in dict binary_op( name="in", - arg_types=[object_rprimitive, true_dict_rprimitive], + arg_types=[object_rprimitive, exact_dict_rprimitive], return_type=c_int_rprimitive, c_function_name="PyDict_Contains", error_kind=ERR_NEG_INT, @@ -164,7 +164,7 @@ # dict1.update(dict2) true_dict_update_op = method_op( name="update", - arg_types=[true_dict_rprimitive, true_dict_rprimitive], + arg_types=[exact_dict_rprimitive, exact_dict_rprimitive], return_type=c_int_rprimitive, c_function_name="PyDict_Update", error_kind=ERR_NEG_INT, @@ -174,7 +174,7 @@ # dictorsubclass.update(dict) dict_update_from_true_dict_op = method_op( name="update", - arg_types=[dict_rprimitive, true_dict_rprimitive], + arg_types=[dict_rprimitive, exact_dict_rprimitive], return_type=c_int_rprimitive, c_function_name="CPyDict_Update", error_kind=ERR_NEG_INT, @@ -184,7 +184,7 @@ # dict.update(dictsubclass) true_dict_update_from_dict_op = method_op( name="update", - arg_types=[true_dict_rprimitive, dict_rprimitive], + arg_types=[exact_dict_rprimitive, dict_rprimitive], return_type=c_int_rprimitive, c_function_name="PyDict_Update", error_kind=ERR_NEG_INT, @@ -204,7 +204,7 @@ # Operation used for **value in with exact dictionary `value`. # This is mostly like dict.update(obj), but has customized error handling. true_dict_update_in_display_op = custom_op( - arg_types=[true_dict_rprimitive, true_dict_rprimitive], + arg_types=[exact_dict_rprimitive, exact_dict_rprimitive], return_type=c_int_rprimitive, c_function_name="PyDict_Update", error_kind=ERR_NEG_INT, @@ -222,7 +222,7 @@ # dict.update(obj) method_op( name="update", - arg_types=[true_dict_rprimitive, object_rprimitive], + arg_types=[exact_dict_rprimitive, object_rprimitive], return_type=c_int_rprimitive, c_function_name="CPyDict_UpdateFromAnyUnsafe", error_kind=ERR_NEG_INT, @@ -240,7 +240,7 @@ # dict.get(key, default) method_op( name="get", - arg_types=[true_dict_rprimitive, object_rprimitive, object_rprimitive], + arg_types=[exact_dict_rprimitive, object_rprimitive, object_rprimitive], return_type=object_rprimitive, c_function_name="CPyDict_Get", error_kind=ERR_MAGIC, @@ -258,7 +258,7 @@ # dict.get(key) true_dict_get_method_with_none = method_op( name="get", - arg_types=[true_dict_rprimitive, object_rprimitive], + arg_types=[exact_dict_rprimitive, object_rprimitive], return_type=object_rprimitive, c_function_name="CPyDict_GetWithNone", error_kind=ERR_MAGIC, @@ -276,7 +276,7 @@ # dict.setdefault(key, default) true_dict_setdefault_op = method_op( name="setdefault", - arg_types=[true_dict_rprimitive, object_rprimitive, object_rprimitive], + arg_types=[exact_dict_rprimitive, object_rprimitive, object_rprimitive], return_type=object_rprimitive, c_function_name="PyDict_SetDefault", error_kind=ERR_NEVER, @@ -294,7 +294,7 @@ # dict.setdefault(key) method_op( name="setdefault", - arg_types=[true_dict_rprimitive, object_rprimitive], + arg_types=[exact_dict_rprimitive, object_rprimitive], return_type=object_rprimitive, c_function_name="CPyDict_SetDefaultWithNone", error_kind=ERR_MAGIC, @@ -323,7 +323,7 @@ # dict.keys() method_op( name="keys", - arg_types=[true_dict_rprimitive], + arg_types=[exact_dict_rprimitive], return_type=object_rprimitive, c_function_name="CPyDict_KeysViewUnsafe", error_kind=ERR_MAGIC, @@ -341,7 +341,7 @@ # dict.values() method_op( name="values", - arg_types=[true_dict_rprimitive], + arg_types=[exact_dict_rprimitive], return_type=object_rprimitive, c_function_name="CPyDict_ValuesViewUnsafe", error_kind=ERR_MAGIC, @@ -359,7 +359,7 @@ # dict.items() method_op( name="items", - arg_types=[true_dict_rprimitive], + arg_types=[exact_dict_rprimitive], return_type=object_rprimitive, c_function_name="CPyDict_ItemsViewUnsafe", error_kind=ERR_MAGIC, @@ -377,7 +377,7 @@ # dict.clear() method_op( name="clear", - arg_types=[true_dict_rprimitive], + arg_types=[exact_dict_rprimitive], return_type=void_rtype, c_function_name="PyDict_Clear", error_kind=ERR_NEVER, @@ -395,8 +395,8 @@ # dict.copy() method_op( name="copy", - arg_types=[true_dict_rprimitive], - return_type=true_dict_rprimitive, + arg_types=[exact_dict_rprimitive], + return_type=exact_dict_rprimitive, c_function_name="PyDict_Copy", error_kind=ERR_NEVER, ) @@ -412,15 +412,15 @@ # dict.copy() custom_op true_dict_copy_op = custom_op( - arg_types=[true_dict_rprimitive], - return_type=true_dict_rprimitive, + arg_types=[exact_dict_rprimitive], + return_type=exact_dict_rprimitive, c_function_name="PyDict_Copy", error_kind=ERR_NEVER, ) # list(dict.keys()) true_dict_keys_op = custom_op( - arg_types=[true_dict_rprimitive], + arg_types=[exact_dict_rprimitive], return_type=list_rprimitive, c_function_name="PyDict_Keys", error_kind=ERR_NEVER, @@ -436,7 +436,7 @@ # list(dict.values()) true_dict_values_op = custom_op( - arg_types=[true_dict_rprimitive], + arg_types=[exact_dict_rprimitive], return_type=list_rprimitive, c_function_name="PyDict_Values", error_kind=ERR_NEVER, @@ -452,7 +452,7 @@ # list(dict.items()) true_dict_items_op = custom_op( - arg_types=[true_dict_rprimitive], + arg_types=[exact_dict_rprimitive], return_type=list_rprimitive, c_function_name="PyDict_Items", error_kind=ERR_NEVER, @@ -468,8 +468,8 @@ # PyDict_Next() fast iteration true_dict_iter_fast_path_op = custom_op( - arg_types=[true_dict_rprimitive], - return_type=true_dict_rprimitive, + arg_types=[exact_dict_rprimitive], + return_type=exact_dict_rprimitive, c_function_name="_CPyDict_GetIterUnsafe", error_kind=ERR_NEVER, ) @@ -532,7 +532,7 @@ ) true_dict_next_item_op = custom_op( - arg_types=[true_dict_rprimitive, int_rprimitive], + arg_types=[exact_dict_rprimitive, int_rprimitive], return_type=dict_next_rtuple_pair, c_function_name="CPyDict_NextItemUnsafe", error_kind=ERR_NEVER, @@ -540,7 +540,7 @@ # check that len(dict) == const during iteration true_dict_check_size_op = custom_op( - arg_types=[true_dict_rprimitive, c_pyssize_t_rprimitive], + arg_types=[exact_dict_rprimitive, c_pyssize_t_rprimitive], return_type=bit_rprimitive, c_function_name="CPyDict_CheckSizeUnsafe", error_kind=ERR_FALSE, @@ -555,7 +555,7 @@ ) true_dict_ssize_t_size_op = custom_op( - arg_types=[true_dict_rprimitive], + arg_types=[exact_dict_rprimitive], return_type=c_pyssize_t_rprimitive, c_function_name="PyDict_Size", error_kind=ERR_NEVER, @@ -570,7 +570,7 @@ # Delete an item from a dict true_dict_del_item = custom_op( - arg_types=[true_dict_rprimitive, object_rprimitive], + arg_types=[exact_dict_rprimitive, object_rprimitive], return_type=c_int_rprimitive, c_function_name="PyDict_DelItem", error_kind=ERR_NEG_INT, diff --git a/mypyc/primitives/misc_ops.py b/mypyc/primitives/misc_ops.py index df1508f65ea9..30d50af9a56f 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, @@ -20,7 +21,6 @@ object_rprimitive, pointer_rprimitive, str_rprimitive, - true_dict_rprimitive, uint8_rprimitive, void_rtype, ) @@ -162,7 +162,7 @@ # Get the sys.modules dictionary get_module_dict_op = custom_op( arg_types=[], - return_type=true_dict_rprimitive, + return_type=exact_dict_rprimitive, c_function_name="PyImport_GetModuleDict", error_kind=ERR_NEVER, is_borrowed=True, @@ -192,7 +192,7 @@ # bool(dict) function_op( name="builtins.bool", - arg_types=[true_dict_rprimitive], + arg_types=[exact_dict_rprimitive], return_type=bit_rprimitive, c_function_name="CPyDict_IsTrue", error_kind=ERR_NEVER, @@ -200,7 +200,7 @@ # bool(dict) custom_op dict_is_true_op = custom_op( - arg_types=[true_dict_rprimitive], + arg_types=[exact_dict_rprimitive], return_type=bit_rprimitive, c_function_name="CPyDict_IsTrue", error_kind=ERR_NEVER, diff --git a/mypyc/test-data/irbuild-basic.test b/mypyc/test-data/irbuild-basic.test index 0da2238a7e59..c38112cfafba 100644 --- a/mypyc/test-data/irbuild-basic.test +++ b/mypyc/test-data/irbuild-basic.test @@ -526,11 +526,11 @@ def __top_level__(): r11 :: native_int[4] r12 :: c_ptr r13 :: object - r14 :: dict[confirmed] + r14 :: dict[exact] r15, r16 :: str r17 :: bit r18 :: str - r19 :: dict[confirmed] + r19 :: dict[exact] r20 :: str r21 :: i32 r22 :: bit @@ -540,7 +540,7 @@ def __top_level__(): r26 :: native_int[1] r27 :: c_ptr r28 :: object - r29 :: dict[confirmed] + r29 :: dict[exact] r30, r31 :: str r32 :: bit r33 :: object @@ -604,18 +604,18 @@ def h() -> int: [out] def f(x): x :: int - r0 :: dict[confirmed] + r0 :: dict[exact] r1 :: str r2, r3 :: object r4 :: object[1] r5 :: object_ptr r6 :: object r7 :: int - r8 :: dict[confirmed] + r8 :: dict[exact] r9 :: str r10, r11 :: object r12, r13 :: int - r14 :: dict[confirmed] + r14 :: dict[exact] r15 :: str r16, r17 :: object r18, r19 :: int @@ -648,10 +648,10 @@ def __top_level__(): r3 :: str r4, r5 :: object r6 :: str - r7 :: dict[confirmed] + r7 :: dict[exact] r8, r9, r10 :: object r11 :: str - r12 :: dict[confirmed] + r12 :: dict[exact] r13 :: object L0: r0 = builtins :: module @@ -966,10 +966,10 @@ def f(o, p, n, b, t, s, a, l, d): s :: tuple[int, int] a :: __main__.A l :: list - d :: dict[confirmed] + d :: dict[exact] r0 :: object l2 :: list - d2 :: dict[confirmed] + d2 :: dict[exact] L0: o = o p = p @@ -1137,7 +1137,7 @@ L0: return r0 def call_python_function(x): x :: int - r0 :: dict[confirmed] + r0 :: dict[exact] r1 :: str r2, r3 :: object r4 :: object[1] @@ -1159,7 +1159,7 @@ def return_float(): L0: return 5.0 def return_callable_type(): - r0 :: dict[confirmed] + r0 :: dict[exact] r1 :: str r2 :: object L0: @@ -1423,7 +1423,7 @@ def f() -> None: print(x) [out] def f(): - r0 :: dict[confirmed] + r0 :: dict[exact] r1 :: str r2 :: object r3 :: int @@ -1452,12 +1452,12 @@ def __top_level__(): r2 :: bit r3 :: str r4 :: object - r5 :: dict[confirmed] + r5 :: dict[exact] r6 :: str r7 :: object r8 :: i32 r9 :: bit - r10 :: dict[confirmed] + r10 :: dict[exact] r11 :: str r12 :: object r13 :: int @@ -1672,7 +1672,7 @@ L0: return r0 def g(): r0 :: tuple[int, int, int] - r1 :: dict[confirmed] + r1 :: dict[exact] r2 :: str r3, r4, r5 :: object r6 :: tuple[int, int, int] @@ -1687,7 +1687,7 @@ L0: return r6 def h(): r0 :: tuple[int, int] - r1 :: dict[confirmed] + r1 :: dict[exact] r2 :: str r3 :: object r4 :: list @@ -1758,10 +1758,10 @@ L0: def h(): r0, r1 :: str r2, r3 :: object - r4, r5 :: dict[confirmed] + r4, r5 :: dict[exact] r6 :: str r7 :: object - r8 :: dict[confirmed] + r8 :: dict[exact] r9 :: i32 r10 :: bit r11 :: object @@ -1931,7 +1931,7 @@ def f() -> Dict[int, int]: return {x: x*x for x in [1,2,3] if x != 2 if x != 3} [out] def f(): - r0 :: dict[confirmed] + r0 :: dict[exact] r1 :: list r2, r3, r4 :: object r5 :: ptr @@ -2149,7 +2149,7 @@ def __top_level__(): r3 :: str r4, r5 :: object r6 :: str - r7 :: dict[confirmed] + r7 :: dict[exact] r8 :: object r9, r10 :: str r11 :: object @@ -2161,53 +2161,53 @@ def __top_level__(): r17 :: object r18 :: tuple[object, object] r19 :: object - r20 :: dict[confirmed] + r20 :: dict[exact] r21 :: str r22 :: object r23 :: object[2] r24 :: object_ptr r25 :: object - r26 :: dict[confirmed] + r26 :: dict[exact] r27 :: str r28 :: i32 r29 :: bit r30 :: str - r31 :: dict[confirmed] + r31 :: dict[exact] r32 :: str r33, r34 :: object r35 :: object[2] r36 :: object_ptr r37 :: object r38 :: tuple - r39 :: dict[confirmed] + r39 :: dict[exact] r40 :: str r41 :: i32 r42 :: bit - r43 :: dict[confirmed] + r43 :: dict[exact] r44 :: str r45, r46, r47 :: object - r48 :: dict[confirmed] + r48 :: dict[exact] r49 :: str r50 :: i32 r51 :: bit r52 :: str - r53 :: dict[confirmed] + r53 :: dict[exact] r54 :: str r55 :: object - r56 :: dict[confirmed] + r56 :: dict[exact] r57 :: str r58 :: object r59 :: object[2] r60 :: object_ptr r61 :: object - r62 :: dict[confirmed] + r62 :: dict[exact] r63 :: str r64 :: i32 r65 :: bit r66 :: list r67, r68, r69 :: object r70 :: ptr - r71 :: dict[confirmed] + r71 :: dict[exact] r72 :: str r73 :: i32 r74 :: bit @@ -2581,19 +2581,19 @@ def c(): r0 :: __main__.c_env r1 :: __main__.d_c_obj r2 :: bool - r3 :: dict[confirmed] + r3 :: dict[exact] r4 :: str r5 :: object r6 :: object[1] r7 :: object_ptr r8 :: object - r9 :: dict[confirmed] + r9 :: dict[exact] r10 :: str r11 :: object r12 :: object[1] r13 :: object_ptr r14, d :: object - r15 :: dict[confirmed] + r15 :: dict[exact] r16 :: str r17 :: i32 r18 :: bit @@ -2643,24 +2643,24 @@ def __top_level__(): r3 :: str r4, r5 :: object r6 :: str - r7 :: dict[confirmed] + r7 :: dict[exact] r8 :: object - r9 :: dict[confirmed] + r9 :: dict[exact] r10 :: str r11 :: object - r12 :: dict[confirmed] + r12 :: dict[exact] r13 :: str r14 :: object r15 :: object[1] r16 :: object_ptr r17 :: object - r18 :: dict[confirmed] + r18 :: dict[exact] r19 :: str r20 :: object r21 :: object[1] r22 :: object_ptr r23 :: object - r24 :: dict[confirmed] + r24 :: dict[exact] r25 :: str r26 :: i32 r27 :: bit @@ -2784,7 +2784,7 @@ def __top_level__(): r3 :: str r4, r5 :: object r6 :: str - r7 :: dict[confirmed] + r7 :: dict[exact] r8 :: object L0: r0 = builtins :: module @@ -3250,7 +3250,7 @@ L0: r1 = PySequence_List(r0) return r1 def h(x): - x :: dict[confirmed] + x :: dict[exact] r0 :: list L0: r0 = PySequence_List(x) @@ -3284,24 +3284,24 @@ x = 1 [file p/m.py] [out] def root(): - r0 :: dict[confirmed] + r0 :: dict[exact] r1, r2 :: object r3 :: bit r4 :: str r5 :: object r6 :: str - r7 :: dict[confirmed] + r7 :: dict[exact] r8 :: str r9 :: object r10 :: i32 r11 :: bit - r12 :: dict[confirmed] + r12 :: dict[exact] r13, r14 :: object r15 :: bit r16 :: str r17 :: object r18 :: str - r19 :: dict[confirmed] + r19 :: dict[exact] r20 :: str r21 :: object r22 :: i32 @@ -3341,18 +3341,18 @@ L4: r23 = r22 >= 0 :: signed return 1 def submodule(): - r0 :: dict[confirmed] + r0 :: dict[exact] r1, r2 :: object r3 :: bit r4 :: str r5 :: object r6 :: str - r7 :: dict[confirmed] + r7 :: dict[exact] r8 :: str r9 :: object r10 :: i32 r11 :: bit - r12 :: dict[confirmed] + r12 :: dict[exact] r13 :: str r14 :: object r15 :: str diff --git a/mypyc/test-data/irbuild-bool.test b/mypyc/test-data/irbuild-bool.test index fa209186b09c..49edfdc0647e 100644 --- a/mypyc/test-data/irbuild-bool.test +++ b/mypyc/test-data/irbuild-bool.test @@ -148,7 +148,7 @@ L2: L3: return r4 def typeddict_to_bool(o): - o :: dict[confirmed] + o :: dict[exact] r0 :: bit L0: r0 = CPyDict_IsTrue(o) diff --git a/mypyc/test-data/irbuild-bytes.test b/mypyc/test-data/irbuild-bytes.test index f0d72cd0d160..c5443e1ea2af 100644 --- a/mypyc/test-data/irbuild-bytes.test +++ b/mypyc/test-data/irbuild-bytes.test @@ -9,7 +9,7 @@ def f(num: int, l: list, d: dict, s: str) -> None: def f(num, l, d, s): num :: int l :: list - d :: dict[confirmed] + d :: dict[exact] s :: str r0, r1 :: object r2, b1 :: bytes diff --git a/mypyc/test-data/irbuild-classes.test b/mypyc/test-data/irbuild-classes.test index cdc467008929..fcbfec095f49 100644 --- a/mypyc/test-data/irbuild-classes.test +++ b/mypyc/test-data/irbuild-classes.test @@ -201,19 +201,19 @@ def __top_level__(): r3 :: str r4, r5 :: object r6 :: str - r7 :: dict[confirmed] + r7 :: dict[exact] r8, r9 :: object r10 :: str - r11 :: dict[confirmed] + r11 :: dict[exact] r12 :: object r13 :: str - r14 :: dict[confirmed] + r14 :: dict[exact] r15 :: str r16 :: object r17 :: object[1] r18 :: object_ptr r19 :: object - r20 :: dict[confirmed] + r20 :: dict[exact] r21 :: str r22 :: i32 r23 :: bit @@ -225,7 +225,7 @@ def __top_level__(): r30 :: tuple r31 :: i32 r32 :: bit - r33 :: dict[confirmed] + r33 :: dict[exact] r34 :: str r35 :: i32 r36 :: bit @@ -236,15 +236,15 @@ def __top_level__(): r42 :: tuple r43 :: i32 r44 :: bit - r45 :: dict[confirmed] + r45 :: dict[exact] r46 :: str r47 :: i32 r48 :: bit r49, r50 :: object - r51 :: dict[confirmed] + r51 :: dict[exact] r52 :: str r53 :: object - r54 :: dict[confirmed] + r54 :: dict[exact] r55 :: str r56, r57 :: object r58 :: tuple @@ -255,7 +255,7 @@ def __top_level__(): r65 :: tuple r66 :: i32 r67 :: bit - r68 :: dict[confirmed] + r68 :: dict[exact] r69 :: str r70 :: i32 r71 :: bit @@ -1064,7 +1064,7 @@ L0: return 1 def B.__mypyc_defaults_setup(__mypyc_self__): __mypyc_self__ :: __main__.B - r0 :: dict[confirmed] + r0 :: dict[exact] r1 :: str r2 :: object r3 :: str diff --git a/mypyc/test-data/irbuild-dict.test b/mypyc/test-data/irbuild-dict.test index ed888ecaa828..685edcd6e206 100644 --- a/mypyc/test-data/irbuild-dict.test +++ b/mypyc/test-data/irbuild-dict.test @@ -4,7 +4,7 @@ def f(d: Dict[int, bool]) -> bool: return d[0] [out] def f(d): - d :: dict[confirmed] + d :: dict[exact] r0, r1 :: object r2 :: bool L0: @@ -19,7 +19,7 @@ def f(d: Dict[int, bool]) -> None: d[0] = False [out] def f(d): - d :: dict[confirmed] + d :: dict[exact] r0, r1 :: object r2 :: i32 r3 :: bit @@ -36,7 +36,7 @@ def f() -> None: d = {} # type: Dict[bool, int] [out] def f(): - r0, d :: dict[confirmed] + r0, d :: dict[exact] L0: r0 = PyDict_New() d = r0 @@ -49,7 +49,7 @@ def f() -> None: [out] def f(): - r0, d :: dict[confirmed] + r0, d :: dict[exact] L0: r0 = PyDict_New() d = r0 @@ -63,7 +63,7 @@ def f(x): x :: object r0 :: str r1, r2 :: object - r3, d :: dict[confirmed] + r3, d :: dict[exact] L0: r0 = '' r1 = object 1 @@ -81,7 +81,7 @@ def f(d: Dict[int, int]) -> bool: return False [out] def f(d): - d :: dict[confirmed] + d :: dict[exact] r0 :: object r1 :: i32 r2 :: bit @@ -108,7 +108,7 @@ def f(d: Dict[int, int]) -> bool: return False [out] def f(d): - d :: dict[confirmed] + d :: dict[exact] r0 :: object r1 :: i32 r2 :: bit @@ -133,7 +133,7 @@ def f(a: Dict[int, int], b: Dict[int, int]) -> None: a.update(b) [out] def f(a, b): - a, b :: dict[confirmed] + a, b :: dict[exact] r0 :: i32 r1 :: bit L0: @@ -149,10 +149,10 @@ def increment(d: Dict[str, int]) -> Dict[str, int]: return d [out] def increment(d): - d :: dict[confirmed] + d :: dict[exact] r0 :: short_int r1 :: native_int - r2 :: dict[confirmed] + r2 :: dict[exact] r3 :: tuple[bool, short_int, object] r4 :: short_int r5 :: bool @@ -195,10 +195,10 @@ def f(x: str, y: Dict[str, int]) -> Dict[str, int]: [out] def f(x, y): x :: str - y :: dict[confirmed] + y :: dict[exact] r0 :: str r1 :: object - r2 :: dict[confirmed] + r2 :: dict[exact] r3 :: i32 r4 :: bit r5 :: object @@ -239,10 +239,10 @@ def typeddict(d: Person) -> None: [typing fixtures/typing-full.pyi] [out] def print_dict_methods(d1, d2): - d1, d2 :: dict[confirmed] + d1, d2 :: dict[exact] r0 :: short_int r1 :: native_int - r2 :: dict[confirmed] + r2 :: dict[exact] r3 :: tuple[bool, short_int, object] r4 :: short_int r5 :: bool @@ -255,7 +255,7 @@ def print_dict_methods(d1, d2): r12, r13 :: bit r14 :: short_int r15 :: native_int - r16 :: dict[confirmed] + r16 :: dict[exact] r17 :: tuple[bool, short_int, object, object] r18 :: short_int r19 :: bool @@ -323,10 +323,10 @@ L11: L12: return 1 def union_of_dicts(d): - d, r0, new :: dict[confirmed] + d, r0, new :: dict[exact] r1 :: short_int r2 :: native_int - r3 :: dict[confirmed] + r3 :: dict[exact] r4 :: tuple[bool, short_int, object, object] r5 :: short_int r6 :: bool @@ -379,10 +379,10 @@ L4: L5: return 1 def typeddict(d): - d :: dict[confirmed] + d :: dict[exact] r0 :: short_int r1 :: native_int - r2 :: dict[confirmed] + r2 :: dict[exact] r3 :: tuple[bool, short_int, object, object] r4 :: short_int r5 :: bool @@ -440,7 +440,7 @@ def f(d: Dict[int, int]) -> None: return d.clear() [out] def f(d): - d :: dict[confirmed] + d :: dict[exact] r0 :: bit L0: r0 = PyDict_Clear(d) @@ -452,7 +452,7 @@ def f(d: Dict[int, int]) -> Dict[int, int]: return d.copy() [out] def f(d): - d, r0 :: dict[confirmed] + d, r0 :: dict[exact] L0: r0 = PyDict_Copy(d) return r0 @@ -481,7 +481,7 @@ def f4(d: Dict[object, object], flag: bool) -> object: return d.setdefault('a', {'c': 1}) [out] def f(d): - d :: dict[confirmed] + d :: dict[exact] r0, r1 :: str r2 :: object L0: @@ -490,7 +490,7 @@ L0: r2 = PyDict_SetDefault(d, r0, r1) return r2 def f2(d, flag): - d :: dict[confirmed] + d :: dict[exact] flag :: bool r0 :: str r1 :: dict @@ -515,7 +515,7 @@ L3: r7 = box(None, 1) return r7 def f3(d, flag): - d :: dict[confirmed] + d :: dict[exact] flag :: bool r0 :: str r1 :: dict @@ -545,14 +545,14 @@ L3: r8 = box(None, 1) return r8 def f4(d, flag): - d :: dict[confirmed] + d :: dict[exact] flag :: bool r0 :: str r1 :: dict r2 :: object r3, r4 :: str r5 :: object - r6 :: dict[confirmed] + r6 :: dict[exact] r7, r8 :: object L0: if flag goto L1 else goto L2 :: bool diff --git a/mypyc/test-data/irbuild-generics.test b/mypyc/test-data/irbuild-generics.test index 8f356e271c2a..b5f80b1ff96d 100644 --- a/mypyc/test-data/irbuild-generics.test +++ b/mypyc/test-data/irbuild-generics.test @@ -211,11 +211,11 @@ def fn_typeddict(t: T) -> None: [typing fixtures/typing-full.pyi] [out] def fn_mapping(m): - m :: dict[confirmed] + m :: dict[exact] r0 :: list r1 :: short_int r2 :: native_int - r3 :: dict[confirmed] + r3 :: dict[exact] r4 :: tuple[bool, short_int, object] r5 :: short_int r6 :: bool @@ -226,7 +226,7 @@ def fn_mapping(m): r13 :: list r14 :: short_int r15 :: native_int - r16 :: dict[confirmed] + r16 :: dict[exact] r17 :: tuple[bool, short_int, object] r18 :: short_int r19 :: bool @@ -238,7 +238,7 @@ def fn_mapping(m): r27 :: set r28 :: short_int r29 :: native_int - r30 :: dict[confirmed] + r30 :: dict[exact] r31 :: tuple[bool, short_int, object] r32 :: short_int r33 :: bool @@ -246,10 +246,10 @@ def fn_mapping(m): r35, x_3 :: str r36 :: i32 r37, r38, r39 :: bit - r40 :: dict[confirmed] + r40 :: dict[exact] r41 :: short_int r42 :: native_int - r43 :: dict[confirmed] + r43 :: dict[exact] r44 :: tuple[bool, short_int, object, object] r45 :: short_int r46 :: bool @@ -357,11 +357,11 @@ L19: L20: return 1 def fn_union(m): - m :: dict[confirmed] + m :: dict[exact] r0 :: list r1 :: short_int r2 :: native_int - r3 :: dict[confirmed] + r3 :: dict[exact] r4 :: tuple[bool, short_int, object] r5 :: short_int r6 :: bool @@ -372,7 +372,7 @@ def fn_union(m): r13 :: list r14 :: short_int r15 :: native_int - r16 :: dict[confirmed] + r16 :: dict[exact] r17 :: tuple[bool, short_int, object] r18 :: short_int r19 :: bool @@ -383,7 +383,7 @@ def fn_union(m): r26 :: set r27 :: short_int r28 :: native_int - r29 :: dict[confirmed] + r29 :: dict[exact] r30 :: tuple[bool, short_int, object] r31 :: short_int r32 :: bool @@ -391,10 +391,10 @@ def fn_union(m): r34, x_3 :: str r35 :: i32 r36, r37, r38 :: bit - r39 :: dict[confirmed] + r39 :: dict[exact] r40 :: short_int r41 :: native_int - r42 :: dict[confirmed] + r42 :: dict[exact] r43 :: tuple[bool, short_int, object, object] r44 :: short_int r45 :: bool @@ -499,11 +499,11 @@ L19: L20: return 1 def fn_typeddict(t): - t :: dict[confirmed] + t :: dict[exact] r0 :: list r1 :: short_int r2 :: native_int - r3 :: dict[confirmed] + r3 :: dict[exact] r4 :: tuple[bool, short_int, object] r5 :: short_int r6 :: bool @@ -514,7 +514,7 @@ def fn_typeddict(t): r13 :: list r14 :: short_int r15 :: native_int - r16 :: dict[confirmed] + r16 :: dict[exact] r17 :: tuple[bool, short_int, object] r18 :: short_int r19 :: bool @@ -524,7 +524,7 @@ def fn_typeddict(t): r25 :: set r26 :: short_int r27 :: native_int - r28 :: dict[confirmed] + r28 :: dict[exact] r29 :: tuple[bool, short_int, object] r30 :: short_int r31 :: bool @@ -532,10 +532,10 @@ def fn_typeddict(t): r33, x_3 :: str r34 :: i32 r35, r36, r37 :: bit - r38 :: dict[confirmed] + r38 :: dict[exact] r39 :: short_int r40 :: native_int - r41 :: dict[confirmed] + r41 :: dict[exact] r42 :: tuple[bool, short_int, object, object] r43 :: short_int r44 :: bool @@ -674,7 +674,7 @@ L2: def inner_deco_obj.__call__(__mypyc_self__, args, kwargs): __mypyc_self__ :: __main__.inner_deco_obj args :: tuple - kwargs :: dict[confirmed] + kwargs :: dict[exact] r0 :: __main__.deco_env r1 :: native_int r2 :: list diff --git a/mypyc/test-data/irbuild-match.test b/mypyc/test-data/irbuild-match.test index 164828b433fc..95ea948e05ea 100644 --- a/mypyc/test-data/irbuild-match.test +++ b/mypyc/test-data/irbuild-match.test @@ -1089,7 +1089,7 @@ def f(x): x :: object r0 :: i32 r1 :: bit - r2, rest :: dict[confirmed] + r2, rest :: dict[exact] r3 :: str r4 :: object r5 :: str @@ -1138,7 +1138,7 @@ def f(x): r8 :: i32 r9 :: bit r10 :: bool - r11, rest :: dict[confirmed] + r11, rest :: dict[exact] r12 :: i32 r13 :: bit r14 :: str diff --git a/mypyc/test-data/irbuild-set.test b/mypyc/test-data/irbuild-set.test index 79a225175482..1876fea88964 100644 --- a/mypyc/test-data/irbuild-set.test +++ b/mypyc/test-data/irbuild-set.test @@ -161,11 +161,11 @@ L5: def test3(): r0, r1, r2 :: str r3, r4, r5 :: object - r6, tmp_dict :: dict[confirmed] + r6, tmp_dict :: dict[exact] r7 :: set r8 :: short_int r9 :: native_int - r10 :: dict[confirmed] + r10 :: dict[exact] r11 :: tuple[bool, short_int, object] r12 :: short_int r13 :: bool @@ -646,7 +646,7 @@ L0: return r3 def not_precomputed_non_final_name(i): i :: int - r0 :: dict[confirmed] + r0 :: dict[exact] r1 :: str r2 :: object r3 :: int @@ -766,7 +766,7 @@ L4: L5: return 1 def not_precomputed(): - r0 :: dict[confirmed] + r0 :: dict[exact] r1 :: str r2 :: object r3 :: int diff --git a/mypyc/test-data/irbuild-singledispatch.test b/mypyc/test-data/irbuild-singledispatch.test index a3df1c363ade..8b94f4171942 100644 --- a/mypyc/test-data/irbuild-singledispatch.test +++ b/mypyc/test-data/irbuild-singledispatch.test @@ -14,7 +14,7 @@ L0: return 0 def f_obj.__init__(__mypyc_self__): __mypyc_self__ :: __main__.f_obj - r0, r1 :: dict[confirmed] + r0, r1 :: dict[exact] r2 :: str r3 :: i32 r4 :: bit @@ -31,13 +31,13 @@ def f_obj.__call__(__mypyc_self__, arg): arg :: object r0 :: ptr r1 :: object - r2 :: dict[confirmed] + r2 :: dict[exact] r3, r4 :: object r5 :: bit r6, r7 :: object r8 :: str r9 :: object - r10 :: dict[confirmed] + r10 :: dict[exact] r11 :: object[2] r12 :: object_ptr r13 :: object @@ -124,7 +124,7 @@ L0: return r0 def f(arg): arg :: object - r0 :: dict[confirmed] + r0 :: dict[exact] r1 :: str r2 :: object r3 :: bool @@ -155,7 +155,7 @@ L0: return 1 def f_obj.__init__(__mypyc_self__): __mypyc_self__ :: __main__.f_obj - r0, r1 :: dict[confirmed] + r0, r1 :: dict[exact] r2 :: str r3 :: i32 r4 :: bit @@ -172,13 +172,13 @@ def f_obj.__call__(__mypyc_self__, x): x :: object r0 :: ptr r1 :: object - r2 :: dict[confirmed] + r2 :: dict[exact] r3, r4 :: object r5 :: bit r6, r7 :: object r8 :: str r9 :: object - r10 :: dict[confirmed] + r10 :: dict[exact] r11 :: object[2] r12 :: object_ptr r13 :: object @@ -255,7 +255,7 @@ L0: return r0 def f(x): x :: object - r0 :: dict[confirmed] + r0 :: dict[exact] r1 :: str r2 :: object r3 :: None diff --git a/mypyc/test-data/irbuild-statements.test b/mypyc/test-data/irbuild-statements.test index 392f4457c72c..535bf8fe7cc7 100644 --- a/mypyc/test-data/irbuild-statements.test +++ b/mypyc/test-data/irbuild-statements.test @@ -263,10 +263,10 @@ def f(d: Dict[int, int]) -> None: d[key] [out] def f(d): - d :: dict[confirmed] + d :: dict[exact] r0 :: short_int r1 :: native_int - r2 :: dict[confirmed] + r2 :: dict[exact] r3 :: tuple[bool, short_int, object] r4 :: short_int r5 :: bool @@ -312,11 +312,11 @@ def sum_over_even_values(d: Dict[int, int]) -> int: return s [out] def sum_over_even_values(d): - d :: dict[confirmed] + d :: dict[exact] s :: int r0 :: short_int r1 :: native_int - r2 :: dict[confirmed] + r2 :: dict[exact] r3 :: tuple[bool, short_int, object] r4 :: short_int r5 :: bool @@ -759,7 +759,7 @@ def delDictMultiple() -> None: def delDict(): r0, r1 :: str r2, r3 :: object - r4, d :: dict[confirmed] + r4, d :: dict[exact] r5 :: str r6 :: i32 r7 :: bit @@ -777,7 +777,7 @@ L0: def delDictMultiple(): r0, r1, r2, r3 :: str r4, r5, r6, r7 :: object - r8, d :: dict[confirmed] + r8, d :: dict[exact] r9, r10 :: str r11 :: i32 r12 :: bit diff --git a/mypyc/test-data/refcount.test b/mypyc/test-data/refcount.test index 91b17fc53a4e..ddcc52ccd087 100644 --- a/mypyc/test-data/refcount.test +++ b/mypyc/test-data/refcount.test @@ -727,10 +727,10 @@ def f(d: Dict[int, int]) -> None: d[key] [out] def f(d): - d :: dict[confirmed] + d :: dict[exact] r0 :: short_int r1 :: native_int - r2 :: dict[confirmed] + r2 :: dict[exact] r3 :: tuple[bool, short_int, object] r4 :: short_int r5 :: bool From 4251e8bac0528217016e5451a29ec78e100f7483 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 4 Aug 2025 02:01:36 +0000 Subject: [PATCH 16/43] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- mypyc/analysis/ircheck.py | 2 +- mypyc/irbuild/builder.py | 2 +- mypyc/irbuild/classdef.py | 2 +- mypyc/irbuild/for_helpers.py | 2 +- mypyc/irbuild/function.py | 2 +- mypyc/irbuild/ll_builder.py | 2 +- mypyc/irbuild/mapper.py | 2 +- mypyc/irbuild/prepare.py | 2 +- mypyc/irbuild/specialize.py | 4 ++-- mypyc/primitives/bytes_ops.py | 2 +- mypyc/primitives/dict_ops.py | 2 +- 11 files changed, 12 insertions(+), 12 deletions(-) diff --git a/mypyc/analysis/ircheck.py b/mypyc/analysis/ircheck.py index bcbe15e8e824..d5f5d5d7353f 100644 --- a/mypyc/analysis/ircheck.py +++ b/mypyc/analysis/ircheck.py @@ -64,6 +64,7 @@ RUnion, bytes_rprimitive, dict_rprimitive, + exact_dict_rprimitive, int_rprimitive, is_float_rprimitive, is_object_rprimitive, @@ -71,7 +72,6 @@ range_rprimitive, set_rprimitive, str_rprimitive, - exact_dict_rprimitive, tuple_rprimitive, ) diff --git a/mypyc/irbuild/builder.py b/mypyc/irbuild/builder.py index 47154ff20d54..338da7f53655 100644 --- a/mypyc/irbuild/builder.py +++ b/mypyc/irbuild/builder.py @@ -93,6 +93,7 @@ bitmap_rprimitive, bytes_rprimitive, c_pyssize_t_rprimitive, + exact_dict_rprimitive, int_rprimitive, is_float_rprimitive, is_list_rprimitive, @@ -103,7 +104,6 @@ none_rprimitive, object_rprimitive, str_rprimitive, - exact_dict_rprimitive, ) from mypyc.irbuild.context import FuncInfo, ImplicitClass from mypyc.irbuild.ll_builder import LowLevelIRBuilder diff --git a/mypyc/irbuild/classdef.py b/mypyc/irbuild/classdef.py index 9db9c258aa61..34238bd7dc7b 100644 --- a/mypyc/irbuild/classdef.py +++ b/mypyc/irbuild/classdef.py @@ -50,11 +50,11 @@ from mypyc.ir.rtypes import ( RType, bool_rprimitive, + exact_dict_rprimitive, is_none_rprimitive, is_object_rprimitive, is_optional_type, object_rprimitive, - exact_dict_rprimitive, ) from mypyc.irbuild.builder import IRBuilder, create_type_params from mypyc.irbuild.function import ( diff --git a/mypyc/irbuild/for_helpers.py b/mypyc/irbuild/for_helpers.py index 178ddca0bfe0..fd3c3a006428 100644 --- a/mypyc/irbuild/for_helpers.py +++ b/mypyc/irbuild/for_helpers.py @@ -52,13 +52,13 @@ c_pyssize_t_rprimitive, int_rprimitive, is_dict_rprimitive, + is_exact_dict_rprimitive, is_fixed_width_rtype, is_immutable_rprimitive, is_list_rprimitive, is_sequence_rprimitive, is_short_int_rprimitive, is_str_rprimitive, - is_exact_dict_rprimitive, is_tuple_rprimitive, object_pointer_rprimitive, object_rprimitive, diff --git a/mypyc/irbuild/function.py b/mypyc/irbuild/function.py index f0f78b667a98..b5b8334e2d7a 100644 --- a/mypyc/irbuild/function.py +++ b/mypyc/irbuild/function.py @@ -56,9 +56,9 @@ from mypyc.ir.rtypes import ( RInstance, bool_rprimitive, + exact_dict_rprimitive, int_rprimitive, object_rprimitive, - exact_dict_rprimitive, ) from mypyc.irbuild.builder import IRBuilder, calculate_arg_defaults, gen_arg_defaults from mypyc.irbuild.callable_class import ( diff --git a/mypyc/irbuild/ll_builder.py b/mypyc/irbuild/ll_builder.py index 3f6e092cf2dd..7ed1e49ba1e5 100644 --- a/mypyc/irbuild/ll_builder.py +++ b/mypyc/irbuild/ll_builder.py @@ -101,6 +101,7 @@ is_bool_or_bit_rprimitive, is_bytes_rprimitive, is_dict_rprimitive, + is_exact_dict_rprimitive, is_fixed_width_rtype, is_float_rprimitive, is_frozenset_rprimitive, @@ -116,7 +117,6 @@ is_short_int_rprimitive, is_str_rprimitive, is_tagged, - is_exact_dict_rprimitive, is_tuple_rprimitive, is_uint8_rprimitive, list_rprimitive, diff --git a/mypyc/irbuild/mapper.py b/mypyc/irbuild/mapper.py index 5d5862a42637..ff11f2e2ca45 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, @@ -45,7 +46,6 @@ range_rprimitive, set_rprimitive, str_rprimitive, - exact_dict_rprimitive, tuple_rprimitive, uint8_rprimitive, ) diff --git a/mypyc/irbuild/prepare.py b/mypyc/irbuild/prepare.py index 8b2dc500cc31..611c776c07ae 100644 --- a/mypyc/irbuild/prepare.py +++ b/mypyc/irbuild/prepare.py @@ -54,10 +54,10 @@ from mypyc.ir.rtypes import ( RInstance, RType, + exact_dict_rprimitive, none_rprimitive, object_pointer_rprimitive, object_rprimitive, - exact_dict_rprimitive, tuple_rprimitive, ) from mypyc.irbuild.mapper import Mapper diff --git a/mypyc/irbuild/specialize.py b/mypyc/irbuild/specialize.py index 0c54b76a8f35..15cd8363f9b6 100644 --- a/mypyc/irbuild/specialize.py +++ b/mypyc/irbuild/specialize.py @@ -53,12 +53,14 @@ bytes_rprimitive, c_int_rprimitive, dict_rprimitive, + exact_dict_rprimitive, int16_rprimitive, int32_rprimitive, int64_rprimitive, int_rprimitive, is_bool_rprimitive, is_dict_rprimitive, + is_exact_dict_rprimitive, is_fixed_width_rtype, is_float_rprimitive, is_int16_rprimitive, @@ -66,12 +68,10 @@ is_int64_rprimitive, is_int_rprimitive, is_list_rprimitive, - is_exact_dict_rprimitive, is_uint8_rprimitive, list_rprimitive, set_rprimitive, str_rprimitive, - exact_dict_rprimitive, uint8_rprimitive, ) from mypyc.irbuild.builder import IRBuilder diff --git a/mypyc/primitives/bytes_ops.py b/mypyc/primitives/bytes_ops.py index 117d842867b7..b0c664e75062 100644 --- a/mypyc/primitives/bytes_ops.py +++ b/mypyc/primitives/bytes_ops.py @@ -10,11 +10,11 @@ c_int_rprimitive, c_pyssize_t_rprimitive, dict_rprimitive, + exact_dict_rprimitive, int_rprimitive, list_rprimitive, object_rprimitive, str_rprimitive, - exact_dict_rprimitive, ) from mypyc.primitives.registry import ( ERR_NEG_INT, diff --git a/mypyc/primitives/dict_ops.py b/mypyc/primitives/dict_ops.py index bb35a1fba3f3..8c3d3c802565 100644 --- a/mypyc/primitives/dict_ops.py +++ b/mypyc/primitives/dict_ops.py @@ -11,10 +11,10 @@ dict_next_rtuple_pair, dict_next_rtuple_single, dict_rprimitive, + exact_dict_rprimitive, int_rprimitive, list_rprimitive, object_rprimitive, - exact_dict_rprimitive, void_rtype, ) from mypyc.primitives.registry import ( From a1f7f4feeb72d89da8268acc6e91f681933a21c2 Mon Sep 17 00:00:00 2001 From: BobTheBuidler Date: Mon, 4 Aug 2025 02:01:36 +0000 Subject: [PATCH 17/43] chore: rename true_dict ops to exact_dict --- mypyc/irbuild/builder.py | 8 ++++---- mypyc/irbuild/expression.py | 4 ++-- mypyc/irbuild/for_helpers.py | 28 +++++++++++++------------- mypyc/irbuild/function.py | 3 ++- mypyc/irbuild/ll_builder.py | 14 ++++++------- mypyc/irbuild/match.py | 4 ++-- mypyc/irbuild/specialize.py | 12 ++++++------ mypyc/primitives/dict_ops.py | 38 ++++++++++++++++++------------------ 8 files changed, 56 insertions(+), 55 deletions(-) diff --git a/mypyc/irbuild/builder.py b/mypyc/irbuild/builder.py index 338da7f53655..8ba8cd1395ad 100644 --- a/mypyc/irbuild/builder.py +++ b/mypyc/irbuild/builder.py @@ -125,7 +125,7 @@ ) from mypyc.irbuild.util import bytes_from_str, is_constant from mypyc.options import CompilerOptions -from mypyc.primitives.dict_ops import dict_set_item_op, true_dict_get_item_op +from mypyc.primitives.dict_ops import dict_set_item_op, exact_dict_get_item_op from mypyc.primitives.generic_ops import iter_op, next_op, py_setattr_op from mypyc.primitives.list_ops import list_get_item_unsafe_op, list_pop_last, to_list from mypyc.primitives.misc_ops import check_unpack_count_op, get_module_dict_op, import_op @@ -436,7 +436,7 @@ def add_to_non_ext_dict( ) -> None: # Add an attribute entry into the class dict of a non-extension class. key_unicode = self.load_str(key) - # must use `dict_set_item_op` instead of `true_dict_set_item_op` because + # must use `dict_set_item_op` instead of `exact_dict_set_item_op` because # it breaks enums, and probably other stuff, if we take the fast path. self.primitive_op(dict_set_item_op, [non_ext.dict, key_unicode, val], line) @@ -473,7 +473,7 @@ def get_module(self, module: str, line: int) -> Value: # Python 3.7 has a nice 'PyImport_GetModule' function that we can't use :( mod_dict = self.call_c(get_module_dict_op, [], line) # Get module object from modules dict. - return self.primitive_op(true_dict_get_item_op, [mod_dict, self.load_str(module)], line) + return self.primitive_op(exact_dict_get_item_op, [mod_dict, self.load_str(module)], line) def get_module_attr(self, module: str, attr: str, line: int) -> Value: """Look up an attribute of a module without storing it in the local namespace. @@ -1390,7 +1390,7 @@ def load_global(self, expr: NameExpr) -> Value: def load_global_str(self, name: str, line: int) -> Value: _globals = self.load_globals_dict() reg = self.load_str(name) - return self.primitive_op(true_dict_get_item_op, [_globals, reg], line) + return self.primitive_op(exact_dict_get_item_op, [_globals, reg], line) def load_globals_dict(self) -> Value: return self.add(LoadStatic(exact_dict_rprimitive, "globals", self.module_name)) diff --git a/mypyc/irbuild/expression.py b/mypyc/irbuild/expression.py index ffb64765005b..a11b74ee8dc7 100644 --- a/mypyc/irbuild/expression.py +++ b/mypyc/irbuild/expression.py @@ -100,7 +100,7 @@ ) from mypyc.irbuild.specialize import apply_function_specialization, apply_method_specialization from mypyc.primitives.bytes_ops import bytes_slice_op -from mypyc.primitives.dict_ops import dict_new_op, exact_dict_set_item_op +from mypyc.primitives.dict_ops import dict_new_op, exact_dict_get_item_op, exact_dict_set_item_op from mypyc.primitives.generic_ops import iter_op, name_op from mypyc.primitives.list_ops import list_append_op, list_extend_op, list_slice_op from mypyc.primitives.misc_ops import ellipsis_op, get_module_dict_op, new_slice_op, type_op @@ -186,7 +186,7 @@ def transform_name_expr(builder: IRBuilder, expr: NameExpr) -> Value: # instead load the module separately on each access. mod_dict = builder.call_c(get_module_dict_op, [], expr.line) obj = builder.primitive_op( - true_dict_get_item_op, [mod_dict, builder.load_str(expr.node.fullname)], expr.line + exact_dict_get_item_op, [mod_dict, builder.load_str(expr.node.fullname)], expr.line ) return obj else: diff --git a/mypyc/irbuild/for_helpers.py b/mypyc/irbuild/for_helpers.py index fd3c3a006428..798ae127672b 100644 --- a/mypyc/irbuild/for_helpers.py +++ b/mypyc/irbuild/for_helpers.py @@ -76,11 +76,11 @@ dict_next_key_op, dict_next_value_op, dict_value_iter_op, - true_dict_check_size_op, - true_dict_iter_fast_path_op, - true_dict_next_item_op, - true_dict_next_key_op, - true_dict_next_value_op, + exact_dict_check_size_op, + exact_dict_iter_fast_path_op, + exact_dict_next_item_op, + exact_dict_next_key_op, + exact_dict_next_value_op, ) from mypyc.primitives.exc_ops import no_err_occurred_op, propagate_if_error_op from mypyc.primitives.generic_ops import aiter_op, anext_op, iter_op, next_op @@ -1043,25 +1043,25 @@ def begin_body(self) -> None: class ForExactDictionaryKeys(ForDictionaryKeys): """Generate optimized IR for a for loop over dictionary items without type checks.""" - dict_next_op = true_dict_next_key_op - dict_iter_op = true_dict_iter_fast_path_op - dict_size_op = true_dict_check_size_op + dict_next_op = exact_dict_next_key_op + dict_iter_op = exact_dict_iter_fast_path_op + dict_size_op = exact_dict_check_size_op class ForExactDictionaryValues(ForDictionaryValues): """Generate optimized IR for a for loop over dictionary items without type checks.""" - dict_next_op = true_dict_next_value_op - dict_iter_op = true_dict_iter_fast_path_op - dict_size_op = true_dict_check_size_op + dict_next_op = exact_dict_next_value_op + dict_iter_op = exact_dict_iter_fast_path_op + dict_size_op = exact_dict_check_size_op class ForExactDictionaryItems(ForDictionaryItems): """Generate optimized IR for a for loop over dictionary items without type checks.""" - dict_next_op = true_dict_next_item_op - dict_iter_op = true_dict_iter_fast_path_op - dict_size_op = true_dict_check_size_op + dict_next_op = exact_dict_next_item_op + dict_iter_op = exact_dict_iter_fast_path_op + dict_size_op = exact_dict_check_size_op class ForRange(ForGenerator): diff --git a/mypyc/irbuild/function.py b/mypyc/irbuild/function.py index b5b8334e2d7a..03d725d15df0 100644 --- a/mypyc/irbuild/function.py +++ b/mypyc/irbuild/function.py @@ -78,6 +78,7 @@ from mypyc.irbuild.targets import AssignmentTarget from mypyc.primitives.dict_ops import ( dict_new_op, + exact_dict_get_method_with_none, exact_dict_set_item_op, ) from mypyc.primitives.generic_ops import py_setattr_op @@ -817,7 +818,7 @@ def generate_singledispatch_dispatch_function( ) call_find_impl, use_cache, call_func = BasicBlock(), BasicBlock(), BasicBlock() get_result = builder.primitive_op( - true_dict_get_method_with_none, [dispatch_cache, arg_type], line + exact_dict_get_method_with_none, [dispatch_cache, arg_type], line ) is_not_none = builder.translate_is_op(get_result, builder.none_object(), "is not", line) impl_to_use = Register(object_rprimitive) diff --git a/mypyc/irbuild/ll_builder.py b/mypyc/irbuild/ll_builder.py index 7ed1e49ba1e5..c49fbd900466 100644 --- a/mypyc/irbuild/ll_builder.py +++ b/mypyc/irbuild/ll_builder.py @@ -138,9 +138,9 @@ dict_new_op, dict_ssize_t_size_op, dict_update_in_display_op, - true_dict_copy_op, - true_dict_ssize_t_size_op, - true_dict_update_in_display_op, + exact_dict_copy_op, + exact_dict_ssize_t_size_op, + exact_dict_update_in_display_op, ) from mypyc.primitives.exc_ops import err_occurred_op, keep_propagating_op from mypyc.primitives.float_ops import copysign_op, int_to_float_op @@ -861,7 +861,7 @@ def _construct_varargs( star2_result = self._create_dict(star2_keys, star2_values, line) if is_exact_dict_rprimitive(value.type): - op = true_dict_update_in_display_op + op = exact_dict_update_in_display_op else: op = dict_update_in_display_op self.call_c(op, [star2_result, value], line=line) @@ -1828,12 +1828,12 @@ def make_dict(self, key_value_pairs: Sequence[DictEntry], line: int) -> Value: if result is None: if len(key_value_pairs) == 1 and is_exact_dict_rprimitive(value.type): # fast path for cases like `my_func(**dict(zip(iterable, other)))` and similar - return self.call_c(true_dict_copy_op, [value], line=line) + return self.call_c(exact_dict_copy_op, [value], line=line) result = self._create_dict(keys, values, line) if is_exact_dict_rprimitive(value.type): - op = true_dict_update_in_display_op + op = exact_dict_update_in_display_op else: op = dict_update_in_display_op @@ -2449,7 +2449,7 @@ def builtin_len(self, val: Value, line: int, use_pyssize_t: bool = False) -> Val size_value = self.load_mem(elem_address, c_pyssize_t_rprimitive) self.add(KeepAlive([val])) elif is_exact_dict_rprimitive(typ): - size_value = self.call_c(true_dict_ssize_t_size_op, [val], line) + size_value = self.call_c(exact_dict_ssize_t_size_op, [val], line) elif is_dict_rprimitive(typ): size_value = self.call_c(dict_ssize_t_size_op, [val], line) elif is_str_rprimitive(typ): diff --git a/mypyc/irbuild/match.py b/mypyc/irbuild/match.py index 17866ea8c2c6..3c56cd7cd432 100644 --- a/mypyc/irbuild/match.py +++ b/mypyc/irbuild/match.py @@ -24,7 +24,7 @@ dict_copy, mapping_has_key, supports_mapping_protocol, - true_dict_del_item, + exact_dict_del_item, ) from mypyc.primitives.generic_ops import generic_ssize_t_len_op from mypyc.primitives.list_ops import ( @@ -239,7 +239,7 @@ def visit_mapping_pattern(self, pattern: MappingPattern) -> None: self.builder.assign(target, rest, pattern.rest.line) for i, key_name in enumerate(keys): - self.builder.call_c(true_dict_del_item, [rest, key_name], pattern.keys[i].line) + self.builder.call_c(exact_dict_del_item, [rest, key_name], pattern.keys[i].line) self.builder.goto(self.code_block) diff --git a/mypyc/irbuild/specialize.py b/mypyc/irbuild/specialize.py index 15cd8363f9b6..b7944ec49b95 100644 --- a/mypyc/irbuild/specialize.py +++ b/mypyc/irbuild/specialize.py @@ -94,9 +94,9 @@ dict_setdefault_spec_init_op, dict_values_op, isinstance_dict, - true_dict_items_op, - true_dict_keys_op, - true_dict_values_op, + exact_dict_items_op, + exact_dict_keys_op, + exact_dict_values_op, ) from mypyc.primitives.float_ops import isinstance_float from mypyc.primitives.int_ops import isinstance_int @@ -260,17 +260,17 @@ def dict_methods_fast_path(builder: IRBuilder, expr: CallExpr, callee: RefExpr) # generic logic. if attr == "keys": if is_exact_dict_rprimitive(rtype): - op = true_dict_keys_op + op = exact_dict_keys_op else: op = dict_keys_op elif attr == "values": if is_exact_dict_rprimitive(rtype): - op = true_dict_values_op + op = exact_dict_values_op else: op = dict_values_op else: if is_exact_dict_rprimitive(rtype): - op = true_dict_items_op + op = exact_dict_items_op else: op = dict_items_op diff --git a/mypyc/primitives/dict_ops.py b/mypyc/primitives/dict_ops.py index 8c3d3c802565..9d56c246b345 100644 --- a/mypyc/primitives/dict_ops.py +++ b/mypyc/primitives/dict_ops.py @@ -95,7 +95,7 @@ ) # dict[key] -true_dict_get_item_op = method_op( +exact_dict_get_item_op = method_op( name="__getitem__", arg_types=[exact_dict_rprimitive, object_rprimitive], return_type=object_rprimitive, @@ -113,7 +113,7 @@ ) # dict[key] = value -true_dict_set_item_op = method_op( +exact_dict_set_item_op = method_op( name="__setitem__", arg_types=[exact_dict_rprimitive, object_rprimitive, object_rprimitive], return_type=c_int_rprimitive, @@ -162,7 +162,7 @@ ) # dict1.update(dict2) -true_dict_update_op = method_op( +exact_dict_update_op = method_op( name="update", arg_types=[exact_dict_rprimitive, exact_dict_rprimitive], return_type=c_int_rprimitive, @@ -172,7 +172,7 @@ ) # dictorsubclass.update(dict) -dict_update_from_true_dict_op = method_op( +dict_update_from_exact_dict_op = method_op( name="update", arg_types=[dict_rprimitive, exact_dict_rprimitive], return_type=c_int_rprimitive, @@ -182,7 +182,7 @@ ) # dict.update(dictsubclass) -true_dict_update_from_dict_op = method_op( +exact_dict_update_from_dict_op = method_op( name="update", arg_types=[exact_dict_rprimitive, dict_rprimitive], return_type=c_int_rprimitive, @@ -203,7 +203,7 @@ # Operation used for **value in with exact dictionary `value`. # This is mostly like dict.update(obj), but has customized error handling. -true_dict_update_in_display_op = custom_op( +exact_dict_update_in_display_op = custom_op( arg_types=[exact_dict_rprimitive, exact_dict_rprimitive], return_type=c_int_rprimitive, c_function_name="PyDict_Update", @@ -256,7 +256,7 @@ ) # dict.get(key) -true_dict_get_method_with_none = method_op( +exact_dict_get_method_with_none = method_op( name="get", arg_types=[exact_dict_rprimitive, object_rprimitive], return_type=object_rprimitive, @@ -274,7 +274,7 @@ ) # dict.setdefault(key, default) -true_dict_setdefault_op = method_op( +exact_dict_setdefault_op = method_op( name="setdefault", arg_types=[exact_dict_rprimitive, object_rprimitive, object_rprimitive], return_type=object_rprimitive, @@ -411,7 +411,7 @@ ) # dict.copy() custom_op -true_dict_copy_op = custom_op( +exact_dict_copy_op = custom_op( arg_types=[exact_dict_rprimitive], return_type=exact_dict_rprimitive, c_function_name="PyDict_Copy", @@ -419,7 +419,7 @@ ) # list(dict.keys()) -true_dict_keys_op = custom_op( +exact_dict_keys_op = custom_op( arg_types=[exact_dict_rprimitive], return_type=list_rprimitive, c_function_name="PyDict_Keys", @@ -435,7 +435,7 @@ ) # list(dict.values()) -true_dict_values_op = custom_op( +exact_dict_values_op = custom_op( arg_types=[exact_dict_rprimitive], return_type=list_rprimitive, c_function_name="PyDict_Values", @@ -451,7 +451,7 @@ ) # list(dict.items()) -true_dict_items_op = custom_op( +exact_dict_items_op = custom_op( arg_types=[exact_dict_rprimitive], return_type=list_rprimitive, c_function_name="PyDict_Items", @@ -467,7 +467,7 @@ ) # PyDict_Next() fast iteration -true_dict_iter_fast_path_op = custom_op( +exact_dict_iter_fast_path_op = custom_op( arg_types=[exact_dict_rprimitive], return_type=exact_dict_rprimitive, c_function_name="_CPyDict_GetIterUnsafe", @@ -517,21 +517,21 @@ error_kind=ERR_NEVER, ) -true_dict_next_key_op = custom_op( +exact_dict_next_key_op = custom_op( arg_types=[object_rprimitive, int_rprimitive], return_type=dict_next_rtuple_single, c_function_name="CPyDict_NextKeyUnsafe", error_kind=ERR_NEVER, ) -true_dict_next_value_op = custom_op( +exact_dict_next_value_op = custom_op( arg_types=[object_rprimitive, int_rprimitive], return_type=dict_next_rtuple_single, c_function_name="CPyDict_NextValueUnsafe", error_kind=ERR_NEVER, ) -true_dict_next_item_op = custom_op( +exact_dict_next_item_op = custom_op( arg_types=[exact_dict_rprimitive, int_rprimitive], return_type=dict_next_rtuple_pair, c_function_name="CPyDict_NextItemUnsafe", @@ -539,7 +539,7 @@ ) # check that len(dict) == const during iteration -true_dict_check_size_op = custom_op( +exact_dict_check_size_op = custom_op( arg_types=[exact_dict_rprimitive, c_pyssize_t_rprimitive], return_type=bit_rprimitive, c_function_name="CPyDict_CheckSizeUnsafe", @@ -554,7 +554,7 @@ error_kind=ERR_FALSE, ) -true_dict_ssize_t_size_op = custom_op( +exact_dict_ssize_t_size_op = custom_op( arg_types=[exact_dict_rprimitive], return_type=c_pyssize_t_rprimitive, c_function_name="PyDict_Size", @@ -569,7 +569,7 @@ ) # Delete an item from a dict -true_dict_del_item = custom_op( +exact_dict_del_item = custom_op( arg_types=[exact_dict_rprimitive, object_rprimitive], return_type=c_int_rprimitive, c_function_name="PyDict_DelItem", From 08674f79df9f63bfd737188985773a384e997193 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 4 Aug 2025 02:01:36 +0000 Subject: [PATCH 18/43] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- mypyc/irbuild/match.py | 2 +- mypyc/irbuild/specialize.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/mypyc/irbuild/match.py b/mypyc/irbuild/match.py index 3c56cd7cd432..89e02228310c 100644 --- a/mypyc/irbuild/match.py +++ b/mypyc/irbuild/match.py @@ -22,9 +22,9 @@ from mypyc.irbuild.builder import IRBuilder from mypyc.primitives.dict_ops import ( dict_copy, + exact_dict_del_item, mapping_has_key, supports_mapping_protocol, - exact_dict_del_item, ) from mypyc.primitives.generic_ops import generic_ssize_t_len_op from mypyc.primitives.list_ops import ( diff --git a/mypyc/irbuild/specialize.py b/mypyc/irbuild/specialize.py index b7944ec49b95..cb65ff0b8932 100644 --- a/mypyc/irbuild/specialize.py +++ b/mypyc/irbuild/specialize.py @@ -93,10 +93,10 @@ dict_keys_op, dict_setdefault_spec_init_op, dict_values_op, - isinstance_dict, exact_dict_items_op, exact_dict_keys_op, exact_dict_values_op, + isinstance_dict, ) from mypyc.primitives.float_ops import isinstance_float from mypyc.primitives.int_ops import isinstance_int From 5211d0bd5027775734ecc222030a140f350ce1b5 Mon Sep 17 00:00:00 2001 From: BobTheBuidler <70677534+BobTheBuidler@users.noreply.github.com> Date: Mon, 4 Aug 2025 02:01:36 +0000 Subject: [PATCH 19/43] Update mapper.py --- mypyc/irbuild/mapper.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/mypyc/irbuild/mapper.py b/mypyc/irbuild/mapper.py index ff11f2e2ca45..248ab7d1046f 100644 --- a/mypyc/irbuild/mapper.py +++ b/mypyc/irbuild/mapper.py @@ -91,11 +91,12 @@ def type_to_rtype(self, typ: Type | None) -> RType: return bytes_rprimitive elif typ.type.fullname == "builtins.list": return list_rprimitive + # TODO: figure out why this breaks tests, fix, and uncomment + # elif typ.type.fullname == "builtins.dict": + # return exact_dict_rprimitive # Dict subclasses are at least somewhat common and we # specifically support them, so make sure that dict operations # get optimized on them. - elif typ.type.fullname == "builtins.dict": - return exact_dict_rprimitive elif any(cls.fullname == "builtins.dict" for cls in typ.type.mro): return dict_rprimitive elif typ.type.fullname == "builtins.set": From c8bd20718dc1b905f915d91234e213562657c3a2 Mon Sep 17 00:00:00 2001 From: BobTheBuidler Date: Mon, 4 Aug 2025 02:01:36 +0000 Subject: [PATCH 20/43] update ir --- mypyc/test-data/irbuild-basic.test | 53 ++++++------ mypyc/test-data/irbuild-bytes.test | 2 +- mypyc/test-data/irbuild-dict.test | 111 +++++++++++++------------- mypyc/test-data/irbuild-generics.test | 71 ++++++++-------- 4 files changed, 121 insertions(+), 116 deletions(-) diff --git a/mypyc/test-data/irbuild-basic.test b/mypyc/test-data/irbuild-basic.test index c38112cfafba..07f3b52912f9 100644 --- a/mypyc/test-data/irbuild-basic.test +++ b/mypyc/test-data/irbuild-basic.test @@ -966,10 +966,10 @@ def f(o, p, n, b, t, s, a, l, d): s :: tuple[int, int] a :: __main__.A l :: list - d :: dict[exact] + d :: dict r0 :: object l2 :: list - d2 :: dict[exact] + d2 :: dict L0: o = o p = p @@ -1758,33 +1758,38 @@ L0: def h(): r0, r1 :: str r2, r3 :: object - r4, r5 :: dict[exact] - r6 :: str - r7 :: object - r8 :: dict[exact] - r9 :: i32 - r10 :: bit - r11 :: object - r12 :: tuple + r4 :: dict[exact] + r5 :: dict + r6 :: dict[exact] + r7 :: str + r8 :: object + r9 :: dict[exact] + r10 :: dict + r11 :: i32 + r12 :: bit r13 :: object - r14 :: tuple[int, int, int] + r14 :: tuple + r15 :: object + r16 :: tuple[int, int, int] L0: r0 = 'b' r1 = 'c' r2 = object 2 r3 = object 3 r4 = CPyDict_Build(2, r0, r2, r1, r3) - r5 = __main__.globals :: static - r6 = 'f' - r7 = CPyDict_GetItemUnsafe(r5, r6) - r8 = PyDict_New() - r9 = PyDict_Update(r8, r4) - r10 = r9 >= 0 :: signed - r11 = object 1 - r12 = PyTuple_Pack(1, r11) - r13 = PyObject_Call(r7, r12, r8) - r14 = unbox(tuple[int, int, int], r13) - return r14 + r5 = cast(dict, r4) + r6 = __main__.globals :: static + r7 = 'f' + r8 = CPyDict_GetItemUnsafe(r6, r7) + r9 = PyDict_New() + r10 = cast(dict, r9) + r11 = CPyDict_UpdateInDisplay(r10, r5) + r12 = r11 >= 0 :: signed + r13 = object 1 + r14 = PyTuple_Pack(1, r13) + r15 = PyObject_Call(r8, r14, r9) + r16 = unbox(tuple[int, int, int], r15) + return r16 [case testFunctionCallWithDefaultArgs] def f(x: int, y: int = 3, z: str = "test") -> None: @@ -1945,6 +1950,7 @@ def f(): r16 :: i32 r17 :: bit r18 :: native_int + r19 :: dict L0: r0 = PyDict_New() r1 = PyList_New(3) @@ -1985,7 +1991,8 @@ L7: r6 = r18 goto L1 L8: - return r0 + r19 = cast(dict, r0) + return r19 [case testLoopsMultipleAssign] from typing import List, Tuple diff --git a/mypyc/test-data/irbuild-bytes.test b/mypyc/test-data/irbuild-bytes.test index c5443e1ea2af..8cfefe03ae22 100644 --- a/mypyc/test-data/irbuild-bytes.test +++ b/mypyc/test-data/irbuild-bytes.test @@ -9,7 +9,7 @@ def f(num: int, l: list, d: dict, s: str) -> None: def f(num, l, d, s): num :: int l :: list - d :: dict[exact] + d :: dict s :: str r0, r1 :: object r2, b1 :: bytes diff --git a/mypyc/test-data/irbuild-dict.test b/mypyc/test-data/irbuild-dict.test index 685edcd6e206..e1c7f0431ce6 100644 --- a/mypyc/test-data/irbuild-dict.test +++ b/mypyc/test-data/irbuild-dict.test @@ -4,12 +4,12 @@ def f(d: Dict[int, bool]) -> bool: return d[0] [out] def f(d): - d :: dict[exact] + d :: dict r0, r1 :: object r2 :: bool L0: r0 = object 0 - r1 = CPyDict_GetItemUnsafe(d, r0) + r1 = CPyDict_GetItem(d, r0) r2 = unbox(bool, r1) return r2 @@ -19,14 +19,14 @@ def f(d: Dict[int, bool]) -> None: d[0] = False [out] def f(d): - d :: dict[exact] + d :: dict r0, r1 :: object r2 :: i32 r3 :: bit L0: r0 = object 0 r1 = box(bool, 0) - r2 = PyDict_SetItem(d, r0, r1) + r2 = CPyDict_SetItem(d, r0, r1) r3 = r2 >= 0 :: signed return 1 @@ -481,93 +481,90 @@ def f4(d: Dict[object, object], flag: bool) -> object: return d.setdefault('a', {'c': 1}) [out] def f(d): - d :: dict[exact] + d :: dict r0, r1 :: str r2 :: object L0: r0 = 'a' r1 = 'b' - r2 = PyDict_SetDefault(d, r0, r1) + r2 = CPyDict_SetDefault(d, r0, r1) return r2 def f2(d, flag): - d :: dict[exact] + d :: dict flag :: bool r0 :: str - r1 :: dict - r2 :: object - r3, r4 :: str - r5 :: set - r6, r7 :: object + r1 :: object + r2, r3 :: str + r4 :: set + r5, r6 :: object L0: if flag goto L1 else goto L2 :: bool L1: r0 = 'a' - r1 = cast(dict, d) - r2 = CPyDict_SetDefaultWithEmptyDatatype(r1, r0, 3) - return r2 + r1 = CPyDict_SetDefaultWithEmptyDatatype(d, r0, 3) + return r1 L2: - r3 = 'a' - r4 = 'b' - r5 = PySet_New(r4) - r6 = PyDict_SetDefault(d, r3, r5) - return r6 + r2 = 'a' + r3 = 'b' + r4 = PySet_New(r3) + r5 = CPyDict_SetDefault(d, r2, r4) + return r5 L3: - r7 = box(None, 1) - return r7 + r6 = box(None, 1) + return r6 def f3(d, flag): - d :: dict[exact] + d :: dict flag :: bool r0 :: str - r1 :: dict - r2 :: object - r3 :: str - r4 :: list - r5 :: object - r6 :: ptr - r7, r8 :: object + r1 :: object + r2 :: str + r3 :: list + r4 :: object + r5 :: ptr + r6, r7 :: object L0: if flag goto L1 else goto L2 :: bool L1: r0 = 'a' - r1 = cast(dict, d) - r2 = CPyDict_SetDefaultWithEmptyDatatype(r1, r0, 1) - return r2 + r1 = CPyDict_SetDefaultWithEmptyDatatype(d, r0, 1) + return r1 L2: - r3 = 'a' - r4 = PyList_New(1) - r5 = object 1 - r6 = list_items r4 - buf_init_item r6, 0, r5 - keep_alive r4 - r7 = PyDict_SetDefault(d, r3, r4) - return r7 + r2 = 'a' + r3 = PyList_New(1) + r4 = object 1 + r5 = list_items r3 + buf_init_item r5, 0, r4 + keep_alive r3 + r6 = CPyDict_SetDefault(d, r2, r3) + return r6 L3: - r8 = box(None, 1) - return r8 + r7 = box(None, 1) + return r7 def f4(d, flag): - d :: dict[exact] + d :: dict flag :: bool r0 :: str - r1 :: dict - r2 :: object - r3, r4 :: str - r5 :: object - r6 :: dict[exact] + r1 :: object + r2, r3 :: str + r4 :: object + r5 :: dict[exact] + r6 :: dict r7, r8 :: object L0: if flag goto L1 else goto L2 :: bool L1: r0 = 'a' - r1 = cast(dict, d) - r2 = CPyDict_SetDefaultWithEmptyDatatype(r1, r0, 2) - return r2 + r1 = CPyDict_SetDefaultWithEmptyDatatype(d, r0, 2) + return r1 L2: - r3 = 'a' - r4 = 'c' - r5 = object 1 - r6 = CPyDict_Build(1, r4, r5) - r7 = PyDict_SetDefault(d, r3, r6) + r2 = 'a' + r3 = 'c' + r4 = object 1 + r5 = CPyDict_Build(1, r3, r4) + r6 = cast(dict, r5) + r7 = CPyDict_SetDefault(d, r2, r6) return r7 L3: r8 = box(None, 1) return r8 + diff --git a/mypyc/test-data/irbuild-generics.test b/mypyc/test-data/irbuild-generics.test index b5f80b1ff96d..496a7af7390f 100644 --- a/mypyc/test-data/irbuild-generics.test +++ b/mypyc/test-data/irbuild-generics.test @@ -211,11 +211,11 @@ def fn_typeddict(t: T) -> None: [typing fixtures/typing-full.pyi] [out] def fn_mapping(m): - m :: dict[exact] + m :: dict r0 :: list r1 :: short_int r2 :: native_int - r3 :: dict[exact] + r3 :: object r4 :: tuple[bool, short_int, object] r5 :: short_int r6 :: bool @@ -226,7 +226,7 @@ def fn_mapping(m): r13 :: list r14 :: short_int r15 :: native_int - r16 :: dict[exact] + r16 :: object r17 :: tuple[bool, short_int, object] r18 :: short_int r19 :: bool @@ -238,7 +238,7 @@ def fn_mapping(m): r27 :: set r28 :: short_int r29 :: native_int - r30 :: dict[exact] + r30 :: object r31 :: tuple[bool, short_int, object] r32 :: short_int r33 :: bool @@ -249,7 +249,7 @@ def fn_mapping(m): r40 :: dict[exact] r41 :: short_int r42 :: native_int - r43 :: dict[exact] + r43 :: object r44 :: tuple[bool, short_int, object, object] r45 :: short_int r46 :: bool @@ -265,9 +265,9 @@ L0: r0 = PyList_New(0) r1 = 0 r2 = PyDict_Size(m) - r3 = _CPyDict_GetIterUnsafe(m) + r3 = CPyDict_GetKeysIter(m) L1: - r4 = CPyDict_NextKeyUnsafe(r3, r1) + r4 = CPyDict_NextKey(r3, r1) r5 = r4[1] r1 = r5 r6 = r4[0] @@ -279,7 +279,7 @@ L2: r9 = PyList_Append(r0, x) r10 = r9 >= 0 :: signed L3: - r11 = CPyDict_CheckSizeUnsafe(m, r2) + r11 = CPyDict_CheckSize(m, r2) goto L1 L4: r12 = CPy_NoErrOccurred() @@ -287,9 +287,9 @@ L5: r13 = PyList_New(0) r14 = 0 r15 = PyDict_Size(m) - r16 = _CPyDict_GetIterUnsafe(m) + r16 = CPyDict_GetValuesIter(m) L6: - r17 = CPyDict_NextValueUnsafe(r16, r14) + r17 = CPyDict_NextValue(r16, r14) r18 = r17[1] r14 = r18 r19 = r17[0] @@ -302,7 +302,7 @@ L7: r23 = PyList_Append(r13, r22) r24 = r23 >= 0 :: signed L8: - r25 = CPyDict_CheckSizeUnsafe(m, r15) + r25 = CPyDict_CheckSize(m, r15) goto L6 L9: r26 = CPy_NoErrOccurred() @@ -310,9 +310,9 @@ L10: r27 = PySet_New(0) r28 = 0 r29 = PyDict_Size(m) - r30 = _CPyDict_GetIterUnsafe(m) + r30 = CPyDict_GetKeysIter(m) L11: - r31 = CPyDict_NextKeyUnsafe(r30, r28) + r31 = CPyDict_NextKey(r30, r28) r32 = r31[1] r28 = r32 r33 = r31[0] @@ -324,7 +324,7 @@ L12: r36 = PySet_Add(r27, x_3) r37 = r36 >= 0 :: signed L13: - r38 = CPyDict_CheckSizeUnsafe(m, r29) + r38 = CPyDict_CheckSize(m, r29) goto L11 L14: r39 = CPy_NoErrOccurred() @@ -332,9 +332,9 @@ L15: r40 = PyDict_New() r41 = 0 r42 = PyDict_Size(m) - r43 = _CPyDict_GetIterUnsafe(m) + r43 = CPyDict_GetItemsIter(m) L16: - r44 = CPyDict_NextItemUnsafe(r43, r41) + r44 = CPyDict_NextItem(r43, r41) r45 = r44[1] r41 = r45 r46 = r44[0] @@ -350,18 +350,18 @@ L17: r52 = PyDict_SetItem(r40, k, r51) r53 = r52 >= 0 :: signed L18: - r54 = CPyDict_CheckSizeUnsafe(m, r42) + r54 = CPyDict_CheckSize(m, r42) goto L16 L19: r55 = CPy_NoErrOccurred() L20: return 1 def fn_union(m): - m :: dict[exact] + m :: dict r0 :: list r1 :: short_int r2 :: native_int - r3 :: dict[exact] + r3 :: object r4 :: tuple[bool, short_int, object] r5 :: short_int r6 :: bool @@ -372,7 +372,7 @@ def fn_union(m): r13 :: list r14 :: short_int r15 :: native_int - r16 :: dict[exact] + r16 :: object r17 :: tuple[bool, short_int, object] r18 :: short_int r19 :: bool @@ -383,7 +383,7 @@ def fn_union(m): r26 :: set r27 :: short_int r28 :: native_int - r29 :: dict[exact] + r29 :: object r30 :: tuple[bool, short_int, object] r31 :: short_int r32 :: bool @@ -394,7 +394,7 @@ def fn_union(m): r39 :: dict[exact] r40 :: short_int r41 :: native_int - r42 :: dict[exact] + r42 :: object r43 :: tuple[bool, short_int, object, object] r44 :: short_int r45 :: bool @@ -409,9 +409,9 @@ L0: r0 = PyList_New(0) r1 = 0 r2 = PyDict_Size(m) - r3 = _CPyDict_GetIterUnsafe(m) + r3 = CPyDict_GetKeysIter(m) L1: - r4 = CPyDict_NextKeyUnsafe(r3, r1) + r4 = CPyDict_NextKey(r3, r1) r5 = r4[1] r1 = r5 r6 = r4[0] @@ -423,7 +423,7 @@ L2: r9 = PyList_Append(r0, x) r10 = r9 >= 0 :: signed L3: - r11 = CPyDict_CheckSizeUnsafe(m, r2) + r11 = CPyDict_CheckSize(m, r2) goto L1 L4: r12 = CPy_NoErrOccurred() @@ -431,9 +431,9 @@ L5: r13 = PyList_New(0) r14 = 0 r15 = PyDict_Size(m) - r16 = _CPyDict_GetIterUnsafe(m) + r16 = CPyDict_GetValuesIter(m) L6: - r17 = CPyDict_NextValueUnsafe(r16, r14) + r17 = CPyDict_NextValue(r16, r14) r18 = r17[1] r14 = r18 r19 = r17[0] @@ -445,7 +445,7 @@ L7: r22 = PyList_Append(r13, x_2) r23 = r22 >= 0 :: signed L8: - r24 = CPyDict_CheckSizeUnsafe(m, r15) + r24 = CPyDict_CheckSize(m, r15) goto L6 L9: r25 = CPy_NoErrOccurred() @@ -453,9 +453,9 @@ L10: r26 = PySet_New(0) r27 = 0 r28 = PyDict_Size(m) - r29 = _CPyDict_GetIterUnsafe(m) + r29 = CPyDict_GetKeysIter(m) L11: - r30 = CPyDict_NextKeyUnsafe(r29, r27) + r30 = CPyDict_NextKey(r29, r27) r31 = r30[1] r27 = r31 r32 = r30[0] @@ -467,7 +467,7 @@ L12: r35 = PySet_Add(r26, x_3) r36 = r35 >= 0 :: signed L13: - r37 = CPyDict_CheckSizeUnsafe(m, r28) + r37 = CPyDict_CheckSize(m, r28) goto L11 L14: r38 = CPy_NoErrOccurred() @@ -475,9 +475,9 @@ L15: r39 = PyDict_New() r40 = 0 r41 = PyDict_Size(m) - r42 = _CPyDict_GetIterUnsafe(m) + r42 = CPyDict_GetItemsIter(m) L16: - r43 = CPyDict_NextItemUnsafe(r42, r40) + r43 = CPyDict_NextItem(r42, r40) r44 = r43[1] r40 = r44 r45 = r43[0] @@ -492,7 +492,7 @@ L17: r50 = PyDict_SetItem(r39, k, v) r51 = r50 >= 0 :: signed L18: - r52 = CPyDict_CheckSizeUnsafe(m, r41) + r52 = CPyDict_CheckSize(m, r41) goto L16 L19: r53 = CPy_NoErrOccurred() @@ -674,7 +674,7 @@ L2: def inner_deco_obj.__call__(__mypyc_self__, args, kwargs): __mypyc_self__ :: __main__.inner_deco_obj args :: tuple - kwargs :: dict[exact] + kwargs :: dict r0 :: __main__.deco_env r1 :: native_int r2 :: list @@ -773,3 +773,4 @@ def f(x): x :: int L0: return x + From f82b681468692eb84b4b1c0544b3ccd24cc97e43 Mon Sep 17 00:00:00 2001 From: BobTheBuidler Date: Mon, 4 Aug 2025 02:01:36 +0000 Subject: [PATCH 21/43] update ir --- mypyc/test-data/irbuild-basic.test | 2 +- mypyc/test-data/irbuild-dict.test | 183 +++++++++++++----------- mypyc/test-data/irbuild-match.test | 88 ++++++------ mypyc/test-data/irbuild-set.test | 68 ++++----- mypyc/test-data/irbuild-statements.test | 72 +++++----- mypyc/test-data/refcount.test | 12 +- 6 files changed, 224 insertions(+), 201 deletions(-) diff --git a/mypyc/test-data/irbuild-basic.test b/mypyc/test-data/irbuild-basic.test index 07f3b52912f9..71551031c1e2 100644 --- a/mypyc/test-data/irbuild-basic.test +++ b/mypyc/test-data/irbuild-basic.test @@ -3257,7 +3257,7 @@ L0: r1 = PySequence_List(r0) return r1 def h(x): - x :: dict[exact] + x :: dict r0 :: list L0: r0 = PySequence_List(x) diff --git a/mypyc/test-data/irbuild-dict.test b/mypyc/test-data/irbuild-dict.test index e1c7f0431ce6..553b93556200 100644 --- a/mypyc/test-data/irbuild-dict.test +++ b/mypyc/test-data/irbuild-dict.test @@ -36,10 +36,12 @@ def f() -> None: d = {} # type: Dict[bool, int] [out] def f(): - r0, d :: dict[exact] + r0 :: dict[exact] + r1, d :: dict L0: r0 = PyDict_New() - d = r0 + r1 = cast(dict, r0) + d = r1 return 1 [case testNewEmptyDictViaFunc] @@ -49,10 +51,12 @@ def f() -> None: [out] def f(): - r0, d :: dict[exact] + r0 :: dict[exact] + r1, d :: dict L0: r0 = PyDict_New() - d = r0 + r1 = cast(dict, r0) + d = r1 return 1 [case testNewDictWithValues] @@ -63,13 +67,15 @@ def f(x): x :: object r0 :: str r1, r2 :: object - r3, d :: dict[exact] + r3 :: dict[exact] + r4, d :: dict L0: r0 = '' r1 = object 1 r2 = object 2 r3 = CPyDict_Build(2, r1, r2, r0, x) - d = r3 + r4 = cast(dict, r3) + d = r4 return 1 [case testInDict] @@ -81,7 +87,7 @@ def f(d: Dict[int, int]) -> bool: return False [out] def f(d): - d :: dict[exact] + d :: dict r0 :: object r1 :: i32 r2 :: bit @@ -108,7 +114,7 @@ def f(d: Dict[int, int]) -> bool: return False [out] def f(d): - d :: dict[exact] + d :: dict r0 :: object r1 :: i32 r2 :: bit @@ -133,11 +139,11 @@ def f(a: Dict[int, int], b: Dict[int, int]) -> None: a.update(b) [out] def f(a, b): - a, b :: dict[exact] + a, b :: dict r0 :: i32 r1 :: bit L0: - r0 = PyDict_Update(a, b) + r0 = CPyDict_Update(a, b) r1 = r0 >= 0 :: signed return 1 @@ -149,10 +155,10 @@ def increment(d: Dict[str, int]) -> Dict[str, int]: return d [out] def increment(d): - d :: dict[exact] + d :: dict r0 :: short_int r1 :: native_int - r2 :: dict[exact] + r2 :: object r3 :: tuple[bool, short_int, object] r4 :: short_int r5 :: bool @@ -164,9 +170,9 @@ def increment(d): L0: r0 = 0 r1 = PyDict_Size(d) - r2 = _CPyDict_GetIterUnsafe(d) + r2 = CPyDict_GetKeysIter(d) L1: - r3 = CPyDict_NextKeyUnsafe(r2, r0) + r3 = CPyDict_NextKey(r2, r0) r4 = r3[1] r0 = r4 r5 = r3[0] @@ -175,13 +181,13 @@ L2: r6 = r3[2] r7 = cast(str, r6) k = r7 - r8 = CPyDict_GetItemUnsafe(d, k) + r8 = CPyDict_GetItem(d, k) r9 = object 1 r10 = PyNumber_InPlaceAdd(r8, r9) - r11 = PyDict_SetItem(d, k, r10) + r11 = CPyDict_SetItem(d, k, r10) r12 = r11 >= 0 :: signed L3: - r13 = CPyDict_CheckSizeUnsafe(d, r1) + r13 = CPyDict_CheckSize(d, r1) goto L1 L4: r14 = CPy_NoErrOccurred() @@ -195,25 +201,29 @@ def f(x: str, y: Dict[str, int]) -> Dict[str, int]: [out] def f(x, y): x :: str - y :: dict[exact] + y :: dict r0 :: str r1 :: object r2 :: dict[exact] - r3 :: i32 - r4 :: bit - r5 :: object - r6 :: i32 - r7 :: bit + r3 :: dict + r4 :: i32 + r5 :: bit + r6 :: object + r7 :: i32 + r8 :: bit + r9 :: dict L0: r0 = 'z' r1 = object 2 r2 = CPyDict_Build(1, x, r1) - r3 = PyDict_Update(r2, y) - r4 = r3 >= 0 :: signed - r5 = object 3 - r6 = PyDict_SetItem(r2, r0, r5) - r7 = r6 >= 0 :: signed - return r2 + r3 = cast(dict, r2) + r4 = CPyDict_UpdateInDisplay(r3, y) + r5 = r4 >= 0 :: signed + r6 = object 3 + r7 = PyDict_SetItem(r2, r0, r6) + r8 = r7 >= 0 :: signed + r9 = cast(dict, r2) + return r9 [case testDictIterationMethods] from typing import Dict, TypedDict, Union @@ -239,10 +249,10 @@ def typeddict(d: Person) -> None: [typing fixtures/typing-full.pyi] [out] def print_dict_methods(d1, d2): - d1, d2 :: dict[exact] + d1, d2 :: dict r0 :: short_int r1 :: native_int - r2 :: dict[exact] + r2 :: object r3 :: tuple[bool, short_int, object] r4 :: short_int r5 :: bool @@ -255,7 +265,7 @@ def print_dict_methods(d1, d2): r12, r13 :: bit r14 :: short_int r15 :: native_int - r16 :: dict[exact] + r16 :: object r17 :: tuple[bool, short_int, object, object] r18 :: short_int r19 :: bool @@ -267,9 +277,9 @@ def print_dict_methods(d1, d2): L0: r0 = 0 r1 = PyDict_Size(d1) - r2 = _CPyDict_GetIterUnsafe(d1) + r2 = CPyDict_GetValuesIter(d1) L1: - r3 = CPyDict_NextValueUnsafe(r2, r0) + r3 = CPyDict_NextValue(r2, r0) r4 = r3[1] r0 = r4 r5 = r3[0] @@ -287,16 +297,16 @@ L3: return 1 L4: L5: - r12 = CPyDict_CheckSizeUnsafe(d1, r1) + r12 = CPyDict_CheckSize(d1, r1) goto L1 L6: r13 = CPy_NoErrOccurred() L7: r14 = 0 r15 = PyDict_Size(d2) - r16 = _CPyDict_GetIterUnsafe(d2) + r16 = CPyDict_GetItemsIter(d2) L8: - r17 = CPyDict_NextItemUnsafe(r16, r14) + r17 = CPyDict_NextItem(r16, r14) r18 = r17[1] r14 = r18 r19 = r17[0] @@ -309,73 +319,76 @@ L9: k = r22 v = r23 r24 = box(int, k) - r25 = CPyDict_GetItemUnsafe(d2, r24) + r25 = CPyDict_GetItem(d2, r24) r26 = box(int, v) r27 = PyNumber_InPlaceAdd(r25, r26) r28 = box(int, k) - r29 = PyDict_SetItem(d2, r28, r27) + r29 = CPyDict_SetItem(d2, r28, r27) r30 = r29 >= 0 :: signed L10: - r31 = CPyDict_CheckSizeUnsafe(d2, r15) + r31 = CPyDict_CheckSize(d2, r15) goto L8 L11: r32 = CPy_NoErrOccurred() L12: return 1 def union_of_dicts(d): - d, r0, new :: dict[exact] - r1 :: short_int - r2 :: native_int - r3 :: dict[exact] - r4 :: tuple[bool, short_int, object, object] - r5 :: short_int - r6 :: bool - r7, r8 :: object - r9 :: str - r10 :: union[int, str] + d :: dict + r0 :: dict[exact] + r1, new :: dict + r2 :: short_int + r3 :: native_int + r4 :: object + r5 :: tuple[bool, short_int, object, object] + r6 :: short_int + r7 :: bool + r8, r9 :: object + r10 :: str + r11 :: union[int, str] k :: str v :: union[int, str] - r11 :: object - r12 :: object[1] - r13 :: object_ptr - r14 :: object - r15 :: int - r16 :: object - r17 :: i32 - r18, r19, r20 :: bit + r12 :: object + r13 :: object[1] + r14 :: object_ptr + r15 :: object + r16 :: int + r17 :: object + r18 :: i32 + r19, r20, r21 :: bit L0: r0 = PyDict_New() - new = r0 - r1 = 0 - r2 = PyDict_Size(d) - r3 = _CPyDict_GetIterUnsafe(d) + r1 = cast(dict, r0) + new = r1 + r2 = 0 + r3 = PyDict_Size(d) + r4 = CPyDict_GetItemsIter(d) L1: - r4 = CPyDict_NextItemUnsafe(r3, r1) - r5 = r4[1] - r1 = r5 - r6 = r4[0] - if r6 goto L2 else goto L4 :: bool + r5 = CPyDict_NextItem(r4, r2) + r6 = r5[1] + r2 = r6 + r7 = r5[0] + if r7 goto L2 else goto L4 :: bool L2: - r7 = r4[2] - r8 = r4[3] - r9 = cast(str, r7) - r10 = cast(union[int, str], r8) - k = r9 - v = r10 - r11 = load_address PyLong_Type - r12 = [v] - r13 = load_address r12 - r14 = PyObject_Vectorcall(r11, r13, 1, 0) + r8 = r5[2] + r9 = r5[3] + r10 = cast(str, r8) + r11 = cast(union[int, str], r9) + k = r10 + v = r11 + r12 = load_address PyLong_Type + r13 = [v] + r14 = load_address r13 + r15 = PyObject_Vectorcall(r12, r14, 1, 0) keep_alive v - r15 = unbox(int, r14) - r16 = box(int, r15) - r17 = PyDict_SetItem(new, k, r16) - r18 = r17 >= 0 :: signed + r16 = unbox(int, r15) + r17 = box(int, r16) + r18 = CPyDict_SetItem(new, k, r17) + r19 = r18 >= 0 :: signed L3: - r19 = CPyDict_CheckSizeUnsafe(d, r2) + r20 = CPyDict_CheckSize(d, r3) goto L1 L4: - r20 = CPy_NoErrOccurred() + r21 = CPy_NoErrOccurred() L5: return 1 def typeddict(d): @@ -440,10 +453,10 @@ def f(d: Dict[int, int]) -> None: return d.clear() [out] def f(d): - d :: dict[exact] + d :: dict r0 :: bit L0: - r0 = PyDict_Clear(d) + r0 = CPyDict_Clear(d) return 1 [case testDictCopy] diff --git a/mypyc/test-data/irbuild-match.test b/mypyc/test-data/irbuild-match.test index 95ea948e05ea..7774c6e83629 100644 --- a/mypyc/test-data/irbuild-match.test +++ b/mypyc/test-data/irbuild-match.test @@ -1089,35 +1089,37 @@ def f(x): x :: object r0 :: i32 r1 :: bit - r2, rest :: dict[exact] - r3 :: str - r4 :: object - r5 :: str - r6 :: object - r7 :: object[1] - r8 :: object_ptr - r9, r10 :: object + r2 :: dict[exact] + r3, rest :: dict + r4 :: str + r5 :: object + r6 :: str + r7 :: object + r8 :: object[1] + r9 :: object_ptr + r10, r11 :: object L0: r0 = CPyMapping_Check(x) r1 = r0 != 0 if r1 goto L1 else goto L3 :: bool L1: r2 = CPyDict_FromAny(x) - rest = r2 + r3 = cast(dict, r2) + rest = r3 L2: - r3 = 'matched' - r4 = builtins :: module - r5 = 'print' - r6 = CPyObject_GetAttr(r4, r5) - r7 = [r3] - r8 = load_address r7 - r9 = PyObject_Vectorcall(r6, r8, 1, 0) - keep_alive r3 + r4 = 'matched' + r5 = builtins :: module + r6 = 'print' + r7 = CPyObject_GetAttr(r5, r6) + r8 = [r4] + r9 = load_address r8 + r10 = PyObject_Vectorcall(r7, r9, 1, 0) + keep_alive r4 goto L4 L3: L4: - r10 = box(None, 1) - return r10 + r11 = box(None, 1) + return r11 [case testMatchMappingPatternWithRestPopKeys_python3_10] def f(x): @@ -1138,16 +1140,17 @@ def f(x): r8 :: i32 r9 :: bit r10 :: bool - r11, rest :: dict[exact] - r12 :: i32 - r13 :: bit - r14 :: str - r15 :: object - r16 :: str - r17 :: object - r18 :: object[1] - r19 :: object_ptr - r20, r21 :: object + r11 :: dict[exact] + r12, rest :: dict + r13 :: i32 + r14 :: bit + r15 :: str + r16 :: object + r17 :: str + r18 :: object + r19 :: object[1] + r20 :: object_ptr + r21, r22 :: object L0: r0 = CPyMapping_Check(x) r1 = r0 != 0 @@ -1167,23 +1170,24 @@ L2: if r10 goto L3 else goto L5 :: bool L3: r11 = CPyDict_FromAny(x) - rest = r11 - r12 = PyDict_DelItem(r11, r2) - r13 = r12 >= 0 :: signed + r12 = cast(dict, r11) + rest = r12 + r13 = PyDict_DelItem(r11, r2) + r14 = r13 >= 0 :: signed L4: - r14 = 'matched' - r15 = builtins :: module - r16 = 'print' - r17 = CPyObject_GetAttr(r15, r16) - r18 = [r14] - r19 = load_address r18 - r20 = PyObject_Vectorcall(r17, r19, 1, 0) - keep_alive r14 + r15 = 'matched' + r16 = builtins :: module + r17 = 'print' + r18 = CPyObject_GetAttr(r16, r17) + r19 = [r15] + r20 = load_address r19 + r21 = PyObject_Vectorcall(r18, r20, 1, 0) + keep_alive r15 goto L6 L5: L6: - r21 = box(None, 1) - return r21 + r22 = box(None, 1) + return r22 [case testMatchEmptySequencePattern_python3_10] def f(x): diff --git a/mypyc/test-data/irbuild-set.test b/mypyc/test-data/irbuild-set.test index 1876fea88964..fd38657f7253 100644 --- a/mypyc/test-data/irbuild-set.test +++ b/mypyc/test-data/irbuild-set.test @@ -161,19 +161,20 @@ L5: def test3(): r0, r1, r2 :: str r3, r4, r5 :: object - r6, tmp_dict :: dict[exact] - r7 :: set - r8 :: short_int - r9 :: native_int - r10 :: dict[exact] - r11 :: tuple[bool, short_int, object] - r12 :: short_int - r13 :: bool - r14 :: object - r15, x, r16 :: int - r17 :: object - r18 :: i32 - r19, r20, r21 :: bit + r6 :: dict[exact] + r7, tmp_dict :: dict + r8 :: set + r9 :: short_int + r10 :: native_int + r11 :: object + r12 :: tuple[bool, short_int, object] + r13 :: short_int + r14 :: bool + r15 :: object + r16, x, r17 :: int + r18 :: object + r19 :: i32 + r20, r21, r22 :: bit c :: set L0: r0 = '1' @@ -183,32 +184,33 @@ L0: r4 = object 3 r5 = object 5 r6 = CPyDict_Build(3, r3, r0, r4, r1, r5, r2) - tmp_dict = r6 - r7 = PySet_New(0) - r8 = 0 - r9 = PyDict_Size(tmp_dict) - r10 = _CPyDict_GetIterUnsafe(tmp_dict) + r7 = cast(dict, r6) + tmp_dict = r7 + r8 = PySet_New(0) + r9 = 0 + r10 = PyDict_Size(tmp_dict) + r11 = CPyDict_GetKeysIter(tmp_dict) L1: - r11 = CPyDict_NextKeyUnsafe(r10, r8) - r12 = r11[1] - r8 = r12 - r13 = r11[0] - if r13 goto L2 else goto L4 :: bool + r12 = CPyDict_NextKey(r11, r9) + r13 = r12[1] + r9 = r13 + r14 = r12[0] + if r14 goto L2 else goto L4 :: bool L2: - r14 = r11[2] - r15 = unbox(int, r14) - x = r15 - r16 = f(x) - r17 = box(int, r16) - r18 = PySet_Add(r7, r17) - r19 = r18 >= 0 :: signed + r15 = r12[2] + r16 = unbox(int, r15) + x = r16 + r17 = f(x) + r18 = box(int, r17) + r19 = PySet_Add(r8, r18) + r20 = r19 >= 0 :: signed L3: - r20 = CPyDict_CheckSizeUnsafe(tmp_dict, r9) + r21 = CPyDict_CheckSize(tmp_dict, r10) goto L1 L4: - r21 = CPy_NoErrOccurred() + r22 = CPy_NoErrOccurred() L5: - c = r7 + c = r8 return 1 def test4(): r0 :: set diff --git a/mypyc/test-data/irbuild-statements.test b/mypyc/test-data/irbuild-statements.test index 535bf8fe7cc7..5d5a7bbe632a 100644 --- a/mypyc/test-data/irbuild-statements.test +++ b/mypyc/test-data/irbuild-statements.test @@ -263,10 +263,10 @@ def f(d: Dict[int, int]) -> None: d[key] [out] def f(d): - d :: dict[exact] + d :: dict r0 :: short_int r1 :: native_int - r2 :: dict[exact] + r2 :: object r3 :: tuple[bool, short_int, object] r4 :: short_int r5 :: bool @@ -278,9 +278,9 @@ def f(d): L0: r0 = 0 r1 = PyDict_Size(d) - r2 = _CPyDict_GetIterUnsafe(d) + r2 = CPyDict_GetKeysIter(d) L1: - r3 = CPyDict_NextKeyUnsafe(r2, r0) + r3 = CPyDict_NextKey(r2, r0) r4 = r3[1] r0 = r4 r5 = r3[0] @@ -290,10 +290,10 @@ L2: r7 = unbox(int, r6) key = r7 r8 = box(int, key) - r9 = CPyDict_GetItemUnsafe(d, r8) + r9 = CPyDict_GetItem(d, r8) r10 = unbox(int, r9) L3: - r11 = CPyDict_CheckSizeUnsafe(d, r1) + r11 = CPyDict_CheckSize(d, r1) goto L1 L4: r12 = CPy_NoErrOccurred() @@ -312,11 +312,11 @@ def sum_over_even_values(d: Dict[int, int]) -> int: return s [out] def sum_over_even_values(d): - d :: dict[exact] + d :: dict s :: int r0 :: short_int r1 :: native_int - r2 :: dict[exact] + r2 :: object r3 :: tuple[bool, short_int, object] r4 :: short_int r5 :: bool @@ -332,9 +332,9 @@ L0: s = 0 r0 = 0 r1 = PyDict_Size(d) - r2 = _CPyDict_GetIterUnsafe(d) + r2 = CPyDict_GetKeysIter(d) L1: - r3 = CPyDict_NextKeyUnsafe(r2, r0) + r3 = CPyDict_NextKey(r2, r0) r4 = r3[1] r0 = r4 r5 = r3[0] @@ -344,7 +344,7 @@ L2: r7 = unbox(int, r6) key = r7 r8 = box(int, key) - r9 = CPyDict_GetItemUnsafe(d, r8) + r9 = CPyDict_GetItem(d, r8) r10 = unbox(int, r9) r11 = CPyTagged_Remainder(r10, 4) r12 = r11 != 0 @@ -353,12 +353,12 @@ L3: goto L5 L4: r13 = box(int, key) - r14 = CPyDict_GetItemUnsafe(d, r13) + r14 = CPyDict_GetItem(d, r13) r15 = unbox(int, r14) r16 = CPyTagged_Add(s, r15) s = r16 L5: - r17 = CPyDict_CheckSizeUnsafe(d, r1) + r17 = CPyDict_CheckSize(d, r1) goto L1 L6: r18 = CPy_NoErrOccurred() @@ -759,30 +759,33 @@ def delDictMultiple() -> None: def delDict(): r0, r1 :: str r2, r3 :: object - r4, d :: dict[exact] - r5 :: str - r6 :: i32 - r7 :: bit + r4 :: dict[exact] + r5, d :: dict + r6 :: str + r7 :: i32 + r8 :: bit L0: r0 = 'one' r1 = 'two' r2 = object 1 r3 = object 2 r4 = CPyDict_Build(2, r0, r2, r1, r3) - d = r4 - r5 = 'one' - r6 = PyObject_DelItem(d, r5) - r7 = r6 >= 0 :: signed + r5 = cast(dict, r4) + d = r5 + r6 = 'one' + r7 = PyObject_DelItem(d, r6) + r8 = r7 >= 0 :: signed return 1 def delDictMultiple(): r0, r1, r2, r3 :: str r4, r5, r6, r7 :: object - r8, d :: dict[exact] - r9, r10 :: str - r11 :: i32 - r12 :: bit - r13 :: i32 - r14 :: bit + r8 :: dict[exact] + r9, d :: dict + r10, r11 :: str + r12 :: i32 + r13 :: bit + r14 :: i32 + r15 :: bit L0: r0 = 'one' r1 = 'two' @@ -793,13 +796,14 @@ L0: r6 = object 3 r7 = object 4 r8 = CPyDict_Build(4, r0, r4, r1, r5, r2, r6, r3, r7) - d = r8 - r9 = 'one' - r10 = 'four' - r11 = PyObject_DelItem(d, r9) - r12 = r11 >= 0 :: signed - r13 = PyObject_DelItem(d, r10) - r14 = r13 >= 0 :: signed + r9 = cast(dict, r8) + d = r9 + r10 = 'one' + r11 = 'four' + r12 = PyObject_DelItem(d, r10) + r13 = r12 >= 0 :: signed + r14 = PyObject_DelItem(d, r11) + r15 = r14 >= 0 :: signed return 1 [case testDelAttribute] diff --git a/mypyc/test-data/refcount.test b/mypyc/test-data/refcount.test index ddcc52ccd087..a71c53041cf7 100644 --- a/mypyc/test-data/refcount.test +++ b/mypyc/test-data/refcount.test @@ -727,10 +727,10 @@ def f(d: Dict[int, int]) -> None: d[key] [out] def f(d): - d :: dict[exact] + d :: dict r0 :: short_int r1 :: native_int - r2 :: dict[exact] + r2 :: object r3 :: tuple[bool, short_int, object] r4 :: short_int r5 :: bool @@ -742,9 +742,9 @@ def f(d): L0: r0 = 0 r1 = PyDict_Size(d) - r2 = _CPyDict_GetIterUnsafe(d) + r2 = CPyDict_GetKeysIter(d) L1: - r3 = CPyDict_NextKeyUnsafe(r2, r0) + r3 = CPyDict_NextKey(r2, r0) r4 = r3[1] r0 = r4 r5 = r3[0] @@ -756,13 +756,13 @@ L2: dec_ref r6 key = r7 r8 = box(int, key) - r9 = CPyDict_GetItemUnsafe(d, r8) + r9 = CPyDict_GetItem(d, r8) dec_ref r8 r10 = unbox(int, r9) dec_ref r9 dec_ref r10 :: int L3: - r11 = CPyDict_CheckSizeUnsafe(d, r1) + r11 = CPyDict_CheckSize(d, r1) goto L1 L4: r12 = CPy_NoErrOccurred() From ee04ff4b2c3d7c397adf9fcf3d035d78f31f34e4 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 4 Aug 2025 02:01:36 +0000 Subject: [PATCH 22/43] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- mypyc/test-data/irbuild-dict.test | 1 - mypyc/test-data/irbuild-generics.test | 1 - 2 files changed, 2 deletions(-) diff --git a/mypyc/test-data/irbuild-dict.test b/mypyc/test-data/irbuild-dict.test index 553b93556200..9bdd5f831ac9 100644 --- a/mypyc/test-data/irbuild-dict.test +++ b/mypyc/test-data/irbuild-dict.test @@ -580,4 +580,3 @@ L2: L3: r8 = box(None, 1) return r8 - diff --git a/mypyc/test-data/irbuild-generics.test b/mypyc/test-data/irbuild-generics.test index 496a7af7390f..c5db874d91d3 100644 --- a/mypyc/test-data/irbuild-generics.test +++ b/mypyc/test-data/irbuild-generics.test @@ -773,4 +773,3 @@ def f(x): x :: int L0: return x - From 58c3b0ee59b6f429a20471ac5f67d7f810b7dfe3 Mon Sep 17 00:00:00 2001 From: BobTheBuidler Date: Mon, 4 Aug 2025 02:01:36 +0000 Subject: [PATCH 23/43] update ir --- mypyc/test-data/irbuild-dict.test | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mypyc/test-data/irbuild-dict.test b/mypyc/test-data/irbuild-dict.test index 9bdd5f831ac9..5eb1b7c7939b 100644 --- a/mypyc/test-data/irbuild-dict.test +++ b/mypyc/test-data/irbuild-dict.test @@ -465,9 +465,9 @@ def f(d: Dict[int, int]) -> Dict[int, int]: return d.copy() [out] def f(d): - d, r0 :: dict[exact] + d, r0 :: dict L0: - r0 = PyDict_Copy(d) + r0 = CPyDict_Copy(d) return r0 [case testDictSetdefault] From 6093dd97398dce4922323a886575721d50c24ac1 Mon Sep 17 00:00:00 2001 From: BobTheBuidler <70677534+BobTheBuidler@users.noreply.github.com> Date: Thu, 14 Aug 2025 01:38:52 -0400 Subject: [PATCH 24/43] Update ll_builder.py --- mypyc/irbuild/ll_builder.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mypyc/irbuild/ll_builder.py b/mypyc/irbuild/ll_builder.py index c49fbd900466..b360a3477f26 100644 --- a/mypyc/irbuild/ll_builder.py +++ b/mypyc/irbuild/ll_builder.py @@ -1942,7 +1942,7 @@ def bool_value(self, value: Value) -> Value: elif is_str_rprimitive(value.type): result = self.call_c(str_check_if_true, [value], value.line) elif is_same_type(value.type, exact_dict_rprimitive): - result = self.call_c(dict_is_true_op, [value], line=value.line) + result = self.primitive_op(dict_is_true_op, [value], line=value.line) elif is_same_type(value.type, list_rprimitive) or is_same_type( value.type, dict_rprimitive of is_same_type(value.type, tuple_rprimitive) ): From 05e1335e27e1e9b91ebde81955b553131ee36ab2 Mon Sep 17 00:00:00 2001 From: BobTheBuidler <70677534+BobTheBuidler@users.noreply.github.com> Date: Thu, 14 Aug 2025 01:39:46 -0400 Subject: [PATCH 25/43] Update misc_ops.py --- mypyc/primitives/misc_ops.py | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/mypyc/primitives/misc_ops.py b/mypyc/primitives/misc_ops.py index 30d50af9a56f..bb92f0807aa0 100644 --- a/mypyc/primitives/misc_ops.py +++ b/mypyc/primitives/misc_ops.py @@ -190,7 +190,7 @@ ) # bool(dict) -function_op( +dict_is_true_op = function_op( name="builtins.bool", arg_types=[exact_dict_rprimitive], return_type=bit_rprimitive, @@ -198,14 +198,6 @@ error_kind=ERR_NEVER, ) -# bool(dict) custom_op -dict_is_true_op = custom_op( - 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 64827cc4e2c088251bc461eff280b3ecbfeab602 Mon Sep 17 00:00:00 2001 From: BobTheBuidler <70677534+BobTheBuidler@users.noreply.github.com> Date: Thu, 14 Aug 2025 19:19:40 -0400 Subject: [PATCH 26/43] Update dict_ops.py --- mypyc/primitives/dict_ops.py | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/mypyc/primitives/dict_ops.py b/mypyc/primitives/dict_ops.py index 9d56c246b345..5e6b279b21b3 100644 --- a/mypyc/primitives/dict_ops.py +++ b/mypyc/primitives/dict_ops.py @@ -113,15 +113,6 @@ ) # dict[key] = value -exact_dict_set_item_op = method_op( - name="__setitem__", - arg_types=[exact_dict_rprimitive, object_rprimitive, object_rprimitive], - return_type=c_int_rprimitive, - c_function_name="PyDict_SetItem", - error_kind=ERR_NEG_INT, -) - -# dictsubclass[key] = value dict_set_item_op = method_op( name="__setitem__", arg_types=[dict_rprimitive, object_rprimitive, object_rprimitive], @@ -132,7 +123,8 @@ # dict[key] = value (exact dict only, no subclasses) # NOTE: this is currently for internal use only, and not used for CallExpr specialization -exact_dict_set_item_op = custom_op( +exact_dict_set_item_op = method_op( + name="__setitem__", arg_types=[dict_rprimitive, object_rprimitive, object_rprimitive], return_type=c_int_rprimitive, c_function_name="PyDict_SetItem", From 6fb71feebb93bec3f8508baae838da508c42f973 Mon Sep 17 00:00:00 2001 From: BobTheBuidler <70677534+BobTheBuidler@users.noreply.github.com> Date: Thu, 14 Aug 2025 19:22:55 -0400 Subject: [PATCH 27/43] Update dict_ops.py --- mypyc/primitives/dict_ops.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mypyc/primitives/dict_ops.py b/mypyc/primitives/dict_ops.py index 5e6b279b21b3..d8bd888202f0 100644 --- a/mypyc/primitives/dict_ops.py +++ b/mypyc/primitives/dict_ops.py @@ -125,7 +125,7 @@ # NOTE: this is currently for internal use only, and not used for CallExpr specialization exact_dict_set_item_op = method_op( name="__setitem__", - arg_types=[dict_rprimitive, object_rprimitive, object_rprimitive], + arg_types=[exact_dict_rprimitive, object_rprimitive, object_rprimitive], return_type=c_int_rprimitive, c_function_name="PyDict_SetItem", error_kind=ERR_NEG_INT, From cf95f9f78cc05340303d6eccf0a030b6f8366cd3 Mon Sep 17 00:00:00 2001 From: BobTheBuidler <70677534+BobTheBuidler@users.noreply.github.com> Date: Sun, 17 Aug 2025 20:58:39 -0400 Subject: [PATCH 28/43] 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 f837d1b9d82cae8156eda4f23cdec064e628db5b Mon Sep 17 00:00:00 2001 From: BobTheBuidler <70677534+BobTheBuidler@users.noreply.github.com> Date: Sun, 17 Aug 2025 21:05:22 -0400 Subject: [PATCH 29/43] Update subtype.py --- mypyc/subtype.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/mypyc/subtype.py b/mypyc/subtype.py index 726a48d7a01d..a8124e5aaa96 100644 --- a/mypyc/subtype.py +++ b/mypyc/subtype.py @@ -14,6 +14,8 @@ RVoid, is_bit_rprimitive, is_bool_rprimitive, + is_dict_rprimive, + is_exact_dict_rprimitive, is_fixed_width_rtype, is_int_rprimitive, is_object_rprimitive, @@ -67,6 +69,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 b97e82313e17e04f740a97dea4e9f26caa1c2d99 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 18 Aug 2025 01:06:44 +0000 Subject: [PATCH 30/43] [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 a8124e5aaa96..7d39069c69bc 100644 --- a/mypyc/subtype.py +++ b/mypyc/subtype.py @@ -14,7 +14,6 @@ RVoid, is_bit_rprimitive, is_bool_rprimitive, - is_dict_rprimive, is_exact_dict_rprimitive, is_fixed_width_rtype, is_int_rprimitive, From 929929389a064ffaffa6fed84a5561e3d2d7d962 Mon Sep 17 00:00:00 2001 From: BobTheBuidler <70677534+BobTheBuidler@users.noreply.github.com> Date: Sun, 17 Aug 2025 21:10:26 -0400 Subject: [PATCH 31/43] Update subtype.py --- mypyc/subtype.py | 1 + 1 file changed, 1 insertion(+) diff --git a/mypyc/subtype.py b/mypyc/subtype.py index 7d39069c69bc..6feb4b83b5cf 100644 --- a/mypyc/subtype.py +++ b/mypyc/subtype.py @@ -14,6 +14,7 @@ RVoid, is_bit_rprimitive, is_bool_rprimitive, + is_dict_rprimitive, is_exact_dict_rprimitive, is_fixed_width_rtype, is_int_rprimitive, From c2b678793f332f79c101979256eaa1689be10e2b Mon Sep 17 00:00:00 2001 From: BobTheBuidler <70677534+BobTheBuidler@users.noreply.github.com> Date: Sun, 17 Aug 2025 21:17:56 -0400 Subject: [PATCH 32/43] Update dict_ops.py --- mypyc/primitives/dict_ops.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/mypyc/primitives/dict_ops.py b/mypyc/primitives/dict_ops.py index d8bd888202f0..7036ef712f73 100644 --- a/mypyc/primitives/dict_ops.py +++ b/mypyc/primitives/dict_ops.py @@ -55,7 +55,7 @@ c_function_name="CPyDict_Build", error_kind=ERR_MAGIC, var_arg_type=object_rprimitive, -) +)f # Construct a dictionary from another dictionary. dict_copy_op = function_op( @@ -129,6 +129,7 @@ return_type=c_int_rprimitive, c_function_name="PyDict_SetItem", error_kind=ERR_NEG_INT, + priority=2, ) # key in dict From d7029acb51ae65511d045f6868518d34f545f8d6 Mon Sep 17 00:00:00 2001 From: BobTheBuidler <70677534+BobTheBuidler@users.noreply.github.com> Date: Sun, 17 Aug 2025 21:19:48 -0400 Subject: [PATCH 33/43] Update dict_ops.py --- mypyc/primitives/dict_ops.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mypyc/primitives/dict_ops.py b/mypyc/primitives/dict_ops.py index 7036ef712f73..130a2a9f2eed 100644 --- a/mypyc/primitives/dict_ops.py +++ b/mypyc/primitives/dict_ops.py @@ -55,7 +55,7 @@ c_function_name="CPyDict_Build", error_kind=ERR_MAGIC, var_arg_type=object_rprimitive, -)f +) # Construct a dictionary from another dictionary. dict_copy_op = function_op( From 66f57e6aa4626f45854d635ad63115643fef814e Mon Sep 17 00:00:00 2001 From: BobTheBuidler <70677534+BobTheBuidler@users.noreply.github.com> Date: Sun, 17 Aug 2025 21:28:39 -0400 Subject: [PATCH 34/43] Update dict_ops.py --- mypyc/primitives/dict_ops.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/mypyc/primitives/dict_ops.py b/mypyc/primitives/dict_ops.py index 130a2a9f2eed..3eb113f61dc3 100644 --- a/mypyc/primitives/dict_ops.py +++ b/mypyc/primitives/dict_ops.py @@ -161,7 +161,7 @@ return_type=c_int_rprimitive, c_function_name="PyDict_Update", error_kind=ERR_NEG_INT, - priority=2, + priority=5, ) # dictorsubclass.update(dict) @@ -171,7 +171,7 @@ return_type=c_int_rprimitive, c_function_name="CPyDict_Update", error_kind=ERR_NEG_INT, - priority=2, + priority=3, ) # dict.update(dictsubclass) @@ -181,7 +181,7 @@ return_type=c_int_rprimitive, c_function_name="PyDict_Update", error_kind=ERR_NEG_INT, - priority=2, + priority=4, ) # dictsubclass1.update(dictsubclass2) @@ -392,6 +392,7 @@ return_type=exact_dict_rprimitive, c_function_name="PyDict_Copy", error_kind=ERR_NEVER, + priority=2, ) # dictsubclass.copy() From c8e19014c8795e3403815ac64d8ac318b6f7d938 Mon Sep 17 00:00:00 2001 From: BobTheBuidler <70677534+BobTheBuidler@users.noreply.github.com> Date: Sun, 17 Aug 2025 21:37:23 -0400 Subject: [PATCH 35/43] Update dict_ops.py --- mypyc/primitives/dict_ops.py | 25 +++++++------------------ 1 file changed, 7 insertions(+), 18 deletions(-) diff --git a/mypyc/primitives/dict_ops.py b/mypyc/primitives/dict_ops.py index 3eb113f61dc3..e7aff450493e 100644 --- a/mypyc/primitives/dict_ops.py +++ b/mypyc/primitives/dict_ops.py @@ -101,6 +101,7 @@ return_type=object_rprimitive, c_function_name="CPyDict_GetItemUnsafe", error_kind=ERR_MAGIC, + priority=2, ) # dictsubclass[key] @@ -141,6 +142,7 @@ error_kind=ERR_NEG_INT, truncated_type=bool_rprimitive, ordering=[1, 0], + priority=2, ) # key in dict or dict subclass @@ -231,15 +233,6 @@ ) # dict.get(key, default) -method_op( - name="get", - arg_types=[exact_dict_rprimitive, object_rprimitive, object_rprimitive], - return_type=object_rprimitive, - c_function_name="CPyDict_Get", - error_kind=ERR_MAGIC, -) - -# dictorsubclass.get(key, default) method_op( name="get", arg_types=[dict_rprimitive, object_rprimitive, object_rprimitive], @@ -273,6 +266,7 @@ return_type=object_rprimitive, c_function_name="PyDict_SetDefault", error_kind=ERR_NEVER, + priority=2, ) # dictorsubclass.setdefault(key, default) @@ -285,15 +279,6 @@ ) # dict.setdefault(key) -method_op( - name="setdefault", - arg_types=[exact_dict_rprimitive, object_rprimitive], - return_type=object_rprimitive, - c_function_name="CPyDict_SetDefaultWithNone", - error_kind=ERR_MAGIC, -) - -# dictorsubclass.setdefault(key) method_op( name="setdefault", arg_types=[dict_rprimitive, object_rprimitive], @@ -320,6 +305,7 @@ return_type=object_rprimitive, c_function_name="CPyDict_KeysViewUnsafe", error_kind=ERR_MAGIC, + priority=2, ) # dictorsubclass.keys() @@ -338,6 +324,7 @@ return_type=object_rprimitive, c_function_name="CPyDict_ValuesViewUnsafe", error_kind=ERR_MAGIC, + priority=2, ) # dictorsubclass.values() @@ -356,6 +343,7 @@ return_type=object_rprimitive, c_function_name="CPyDict_ItemsViewUnsafe", error_kind=ERR_MAGIC, + priority=2, ) # dictorsubclass.items() @@ -374,6 +362,7 @@ return_type=void_rtype, c_function_name="PyDict_Clear", error_kind=ERR_NEVER, + priority=2, ) # dictsubclass.clear() From 0a376c61ee32b5bcb25dd53abda5b883d9494b36 Mon Sep 17 00:00:00 2001 From: BobTheBuidler <70677534+BobTheBuidler@users.noreply.github.com> Date: Sun, 17 Aug 2025 21:40:23 -0400 Subject: [PATCH 36/43] Update dict_ops.py --- mypyc/primitives/dict_ops.py | 1 + 1 file changed, 1 insertion(+) diff --git a/mypyc/primitives/dict_ops.py b/mypyc/primitives/dict_ops.py index e7aff450493e..04fa3d5af920 100644 --- a/mypyc/primitives/dict_ops.py +++ b/mypyc/primitives/dict_ops.py @@ -248,6 +248,7 @@ return_type=object_rprimitive, c_function_name="CPyDict_GetWithNone", error_kind=ERR_MAGIC, + priority=2, ) # dictorsubclass.get(key) From 06043906419d754ba05f67469bd5c0bbe8b151c4 Mon Sep 17 00:00:00 2001 From: BobTheBuidler <70677534+BobTheBuidler@users.noreply.github.com> Date: Sun, 17 Aug 2025 21:58:37 -0400 Subject: [PATCH 37/43] 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 d5f5d5d7353f..746a393273a3 100644 --- a/mypyc/analysis/ircheck.py +++ b/mypyc/analysis/ircheck.py @@ -199,7 +199,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 90e75a500df6886cfe16cafbea5fa2982f08ad38 Mon Sep 17 00:00:00 2001 From: BobTheBuidler Date: Mon, 18 Aug 2025 02:20:35 +0000 Subject: [PATCH 38/43] update it --- mypyc/test-data/irbuild-basic.test | 4 +- mypyc/test-data/irbuild-dict.test | 141 +++++++++++------------- mypyc/test-data/irbuild-generics.test | 1 + mypyc/test-data/irbuild-match.test | 86 +++++++-------- mypyc/test-data/irbuild-set.test | 67 ++++++----- mypyc/test-data/irbuild-statements.test | 44 ++++---- 6 files changed, 164 insertions(+), 179 deletions(-) diff --git a/mypyc/test-data/irbuild-basic.test b/mypyc/test-data/irbuild-basic.test index 71551031c1e2..919accf9e6ba 100644 --- a/mypyc/test-data/irbuild-basic.test +++ b/mypyc/test-data/irbuild-basic.test @@ -1950,7 +1950,6 @@ def f(): r16 :: i32 r17 :: bit r18 :: native_int - r19 :: dict L0: r0 = PyDict_New() r1 = PyList_New(3) @@ -1991,8 +1990,7 @@ L7: r6 = r18 goto L1 L8: - r19 = cast(dict, r0) - return r19 + return r0 [case testLoopsMultipleAssign] from typing import List, Tuple diff --git a/mypyc/test-data/irbuild-dict.test b/mypyc/test-data/irbuild-dict.test index 5eb1b7c7939b..bce82678f026 100644 --- a/mypyc/test-data/irbuild-dict.test +++ b/mypyc/test-data/irbuild-dict.test @@ -37,11 +37,10 @@ def f() -> None: [out] def f(): r0 :: dict[exact] - r1, d :: dict + d :: dict L0: r0 = PyDict_New() - r1 = cast(dict, r0) - d = r1 + d = r0 return 1 [case testNewEmptyDictViaFunc] @@ -52,11 +51,10 @@ def f() -> None: [out] def f(): r0 :: dict[exact] - r1, d :: dict + d :: dict L0: r0 = PyDict_New() - r1 = cast(dict, r0) - d = r1 + d = r0 return 1 [case testNewDictWithValues] @@ -68,14 +66,13 @@ def f(x): r0 :: str r1, r2 :: object r3 :: dict[exact] - r4, d :: dict + d :: dict L0: r0 = '' r1 = object 1 r2 = object 2 r3 = CPyDict_Build(2, r1, r2, r0, x) - r4 = cast(dict, r3) - d = r4 + d = r3 return 1 [case testInDict] @@ -205,25 +202,21 @@ def f(x, y): r0 :: str r1 :: object r2 :: dict[exact] - r3 :: dict - r4 :: i32 - r5 :: bit - r6 :: object - r7 :: i32 - r8 :: bit - r9 :: dict + r3 :: i32 + r4 :: bit + r5 :: object + r6 :: i32 + r7 :: bit L0: r0 = 'z' r1 = object 2 r2 = CPyDict_Build(1, x, r1) - r3 = cast(dict, r2) - r4 = CPyDict_UpdateInDisplay(r3, y) - r5 = r4 >= 0 :: signed - r6 = object 3 - r7 = PyDict_SetItem(r2, r0, r6) - r8 = r7 >= 0 :: signed - r9 = cast(dict, r2) - return r9 + r3 = CPyDict_UpdateInDisplay(r2, y) + r4 = r3 >= 0 :: signed + r5 = object 3 + r6 = PyDict_SetItem(r2, r0, r5) + r7 = r6 >= 0 :: signed + return r2 [case testDictIterationMethods] from typing import Dict, TypedDict, Union @@ -335,60 +328,59 @@ L12: def union_of_dicts(d): d :: dict r0 :: dict[exact] - r1, new :: dict - r2 :: short_int - r3 :: native_int - r4 :: object - r5 :: tuple[bool, short_int, object, object] - r6 :: short_int - r7 :: bool - r8, r9 :: object - r10 :: str - r11 :: union[int, str] + new :: dict + r1 :: short_int + r2 :: native_int + r3 :: object + r4 :: tuple[bool, short_int, object, object] + r5 :: short_int + r6 :: bool + r7, r8 :: object + r9 :: str + r10 :: union[int, str] k :: str v :: union[int, str] - r12 :: object - r13 :: object[1] - r14 :: object_ptr - r15 :: object - r16 :: int - r17 :: object - r18 :: i32 - r19, r20, r21 :: bit + r11 :: object + r12 :: object[1] + r13 :: object_ptr + r14 :: object + r15 :: int + r16 :: object + r17 :: i32 + r18, r19, r20 :: bit L0: r0 = PyDict_New() - r1 = cast(dict, r0) - new = r1 - r2 = 0 - r3 = PyDict_Size(d) - r4 = CPyDict_GetItemsIter(d) + new = r0 + r1 = 0 + r2 = PyDict_Size(d) + r3 = CPyDict_GetItemsIter(d) L1: - r5 = CPyDict_NextItem(r4, r2) - r6 = r5[1] - r2 = r6 - r7 = r5[0] - if r7 goto L2 else goto L4 :: bool + r4 = CPyDict_NextItem(r3, r1) + r5 = r4[1] + r1 = r5 + r6 = r4[0] + if r6 goto L2 else goto L4 :: bool L2: - r8 = r5[2] - r9 = r5[3] - r10 = cast(str, r8) - r11 = cast(union[int, str], r9) - k = r10 - v = r11 - r12 = load_address PyLong_Type - r13 = [v] - r14 = load_address r13 - r15 = PyObject_Vectorcall(r12, r14, 1, 0) + r7 = r4[2] + r8 = r4[3] + r9 = cast(str, r7) + r10 = cast(union[int, str], r8) + k = r9 + v = r10 + r11 = load_address PyLong_Type + r12 = [v] + r13 = load_address r12 + r14 = PyObject_Vectorcall(r11, r13, 1, 0) keep_alive v - r16 = unbox(int, r15) - r17 = box(int, r16) - r18 = CPyDict_SetItem(new, k, r17) - r19 = r18 >= 0 :: signed + r15 = unbox(int, r14) + r16 = box(int, r15) + r17 = CPyDict_SetItem(new, k, r16) + r18 = r17 >= 0 :: signed L3: - r20 = CPyDict_CheckSize(d, r3) + r19 = CPyDict_CheckSize(d, r2) goto L1 L4: - r21 = CPy_NoErrOccurred() + r20 = CPy_NoErrOccurred() L5: return 1 def typeddict(d): @@ -561,8 +553,7 @@ def f4(d, flag): r2, r3 :: str r4 :: object r5 :: dict[exact] - r6 :: dict - r7, r8 :: object + r6, r7 :: object L0: if flag goto L1 else goto L2 :: bool L1: @@ -574,9 +565,9 @@ L2: r3 = 'c' r4 = object 1 r5 = CPyDict_Build(1, r3, r4) - r6 = cast(dict, r5) - r7 = CPyDict_SetDefault(d, r2, r6) - return r7 + r6 = CPyDict_SetDefault(d, r2, r5) + return r6 L3: - r8 = box(None, 1) - return r8 + r7 = box(None, 1) + return r7 + diff --git a/mypyc/test-data/irbuild-generics.test b/mypyc/test-data/irbuild-generics.test index c5db874d91d3..496a7af7390f 100644 --- a/mypyc/test-data/irbuild-generics.test +++ b/mypyc/test-data/irbuild-generics.test @@ -773,3 +773,4 @@ def f(x): x :: int L0: return x + diff --git a/mypyc/test-data/irbuild-match.test b/mypyc/test-data/irbuild-match.test index 7774c6e83629..e46a1466bb81 100644 --- a/mypyc/test-data/irbuild-match.test +++ b/mypyc/test-data/irbuild-match.test @@ -1090,36 +1090,35 @@ def f(x): r0 :: i32 r1 :: bit r2 :: dict[exact] - r3, rest :: dict - r4 :: str - r5 :: object - r6 :: str - r7 :: object - r8 :: object[1] - r9 :: object_ptr - r10, r11 :: object + rest :: dict + r3 :: str + r4 :: object + r5 :: str + r6 :: object + r7 :: object[1] + r8 :: object_ptr + r9, r10 :: object L0: r0 = CPyMapping_Check(x) r1 = r0 != 0 if r1 goto L1 else goto L3 :: bool L1: r2 = CPyDict_FromAny(x) - r3 = cast(dict, r2) - rest = r3 + rest = r2 L2: - r4 = 'matched' - r5 = builtins :: module - r6 = 'print' - r7 = CPyObject_GetAttr(r5, r6) - r8 = [r4] - r9 = load_address r8 - r10 = PyObject_Vectorcall(r7, r9, 1, 0) - keep_alive r4 + r3 = 'matched' + r4 = builtins :: module + r5 = 'print' + r6 = CPyObject_GetAttr(r4, r5) + r7 = [r3] + r8 = load_address r7 + r9 = PyObject_Vectorcall(r6, r8, 1, 0) + keep_alive r3 goto L4 L3: L4: - r11 = box(None, 1) - return r11 + r10 = box(None, 1) + return r10 [case testMatchMappingPatternWithRestPopKeys_python3_10] def f(x): @@ -1141,16 +1140,16 @@ def f(x): r9 :: bit r10 :: bool r11 :: dict[exact] - r12, rest :: dict - r13 :: i32 - r14 :: bit - r15 :: str - r16 :: object - r17 :: str - r18 :: object - r19 :: object[1] - r20 :: object_ptr - r21, r22 :: object + rest :: dict + r12 :: i32 + r13 :: bit + r14 :: str + r15 :: object + r16 :: str + r17 :: object + r18 :: object[1] + r19 :: object_ptr + r20, r21 :: object L0: r0 = CPyMapping_Check(x) r1 = r0 != 0 @@ -1170,24 +1169,23 @@ L2: if r10 goto L3 else goto L5 :: bool L3: r11 = CPyDict_FromAny(x) - r12 = cast(dict, r11) - rest = r12 - r13 = PyDict_DelItem(r11, r2) - r14 = r13 >= 0 :: signed + rest = r11 + r12 = PyDict_DelItem(r11, r2) + r13 = r12 >= 0 :: signed L4: - r15 = 'matched' - r16 = builtins :: module - r17 = 'print' - r18 = CPyObject_GetAttr(r16, r17) - r19 = [r15] - r20 = load_address r19 - r21 = PyObject_Vectorcall(r18, r20, 1, 0) - keep_alive r15 + r14 = 'matched' + r15 = builtins :: module + r16 = 'print' + r17 = CPyObject_GetAttr(r15, r16) + r18 = [r14] + r19 = load_address r18 + r20 = PyObject_Vectorcall(r17, r19, 1, 0) + keep_alive r14 goto L6 L5: L6: - r22 = box(None, 1) - return r22 + r21 = box(None, 1) + return r21 [case testMatchEmptySequencePattern_python3_10] def f(x): diff --git a/mypyc/test-data/irbuild-set.test b/mypyc/test-data/irbuild-set.test index fd38657f7253..63b5fec940c8 100644 --- a/mypyc/test-data/irbuild-set.test +++ b/mypyc/test-data/irbuild-set.test @@ -162,19 +162,19 @@ def test3(): r0, r1, r2 :: str r3, r4, r5 :: object r6 :: dict[exact] - r7, tmp_dict :: dict - r8 :: set - r9 :: short_int - r10 :: native_int - r11 :: object - r12 :: tuple[bool, short_int, object] - r13 :: short_int - r14 :: bool - r15 :: object - r16, x, r17 :: int - r18 :: object - r19 :: i32 - r20, r21, r22 :: bit + tmp_dict :: dict + r7 :: set + r8 :: short_int + r9 :: native_int + r10 :: object + r11 :: tuple[bool, short_int, object] + r12 :: short_int + r13 :: bool + r14 :: object + r15, x, r16 :: int + r17 :: object + r18 :: i32 + r19, r20, r21 :: bit c :: set L0: r0 = '1' @@ -184,33 +184,32 @@ L0: r4 = object 3 r5 = object 5 r6 = CPyDict_Build(3, r3, r0, r4, r1, r5, r2) - r7 = cast(dict, r6) - tmp_dict = r7 - r8 = PySet_New(0) - r9 = 0 - r10 = PyDict_Size(tmp_dict) - r11 = CPyDict_GetKeysIter(tmp_dict) + tmp_dict = r6 + r7 = PySet_New(0) + r8 = 0 + r9 = PyDict_Size(tmp_dict) + r10 = CPyDict_GetKeysIter(tmp_dict) L1: - r12 = CPyDict_NextKey(r11, r9) - r13 = r12[1] - r9 = r13 - r14 = r12[0] - if r14 goto L2 else goto L4 :: bool + r11 = CPyDict_NextKey(r10, r8) + r12 = r11[1] + r8 = r12 + r13 = r11[0] + if r13 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(r8, r18) - r20 = r19 >= 0 :: signed + r14 = r11[2] + r15 = unbox(int, r14) + x = r15 + r16 = f(x) + r17 = box(int, r16) + r18 = PySet_Add(r7, r17) + r19 = r18 >= 0 :: signed L3: - r21 = CPyDict_CheckSize(tmp_dict, r10) + r20 = CPyDict_CheckSize(tmp_dict, r9) goto L1 L4: - r22 = CPy_NoErrOccurred() + r21 = CPy_NoErrOccurred() L5: - c = r8 + c = r7 return 1 def test4(): r0 :: set diff --git a/mypyc/test-data/irbuild-statements.test b/mypyc/test-data/irbuild-statements.test index 5d5a7bbe632a..46643136a131 100644 --- a/mypyc/test-data/irbuild-statements.test +++ b/mypyc/test-data/irbuild-statements.test @@ -760,32 +760,31 @@ def delDict(): r0, r1 :: str r2, r3 :: object r4 :: dict[exact] - r5, d :: dict - r6 :: str - r7 :: i32 - r8 :: bit + d :: dict + r5 :: str + r6 :: i32 + r7 :: bit L0: r0 = 'one' r1 = 'two' r2 = object 1 r3 = object 2 r4 = CPyDict_Build(2, r0, r2, r1, r3) - r5 = cast(dict, r4) - d = r5 - r6 = 'one' - r7 = PyObject_DelItem(d, r6) - r8 = r7 >= 0 :: signed + d = r4 + r5 = 'one' + r6 = PyObject_DelItem(d, r5) + r7 = r6 >= 0 :: signed return 1 def delDictMultiple(): r0, r1, r2, r3 :: str r4, r5, r6, r7 :: object r8 :: dict[exact] - r9, d :: dict - r10, r11 :: str - r12 :: i32 - r13 :: bit - r14 :: i32 - r15 :: bit + d :: dict + r9, r10 :: str + r11 :: i32 + r12 :: bit + r13 :: i32 + r14 :: bit L0: r0 = 'one' r1 = 'two' @@ -796,14 +795,13 @@ L0: r6 = object 3 r7 = object 4 r8 = CPyDict_Build(4, r0, r4, r1, r5, r2, r6, r3, r7) - r9 = cast(dict, r8) - d = r9 - r10 = 'one' - r11 = 'four' - r12 = PyObject_DelItem(d, r10) - r13 = r12 >= 0 :: signed - r14 = PyObject_DelItem(d, r11) - r15 = r14 >= 0 :: signed + d = r8 + r9 = 'one' + r10 = 'four' + r11 = PyObject_DelItem(d, r9) + r12 = r11 >= 0 :: signed + r13 = PyObject_DelItem(d, r10) + r14 = r13 >= 0 :: signed return 1 [case testDelAttribute] From e86124d4939c7798dd0dc29ed16a92072ae6f661 Mon Sep 17 00:00:00 2001 From: BobTheBuidler Date: Mon, 18 Aug 2025 02:43:54 +0000 Subject: [PATCH 39/43] update it --- mypyc/test-data/irbuild-basic.test | 45 +++++++++++++----------------- 1 file changed, 20 insertions(+), 25 deletions(-) diff --git a/mypyc/test-data/irbuild-basic.test b/mypyc/test-data/irbuild-basic.test index 919accf9e6ba..eab66b7236b7 100644 --- a/mypyc/test-data/irbuild-basic.test +++ b/mypyc/test-data/irbuild-basic.test @@ -1758,38 +1758,33 @@ L0: def h(): r0, r1 :: str r2, r3 :: object - r4 :: dict[exact] - r5 :: dict - r6 :: dict[exact] - r7 :: str - r8 :: object - r9 :: dict[exact] - r10 :: dict - r11 :: i32 - r12 :: bit + r4, r5 :: dict[exact] + r6 :: str + r7 :: object + r8 :: dict[exact] + r9 :: i32 + r10 :: bit + r11 :: object + r12 :: tuple r13 :: object - r14 :: tuple - r15 :: object - r16 :: tuple[int, int, int] + r14 :: tuple[int, int, int] L0: r0 = 'b' r1 = 'c' r2 = object 2 r3 = object 3 r4 = CPyDict_Build(2, r0, r2, r1, r3) - r5 = cast(dict, r4) - r6 = __main__.globals :: static - r7 = 'f' - r8 = CPyDict_GetItemUnsafe(r6, r7) - r9 = PyDict_New() - r10 = cast(dict, r9) - r11 = CPyDict_UpdateInDisplay(r10, r5) - r12 = r11 >= 0 :: signed - r13 = object 1 - r14 = PyTuple_Pack(1, r13) - r15 = PyObject_Call(r8, r14, r9) - r16 = unbox(tuple[int, int, int], r15) - return r16 + r5 = __main__.globals :: static + r6 = 'f' + r7 = CPyDict_GetItemUnsafe(r5, r6) + r8 = PyDict_New() + r9 = PyDict_Update(r8, r4) + r10 = r9 >= 0 :: signed + r11 = object 1 + r12 = PyTuple_Pack(1, r11) + r13 = PyObject_Call(r7, r12, r8) + r14 = unbox(tuple[int, int, int], r13) + return r14 [case testFunctionCallWithDefaultArgs] def f(x: int, y: int = 3, z: str = "test") -> None: From f01d87f53987bb1c72e6fc1a29019b05927f1079 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 18 Aug 2025 02:22:15 +0000 Subject: [PATCH 40/43] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- mypyc/test-data/irbuild-dict.test | 1 - mypyc/test-data/irbuild-generics.test | 1 - 2 files changed, 2 deletions(-) diff --git a/mypyc/test-data/irbuild-dict.test b/mypyc/test-data/irbuild-dict.test index bce82678f026..5519c15a1b66 100644 --- a/mypyc/test-data/irbuild-dict.test +++ b/mypyc/test-data/irbuild-dict.test @@ -570,4 +570,3 @@ L2: L3: r7 = box(None, 1) return r7 - diff --git a/mypyc/test-data/irbuild-generics.test b/mypyc/test-data/irbuild-generics.test index 496a7af7390f..c5db874d91d3 100644 --- a/mypyc/test-data/irbuild-generics.test +++ b/mypyc/test-data/irbuild-generics.test @@ -773,4 +773,3 @@ def f(x): x :: int L0: return x - From 77ac6bfb69c8951fe99bdd426e314d7facfae306 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 8 Sep 2025 18:13:37 +0000 Subject: [PATCH 41/43] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- mypyc/irbuild/ll_builder.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/mypyc/irbuild/ll_builder.py b/mypyc/irbuild/ll_builder.py index b360a3477f26..72f95ee14211 100644 --- a/mypyc/irbuild/ll_builder.py +++ b/mypyc/irbuild/ll_builder.py @@ -127,6 +127,7 @@ pointer_rprimitive, short_int_rprimitive, str_rprimitive, + tuple_rprimitive, ) from mypyc.irbuild.util import concrete_arg_kind from mypyc.options import CompilerOptions @@ -1943,8 +1944,10 @@ def bool_value(self, value: Value) -> Value: result = self.call_c(str_check_if_true, [value], value.line) elif is_same_type(value.type, exact_dict_rprimitive): result = self.primitive_op(dict_is_true_op, [value], line=value.line) - elif is_same_type(value.type, list_rprimitive) or is_same_type( - value.type, dict_rprimitive of is_same_type(value.type, tuple_rprimitive) + elif ( + is_same_type(value.type, list_rprimitive) + or is_same_type(value.type, dict_rprimitive) + or is_same_type(value.type, tuple_rprimitive) ): length = self.builtin_len(value, value.line) zero = Integer(0) From 92598afac0b3631cbf96f65088051afa6667bad4 Mon Sep 17 00:00:00 2001 From: BobTheBuidler Date: Sat, 13 Sep 2025 02:39:23 +0000 Subject: [PATCH 42/43] fix: ir --- mypyc/test-data/irbuild-basic.test | 31 +++++++++++++----------- mypyc/test-data/irbuild-generics.test | 34 +++++++++++++++------------ 2 files changed, 36 insertions(+), 29 deletions(-) diff --git a/mypyc/test-data/irbuild-basic.test b/mypyc/test-data/irbuild-basic.test index eab66b7236b7..da992ff87d22 100644 --- a/mypyc/test-data/irbuild-basic.test +++ b/mypyc/test-data/irbuild-basic.test @@ -1680,7 +1680,7 @@ L0: r0 = (2, 4, 6) r1 = __main__.globals :: static r2 = 'f' - r3 = CPyDict_GetItem(r1, r2) + r3 = CPyDict_GetItemUnsafe(r1, r2) r4 = box(tuple[int, int, int], r0) r5 = PyObject_CallObject(r3, r4) r6 = unbox(tuple[int, int, int], r5) @@ -1732,11 +1732,11 @@ L0: def g(): r0, r1, r2 :: str r3, r4, r5 :: object - r6, r7 :: dict + r6, r7 :: dict[exact] r8 :: str r9 :: object r10 :: tuple - r11 :: dict + r11 :: dict[exact] r12 :: object r13 :: tuple[int, int, int] L0: @@ -1749,7 +1749,7 @@ L0: r6 = CPyDict_Build(3, r0, r3, r1, r4, r2, r5) r7 = __main__.globals :: static r8 = 'f' - r9 = CPyDict_GetItem(r7, r8) + r9 = CPyDict_GetItemUnsafe(r7, r8) r10 = CPyTuple_LoadEmptyTupleConstant() r11 = PyDict_Copy(r6) r12 = PyObject_Call(r9, r10, r11) @@ -3675,15 +3675,16 @@ def wrapper_deco_obj.__call__(__mypyc_self__, lst, kwargs): r0 :: __main__.deco_env r1 :: object r2 :: tuple - r3 :: dict - r4 :: object + r3, r4 :: dict[exact] + r5 :: object L0: r0 = __mypyc_self__.__mypyc_env__ r1 = r0.fn r2 = PyList_AsTuple(lst) - r3 = PyDict_Copy(kwargs) - r4 = PyObject_Call(r1, r2, r3) - return r4 + r3 = cast(dict[exact], kwargs) + r4 = PyDict_Copy(r3) + r5 = PyObject_Call(r1, r2, r4) + return r5 def deco(fn): fn :: object r0 :: __main__.deco_env @@ -3776,15 +3777,16 @@ def wrapper_deco_obj.__call__(__mypyc_self__, args, kwargs): r0 :: __main__.deco_env r1 :: object r2 :: tuple - r3 :: dict - r4 :: object + r3, r4 :: dict[exact] + r5 :: object L0: r0 = __mypyc_self__.__mypyc_env__ r1 = r0.fn r2 = PySequence_Tuple(args) - r3 = PyDict_Copy(kwargs) - r4 = PyObject_Call(r1, r2, r3) - return r4 + r3 = cast(dict[exact], kwargs) + r4 = PyDict_Copy(r3) + r5 = PyObject_Call(r1, r2, r4) + return r5 def deco(fn): fn :: object r0 :: __main__.deco_env @@ -3799,3 +3801,4 @@ L0: r2.__mypyc_env__ = r0; r3 = is_error wrapper = r2 return wrapper + diff --git a/mypyc/test-data/irbuild-generics.test b/mypyc/test-data/irbuild-generics.test index c5db874d91d3..50febd6b9d9b 100644 --- a/mypyc/test-data/irbuild-generics.test +++ b/mypyc/test-data/irbuild-generics.test @@ -166,14 +166,16 @@ execute(f, 1) def execute(func, args, kwargs): func :: object args :: tuple - kwargs, r0 :: dict - r1 :: object - r2 :: int + kwargs :: dict + r0, r1 :: dict[exact] + r2 :: object + r3 :: int L0: - r0 = PyDict_Copy(kwargs) - r1 = PyObject_Call(func, args, r0) - r2 = unbox(int, r1) - return r2 + r0 = cast(dict[exact], kwargs) + r1 = PyDict_Copy(r0) + r2 = PyObject_Call(func, args, r1) + r3 = unbox(int, r2) + return r3 def f(x): x :: int L0: @@ -683,7 +685,7 @@ def inner_deco_obj.__call__(__mypyc_self__, args, kwargs): r5, x :: object r6 :: native_int can_listcomp :: list - r7 :: dict + r7 :: dict[exact] r8 :: short_int r9 :: native_int r10 :: object @@ -698,9 +700,9 @@ def inner_deco_obj.__call__(__mypyc_self__, args, kwargs): can_dictcomp :: dict r21, can_iter, r22, can_use_keys, r23, can_use_values :: list r24 :: object - r25 :: dict - r26 :: object - r27 :: int + r25, r26 :: dict[exact] + r27 :: object + r28 :: int L0: r0 = __mypyc_self__.__mypyc_env__ r1 = var_object_size args @@ -751,10 +753,11 @@ L9: r23 = CPyDict_Values(kwargs) can_use_values = r23 r24 = r0.func - r25 = PyDict_Copy(kwargs) - r26 = PyObject_Call(r24, args, r25) - r27 = unbox(int, r26) - return r27 + r25 = cast(dict[exact], kwargs) + r26 = PyDict_Copy(r25) + r27 = PyObject_Call(r24, args, r26) + r28 = unbox(int, r27) + return r28 def deco(func): func :: object r0 :: __main__.deco_env @@ -773,3 +776,4 @@ def f(x): x :: int L0: return x + From 677994d6c9f95d6d83b0a83307d951d009114bd7 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Sat, 13 Sep 2025 02:40:48 +0000 Subject: [PATCH 43/43] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- mypyc/test-data/irbuild-basic.test | 1 - mypyc/test-data/irbuild-generics.test | 1 - 2 files changed, 2 deletions(-) diff --git a/mypyc/test-data/irbuild-basic.test b/mypyc/test-data/irbuild-basic.test index da992ff87d22..3c9234d25cf7 100644 --- a/mypyc/test-data/irbuild-basic.test +++ b/mypyc/test-data/irbuild-basic.test @@ -3801,4 +3801,3 @@ L0: r2.__mypyc_env__ = r0; r3 = is_error wrapper = r2 return wrapper - diff --git a/mypyc/test-data/irbuild-generics.test b/mypyc/test-data/irbuild-generics.test index 50febd6b9d9b..dda5ed5b5631 100644 --- a/mypyc/test-data/irbuild-generics.test +++ b/mypyc/test-data/irbuild-generics.test @@ -776,4 +776,3 @@ def f(x): x :: int L0: return x -