diff --git a/mypy/checkexpr.py b/mypy/checkexpr.py index 6ae75daee98c..812121994fd7 100644 --- a/mypy/checkexpr.py +++ b/mypy/checkexpr.py @@ -15,7 +15,7 @@ import mypy.errorcodes as codes from mypy import applytype, erasetype, join, message_registry, nodes, operators, types from mypy.argmap import ArgTypeExpander, map_actuals_to_formals, map_formals_to_actuals -from mypy.checkmember import analyze_member_access, typeddict_callable +from mypy.checkmember import analyze_member_access from mypy.checkstrformat import StringFormatterChecker from mypy.erasetype import erase_type, remove_instance_last_known_values, replace_meta_vars from mypy.errors import ErrorWatcher, report_internal_error @@ -957,7 +957,20 @@ def typeddict_callable(self, info: TypeInfo) -> CallableType: Note it is not safe to move this to type_object_type() since it will crash on plugin-generated TypedDicts, that may not have the special_alias. """ - return typeddict_callable(info, self.named_type) + assert info.special_alias is not None + target = info.special_alias.target + assert isinstance(target, ProperType) and isinstance(target, TypedDictType) + expected_types = list(target.items.values()) + kinds = [ArgKind.ARG_NAMED] * len(expected_types) + names = list(target.items.keys()) + return CallableType( + expected_types, + kinds, + names, + target, + self.named_type("builtins.type"), + variables=info.defn.type_vars, + ) def typeddict_callable_from_context(self, callee: TypedDictType) -> CallableType: return CallableType( diff --git a/mypy/checkmember.py b/mypy/checkmember.py index 40a31cd7ba72..0535486bfd4a 100644 --- a/mypy/checkmember.py +++ b/mypy/checkmember.py @@ -19,7 +19,6 @@ ARG_STAR, EXCLUDED_ENUM_ATTRIBUTES, SYMBOL_FUNCBASE_TYPES, - ArgKind, Context, Decorator, FuncBase, @@ -1094,7 +1093,7 @@ def analyze_class_attribute_access( if isinstance(node.node, TypeInfo): if node.node.typeddict_type: # We special-case TypedDict, because they don't define any constructor. - return typeddict_callable(node.node, mx.named_type) + return mx.chk.expr_checker.typeddict_callable(node.node) elif node.node.fullname == "types.NoneType": # We special case NoneType, because its stub definition is not related to None. return TypeType(NoneType()) @@ -1280,31 +1279,6 @@ class B(A[str]): pass return t -def typeddict_callable(info: TypeInfo, named_type: Callable[[str], Instance]) -> CallableType: - """Construct a reasonable type for a TypedDict type in runtime context. - - If it appears as a callee, it will be special-cased anyway, e.g. it is - also allowed to accept a single positional argument if it is a dict literal. - - Note it is not safe to move this to type_object_type() since it will crash - on plugin-generated TypedDicts, that may not have the special_alias. - """ - assert info.special_alias is not None - target = info.special_alias.target - assert isinstance(target, ProperType) and isinstance(target, TypedDictType) - expected_types = list(target.items.values()) - kinds = [ArgKind.ARG_NAMED] * len(expected_types) - names = list(target.items.keys()) - return CallableType( - expected_types, - kinds, - names, - target, - named_type("builtins.type"), - variables=info.defn.type_vars, - ) - - def analyze_decorator_or_funcbase_access( defn: Decorator | FuncBase, itype: Instance, name: str, mx: MemberContext ) -> Type: