From c5a11a12648878122aa9f4f68cdc22da17133f6e Mon Sep 17 00:00:00 2001 From: BobTheBuidler Date: Mon, 4 Aug 2025 02:01:35 +0000 Subject: [PATCH 01/23] feat: true dict rprimitive --- mypyc/annotate.py | 2 +- mypyc/ir/rtypes.py | 18 +- mypyc/irbuild/builder.py | 12 +- mypyc/irbuild/classdef.py | 14 +- mypyc/irbuild/expression.py | 6 +- mypyc/irbuild/for_helpers.py | 54 ++++- mypyc/irbuild/function.py | 28 ++- mypyc/irbuild/ll_builder.py | 28 ++- 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 | 254 ++++++++++---------- mypyc/test-data/irbuild-bool.test | 16 +- mypyc/test-data/irbuild-classes.test | 36 +-- mypyc/test-data/irbuild-dict.test | 159 ++++++------ mypyc/test-data/irbuild-generics.test | 135 ++++++----- mypyc/test-data/irbuild-match.test | 88 +++---- mypyc/test-data/irbuild-set.test | 76 +++--- mypyc/test-data/irbuild-singledispatch.test | 24 +- mypyc/test-data/irbuild-statements.test | 46 ++-- mypyc/test-data/run-dicts.test | 10 +- 27 files changed, 994 insertions(+), 467 deletions(-) diff --git a/mypyc/annotate.py b/mypyc/annotate.py index 6736ca63c9e8..dcf0cecfc2e8 100644 --- a/mypyc/annotate.py +++ b/mypyc/annotate.py @@ -215,7 +215,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 c0871bba258c..4d70357aaf9c 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) @@ -599,7 +606,14 @@ def is_list_rprimitive(rtype: RType) -> bool: def is_dict_rprimitive(rtype: RType) -> bool: - 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) -> bool: + return isinstance(rtype, RPrimitive) and rtype.name == "builtins.dict[confirmed]" def is_set_rprimitive(rtype: RType) -> bool: diff --git a/mypyc/irbuild/builder.py b/mypyc/irbuild/builder.py index ec3c1b1b1f3c..faf4e7fe4e29 100644 --- a/mypyc/irbuild/builder.py +++ b/mypyc/irbuild/builder.py @@ -92,7 +92,6 @@ RUnion, bitmap_rprimitive, c_pyssize_t_rprimitive, - dict_rprimitive, int_rprimitive, is_float_rprimitive, is_list_rprimitive, @@ -103,6 +102,7 @@ none_rprimitive, object_rprimitive, str_rprimitive, + true_dict_rprimitive, ) from mypyc.irbuild.context import FuncInfo, ImplicitClass from mypyc.irbuild.ll_builder import LowLevelIRBuilder @@ -124,7 +124,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 @@ -435,6 +435,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 @@ -470,7 +472,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. @@ -1378,10 +1380,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 3282e836ac9e..378aa0d28a3a 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 ( @@ -66,7 +66,7 @@ ) from mypyc.irbuild.prepare import GENERATOR_HELPER_NAME from mypyc.irbuild.util import dataclass_type, get_func_def, is_constant, is_dataclass_decorator -from mypyc.primitives.dict_ops import dict_new_op, dict_set_item_op +from mypyc.primitives.dict_ops import dict_new_op, true_dict_set_item_op from mypyc.primitives.generic_ops import ( iter_op, next_op, @@ -272,7 +272,7 @@ def finalize(self, ir: ClassIR) -> None: # Add the non-extension class to the dict self.builder.primitive_op( - dict_set_item_op, + true_dict_set_item_op, [ self.builder.load_globals_dict(), self.builder.load_str(self.cdef.name), @@ -488,7 +488,9 @@ def allocate_class(builder: IRBuilder, cdef: ClassDef) -> Value: # Add it to the dict builder.primitive_op( - dict_set_item_op, [builder.load_globals_dict(), builder.load_str(cdef.name), tp], cdef.line + true_dict_set_item_op, + [builder.load_globals_dict(), builder.load_str(cdef.name), tp], + cdef.line, ) return tp @@ -609,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) @@ -672,7 +674,7 @@ def add_non_ext_class_attr_ann( typ = builder.add(LoadAddress(type_object_op.type, type_object_op.src, stmt.line)) key = builder.load_str(lvalue.name) - builder.primitive_op(dict_set_item_op, [non_ext.anns, key, typ], stmt.line) + builder.primitive_op(true_dict_set_item_op, [non_ext.anns, key, typ], stmt.line) def add_non_ext_class_attr( diff --git a/mypyc/irbuild/expression.py b/mypyc/irbuild/expression.py index 990c904dc447..ab4cdc485e2a 100644 --- a/mypyc/irbuild/expression.py +++ b/mypyc/irbuild/expression.py @@ -97,7 +97,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, dict_set_item_op +from mypyc.primitives.dict_ops import dict_new_op, true_dict_get_item_op, true_dict_set_item_op from mypyc.primitives.generic_ops import iter_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 @@ -183,7 +183,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: @@ -1030,7 +1030,7 @@ def transform_dictionary_comprehension(builder: IRBuilder, o: DictionaryComprehe def gen_inner_stmts() -> None: k = builder.accept(o.key) v = builder.accept(o.value) - builder.primitive_op(dict_set_item_op, [builder.read(d), k, v], o.line) + builder.primitive_op(true_dict_set_item_op, [builder.read(d), k, v], o.line) comprehension_helper(builder, loop_params, gen_inner_stmts, o.line) return builder.read(d) diff --git a/mypyc/irbuild/for_helpers.py b/mypyc/irbuild/for_helpers.py index 5cf89f579ec4..bb92936c453a 100644 --- a/mypyc/irbuild/for_helpers.py +++ b/mypyc/irbuild/for_helpers.py @@ -52,6 +52,7 @@ is_sequence_rprimitive, is_short_int_rprimitive, is_str_rprimitive, + is_true_dict_rprimitive, is_tuple_rprimitive, object_pointer_rprimitive, object_rprimitive, @@ -69,6 +70,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 @@ -415,8 +421,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 @@ -498,13 +506,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 @@ -867,6 +884,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 @@ -913,7 +931,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, ) @@ -991,6 +1009,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 90506adde672..c8c9a60dbc04 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 ( @@ -76,7 +76,11 @@ ) 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, dict_set_item_op +from mypyc.primitives.dict_ops import ( + dict_new_op, + true_dict_get_method_with_none, + true_dict_set_item_op, +) from mypyc.primitives.generic_ops import py_setattr_op from mypyc.primitives.misc_ops import register_function from mypyc.primitives.registry import builtin_names @@ -124,7 +128,7 @@ def transform_decorator(builder: IRBuilder, dec: Decorator) -> None: if decorated_func is not None: # Set the callable object representing the decorated function as a global. builder.primitive_op( - dict_set_item_op, + true_dict_set_item_op, [builder.load_globals_dict(), builder.load_str(dec.func.name), decorated_func], decorated_func.line, ) @@ -797,10 +801,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) @@ -813,7 +819,7 @@ def generate_singledispatch_dispatch_function( find_impl = builder.load_module_attr_by_fullname("functools._find_impl", line) registry = load_singledispatch_registry(builder, dispatch_func_obj, line) uncached_impl = builder.py_call(find_impl, [arg_type, registry], line) - builder.primitive_op(dict_set_item_op, [dispatch_cache, arg_type, uncached_impl], line) + builder.primitive_op(true_dict_set_item_op, [dispatch_cache, arg_type, uncached_impl], line) builder.assign(impl_to_use, uncached_impl, line) builder.goto(call_func) @@ -877,8 +883,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) @@ -941,7 +947,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: @@ -990,9 +996,9 @@ def maybe_insert_into_registry_dict(builder: IRBuilder, fitem: FuncDef) -> None: registry = load_singledispatch_registry(builder, dispatch_func_obj, line) for typ in types: loaded_type = load_type(builder, typ, None, line) - builder.primitive_op(dict_set_item_op, [registry, loaded_type, to_insert], line) + builder.primitive_op(true_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 a5e28268efed..ae118e25b25f 100644 --- a/mypyc/irbuild/ll_builder.py +++ b/mypyc/irbuild/ll_builder.py @@ -111,6 +111,7 @@ is_short_int_rprimitive, is_str_rprimitive, is_tagged, + is_true_dict_rprimitive, is_tuple_rprimitive, is_uint8_rprimitive, list_rprimitive, @@ -121,6 +122,7 @@ pointer_rprimitive, short_int_rprimitive, str_rprimitive, + true_dict_rprimitive, ) from mypyc.irbuild.util import concrete_arg_kind from mypyc.options import CompilerOptions @@ -130,6 +132,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 @@ -163,6 +168,7 @@ bool_op, buf_init_item, debug_print_op, + dict_is_true_op, fast_isinstance_op, none_object_op, not_implemented_op, @@ -793,8 +799,11 @@ def _construct_varargs( elif kind == ARG_STAR2: if star2_result is None: 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 @@ -1658,9 +1667,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) @@ -1764,6 +1782,8 @@ def bool_value(self, value: Value) -> Value: result = self.add(ComparisonOp(value, zero, ComparisonOp.NEQ)) elif is_same_type(value.type, str_rprimitive): result = self.call_c(str_check_if_true, [value], value.line) + 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 ): @@ -2269,6 +2289,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 815688d90fb6..2d790f4caafc 100644 --- a/mypyc/irbuild/mapper.py +++ b/mypyc/irbuild/mapper.py @@ -44,6 +44,7 @@ range_rprimitive, set_rprimitive, str_rprimitive, + true_dict_rprimitive, tuple_rprimitive, uint8_rprimitive, ) @@ -151,7 +152,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)): @@ -166,7 +167,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 1d6117ab7b1e..410a00b68aa1 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 @@ -543,7 +543,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 3015640fb3fd..67043eee23eb 100644 --- a/mypyc/irbuild/specialize.py +++ b/mypyc/irbuild/specialize.py @@ -64,10 +64,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 @@ -90,6 +92,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 @@ -249,11 +254,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") @@ -362,6 +378,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 @@ -603,6 +620,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 1881aa97f308..5f7eb34a5dcc 100644 --- a/mypyc/lib-rt/CPy.h +++ b/mypyc/lib-rt/CPy.h @@ -702,6 +702,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)) { @@ -716,6 +727,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 ac928bb0eb50..e192728c94d0 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,13 +50,22 @@ # 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, ) # Construct a dictionary from another dictionary. +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], @@ -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], @@ -99,6 +130,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], @@ -110,6 +152,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], @@ -129,6 +201,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], @@ -138,6 +219,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], @@ -147,6 +237,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], @@ -156,6 +255,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], @@ -165,6 +273,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], @@ -185,6 +302,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], @@ -194,6 +320,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], @@ -203,6 +338,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], @@ -212,6 +356,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], @@ -221,6 +374,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], @@ -230,30 +392,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, @@ -296,7 +490,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, @@ -304,6 +527,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, @@ -312,6 +542,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 e3d59f53ed76..287bb9be516c 100644 --- a/mypyc/primitives/misc_ops.py +++ b/mypyc/primitives/misc_ops.py @@ -16,6 +16,7 @@ object_rprimitive, pointer_rprimitive, str_rprimitive, + true_dict_rprimitive, void_rtype, ) from mypyc.primitives.registry import ( @@ -155,7 +156,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, @@ -182,6 +183,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 4a7d315ec836..51ba9dab7672 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,20 +1672,20 @@ L0: return r0 def g(): r0 :: tuple[int, int, int] - r1 :: dict + r1 :: dict[confirmed] r2 :: str r3 :: object r4 :: list r5, r6 :: object r7 :: tuple - r8 :: dict + r8 :: dict[confirmed] r9 :: object r10 :: tuple[int, int, int] L0: r0 = (2, 4, 6) r1 = __main__.globals :: static r2 = 'f' - r3 = CPyDict_GetItem(r1, r2) + r3 = CPyDict_GetItemUnsafe(r1, r2) r4 = PyList_New(0) r5 = box(tuple[int, int, int], r0) r6 = CPyList_Extend(r4, r5) @@ -1696,7 +1696,7 @@ L0: return r10 def h(): r0 :: tuple[int, int] - r1 :: dict + r1 :: dict[confirmed] r2 :: str r3 :: object r4 :: list @@ -1704,14 +1704,14 @@ def h(): r6 :: ptr r7, r8 :: object r9 :: tuple - r10 :: dict + r10 :: dict[confirmed] r11 :: object r12 :: tuple[int, int, int] 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 @@ -1743,15 +1743,18 @@ L0: def g(): r0, r1, r2 :: str r3, r4, r5 :: object - r6, r7 :: dict - r8 :: str - r9 :: object - r10 :: dict - r11 :: i32 - r12 :: bit - r13 :: tuple - r14 :: object - r15 :: tuple[int, int, int] + r6 :: dict[confirmed] + r7 :: dict + r8 :: dict[confirmed] + r9 :: str + r10 :: object + r11 :: dict[confirmed] + r12 :: dict + r13 :: i32 + r14 :: bit + r15 :: tuple + r16 :: object + r17 :: tuple[int, int, int] L0: r0 = 'a' r1 = 'b' @@ -1760,46 +1763,53 @@ L0: r4 = object 2 r5 = object 3 r6 = CPyDict_Build(3, r0, r3, r1, r4, r2, r5) - r7 = __main__.globals :: static - r8 = 'f' - r9 = CPyDict_GetItem(r7, r8) - r10 = PyDict_New() - r11 = CPyDict_UpdateInDisplay(r10, r6) - r12 = r11 >= 0 :: signed - r13 = PyTuple_Pack(0) - r14 = PyObject_Call(r9, r13, r10) - r15 = unbox(tuple[int, int, int], r14) - return r15 + r7 = cast(dict, r6) + r8 = __main__.globals :: static + r9 = 'f' + r10 = CPyDict_GetItemUnsafe(r8, r9) + r11 = PyDict_New() + r12 = cast(dict, r11) + r13 = CPyDict_UpdateInDisplay(r12, r7) + r14 = r13 >= 0 :: signed + r15 = PyTuple_Pack(0) + r16 = PyObject_Call(r10, r15, r11) + r17 = unbox(tuple[int, int, int], r16) + return r17 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: @@ -1946,7 +1956,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 @@ -1960,6 +1970,7 @@ def f(): r16 :: i32 r17 :: bit r18 :: native_int + r19 :: dict L0: r0 = PyDict_New() r1 = PyList_New(3) @@ -1993,14 +2004,15 @@ L6: r13 = CPyTagged_Multiply(x, x) r14 = box(int, x) r15 = box(int, r13) - r16 = CPyDict_SetItem(r0, r14, r15) + r16 = PyDict_SetItem(r0, r14, r15) r17 = r16 >= 0 :: signed L7: r18 = r6 + 1 r6 = r18 goto L1 L8: - return r0 + r19 = cast(dict, r0) + return r19 [case testLoopsMultipleAssign] from typing import List, Tuple @@ -2164,7 +2176,7 @@ def __top_level__(): r3 :: str r4, r5 :: object r6 :: str - r7 :: dict + r7 :: dict[confirmed] r8 :: object r9, r10 :: str r11 :: object @@ -2176,53 +2188,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 @@ -2254,19 +2266,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 @@ -2275,31 +2287,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 @@ -2312,7 +2324,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 @@ -2576,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 @@ -2605,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) @@ -2620,7 +2632,7 @@ L0: d = r14 r15 = __main__.globals :: static r16 = 'd' - r17 = CPyDict_SetItem(r15, r16, r14) + r17 = PyDict_SetItem(r15, r16, r14) r18 = r17 >= 0 :: signed r19 = 'c' r20 = builtins :: module @@ -2638,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 @@ -2676,24 +2688,24 @@ 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) keep_alive r17 r24 = __main__.globals :: static r25 = 'c' - r26 = CPyDict_SetItem(r24, r25, r23) + r26 = PyDict_SetItem(r24, r25, r23) r27 = r26 >= 0 :: signed return 1 @@ -2779,7 +2791,7 @@ def __top_level__(): r3 :: str r4, r5 :: object r6 :: str - r7 :: dict + r7 :: dict[confirmed] r8 :: object L0: r0 = builtins :: module @@ -3279,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 @@ -3315,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 @@ -3331,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 @@ -3367,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 9810daf487fa..17159e31086d 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 1a2c237cc3c9..1449c8e4d01e 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__' @@ -303,7 +303,7 @@ L2: __main__.C = r27 :: type r33 = __main__.globals :: static r34 = 'C' - r35 = CPyDict_SetItem(r33, r34, r27) + r35 = PyDict_SetItem(r33, r34, r27) r36 = r35 >= 0 :: signed r37 = :: object r38 = '__main__' @@ -316,16 +316,16 @@ L2: __main__.S = r40 :: type r45 = __main__.globals :: static r46 = 'S' - r47 = CPyDict_SetItem(r45, r46, r40) + r47 = PyDict_SetItem(r45, r46, r40) r48 = r47 >= 0 :: signed r49 = __main__.C :: type 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__' @@ -340,7 +340,7 @@ L2: __main__.D = r61 :: type r68 = __main__.globals :: static r69 = 'D' - r70 = CPyDict_SetItem(r68, r69, r61) + r70 = PyDict_SetItem(r68, r69, r61) r71 = r70 >= 0 :: signed return 1 @@ -1024,7 +1024,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 @@ -1033,7 +1033,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 d39d47e397a1..7c2b1d6e006c 100644 --- a/mypyc/test-data/irbuild-generics.test +++ b/mypyc/test-data/irbuild-generics.test @@ -169,22 +169,24 @@ def execute(func, args, kwargs): kwargs :: dict r0 :: list r1 :: object - r2 :: dict - r3 :: i32 - r4 :: bit - r5 :: tuple - r6 :: object - r7 :: int + r2 :: dict[confirmed] + r3 :: dict + r4 :: i32 + r5 :: bit + r6 :: tuple + r7 :: object + r8 :: int L0: r0 = PyList_New(0) r1 = CPyList_Extend(r0, args) r2 = PyDict_New() - r3 = CPyDict_UpdateInDisplay(r2, kwargs) - r4 = r3 >= 0 :: signed - r5 = PyList_AsTuple(r0) - r6 = PyObject_Call(func, r5, r2) - r7 = unbox(int, r6) - return r7 + r3 = cast(dict, r2) + r4 = CPyDict_UpdateInDisplay(r3, kwargs) + r5 = r4 >= 0 :: signed + r6 = PyList_AsTuple(r0) + r7 = PyObject_Call(func, r6, r2) + r8 = unbox(int, r7) + return r8 def f(x): x :: int L0: @@ -257,7 +259,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 @@ -358,7 +360,7 @@ L17: k = r49 v = r50 r51 = box(int, v) - r52 = CPyDict_SetItem(r40, k, r51) + r52 = PyDict_SetItem(r40, k, r51) r53 = r52 >= 0 :: signed L18: r54 = CPyDict_CheckSize(m, r42) @@ -402,7 +404,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 @@ -500,7 +502,7 @@ L17: r49 = cast(union[int, str], r47) k = r48 v = r49 - r50 = CPyDict_SetItem(r39, k, v) + r50 = PyDict_SetItem(r39, k, v) r51 = r50 >= 0 :: signed L18: r52 = CPyDict_CheckSize(m, r41) @@ -510,11 +512,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 @@ -525,7 +527,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 @@ -535,7 +537,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 @@ -543,10 +545,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 @@ -559,9 +561,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] @@ -573,7 +575,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() @@ -581,9 +583,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] @@ -594,7 +596,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() @@ -602,9 +604,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] @@ -616,7 +618,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() @@ -624,9 +626,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] @@ -637,10 +639,10 @@ L17: r47 = cast(str, r45) k = r47 v = r46 - r48 = CPyDict_SetItem(r38, k, v) + 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() @@ -694,7 +696,7 @@ def inner_deco_obj.__call__(__mypyc_self__, args, kwargs): r6, x :: object r7 :: native_int can_listcomp :: list - r8 :: dict + r8 :: dict[confirmed] r9 :: short_int r10 :: native_int r11 :: object @@ -706,17 +708,18 @@ def inner_deco_obj.__call__(__mypyc_self__, args, kwargs): v :: object r18 :: i32 r19, r20, r21 :: bit - can_dictcomp :: dict - r22, can_iter, r23, can_use_keys, r24, can_use_values :: list - r25 :: object - r26 :: list - r27 :: object - r28 :: dict - r29 :: i32 - r30 :: bit - r31 :: tuple - r32 :: object - r33 :: int + r22, can_dictcomp :: dict + r23, can_iter, r24, can_use_keys, r25, can_use_values :: list + r26 :: object + r27 :: list + r28 :: object + r29 :: dict[confirmed] + r30 :: dict + r31 :: i32 + r32 :: bit + r33 :: tuple + r34 :: object + r35 :: int L0: r0 = __mypyc_self__.__mypyc_env__ r1 = var_object_size args @@ -752,7 +755,7 @@ L6: r17 = cast(str, r15) k = r17 v = r16 - r18 = CPyDict_SetItem(r8, k, v) + r18 = PyDict_SetItem(r8, k, v) r19 = r18 >= 0 :: signed L7: r20 = CPyDict_CheckSize(kwargs, r10) @@ -760,23 +763,25 @@ L7: L8: r21 = CPy_NoErrOccurred() L9: - can_dictcomp = r8 - r22 = PySequence_List(kwargs) - can_iter = r22 - r23 = CPyDict_Keys(kwargs) - can_use_keys = r23 - r24 = CPyDict_Values(kwargs) - can_use_values = r24 - r25 = r0.func - r26 = PyList_New(0) - r27 = CPyList_Extend(r26, args) - r28 = PyDict_New() - r29 = CPyDict_UpdateInDisplay(r28, kwargs) - r30 = r29 >= 0 :: signed - r31 = PyList_AsTuple(r26) - r32 = PyObject_Call(r25, r31, r28) - r33 = unbox(int, r32) - return r33 + r22 = cast(dict, r8) + can_dictcomp = r22 + r23 = PySequence_List(kwargs) + can_iter = r23 + r24 = PyDict_Keys(kwargs) + can_use_keys = r24 + r25 = PyDict_Values(kwargs) + can_use_values = r25 + r26 = r0.func + r27 = PyList_New(0) + r28 = CPyList_Extend(r27, args) + r29 = PyDict_New() + r30 = cast(dict, r29) + r31 = CPyDict_UpdateInDisplay(r30, kwargs) + r32 = r31 >= 0 :: signed + r33 = PyList_AsTuple(r27) + r34 = PyObject_Call(r26, r33, r29) + r35 = unbox(int, r34) + return r35 def deco(func): func :: object r0 :: __main__.deco_env 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 ef11ae04dc64..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 @@ -76,7 +76,7 @@ L2: r12 = load_address r11 r13 = PyObject_Vectorcall(r9, r12, 2, 0) keep_alive r1, r10 - r14 = CPyDict_SetItem(r2, r1, r13) + r14 = PyDict_SetItem(r2, r1, r13) r15 = r14 >= 0 :: signed r6 = r13 L3: @@ -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 @@ -214,7 +214,7 @@ L2: r12 = load_address r11 r13 = PyObject_Vectorcall(r9, r12, 2, 0) keep_alive r1, r10 - r14 = CPyDict_SetItem(r2, r1, r13) + r14 = PyDict_SetItem(r2, r1, r13) r15 = r14 >= 0 :: signed r6 = r13 L3: @@ -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 d1cedf07f33a37b3c1fbf167838cdb7eb833cf06 Mon Sep 17 00:00:00 2001 From: BobTheBuidler Date: Mon, 4 Aug 2025 02:01:35 +0000 Subject: [PATCH 02/23] 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 e192728c94d0..21c799d17927 100644 --- a/mypyc/primitives/dict_ops.py +++ b/mypyc/primitives/dict_ops.py @@ -403,7 +403,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, ) @@ -419,7 +419,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, ) @@ -435,7 +435,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 8649798e70ee404e64c75b0ab8555b0e22738e24 Mon Sep 17 00:00:00 2001 From: BobTheBuidler Date: Mon, 4 Aug 2025 02:01:35 +0000 Subject: [PATCH 03/23] 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 ae118e25b25f..59a50527f521 100644 --- a/mypyc/irbuild/ll_builder.py +++ b/mypyc/irbuild/ll_builder.py @@ -799,7 +799,7 @@ def _construct_varargs( elif kind == ARG_STAR2: if star2_result is None: 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 @@ -1667,13 +1667,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 34501b11aa4d141a7d1d38266f7cb2b942232551 Mon Sep 17 00:00:00 2001 From: BobTheBuidler Date: Mon, 4 Aug 2025 02:01:35 +0000 Subject: [PATCH 04/23] 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 59a50527f521..deebc4cff67b 100644 --- a/mypyc/irbuild/ll_builder.py +++ b/mypyc/irbuild/ll_builder.py @@ -134,7 +134,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 @@ -800,7 +800,7 @@ def _construct_varargs( if star2_result is None: 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) @@ -1674,7 +1674,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 21c799d17927..5843617f6dd6 100644 --- a/mypyc/primitives/dict_ops.py +++ b/mypyc/primitives/dict_ops.py @@ -191,6 +191,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 a09bc0dcb8ce15eda34eb72b52dbf8afb3a017c5 Mon Sep 17 00:00:00 2001 From: BobTheBuidler Date: Mon, 4 Aug 2025 02:01:36 +0000 Subject: [PATCH 05/23] 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 5843617f6dd6..b08c1aa6a7d7 100644 --- a/mypyc/primitives/dict_ops.py +++ b/mypyc/primitives/dict_ops.py @@ -383,7 +383,7 @@ ) # dict.copy() -true_dict_copy_op = method_op( +method_op( name="copy", arg_types=[true_dict_rprimitive], return_type=true_dict_rprimitive, @@ -400,6 +400,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 7f75ce5787a3ba2931c567c713b643552fbf8321 Mon Sep 17 00:00:00 2001 From: BobTheBuidler Date: Mon, 4 Aug 2025 02:01:36 +0000 Subject: [PATCH 06/23] 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 b08c1aa6a7d7..2a7c14df7613 100644 --- a/mypyc/primitives/dict_ops.py +++ b/mypyc/primitives/dict_ops.py @@ -401,8 +401,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 e0f162fe7fabc4a35a4bc8db0b0c73ebc2bd1f9b Mon Sep 17 00:00:00 2001 From: BobTheBuidler Date: Mon, 4 Aug 2025 02:01:36 +0000 Subject: [PATCH 07/23] feat: use true_dict_rprimitive for builtins.dict --- mypyc/analysis/ircheck.py | 2 + mypyc/irbuild/mapper.py | 2 + mypyc/test-data/irbuild-basic.test | 98 ++++---- mypyc/test-data/irbuild-bytes.test | 2 +- mypyc/test-data/irbuild-dict.test | 298 ++++++++++++------------ mypyc/test-data/irbuild-generics.test | 164 +++++++------ 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, 390 insertions(+), 418 deletions(-) diff --git a/mypyc/analysis/ircheck.py b/mypyc/analysis/ircheck.py index 4ad2a52c1036..997be4f48c2f 100644 --- a/mypyc/analysis/ircheck.py +++ b/mypyc/analysis/ircheck.py @@ -70,6 +70,7 @@ range_rprimitive, set_rprimitive, str_rprimitive, + true_dict_rprimitive, tuple_rprimitive, ) @@ -176,6 +177,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 2d790f4caafc..70bc6b5df9d6 100644 --- a/mypyc/irbuild/mapper.py +++ b/mypyc/irbuild/mapper.py @@ -93,6 +93,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 51ba9dab7672..586c22bc0ed6 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 @@ -1743,18 +1743,15 @@ L0: def g(): r0, r1, r2 :: str r3, r4, r5 :: object - r6 :: dict[confirmed] - r7 :: dict - r8 :: dict[confirmed] - r9 :: str - r10 :: object - r11 :: dict[confirmed] - r12 :: dict - r13 :: i32 - r14 :: bit - r15 :: tuple - r16 :: object - r17 :: tuple[int, int, int] + r6, r7 :: dict[confirmed] + r8 :: str + r9 :: object + r10 :: dict[confirmed] + r11 :: i32 + r12 :: bit + r13 :: tuple + r14 :: object + r15 :: tuple[int, int, int] L0: r0 = 'a' r1 = 'b' @@ -1763,53 +1760,46 @@ L0: r4 = object 2 r5 = object 3 r6 = CPyDict_Build(3, r0, r3, r1, r4, r2, r5) - r7 = cast(dict, r6) - r8 = __main__.globals :: static - r9 = 'f' - r10 = CPyDict_GetItemUnsafe(r8, r9) - r11 = PyDict_New() - r12 = cast(dict, r11) - r13 = CPyDict_UpdateInDisplay(r12, r7) - r14 = r13 >= 0 :: signed - r15 = PyTuple_Pack(0) - r16 = PyObject_Call(r10, r15, r11) - r17 = unbox(tuple[int, int, int], r16) - return r17 + r7 = __main__.globals :: static + r8 = 'f' + r9 = CPyDict_GetItemUnsafe(r7, r8) + r10 = PyDict_New() + r11 = PyDict_Update(r10, r6) + r12 = r11 >= 0 :: signed + r13 = PyTuple_Pack(0) + r14 = PyObject_Call(r9, r13, r10) + r15 = unbox(tuple[int, int, int], r14) + return r15 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: @@ -1970,7 +1960,6 @@ def f(): r16 :: i32 r17 :: bit r18 :: native_int - r19 :: dict L0: r0 = PyDict_New() r1 = PyList_New(3) @@ -2011,8 +2000,7 @@ L7: r6 = r18 goto L1 L8: - r19 = cast(dict, r0) - return r19 + return r0 [case testLoopsMultipleAssign] from typing import List, Tuple @@ -3257,7 +3245,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 476c5ac59f48..912338ce3540 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 7c2b1d6e006c..3aad6d3aaa93 100644 --- a/mypyc/test-data/irbuild-generics.test +++ b/mypyc/test-data/irbuild-generics.test @@ -166,27 +166,25 @@ execute(f, 1) def execute(func, args, kwargs): func :: object args :: tuple - kwargs :: dict + kwargs :: dict[confirmed] r0 :: list r1 :: object r2 :: dict[confirmed] - r3 :: dict - r4 :: i32 - r5 :: bit - r6 :: tuple - r7 :: object - r8 :: int + r3 :: i32 + r4 :: bit + r5 :: tuple + r6 :: object + r7 :: int L0: r0 = PyList_New(0) r1 = CPyList_Extend(r0, args) r2 = PyDict_New() - r3 = cast(dict, r2) - r4 = CPyDict_UpdateInDisplay(r3, kwargs) - r5 = r4 >= 0 :: signed - r6 = PyList_AsTuple(r0) - r7 = PyObject_Call(func, r6, r2) - r8 = unbox(int, r7) - return r8 + r3 = PyDict_Update(r2, kwargs) + r4 = r3 >= 0 :: signed + r5 = PyList_AsTuple(r0) + r6 = PyObject_Call(func, r5, r2) + r7 = unbox(int, r6) + return r7 def f(x): x :: int L0: @@ -224,11 +222,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 @@ -239,7 +237,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 @@ -251,7 +249,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 @@ -262,7 +260,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 @@ -278,9 +276,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] @@ -292,7 +290,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() @@ -300,9 +298,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] @@ -315,7 +313,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() @@ -323,9 +321,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] @@ -337,7 +335,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() @@ -345,9 +343,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] @@ -363,18 +361,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 @@ -385,7 +383,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 @@ -396,7 +394,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 @@ -407,7 +405,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 @@ -422,9 +420,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] @@ -436,7 +434,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() @@ -444,9 +442,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] @@ -458,7 +456,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() @@ -466,9 +464,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] @@ -480,7 +478,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() @@ -488,9 +486,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] @@ -505,7 +503,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() @@ -687,7 +685,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 @@ -699,7 +697,7 @@ def inner_deco_obj.__call__(__mypyc_self__, args, kwargs): r8 :: dict[confirmed] r9 :: short_int r10 :: native_int - r11 :: object + r11 :: dict[confirmed] r12 :: tuple[bool, short_int, object, object] r13 :: short_int r14 :: bool @@ -708,18 +706,17 @@ def inner_deco_obj.__call__(__mypyc_self__, args, kwargs): v :: object r18 :: i32 r19, r20, r21 :: bit - r22, can_dictcomp :: dict - r23, can_iter, r24, can_use_keys, r25, can_use_values :: list - r26 :: object - r27 :: list - r28 :: object - r29 :: dict[confirmed] - r30 :: dict - r31 :: i32 - r32 :: bit - r33 :: tuple - r34 :: object - r35 :: int + can_dictcomp :: dict[confirmed] + r22, can_iter, r23, can_use_keys, r24, can_use_values :: list + r25 :: object + r26 :: list + r27 :: object + r28 :: dict[confirmed] + r29 :: i32 + r30 :: bit + r31 :: tuple + r32 :: object + r33 :: int L0: r0 = __mypyc_self__.__mypyc_env__ r1 = var_object_size args @@ -742,9 +739,9 @@ L4: r8 = PyDict_New() r9 = 0 r10 = PyDict_Size(kwargs) - r11 = CPyDict_GetItemsIter(kwargs) + r11 = _CPyDict_GetIterUnsafe(kwargs) L5: - r12 = CPyDict_NextItem(r11, r9) + r12 = CPyDict_NextItemUnsafe(r11, r9) r13 = r12[1] r9 = r13 r14 = r12[0] @@ -758,30 +755,28 @@ L6: r18 = PyDict_SetItem(r8, k, v) r19 = r18 >= 0 :: signed L7: - r20 = CPyDict_CheckSize(kwargs, r10) + r20 = CPyDict_CheckSizeUnsafe(kwargs, r10) goto L5 L8: r21 = CPy_NoErrOccurred() L9: - r22 = cast(dict, r8) - can_dictcomp = r22 - r23 = PySequence_List(kwargs) - can_iter = r23 - r24 = PyDict_Keys(kwargs) - can_use_keys = r24 - r25 = PyDict_Values(kwargs) - can_use_values = r25 - r26 = r0.func - r27 = PyList_New(0) - r28 = CPyList_Extend(r27, args) - r29 = PyDict_New() - r30 = cast(dict, r29) - r31 = CPyDict_UpdateInDisplay(r30, kwargs) - r32 = r31 >= 0 :: signed - r33 = PyList_AsTuple(r27) - r34 = PyObject_Call(r26, r33, r29) - r35 = unbox(int, r34) - return r35 + can_dictcomp = r8 + r22 = PySequence_List(kwargs) + can_iter = r22 + r23 = PyDict_Keys(kwargs) + can_use_keys = r23 + r24 = PyDict_Values(kwargs) + can_use_values = r24 + r25 = r0.func + r26 = PyList_New(0) + r27 = CPyList_Extend(r26, args) + r28 = PyDict_New() + r29 = PyDict_Update(r28, kwargs) + r30 = r29 >= 0 :: signed + r31 = PyList_AsTuple(r26) + r32 = PyObject_Call(r25, r31, r28) + r33 = unbox(int, r32) + return r33 def deco(func): func :: object r0 :: __main__.deco_env @@ -800,3 +795,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 2297bd37b7d7284a9a9a1a6d267966c6fb9f8bb3 Mon Sep 17 00:00:00 2001 From: BobTheBuidler Date: Mon, 4 Aug 2025 02:01:36 +0000 Subject: [PATCH 08/23] 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 287bb9be516c..90e486330016 100644 --- a/mypyc/primitives/misc_ops.py +++ b/mypyc/primitives/misc_ops.py @@ -184,7 +184,7 @@ ) # bool(dict) -dict_is_true_op = function_op( +function_op( name="builtins.bool", arg_types=[true_dict_rprimitive], return_type=bit_rprimitive, @@ -192,6 +192,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 3208af0bec87f9d0fcb1f7fbbef7b2a32d331733 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/23] [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 3aad6d3aaa93..6d19794f1cc6 100644 --- a/mypyc/test-data/irbuild-generics.test +++ b/mypyc/test-data/irbuild-generics.test @@ -795,4 +795,3 @@ def f(x): x :: int L0: return x - From dda49ffe5de029c315938c0d9bb6e0ad37129687 Mon Sep 17 00:00:00 2001 From: BobTheBuidler Date: Mon, 4 Aug 2025 02:01:36 +0000 Subject: [PATCH 10/23] 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 90e486330016..cdc8568298e8 100644 --- a/mypyc/primitives/misc_ops.py +++ b/mypyc/primitives/misc_ops.py @@ -193,7 +193,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 14c4e788f03338a0687d52b83471e103e5c2fb59 Mon Sep 17 00:00:00 2001 From: BobTheBuidler Date: Mon, 4 Aug 2025 02:01:36 +0000 Subject: [PATCH 11/23] 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 2a7c14df7613..75c7c24b16c9 100644 --- a/mypyc/primitives/dict_ops.py +++ b/mypyc/primitives/dict_ops.py @@ -370,7 +370,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 311a466e8be7eb02ee3d196afb6b66244f8bfde5 Mon Sep 17 00:00:00 2001 From: BobTheBuidler Date: Mon, 4 Aug 2025 02:01:36 +0000 Subject: [PATCH 12/23] 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 75c7c24b16c9..46ae8dd6ad31 100644 --- a/mypyc/primitives/dict_ops.py +++ b/mypyc/primitives/dict_ops.py @@ -461,7 +461,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 fc762c276af5c24906a1b18af07f40e3a5166126 Mon Sep 17 00:00:00 2001 From: BobTheBuidler Date: Mon, 4 Aug 2025 02:01:36 +0000 Subject: [PATCH 13/23] 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 46ae8dd6ad31..1aca33ba66b3 100644 --- a/mypyc/primitives/dict_ops.py +++ b/mypyc/primitives/dict_ops.py @@ -269,7 +269,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) @@ -388,7 +388,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() @@ -405,7 +405,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()) @@ -413,7 +413,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()) @@ -429,7 +429,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()) @@ -445,7 +445,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 cdc8568298e8..42e111115221 100644 --- a/mypyc/primitives/misc_ops.py +++ b/mypyc/primitives/misc_ops.py @@ -189,7 +189,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 @@ -197,7 +197,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 6c697df7447e8dd726aefb136cfb0aec4dcc9ab1 Mon Sep 17 00:00:00 2001 From: BobTheBuidler Date: Mon, 4 Aug 2025 02:01:36 +0000 Subject: [PATCH 14/23] 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 1aca33ba66b3..902c14404770 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, @@ -368,7 +369,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 6ac41c330e9147da7cedc207b7961c838b2689d4 Mon Sep 17 00:00:00 2001 From: BobTheBuidler Date: Mon, 4 Aug 2025 02:01:36 +0000 Subject: [PATCH 15/23] 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 | 14 +-- 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 | 104 ++++++++++---------- 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 | 50 +++++----- 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, 227 insertions(+), 227 deletions(-) diff --git a/mypyc/analysis/ircheck.py b/mypyc/analysis/ircheck.py index 997be4f48c2f..e5cce59faba7 100644 --- a/mypyc/analysis/ircheck.py +++ b/mypyc/analysis/ircheck.py @@ -70,7 +70,7 @@ range_rprimitive, set_rprimitive, str_rprimitive, - true_dict_rprimitive, + exact_dict_rprimitive, tuple_rprimitive, ) @@ -177,7 +177,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 4d70357aaf9c..4e398ef8735c 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.""" @@ -608,12 +608,12 @@ def is_list_rprimitive(rtype: RType) -> bool: def is_dict_rprimitive(rtype: RType) -> bool: return isinstance(rtype, RPrimitive) and rtype.name in ( "builtins.dict", - "builtins.dict[confirmed]", + "builtins.dict[exact]", ) -def is_true_dict_rprimitive(rtype: RType) -> bool: - return isinstance(rtype, RPrimitive) and rtype.name == "builtins.dict[confirmed]" +def is_exact_dict_rprimitive(rtype: RType) -> bool: + return isinstance(rtype, RPrimitive) and rtype.name == "builtins.dict[exact]" def is_set_rprimitive(rtype: RType) -> bool: diff --git a/mypyc/irbuild/builder.py b/mypyc/irbuild/builder.py index faf4e7fe4e29..faaf4e378c79 100644 --- a/mypyc/irbuild/builder.py +++ b/mypyc/irbuild/builder.py @@ -102,7 +102,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 @@ -1383,7 +1383,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 378aa0d28a3a..a4a90ee3c8d9 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 bb92936c453a..03186729101f 100644 --- a/mypyc/irbuild/for_helpers.py +++ b/mypyc/irbuild/for_helpers.py @@ -52,7 +52,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, @@ -422,7 +422,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) @@ -506,20 +506,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) @@ -1009,7 +1009,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 @@ -1017,7 +1017,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 @@ -1025,7 +1025,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 c8c9a60dbc04..cb29e803343f 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 ( @@ -801,7 +801,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( @@ -883,8 +883,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) @@ -947,7 +947,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: @@ -998,7 +998,7 @@ def maybe_insert_into_registry_dict(builder: IRBuilder, fitem: FuncDef) -> None: loaded_type = load_type(builder, typ, None, line) builder.primitive_op(true_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 deebc4cff67b..283da36ca484 100644 --- a/mypyc/irbuild/ll_builder.py +++ b/mypyc/irbuild/ll_builder.py @@ -111,7 +111,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, @@ -122,7 +122,7 @@ pointer_rprimitive, short_int_rprimitive, str_rprimitive, - true_dict_rprimitive, + exact_dict_rprimitive, ) from mypyc.irbuild.util import concrete_arg_kind from mypyc.options import CompilerOptions @@ -799,7 +799,7 @@ def _construct_varargs( elif kind == ARG_STAR2: if star2_result is None: 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 @@ -1667,13 +1667,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 @@ -1782,7 +1782,7 @@ def bool_value(self, value: Value) -> Value: result = self.add(ComparisonOp(value, zero, ComparisonOp.NEQ)) elif is_same_type(value.type, str_rprimitive): 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 @@ -2289,7 +2289,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 70bc6b5df9d6..08fcd7937a67 100644 --- a/mypyc/irbuild/mapper.py +++ b/mypyc/irbuild/mapper.py @@ -44,7 +44,7 @@ range_rprimitive, set_rprimitive, str_rprimitive, - true_dict_rprimitive, + exact_dict_rprimitive, tuple_rprimitive, uint8_rprimitive, ) @@ -94,7 +94,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": @@ -154,7 +154,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)): @@ -169,7 +169,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 410a00b68aa1..d737b00714c4 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 @@ -543,7 +543,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 67043eee23eb..baff29718799 100644 --- a/mypyc/irbuild/specialize.py +++ b/mypyc/irbuild/specialize.py @@ -64,12 +64,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 @@ -254,17 +254,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 @@ -378,7 +378,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 @@ -620,7 +620,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 902c14404770..ead895e42596 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. 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, @@ -133,7 +133,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, @@ -155,7 +155,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, @@ -165,7 +165,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, @@ -175,7 +175,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, @@ -195,7 +195,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, @@ -213,7 +213,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, @@ -231,7 +231,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, @@ -249,7 +249,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, @@ -267,7 +267,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, @@ -285,7 +285,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, @@ -314,7 +314,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, @@ -332,7 +332,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, @@ -350,7 +350,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, @@ -368,7 +368,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, @@ -386,8 +386,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, ) @@ -403,15 +403,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, @@ -427,7 +427,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, @@ -443,7 +443,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, @@ -459,8 +459,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, ) @@ -523,7 +523,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, @@ -531,7 +531,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, @@ -546,7 +546,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, @@ -561,7 +561,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 42e111115221..df51ccd0a2f2 100644 --- a/mypyc/primitives/misc_ops.py +++ b/mypyc/primitives/misc_ops.py @@ -16,7 +16,7 @@ object_rprimitive, pointer_rprimitive, str_rprimitive, - true_dict_rprimitive, + exact_dict_rprimitive, void_rtype, ) from mypyc.primitives.registry import ( @@ -156,7 +156,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, @@ -186,7 +186,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, @@ -194,7 +194,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 586c22bc0ed6..784958a539b9 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,13 +1672,13 @@ L0: return r0 def g(): r0 :: tuple[int, int, int] - r1 :: dict[confirmed] + r1 :: dict[exact] r2 :: str r3 :: object r4 :: list r5, r6 :: object r7 :: tuple - r8 :: dict[confirmed] + r8 :: dict[exact] r9 :: object r10 :: tuple[int, int, int] L0: @@ -1696,7 +1696,7 @@ L0: return r10 def h(): r0 :: tuple[int, int] - r1 :: dict[confirmed] + r1 :: dict[exact] r2 :: str r3 :: object r4 :: list @@ -1704,7 +1704,7 @@ def h(): r6 :: ptr r7, r8 :: object r9 :: tuple - r10 :: dict[confirmed] + r10 :: dict[exact] r11 :: object r12 :: tuple[int, int, int] L0: @@ -1743,10 +1743,10 @@ L0: def g(): r0, r1, r2 :: str r3, r4, r5 :: object - r6, r7 :: dict[confirmed] + r6, r7 :: dict[exact] r8 :: str r9 :: object - r10 :: dict[confirmed] + r10 :: dict[exact] r11 :: i32 r12 :: bit r13 :: tuple @@ -1773,10 +1773,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 @@ -1946,7 +1946,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 @@ -2164,7 +2164,7 @@ def __top_level__(): r3 :: str r4, r5 :: object r6 :: str - r7 :: dict[confirmed] + r7 :: dict[exact] r8 :: object r9, r10 :: str r11 :: object @@ -2176,53 +2176,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 @@ -2576,19 +2576,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 @@ -2638,24 +2638,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 @@ -2779,7 +2779,7 @@ def __top_level__(): r3 :: str r4, r5 :: object r6 :: str - r7 :: dict[confirmed] + r7 :: dict[exact] r8 :: object L0: r0 = builtins :: module @@ -3245,7 +3245,7 @@ L0: r1 = PySequence_List(r0) return r1 def h(x): - x :: dict[confirmed] + x :: dict[exact] r0 :: list L0: r0 = PySequence_List(x) @@ -3279,24 +3279,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 @@ -3336,18 +3336,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 17159e31086d..da45e439566b 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 912338ce3540..b3fd41077d3f 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 1449c8e4d01e..85bc784fb9fd 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 @@ -1024,7 +1024,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 6d19794f1cc6..d619305f3e3c 100644 --- a/mypyc/test-data/irbuild-generics.test +++ b/mypyc/test-data/irbuild-generics.test @@ -166,10 +166,10 @@ execute(f, 1) def execute(func, args, kwargs): func :: object args :: tuple - kwargs :: dict[confirmed] + kwargs :: dict[exact] r0 :: list r1 :: object - r2 :: dict[confirmed] + r2 :: dict[exact] r3 :: i32 r4 :: bit r5 :: tuple @@ -222,11 +222,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 @@ -237,7 +237,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 @@ -249,7 +249,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 @@ -257,10 +257,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 @@ -368,11 +368,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 @@ -383,7 +383,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 @@ -394,7 +394,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 @@ -402,10 +402,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 @@ -510,11 +510,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 @@ -525,7 +525,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 @@ -535,7 +535,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 @@ -543,10 +543,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 @@ -685,7 +685,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 @@ -694,10 +694,10 @@ def inner_deco_obj.__call__(__mypyc_self__, args, kwargs): r6, x :: object r7 :: native_int can_listcomp :: list - r8 :: dict[confirmed] + r8 :: dict[exact] r9 :: short_int r10 :: native_int - r11 :: dict[confirmed] + r11 :: dict[exact] r12 :: tuple[bool, short_int, object, object] r13 :: short_int r14 :: bool @@ -706,12 +706,12 @@ def inner_deco_obj.__call__(__mypyc_self__, args, kwargs): v :: object r18 :: i32 r19, r20, r21 :: bit - can_dictcomp :: dict[confirmed] + can_dictcomp :: dict[exact] r22, can_iter, r23, can_use_keys, r24, can_use_values :: list r25 :: object r26 :: list r27 :: object - r28 :: dict[confirmed] + r28 :: dict[exact] r29 :: i32 r30 :: bit r31 :: tuple 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 b28057e3f34b51f8c07755b5953559e2c1f2741f 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/23] [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 | 4 ++-- 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 +- mypyc/primitives/misc_ops.py | 2 +- 12 files changed, 14 insertions(+), 14 deletions(-) diff --git a/mypyc/analysis/ircheck.py b/mypyc/analysis/ircheck.py index e5cce59faba7..da203371766b 100644 --- a/mypyc/analysis/ircheck.py +++ b/mypyc/analysis/ircheck.py @@ -63,6 +63,7 @@ RUnion, bytes_rprimitive, dict_rprimitive, + exact_dict_rprimitive, int_rprimitive, is_float_rprimitive, is_object_rprimitive, @@ -70,7 +71,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 faaf4e378c79..6ba3acd6ce24 100644 --- a/mypyc/irbuild/builder.py +++ b/mypyc/irbuild/builder.py @@ -92,6 +92,7 @@ RUnion, bitmap_rprimitive, c_pyssize_t_rprimitive, + exact_dict_rprimitive, int_rprimitive, is_float_rprimitive, is_list_rprimitive, @@ -102,7 +103,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 a4a90ee3c8d9..b8deb0e44553 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 03186729101f..e3bfb3473088 100644 --- a/mypyc/irbuild/for_helpers.py +++ b/mypyc/irbuild/for_helpers.py @@ -47,12 +47,12 @@ c_pyssize_t_rprimitive, int_rprimitive, is_dict_rprimitive, + is_exact_dict_rprimitive, is_fixed_width_rtype, 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 cb29e803343f..b127b7af596d 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 283da36ca484..00ea8b560321 100644 --- a/mypyc/irbuild/ll_builder.py +++ b/mypyc/irbuild/ll_builder.py @@ -93,11 +93,13 @@ c_size_t_rprimitive, check_native_int_range, dict_rprimitive, + exact_dict_rprimitive, float_rprimitive, int_rprimitive, 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, @@ -111,7 +113,6 @@ is_short_int_rprimitive, is_str_rprimitive, is_tagged, - is_exact_dict_rprimitive, is_tuple_rprimitive, is_uint8_rprimitive, list_rprimitive, @@ -122,7 +123,6 @@ pointer_rprimitive, short_int_rprimitive, str_rprimitive, - exact_dict_rprimitive, ) from mypyc.irbuild.util import concrete_arg_kind from mypyc.options import CompilerOptions diff --git a/mypyc/irbuild/mapper.py b/mypyc/irbuild/mapper.py index 08fcd7937a67..57c4e4dddb9b 100644 --- a/mypyc/irbuild/mapper.py +++ b/mypyc/irbuild/mapper.py @@ -32,6 +32,7 @@ bool_rprimitive, bytes_rprimitive, dict_rprimitive, + exact_dict_rprimitive, float_rprimitive, frozenset_rprimitive, int16_rprimitive, @@ -44,7 +45,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 d737b00714c4..dc9989413423 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 baff29718799..c892cbd9d30c 100644 --- a/mypyc/irbuild/specialize.py +++ b/mypyc/irbuild/specialize.py @@ -51,12 +51,14 @@ bool_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, @@ -64,12 +66,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 ead895e42596..7fa30c1c41f0 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 ( diff --git a/mypyc/primitives/misc_ops.py b/mypyc/primitives/misc_ops.py index df51ccd0a2f2..b814ff0db1d0 100644 --- a/mypyc/primitives/misc_ops.py +++ b/mypyc/primitives/misc_ops.py @@ -11,12 +11,12 @@ c_pyssize_t_rprimitive, cstring_rprimitive, dict_rprimitive, + exact_dict_rprimitive, int_rprimitive, object_pointer_rprimitive, object_rprimitive, pointer_rprimitive, str_rprimitive, - exact_dict_rprimitive, void_rtype, ) from mypyc.primitives.registry import ( From 697982430a28a4e46f50a8e336898cdfbf922243 Mon Sep 17 00:00:00 2001 From: BobTheBuidler Date: Mon, 4 Aug 2025 02:01:36 +0000 Subject: [PATCH 17/23] chore: rename true_dict ops to exact_dict --- mypyc/irbuild/builder.py | 8 ++++---- mypyc/irbuild/classdef.py | 8 ++++---- mypyc/irbuild/expression.py | 6 +++--- mypyc/irbuild/for_helpers.py | 28 +++++++++++++------------- mypyc/irbuild/function.py | 12 ++++++------ mypyc/irbuild/ll_builder.py | 14 ++++++------- mypyc/irbuild/match.py | 4 ++-- mypyc/irbuild/specialize.py | 12 ++++++------ mypyc/primitives/dict_ops.py | 38 ++++++++++++++++++------------------ 9 files changed, 65 insertions(+), 65 deletions(-) diff --git a/mypyc/irbuild/builder.py b/mypyc/irbuild/builder.py index 6ba3acd6ce24..d47bfd716bcf 100644 --- a/mypyc/irbuild/builder.py +++ b/mypyc/irbuild/builder.py @@ -124,7 +124,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 @@ -435,7 +435,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) @@ -472,7 +472,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. @@ -1380,7 +1380,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/classdef.py b/mypyc/irbuild/classdef.py index b8deb0e44553..9efce37187ec 100644 --- a/mypyc/irbuild/classdef.py +++ b/mypyc/irbuild/classdef.py @@ -66,7 +66,7 @@ ) from mypyc.irbuild.prepare import GENERATOR_HELPER_NAME from mypyc.irbuild.util import dataclass_type, get_func_def, is_constant, is_dataclass_decorator -from mypyc.primitives.dict_ops import dict_new_op, true_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, next_op, @@ -272,7 +272,7 @@ def finalize(self, ir: ClassIR) -> None: # Add the non-extension class to the dict self.builder.primitive_op( - true_dict_set_item_op, + exact_dict_set_item_op, [ self.builder.load_globals_dict(), self.builder.load_str(self.cdef.name), @@ -488,7 +488,7 @@ def allocate_class(builder: IRBuilder, cdef: ClassDef) -> Value: # Add it to the dict builder.primitive_op( - true_dict_set_item_op, + exact_dict_set_item_op, [builder.load_globals_dict(), builder.load_str(cdef.name), tp], cdef.line, ) @@ -674,7 +674,7 @@ def add_non_ext_class_attr_ann( typ = builder.add(LoadAddress(type_object_op.type, type_object_op.src, stmt.line)) key = builder.load_str(lvalue.name) - builder.primitive_op(true_dict_set_item_op, [non_ext.anns, key, typ], stmt.line) + builder.primitive_op(exact_dict_set_item_op, [non_ext.anns, key, typ], stmt.line) def add_non_ext_class_attr( diff --git a/mypyc/irbuild/expression.py b/mypyc/irbuild/expression.py index ab4cdc485e2a..8d45816eadad 100644 --- a/mypyc/irbuild/expression.py +++ b/mypyc/irbuild/expression.py @@ -97,7 +97,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, true_dict_get_item_op, true_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 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 @@ -183,7 +183,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: @@ -1030,7 +1030,7 @@ def transform_dictionary_comprehension(builder: IRBuilder, o: DictionaryComprehe def gen_inner_stmts() -> None: k = builder.accept(o.key) v = builder.accept(o.value) - builder.primitive_op(true_dict_set_item_op, [builder.read(d), k, v], o.line) + builder.primitive_op(exact_dict_set_item_op, [builder.read(d), k, v], o.line) comprehension_helper(builder, loop_params, gen_inner_stmts, o.line) return builder.read(d) diff --git a/mypyc/irbuild/for_helpers.py b/mypyc/irbuild/for_helpers.py index e3bfb3473088..e28d0ccffc7b 100644 --- a/mypyc/irbuild/for_helpers.py +++ b/mypyc/irbuild/for_helpers.py @@ -70,11 +70,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 @@ -1012,25 +1012,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 b127b7af596d..071eb868d6dc 100644 --- a/mypyc/irbuild/function.py +++ b/mypyc/irbuild/function.py @@ -78,8 +78,8 @@ from mypyc.irbuild.targets import AssignmentTarget from mypyc.primitives.dict_ops import ( dict_new_op, - true_dict_get_method_with_none, - true_dict_set_item_op, + exact_dict_get_method_with_none, + exact_dict_set_item_op, ) from mypyc.primitives.generic_ops import py_setattr_op from mypyc.primitives.misc_ops import register_function @@ -128,7 +128,7 @@ def transform_decorator(builder: IRBuilder, dec: Decorator) -> None: if decorated_func is not None: # Set the callable object representing the decorated function as a global. builder.primitive_op( - true_dict_set_item_op, + exact_dict_set_item_op, [builder.load_globals_dict(), builder.load_str(dec.func.name), decorated_func], decorated_func.line, ) @@ -805,7 +805,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) @@ -819,7 +819,7 @@ def generate_singledispatch_dispatch_function( find_impl = builder.load_module_attr_by_fullname("functools._find_impl", line) registry = load_singledispatch_registry(builder, dispatch_func_obj, line) uncached_impl = builder.py_call(find_impl, [arg_type, registry], line) - builder.primitive_op(true_dict_set_item_op, [dispatch_cache, arg_type, uncached_impl], line) + builder.primitive_op(exact_dict_set_item_op, [dispatch_cache, arg_type, uncached_impl], line) builder.assign(impl_to_use, uncached_impl, line) builder.goto(call_func) @@ -996,7 +996,7 @@ def maybe_insert_into_registry_dict(builder: IRBuilder, fitem: FuncDef) -> None: registry = load_singledispatch_registry(builder, dispatch_func_obj, line) for typ in types: loaded_type = load_type(builder, typ, None, line) - builder.primitive_op(true_dict_set_item_op, [registry, loaded_type, to_insert], line) + builder.primitive_op(exact_dict_set_item_op, [registry, loaded_type, to_insert], line) dispatch_cache = builder.builder.get_attr( dispatch_func_obj, "dispatch_cache", exact_dict_rprimitive, line ) diff --git a/mypyc/irbuild/ll_builder.py b/mypyc/irbuild/ll_builder.py index 00ea8b560321..55434be4db75 100644 --- a/mypyc/irbuild/ll_builder.py +++ b/mypyc/irbuild/ll_builder.py @@ -132,9 +132,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 @@ -800,7 +800,7 @@ def _construct_varargs( if star2_result is None: 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) @@ -1669,12 +1669,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 @@ -2290,7 +2290,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 c892cbd9d30c..9a2998db8b8e 100644 --- a/mypyc/irbuild/specialize.py +++ b/mypyc/irbuild/specialize.py @@ -92,9 +92,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 @@ -255,17 +255,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 7fa30c1c41f0..405d02463f33 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, @@ -153,7 +153,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, @@ -163,7 +163,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, @@ -173,7 +173,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, @@ -194,7 +194,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", @@ -247,7 +247,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, @@ -265,7 +265,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, @@ -402,7 +402,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", @@ -410,7 +410,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", @@ -426,7 +426,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", @@ -442,7 +442,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", @@ -458,7 +458,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", @@ -508,21 +508,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", @@ -530,7 +530,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", @@ -545,7 +545,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", @@ -560,7 +560,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 3501cdb9faf9ccb8a2501c129d5b8ad01183673d 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/23] [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 9a2998db8b8e..5462ded820ca 100644 --- a/mypyc/irbuild/specialize.py +++ b/mypyc/irbuild/specialize.py @@ -91,10 +91,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 6054288d0a21ae381959e807d9175da84aa05193 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/23] 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 57c4e4dddb9b..aa365df12c51 100644 --- a/mypyc/irbuild/mapper.py +++ b/mypyc/irbuild/mapper.py @@ -90,11 +90,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 e3fde02fc695011ac38b72c3ee7abe08c2282bf6 Mon Sep 17 00:00:00 2001 From: BobTheBuidler Date: Mon, 4 Aug 2025 02:01:36 +0000 Subject: [PATCH 20/23] update ir --- mypyc/test-data/irbuild-basic.test | 96 ++++++++------- mypyc/test-data/irbuild-bytes.test | 2 +- mypyc/test-data/irbuild-dict.test | 111 +++++++++-------- mypyc/test-data/irbuild-generics.test | 164 +++++++++++++------------- 4 files changed, 194 insertions(+), 179 deletions(-) diff --git a/mypyc/test-data/irbuild-basic.test b/mypyc/test-data/irbuild-basic.test index 784958a539b9..9dd1c231deac 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 @@ -1743,15 +1743,18 @@ L0: def g(): r0, r1, r2 :: str r3, r4, r5 :: object - r6, r7 :: dict[exact] - r8 :: str - r9 :: object - r10 :: dict[exact] - r11 :: i32 - r12 :: bit - r13 :: tuple - r14 :: object - r15 :: tuple[int, int, int] + r6 :: dict[exact] + r7 :: dict + r8 :: dict[exact] + r9 :: str + r10 :: object + r11 :: dict[exact] + r12 :: dict + r13 :: i32 + r14 :: bit + r15 :: tuple + r16 :: object + r17 :: tuple[int, int, int] L0: r0 = 'a' r1 = 'b' @@ -1760,46 +1763,53 @@ L0: r4 = object 2 r5 = object 3 r6 = CPyDict_Build(3, r0, r3, r1, r4, r2, r5) - r7 = __main__.globals :: static - r8 = 'f' - r9 = CPyDict_GetItemUnsafe(r7, r8) - r10 = PyDict_New() - r11 = PyDict_Update(r10, r6) - r12 = r11 >= 0 :: signed - r13 = PyTuple_Pack(0) - r14 = PyObject_Call(r9, r13, r10) - r15 = unbox(tuple[int, int, int], r14) - return r15 + r7 = cast(dict, r6) + r8 = __main__.globals :: static + r9 = 'f' + r10 = CPyDict_GetItemUnsafe(r8, r9) + r11 = PyDict_New() + r12 = cast(dict, r11) + r13 = CPyDict_UpdateInDisplay(r12, r7) + r14 = r13 >= 0 :: signed + r15 = PyTuple_Pack(0) + r16 = PyObject_Call(r10, r15, r11) + r17 = unbox(tuple[int, int, int], r16) + return r17 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: @@ -1960,6 +1970,7 @@ def f(): r16 :: i32 r17 :: bit r18 :: native_int + r19 :: dict L0: r0 = PyDict_New() r1 = PyList_New(3) @@ -2000,7 +2011,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 b3fd41077d3f..476c5ac59f48 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 d619305f3e3c..3fed7849855e 100644 --- a/mypyc/test-data/irbuild-generics.test +++ b/mypyc/test-data/irbuild-generics.test @@ -166,25 +166,27 @@ execute(f, 1) def execute(func, args, kwargs): func :: object args :: tuple - kwargs :: dict[exact] + kwargs :: dict r0 :: list r1 :: object r2 :: dict[exact] - r3 :: i32 - r4 :: bit - r5 :: tuple - r6 :: object - r7 :: int + r3 :: dict + r4 :: i32 + r5 :: bit + r6 :: tuple + r7 :: object + r8 :: int L0: r0 = PyList_New(0) r1 = CPyList_Extend(r0, args) r2 = PyDict_New() - r3 = PyDict_Update(r2, kwargs) - r4 = r3 >= 0 :: signed - r5 = PyList_AsTuple(r0) - r6 = PyObject_Call(func, r5, r2) - r7 = unbox(int, r6) - return r7 + r3 = cast(dict, r2) + r4 = CPyDict_UpdateInDisplay(r3, kwargs) + r5 = r4 >= 0 :: signed + r6 = PyList_AsTuple(r0) + r7 = PyObject_Call(func, r6, r2) + r8 = unbox(int, r7) + return r8 def f(x): x :: int L0: @@ -222,11 +224,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 @@ -237,7 +239,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 @@ -249,7 +251,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 @@ -260,7 +262,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 @@ -276,9 +278,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] @@ -290,7 +292,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() @@ -298,9 +300,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] @@ -313,7 +315,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() @@ -321,9 +323,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] @@ -335,7 +337,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() @@ -343,9 +345,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] @@ -361,18 +363,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 @@ -383,7 +385,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 @@ -394,7 +396,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 @@ -405,7 +407,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 @@ -420,9 +422,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] @@ -434,7 +436,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() @@ -442,9 +444,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] @@ -456,7 +458,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() @@ -464,9 +466,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] @@ -478,7 +480,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() @@ -486,9 +488,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] @@ -503,7 +505,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() @@ -685,7 +687,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 @@ -697,7 +699,7 @@ def inner_deco_obj.__call__(__mypyc_self__, args, kwargs): r8 :: dict[exact] r9 :: short_int r10 :: native_int - r11 :: dict[exact] + r11 :: object r12 :: tuple[bool, short_int, object, object] r13 :: short_int r14 :: bool @@ -706,17 +708,18 @@ def inner_deco_obj.__call__(__mypyc_self__, args, kwargs): v :: object r18 :: i32 r19, r20, r21 :: bit - can_dictcomp :: dict[exact] - r22, can_iter, r23, can_use_keys, r24, can_use_values :: list - r25 :: object - r26 :: list - r27 :: object - r28 :: dict[exact] - r29 :: i32 - r30 :: bit - r31 :: tuple - r32 :: object - r33 :: int + r22, can_dictcomp :: dict + r23, can_iter, r24, can_use_keys, r25, can_use_values :: list + r26 :: object + r27 :: list + r28 :: object + r29 :: dict[exact] + r30 :: dict + r31 :: i32 + r32 :: bit + r33 :: tuple + r34 :: object + r35 :: int L0: r0 = __mypyc_self__.__mypyc_env__ r1 = var_object_size args @@ -739,9 +742,9 @@ L4: r8 = PyDict_New() r9 = 0 r10 = PyDict_Size(kwargs) - r11 = _CPyDict_GetIterUnsafe(kwargs) + r11 = CPyDict_GetItemsIter(kwargs) L5: - r12 = CPyDict_NextItemUnsafe(r11, r9) + r12 = CPyDict_NextItem(r11, r9) r13 = r12[1] r9 = r13 r14 = r12[0] @@ -755,28 +758,30 @@ L6: r18 = PyDict_SetItem(r8, k, v) r19 = r18 >= 0 :: signed L7: - r20 = CPyDict_CheckSizeUnsafe(kwargs, r10) + r20 = CPyDict_CheckSize(kwargs, r10) goto L5 L8: r21 = CPy_NoErrOccurred() L9: - can_dictcomp = r8 - r22 = PySequence_List(kwargs) - can_iter = r22 - r23 = PyDict_Keys(kwargs) - can_use_keys = r23 - r24 = PyDict_Values(kwargs) - can_use_values = r24 - r25 = r0.func - r26 = PyList_New(0) - r27 = CPyList_Extend(r26, args) - r28 = PyDict_New() - r29 = PyDict_Update(r28, kwargs) - r30 = r29 >= 0 :: signed - r31 = PyList_AsTuple(r26) - r32 = PyObject_Call(r25, r31, r28) - r33 = unbox(int, r32) - return r33 + r22 = cast(dict, r8) + can_dictcomp = r22 + r23 = PySequence_List(kwargs) + can_iter = r23 + r24 = CPyDict_Keys(kwargs) + can_use_keys = r24 + r25 = CPyDict_Values(kwargs) + can_use_values = r25 + r26 = r0.func + r27 = PyList_New(0) + r28 = CPyList_Extend(r27, args) + r29 = PyDict_New() + r30 = cast(dict, r29) + r31 = CPyDict_UpdateInDisplay(r30, kwargs) + r32 = r31 >= 0 :: signed + r33 = PyList_AsTuple(r27) + r34 = PyObject_Call(r26, r33, r29) + r35 = unbox(int, r34) + return r35 def deco(func): func :: object r0 :: __main__.deco_env @@ -795,3 +800,4 @@ def f(x): x :: int L0: return x + From efbba270d880f4b850b868c5b200d3080a330242 Mon Sep 17 00:00:00 2001 From: BobTheBuidler Date: Mon, 4 Aug 2025 02:01:36 +0000 Subject: [PATCH 21/23] 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 9dd1c231deac..3b3bd008b9b5 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 ee8da403437b4b6264b8900e70349e0dcf246b46 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/23] [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 3fed7849855e..17f543ed8eda 100644 --- a/mypyc/test-data/irbuild-generics.test +++ b/mypyc/test-data/irbuild-generics.test @@ -800,4 +800,3 @@ def f(x): x :: int L0: return x - From ba74ed0f44280d3bf193ba19021ba6cb07dd54fb Mon Sep 17 00:00:00 2001 From: BobTheBuidler Date: Mon, 4 Aug 2025 02:01:36 +0000 Subject: [PATCH 23/23] 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]