| from typing import List, Optional, Callable, Tuple, Iterator, Set, Union, cast |
| from contextlib import contextmanager |
| |
| from mypy.types import ( |
| Type, AnyType, UnboundType, TypeVisitor, FormalArgument, NoneTyp, function_type, |
| Instance, TypeVarType, CallableType, TupleType, TypedDictType, UnionType, Overloaded, |
| ErasedType, PartialType, DeletedType, UninhabitedType, TypeType, is_named_instance, |
| FunctionLike, TypeOfAny, LiteralType, |
| ) |
| import mypy.applytype |
| import mypy.constraints |
| import mypy.typeops |
| import mypy.sametypes |
| from mypy.erasetype import erase_type |
| # Circular import; done in the function instead. |
| # import mypy.solve |
| from mypy import messages |
| from mypy.nodes import ( |
| FuncBase, Var, Decorator, OverloadedFuncDef, TypeInfo, CONTRAVARIANT, COVARIANT, |
| ARG_POS, ARG_OPT, ARG_STAR, ARG_STAR2 |
| ) |
| from mypy.maptype import map_instance_to_supertype |
| from mypy.expandtype import expand_type_by_instance |
| from mypy.typestate import TypeState, SubtypeKind |
| from mypy import state |
| |
| MYPY = False |
| if MYPY: |
| from typing_extensions import Final |
| |
| |
| # Flags for detected protocol members |
| IS_SETTABLE = 1 # type: Final |
| IS_CLASSVAR = 2 # type: Final |
| IS_CLASS_OR_STATIC = 3 # type: Final |
| |
| |
| TypeParameterChecker = Callable[[Type, Type, int], bool] |
| |
| |
| def check_type_parameter(lefta: Type, righta: Type, variance: int) -> bool: |
| if variance == COVARIANT: |
| return is_subtype(lefta, righta) |
| elif variance == CONTRAVARIANT: |
| return is_subtype(righta, lefta) |
| else: |
| return is_equivalent(lefta, righta) |
| |
| |
| def ignore_type_parameter(s: Type, t: Type, v: int) -> bool: |
| return True |
| |
| |
| def is_subtype(left: Type, right: Type, |
| *, |
| ignore_type_params: bool = False, |
| ignore_pos_arg_names: bool = False, |
| ignore_declared_variance: bool = False, |
| ignore_promotions: bool = False) -> bool: |
| """Is 'left' subtype of 'right'? |
| |
| Also consider Any to be a subtype of any type, and vice versa. This |
| recursively applies to components of composite types (List[int] is subtype |
| of List[Any], for example). |
| |
| type_parameter_checker is used to check the type parameters (for example, |
| A with B in is_subtype(C[A], C[B]). The default checks for subtype relation |
| between the type arguments (e.g., A and B), taking the variance of the |
| type var into account. |
| """ |
| if (isinstance(right, AnyType) or isinstance(right, UnboundType) |
| or isinstance(right, ErasedType)): |
| return True |
| elif isinstance(right, UnionType) and not isinstance(left, UnionType): |
| # Normally, when 'left' is not itself a union, the only way |
| # 'left' can be a subtype of the union 'right' is if it is a |
| # subtype of one of the items making up the union. |
| is_subtype_of_item = any(is_subtype(left, item, |
| ignore_type_params=ignore_type_params, |
| ignore_pos_arg_names=ignore_pos_arg_names, |
| ignore_declared_variance=ignore_declared_variance, |
| ignore_promotions=ignore_promotions) |
| for item in right.items) |
| # However, if 'left' is a type variable T, T might also have |
| # an upper bound which is itself a union. This case will be |
| # handled below by the SubtypeVisitor. We have to check both |
| # possibilities, to handle both cases like T <: Union[T, U] |
| # and cases like T <: B where B is the upper bound of T and is |
| # a union. (See #2314.) |
| if not isinstance(left, TypeVarType): |
| return is_subtype_of_item |
| elif is_subtype_of_item: |
| return True |
| # otherwise, fall through |
| return left.accept(SubtypeVisitor(right, |
| ignore_type_params=ignore_type_params, |
| ignore_pos_arg_names=ignore_pos_arg_names, |
| ignore_declared_variance=ignore_declared_variance, |
| ignore_promotions=ignore_promotions)) |
| |
| |
| def is_subtype_ignoring_tvars(left: Type, right: Type) -> bool: |
| return is_subtype(left, right, ignore_type_params=True) |
| |
| |
| def is_equivalent(a: Type, b: Type, |
| *, |
| ignore_type_params: bool = False, |
| ignore_pos_arg_names: bool = False |
| ) -> bool: |
| return ( |
| is_subtype(a, b, ignore_type_params=ignore_type_params, |
| ignore_pos_arg_names=ignore_pos_arg_names) |
| and is_subtype(b, a, ignore_type_params=ignore_type_params, |
| ignore_pos_arg_names=ignore_pos_arg_names)) |
| |
| |
| class SubtypeVisitor(TypeVisitor[bool]): |
| |
| def __init__(self, right: Type, |
| *, |
| ignore_type_params: bool, |
| ignore_pos_arg_names: bool = False, |
| ignore_declared_variance: bool = False, |
| ignore_promotions: bool = False) -> None: |
| self.right = right |
| self.ignore_type_params = ignore_type_params |
| self.ignore_pos_arg_names = ignore_pos_arg_names |
| self.ignore_declared_variance = ignore_declared_variance |
| self.ignore_promotions = ignore_promotions |
| self.check_type_parameter = (ignore_type_parameter if ignore_type_params else |
| check_type_parameter) |
| self._subtype_kind = SubtypeVisitor.build_subtype_kind( |
| ignore_type_params=ignore_type_params, |
| ignore_pos_arg_names=ignore_pos_arg_names, |
| ignore_declared_variance=ignore_declared_variance, |
| ignore_promotions=ignore_promotions) |
| |
| @staticmethod |
| def build_subtype_kind(*, |
| ignore_type_params: bool = False, |
| ignore_pos_arg_names: bool = False, |
| ignore_declared_variance: bool = False, |
| ignore_promotions: bool = False) -> SubtypeKind: |
| return (False, # is proper subtype? |
| ignore_type_params, |
| ignore_pos_arg_names, |
| ignore_declared_variance, |
| ignore_promotions) |
| |
| def _is_subtype(self, left: Type, right: Type) -> bool: |
| return is_subtype(left, right, |
| ignore_type_params=self.ignore_type_params, |
| ignore_pos_arg_names=self.ignore_pos_arg_names, |
| ignore_declared_variance=self.ignore_declared_variance, |
| ignore_promotions=self.ignore_promotions) |
| |
| # visit_x(left) means: is left (which is an instance of X) a subtype of |
| # right? |
| |
| def visit_unbound_type(self, left: UnboundType) -> bool: |
| return True |
| |
| def visit_any(self, left: AnyType) -> bool: |
| return True |
| |
| def visit_none_type(self, left: NoneTyp) -> bool: |
| if state.strict_optional: |
| return (isinstance(self.right, NoneTyp) or |
| is_named_instance(self.right, 'builtins.object') or |
| isinstance(self.right, Instance) and self.right.type.is_protocol and |
| not self.right.type.protocol_members) |
| else: |
| return True |
| |
| def visit_uninhabited_type(self, left: UninhabitedType) -> bool: |
| return True |
| |
| def visit_erased_type(self, left: ErasedType) -> bool: |
| return True |
| |
| def visit_deleted_type(self, left: DeletedType) -> bool: |
| return True |
| |
| def visit_instance(self, left: Instance) -> bool: |
| if left.type.fallback_to_any: |
| if isinstance(self.right, NoneTyp): |
| # NOTE: `None` is a *non-subclassable* singleton, therefore no class |
| # can by a subtype of it, even with an `Any` fallback. |
| # This special case is needed to treat descriptors in classes with |
| # dynamic base classes correctly, see #5456. |
| return False |
| return True |
| right = self.right |
| if isinstance(right, TupleType) and mypy.typeops.tuple_fallback(right).type.is_enum: |
| return self._is_subtype(left, mypy.typeops.tuple_fallback(right)) |
| if isinstance(right, Instance): |
| if TypeState.is_cached_subtype_check(self._subtype_kind, left, right): |
| return True |
| if not self.ignore_promotions: |
| for base in left.type.mro: |
| if base._promote and self._is_subtype(base._promote, self.right): |
| TypeState.record_subtype_cache_entry(self._subtype_kind, left, right) |
| return True |
| rname = right.type.fullname() |
| # Always try a nominal check if possible, |
| # there might be errors that a user wants to silence *once*. |
| if ((left.type.has_base(rname) or rname == 'builtins.object') and |
| not self.ignore_declared_variance): |
| # Map left type to corresponding right instances. |
| t = map_instance_to_supertype(left, right.type) |
| nominal = all(self.check_type_parameter(lefta, righta, tvar.variance) |
| for lefta, righta, tvar in |
| zip(t.args, right.args, right.type.defn.type_vars)) |
| if nominal: |
| TypeState.record_subtype_cache_entry(self._subtype_kind, left, right) |
| return nominal |
| if right.type.is_protocol and is_protocol_implementation(left, right): |
| return True |
| return False |
| if isinstance(right, TypeType): |
| item = right.item |
| if isinstance(item, TupleType): |
| item = mypy.typeops.tuple_fallback(item) |
| if is_named_instance(left, 'builtins.type'): |
| return self._is_subtype(TypeType(AnyType(TypeOfAny.special_form)), right) |
| if left.type.is_metaclass(): |
| if isinstance(item, AnyType): |
| return True |
| if isinstance(item, Instance): |
| return is_named_instance(item, 'builtins.object') |
| if isinstance(right, CallableType): |
| # Special case: Instance can be a subtype of Callable. |
| call = find_member('__call__', left, left) |
| if call: |
| return self._is_subtype(call, right) |
| return False |
| else: |
| return False |
| |
| def visit_type_var(self, left: TypeVarType) -> bool: |
| right = self.right |
| if isinstance(right, TypeVarType) and left.id == right.id: |
| return True |
| if left.values and self._is_subtype(UnionType.make_simplified_union(left.values), right): |
| return True |
| return self._is_subtype(left.upper_bound, self.right) |
| |
| def visit_callable_type(self, left: CallableType) -> bool: |
| right = self.right |
| if isinstance(right, CallableType): |
| return is_callable_compatible( |
| left, right, |
| is_compat=self._is_subtype, |
| ignore_pos_arg_names=self.ignore_pos_arg_names) |
| elif isinstance(right, Overloaded): |
| return all(self._is_subtype(left, item) for item in right.items()) |
| elif isinstance(right, Instance): |
| if right.type.is_protocol and right.type.protocol_members == ['__call__']: |
| # OK, a callable can implement a protocol with a single `__call__` member. |
| # TODO: we should probably explicitly exclude self-types in this case. |
| call = find_member('__call__', right, left) |
| assert call is not None |
| if self._is_subtype(left, call): |
| return True |
| return self._is_subtype(left.fallback, right) |
| elif isinstance(right, TypeType): |
| # This is unsound, we don't check the __init__ signature. |
| return left.is_type_obj() and self._is_subtype(left.ret_type, right.item) |
| else: |
| return False |
| |
| def visit_tuple_type(self, left: TupleType) -> bool: |
| right = self.right |
| if isinstance(right, Instance): |
| if is_named_instance(right, 'typing.Sized'): |
| return True |
| elif (is_named_instance(right, 'builtins.tuple') or |
| is_named_instance(right, 'typing.Iterable') or |
| is_named_instance(right, 'typing.Container') or |
| is_named_instance(right, 'typing.Sequence') or |
| is_named_instance(right, 'typing.Reversible')): |
| if right.args: |
| iter_type = right.args[0] |
| else: |
| iter_type = AnyType(TypeOfAny.special_form) |
| return all(self._is_subtype(li, iter_type) for li in left.items) |
| elif self._is_subtype(mypy.typeops.tuple_fallback(left), right): |
| return True |
| return False |
| elif isinstance(right, TupleType): |
| if len(left.items) != len(right.items): |
| return False |
| for l, r in zip(left.items, right.items): |
| if not self._is_subtype(l, r): |
| return False |
| rfallback = mypy.typeops.tuple_fallback(right) |
| if is_named_instance(rfallback, 'builtins.tuple'): |
| # No need to verify fallback. This is useful since the calculated fallback |
| # may be inconsistent due to how we calculate joins between unions vs. |
| # non-unions. For example, join(int, str) == object, whereas |
| # join(Union[int, C], Union[str, C]) == Union[int, str, C]. |
| return True |
| lfallback = mypy.typeops.tuple_fallback(left) |
| if not self._is_subtype(lfallback, rfallback): |
| return False |
| return True |
| else: |
| return False |
| |
| def visit_typeddict_type(self, left: TypedDictType) -> bool: |
| right = self.right |
| if isinstance(right, Instance): |
| return self._is_subtype(left.fallback, right) |
| elif isinstance(right, TypedDictType): |
| if not left.names_are_wider_than(right): |
| return False |
| for name, l, r in left.zip(right): |
| if not is_equivalent(l, r, |
| ignore_type_params=self.ignore_type_params): |
| return False |
| # Non-required key is not compatible with a required key since |
| # indexing may fail unexpectedly if a required key is missing. |
| # Required key is not compatible with a non-required key since |
| # the prior doesn't support 'del' but the latter should support |
| # it. |
| # |
| # NOTE: 'del' support is currently not implemented (#3550). We |
| # don't want to have to change subtyping after 'del' support |
| # lands so here we are anticipating that change. |
| if (name in left.required_keys) != (name in right.required_keys): |
| return False |
| # (NOTE: Fallbacks don't matter.) |
| return True |
| else: |
| return False |
| |
| def visit_literal_type(self, left: LiteralType) -> bool: |
| if isinstance(self.right, LiteralType): |
| return left == self.right |
| else: |
| return self._is_subtype(left.fallback, self.right) |
| |
| def visit_overloaded(self, left: Overloaded) -> bool: |
| right = self.right |
| if isinstance(right, Instance): |
| if right.type.is_protocol and right.type.protocol_members == ['__call__']: |
| # same as for CallableType |
| call = find_member('__call__', right, left) |
| assert call is not None |
| if self._is_subtype(left, call): |
| return True |
| return self._is_subtype(left.fallback, right) |
| elif isinstance(right, CallableType): |
| for item in left.items(): |
| if self._is_subtype(item, right): |
| return True |
| return False |
| elif isinstance(right, Overloaded): |
| # Ensure each overload in the right side (the supertype) is accounted for. |
| previous_match_left_index = -1 |
| matched_overloads = set() |
| possible_invalid_overloads = set() |
| |
| for right_index, right_item in enumerate(right.items()): |
| found_match = False |
| |
| for left_index, left_item in enumerate(left.items()): |
| subtype_match = self._is_subtype(left_item, right_item)\ |
| |
| # Order matters: we need to make sure that the index of |
| # this item is at least the index of the previous one. |
| if subtype_match and previous_match_left_index <= left_index: |
| if not found_match: |
| # Update the index of the previous match. |
| previous_match_left_index = left_index |
| found_match = True |
| matched_overloads.add(left_item) |
| possible_invalid_overloads.discard(left_item) |
| else: |
| # If this one overlaps with the supertype in any way, but it wasn't |
| # an exact match, then it's a potential error. |
| if (is_callable_compatible(left_item, right_item, |
| is_compat=self._is_subtype, ignore_return=True, |
| ignore_pos_arg_names=self.ignore_pos_arg_names) or |
| is_callable_compatible(right_item, left_item, |
| is_compat=self._is_subtype, ignore_return=True, |
| ignore_pos_arg_names=self.ignore_pos_arg_names)): |
| # If this is an overload that's already been matched, there's no |
| # problem. |
| if left_item not in matched_overloads: |
| possible_invalid_overloads.add(left_item) |
| |
| if not found_match: |
| return False |
| |
| if possible_invalid_overloads: |
| # There were potentially invalid overloads that were never matched to the |
| # supertype. |
| return False |
| return True |
| elif isinstance(right, UnboundType): |
| return True |
| elif isinstance(right, TypeType): |
| # All the items must have the same type object status, so |
| # it's sufficient to query only (any) one of them. |
| # This is unsound, we don't check all the __init__ signatures. |
| return left.is_type_obj() and self._is_subtype(left.items()[0], right) |
| else: |
| return False |
| |
| def visit_union_type(self, left: UnionType) -> bool: |
| return all(self._is_subtype(item, self.right) for item in left.items) |
| |
| def visit_partial_type(self, left: PartialType) -> bool: |
| # This is indeterminate as we don't really know the complete type yet. |
| raise RuntimeError |
| |
| def visit_type_type(self, left: TypeType) -> bool: |
| right = self.right |
| if isinstance(right, TypeType): |
| return self._is_subtype(left.item, right.item) |
| if isinstance(right, CallableType): |
| # This is unsound, we don't check the __init__ signature. |
| return self._is_subtype(left.item, right.ret_type) |
| if isinstance(right, Instance): |
| if right.type.fullname() in ['builtins.object', 'builtins.type']: |
| return True |
| item = left.item |
| if isinstance(item, TypeVarType): |
| item = item.upper_bound |
| if isinstance(item, Instance): |
| metaclass = item.type.metaclass_type |
| return metaclass is not None and self._is_subtype(metaclass, right) |
| return False |
| |
| |
| @contextmanager |
| def pop_on_exit(stack: List[Tuple[Instance, Instance]], |
| left: Instance, right: Instance) -> Iterator[None]: |
| stack.append((left, right)) |
| yield |
| stack.pop() |
| |
| |
| def is_protocol_implementation(left: Instance, right: Instance, |
| proper_subtype: bool = False) -> bool: |
| """Check whether 'left' implements the protocol 'right'. |
| |
| If 'proper_subtype' is True, then check for a proper subtype. |
| Treat recursive protocols by using the 'assuming' structural subtype matrix |
| (in sparse representation, i.e. as a list of pairs (subtype, supertype)), |
| see also comment in nodes.TypeInfo. When we enter a check for classes |
| (A, P), defined as following:: |
| |
| class P(Protocol): |
| def f(self) -> P: ... |
| class A: |
| def f(self) -> A: ... |
| |
| this results in A being a subtype of P without infinite recursion. |
| On every false result, we pop the assumption, thus avoiding an infinite recursion |
| as well. |
| """ |
| assert right.type.is_protocol |
| # We need to record this check to generate protocol fine-grained dependencies. |
| TypeState.record_protocol_subtype_check(left.type, right.type) |
| assuming = right.type.assuming_proper if proper_subtype else right.type.assuming |
| for (l, r) in reversed(assuming): |
| if (mypy.sametypes.is_same_type(l, left) |
| and mypy.sametypes.is_same_type(r, right)): |
| return True |
| with pop_on_exit(assuming, left, right): |
| for member in right.type.protocol_members: |
| # nominal subtyping currently ignores '__init__' and '__new__' signatures |
| if member in ('__init__', '__new__'): |
| continue |
| ignore_names = member != '__call__' # __call__ can be passed kwargs |
| # The third argument below indicates to what self type is bound. |
| # We always bind self to the subtype. (Similarly to nominal types). |
| supertype = find_member(member, right, left) |
| assert supertype is not None |
| subtype = find_member(member, left, left) |
| # Useful for debugging: |
| # print(member, 'of', left, 'has type', subtype) |
| # print(member, 'of', right, 'has type', supertype) |
| if not subtype: |
| return False |
| if not proper_subtype: |
| # Nominal check currently ignores arg names |
| # NOTE: If we ever change this, be sure to also change the call to |
| # SubtypeVisitor.build_subtype_kind(...) down below. |
| is_compat = is_subtype(subtype, supertype, ignore_pos_arg_names=ignore_names) |
| else: |
| is_compat = is_proper_subtype(subtype, supertype) |
| if not is_compat: |
| return False |
| if isinstance(subtype, NoneTyp) and isinstance(supertype, CallableType): |
| # We want __hash__ = None idiom to work even without --strict-optional |
| return False |
| subflags = get_member_flags(member, left.type) |
| superflags = get_member_flags(member, right.type) |
| if IS_SETTABLE in superflags: |
| # Check opposite direction for settable attributes. |
| if not is_subtype(supertype, subtype): |
| return False |
| if (IS_CLASSVAR in subflags) != (IS_CLASSVAR in superflags): |
| return False |
| if IS_SETTABLE in superflags and IS_SETTABLE not in subflags: |
| return False |
| # This rule is copied from nominal check in checker.py |
| if IS_CLASS_OR_STATIC in superflags and IS_CLASS_OR_STATIC not in subflags: |
| return False |
| |
| if not proper_subtype: |
| # Nominal check currently ignores arg names, but __call__ is special for protocols |
| ignore_names = right.type.protocol_members != ['__call__'] |
| subtype_kind = SubtypeVisitor.build_subtype_kind(ignore_pos_arg_names=ignore_names) |
| else: |
| subtype_kind = ProperSubtypeVisitor.build_subtype_kind() |
| TypeState.record_subtype_cache_entry(subtype_kind, left, right) |
| return True |
| |
| |
| def find_member(name: str, itype: Instance, subtype: Type) -> Optional[Type]: |
| """Find the type of member by 'name' in 'itype's TypeInfo. |
| |
| Fin the member type after applying type arguments from 'itype', and binding |
| 'self' to 'subtype'. Return None if member was not found. |
| """ |
| # TODO: this code shares some logic with checkmember.analyze_member_access, |
| # consider refactoring. |
| info = itype.type |
| method = info.get_method(name) |
| if method: |
| if method.is_property: |
| assert isinstance(method, OverloadedFuncDef) |
| dec = method.items[0] |
| assert isinstance(dec, Decorator) |
| return find_node_type(dec.var, itype, subtype) |
| return find_node_type(method, itype, subtype) |
| else: |
| # don't have such method, maybe variable or decorator? |
| node = info.get(name) |
| if not node: |
| v = None |
| else: |
| v = node.node |
| if isinstance(v, Decorator): |
| v = v.var |
| if isinstance(v, Var): |
| return find_node_type(v, itype, subtype) |
| if not v and name not in ['__getattr__', '__setattr__', '__getattribute__']: |
| for method_name in ('__getattribute__', '__getattr__'): |
| # Normally, mypy assumes that instances that define __getattr__ have all |
| # attributes with the corresponding return type. If this will produce |
| # many false negatives, then this could be prohibited for |
| # structural subtyping. |
| method = info.get_method(method_name) |
| if method and method.info.fullname() != 'builtins.object': |
| getattr_type = find_node_type(method, itype, subtype) |
| if isinstance(getattr_type, CallableType): |
| return getattr_type.ret_type |
| if itype.type.fallback_to_any: |
| return AnyType(TypeOfAny.special_form) |
| return None |
| |
| |
| def get_member_flags(name: str, info: TypeInfo) -> Set[int]: |
| """Detect whether a member 'name' is settable, whether it is an |
| instance or class variable, and whether it is class or static method. |
| |
| The flags are defined as following: |
| * IS_SETTABLE: whether this attribute can be set, not set for methods and |
| non-settable properties; |
| * IS_CLASSVAR: set if the variable is annotated as 'x: ClassVar[t]'; |
| * IS_CLASS_OR_STATIC: set for methods decorated with @classmethod or |
| with @staticmethod. |
| """ |
| method = info.get_method(name) |
| setattr_meth = info.get_method('__setattr__') |
| if method: |
| # this could be settable property |
| if method.is_property: |
| assert isinstance(method, OverloadedFuncDef) |
| dec = method.items[0] |
| assert isinstance(dec, Decorator) |
| if dec.var.is_settable_property or setattr_meth: |
| return {IS_SETTABLE} |
| return set() |
| node = info.get(name) |
| if not node: |
| if setattr_meth: |
| return {IS_SETTABLE} |
| return set() |
| v = node.node |
| if isinstance(v, Decorator): |
| if v.var.is_staticmethod or v.var.is_classmethod: |
| return {IS_CLASS_OR_STATIC} |
| # just a variable |
| if isinstance(v, Var) and not v.is_property: |
| flags = {IS_SETTABLE} |
| if v.is_classvar: |
| flags.add(IS_CLASSVAR) |
| return flags |
| return set() |
| |
| |
| def find_node_type(node: Union[Var, FuncBase], itype: Instance, subtype: Type) -> Type: |
| """Find type of a variable or method 'node' (maybe also a decorated method). |
| Apply type arguments from 'itype', and bind 'self' to 'subtype'. |
| """ |
| from mypy.checkmember import bind_self |
| if isinstance(node, FuncBase): |
| typ = function_type(node, |
| fallback=Instance(itype.type.mro[-1], [])) # type: Optional[Type] |
| else: |
| typ = node.type |
| if typ is None: |
| return AnyType(TypeOfAny.from_error) |
| # We don't need to bind 'self' for static methods, since there is no 'self'. |
| if (isinstance(node, FuncBase) |
| or (isinstance(typ, FunctionLike) |
| and node.is_initialized_in_class |
| and not node.is_staticmethod)): |
| assert isinstance(typ, FunctionLike) |
| signature = bind_self(typ, subtype) |
| if node.is_property: |
| assert isinstance(signature, CallableType) |
| typ = signature.ret_type |
| else: |
| typ = signature |
| itype = map_instance_to_supertype(itype, node.info) |
| typ = expand_type_by_instance(typ, itype) |
| return typ |
| |
| |
| def non_method_protocol_members(tp: TypeInfo) -> List[str]: |
| """Find all non-callable members of a protocol.""" |
| |
| assert tp.is_protocol |
| result = [] # type: List[str] |
| anytype = AnyType(TypeOfAny.special_form) |
| instance = Instance(tp, [anytype] * len(tp.defn.type_vars)) |
| |
| for member in tp.protocol_members: |
| typ = find_member(member, instance, instance) |
| if not isinstance(typ, CallableType): |
| result.append(member) |
| return result |
| |
| |
| def is_callable_compatible(left: CallableType, right: CallableType, |
| *, |
| is_compat: Callable[[Type, Type], bool], |
| is_compat_return: Optional[Callable[[Type, Type], bool]] = None, |
| ignore_return: bool = False, |
| ignore_pos_arg_names: bool = False, |
| check_args_covariantly: bool = False, |
| allow_partial_overlap: bool = False) -> bool: |
| """Is the left compatible with the right, using the provided compatibility check? |
| |
| is_compat: |
| The check we want to run against the parameters. |
| |
| is_compat_return: |
| The check we want to run against the return type. |
| If None, use the 'is_compat' check. |
| |
| check_args_covariantly: |
| If true, check if the left's args is compatible with the right's |
| instead of the other way around (contravariantly). |
| |
| This function is mostly used to check if the left is a subtype of the right which |
| is why the default is to check the args contravariantly. However, it's occasionally |
| useful to check the args using some other check, so we leave the variance |
| configurable. |
| |
| For example, when checking the validity of overloads, it's useful to see if |
| the first overload alternative has more precise arguments then the second. |
| We would want to check the arguments covariantly in that case. |
| |
| Note! The following two function calls are NOT equivalent: |
| |
| is_callable_compatible(f, g, is_compat=is_subtype, check_args_covariantly=False) |
| is_callable_compatible(g, f, is_compat=is_subtype, check_args_covariantly=True) |
| |
| The two calls are similar in that they both check the function arguments in |
| the same direction: they both run `is_subtype(argument_from_g, argument_from_f)`. |
| |
| However, the two calls differ in which direction they check things like |
| keyword arguments. For example, suppose f and g are defined like so: |
| |
| def f(x: int, *y: int) -> int: ... |
| def g(x: int) -> int: ... |
| |
| In this case, the first call will succeed and the second will fail: f is a |
| valid stand-in for g but not vice-versa. |
| |
| allow_partial_overlap: |
| By default this function returns True if and only if *all* calls to left are |
| also calls to right (with respect to the provided 'is_compat' function). |
| |
| If this parameter is set to 'True', we return True if *there exists at least one* |
| call to left that's also a call to right. |
| |
| In other words, we perform an existential check instead of a universal one; |
| we require left to only overlap with right instead of being a subset. |
| |
| For example, suppose we set 'is_compat' to some subtype check and compare following: |
| |
| f(x: float, y: str = "...", *args: bool) -> str |
| g(*args: int) -> str |
| |
| This function would normally return 'False': f is not a subtype of g. |
| However, we would return True if this parameter is set to 'True': the two |
| calls are compatible if the user runs "f_or_g(3)". In the context of that |
| specific call, the two functions effectively have signatures of: |
| |
| f2(float) -> str |
| g2(int) -> str |
| |
| Here, f2 is a valid subtype of g2 so we return True. |
| |
| Specifically, if this parameter is set this function will: |
| |
| - Ignore optional arguments on either the left or right that have no |
| corresponding match. |
| - No longer mandate optional arguments on either side are also optional |
| on the other. |
| - No longer mandate that if right has a *arg or **kwarg that left must also |
| have the same. |
| |
| Note: when this argument is set to True, this function becomes "symmetric" -- |
| the following calls are equivalent: |
| |
| is_callable_compatible(f, g, |
| is_compat=some_check, |
| check_args_covariantly=False, |
| allow_partial_overlap=True) |
| is_callable_compatible(g, f, |
| is_compat=some_check, |
| check_args_covariantly=True, |
| allow_partial_overlap=True) |
| |
| If the 'some_check' function is also symmetric, the two calls would be equivalent |
| whether or not we check the args covariantly. |
| """ |
| if is_compat_return is None: |
| is_compat_return = is_compat |
| |
| # If either function is implicitly typed, ignore positional arg names too |
| if left.implicit or right.implicit: |
| ignore_pos_arg_names = True |
| |
| # Non-type cannot be a subtype of type. |
| if right.is_type_obj() and not left.is_type_obj(): |
| return False |
| |
| # A callable L is a subtype of a generic callable R if L is a |
| # subtype of every type obtained from R by substituting types for |
| # the variables of R. We can check this by simply leaving the |
| # generic variables of R as type variables, effectively varying |
| # over all possible values. |
| |
| # It's okay even if these variables share ids with generic |
| # type variables of L, because generating and solving |
| # constraints for the variables of L to make L a subtype of R |
| # (below) treats type variables on the two sides as independent. |
| if left.variables: |
| # Apply generic type variables away in left via type inference. |
| unified = unify_generic_callable(left, right, ignore_return=ignore_return) |
| if unified is None: |
| return False |
| else: |
| left = unified |
| |
| # If we allow partial overlaps, we don't need to leave R generic: |
| # if we can find even just a single typevar assignment which |
| # would make these callables compatible, we should return True. |
| |
| # So, we repeat the above checks in the opposite direction. This also |
| # lets us preserve the 'symmetry' property of allow_partial_overlap. |
| if allow_partial_overlap and right.variables: |
| unified = unify_generic_callable(right, left, ignore_return=ignore_return) |
| if unified is not None: |
| right = unified |
| |
| # Check return types. |
| if not ignore_return and not is_compat_return(left.ret_type, right.ret_type): |
| return False |
| |
| if check_args_covariantly: |
| is_compat = flip_compat_check(is_compat) |
| |
| if right.is_ellipsis_args: |
| return True |
| |
| left_star = left.var_arg() |
| left_star2 = left.kw_arg() |
| right_star = right.var_arg() |
| right_star2 = right.kw_arg() |
| |
| # Match up corresponding arguments and check them for compatibility. In |
| # every pair (argL, argR) of corresponding arguments from L and R, argL must |
| # be "more general" than argR if L is to be a subtype of R. |
| |
| # Arguments are corresponding if they either share a name, share a position, |
| # or both. If L's corresponding argument is ambiguous, L is not a subtype of R. |
| |
| # If left has one corresponding argument by name and another by position, |
| # consider them to be one "merged" argument (and not ambiguous) if they're |
| # both optional, they're name-only and position-only respectively, and they |
| # have the same type. This rule allows functions with (*args, **kwargs) to |
| # properly stand in for the full domain of formal arguments that they're |
| # used for in practice. |
| |
| # Every argument in R must have a corresponding argument in L, and every |
| # required argument in L must have a corresponding argument in R. |
| |
| # Phase 1: Confirm every argument in R has a corresponding argument in L. |
| |
| # Phase 1a: If left and right can both accept an infinite number of args, |
| # their types must be compatible. |
| # |
| # Furthermore, if we're checking for compatibility in all cases, |
| # we confirm that if R accepts an infinite number of arguments, |
| # L must accept the same. |
| def _incompatible(left_arg: Optional[FormalArgument], |
| right_arg: Optional[FormalArgument]) -> bool: |
| if right_arg is None: |
| return False |
| if left_arg is None: |
| return not allow_partial_overlap |
| return not is_compat(right_arg.typ, left_arg.typ) |
| |
| if _incompatible(left_star, right_star) or _incompatible(left_star2, right_star2): |
| return False |
| |
| # Phase 1b: Check non-star args: for every arg right can accept, left must |
| # also accept. The only exception is if we are allowing partial |
| # partial overlaps: in that case, we ignore optional args on the right. |
| for right_arg in right.formal_arguments(): |
| left_arg = left.corresponding_argument(right_arg) |
| if left_arg is None: |
| if allow_partial_overlap and not right_arg.required: |
| continue |
| return False |
| if not are_args_compatible(left_arg, right_arg, ignore_pos_arg_names, |
| allow_partial_overlap, is_compat): |
| return False |
| |
| # Phase 1c: Check var args. Right has an infinite series of optional positional |
| # arguments. Get all further positional args of left, and make sure |
| # they're more general then the corresponding member in right. |
| if right_star is not None: |
| # Synthesize an anonymous formal argument for the right |
| right_by_position = right.try_synthesizing_arg_from_vararg(None) |
| assert right_by_position is not None |
| |
| i = right_star.pos |
| assert i is not None |
| while i < len(left.arg_kinds) and left.arg_kinds[i] in (ARG_POS, ARG_OPT): |
| if allow_partial_overlap and left.arg_kinds[i] == ARG_OPT: |
| break |
| |
| left_by_position = left.argument_by_position(i) |
| assert left_by_position is not None |
| |
| if not are_args_compatible(left_by_position, right_by_position, |
| ignore_pos_arg_names, allow_partial_overlap, |
| is_compat): |
| return False |
| i += 1 |
| |
| # Phase 1d: Check kw args. Right has an infinite series of optional named |
| # arguments. Get all further named args of left, and make sure |
| # they're more general then the corresponding member in right. |
| if right_star2 is not None: |
| right_names = {name for name in right.arg_names if name is not None} |
| left_only_names = set() |
| for name, kind in zip(left.arg_names, left.arg_kinds): |
| if name is None or kind in (ARG_STAR, ARG_STAR2) or name in right_names: |
| continue |
| left_only_names.add(name) |
| |
| # Synthesize an anonymous formal argument for the right |
| right_by_name = right.try_synthesizing_arg_from_kwarg(None) |
| assert right_by_name is not None |
| |
| for name in left_only_names: |
| left_by_name = left.argument_by_name(name) |
| assert left_by_name is not None |
| |
| if allow_partial_overlap and not left_by_name.required: |
| continue |
| |
| if not are_args_compatible(left_by_name, right_by_name, ignore_pos_arg_names, |
| allow_partial_overlap, is_compat): |
| return False |
| |
| # Phase 2: Left must not impose additional restrictions. |
| # (Every required argument in L must have a corresponding argument in R) |
| # Note: we already checked the *arg and **kwarg arguments in phase 1a. |
| for left_arg in left.formal_arguments(): |
| right_by_name = (right.argument_by_name(left_arg.name) |
| if left_arg.name is not None |
| else None) |
| |
| right_by_pos = (right.argument_by_position(left_arg.pos) |
| if left_arg.pos is not None |
| else None) |
| |
| # If the left hand argument corresponds to two right-hand arguments, |
| # neither of them can be required. |
| if (right_by_name is not None |
| and right_by_pos is not None |
| and right_by_name != right_by_pos |
| and (right_by_pos.required or right_by_name.required)): |
| return False |
| |
| # All *required* left-hand arguments must have a corresponding |
| # right-hand argument. Optional args do not matter. |
| if left_arg.required and right_by_pos is None and right_by_name is None: |
| return False |
| |
| return True |
| |
| |
| def are_args_compatible( |
| left: FormalArgument, |
| right: FormalArgument, |
| ignore_pos_arg_names: bool, |
| allow_partial_overlap: bool, |
| is_compat: Callable[[Type, Type], bool]) -> bool: |
| def is_different(left_item: Optional[object], right_item: Optional[object]) -> bool: |
| """Checks if the left and right items are different. |
| |
| If the right item is unspecified (e.g. if the right callable doesn't care |
| about what name or position its arg has), we default to returning False. |
| |
| If we're allowing partial overlap, we also default to returning False |
| if the left callable also doesn't care.""" |
| if right_item is None: |
| return False |
| if allow_partial_overlap and left_item is None: |
| return False |
| return left_item != right_item |
| |
| # If right has a specific name it wants this argument to be, left must |
| # have the same. |
| if is_different(left.name, right.name): |
| # But pay attention to whether we're ignoring positional arg names |
| if not ignore_pos_arg_names or right.pos is None: |
| return False |
| |
| # If right is at a specific position, left must have the same: |
| if is_different(left.pos, right.pos): |
| return False |
| |
| # If right's argument is optional, left's must also be |
| # (unless we're relaxing the checks to allow potential |
| # rather then definite compatibility). |
| if not allow_partial_overlap and not right.required and left.required: |
| return False |
| |
| # If we're allowing partial overlaps and neither arg is required, |
| # the types don't actually need to be the same |
| if allow_partial_overlap and not left.required and not right.required: |
| return True |
| |
| # Left must have a more general type |
| return is_compat(right.typ, left.typ) |
| |
| |
| def flip_compat_check(is_compat: Callable[[Type, Type], bool]) -> Callable[[Type, Type], bool]: |
| def new_is_compat(left: Type, right: Type) -> bool: |
| return is_compat(right, left) |
| return new_is_compat |
| |
| |
| def unify_generic_callable(type: CallableType, target: CallableType, |
| ignore_return: bool, |
| return_constraint_direction: int = mypy.constraints.SUBTYPE_OF, |
| ) -> Optional[CallableType]: |
| """Try to unify a generic callable type with another callable type. |
| |
| Return unified CallableType if successful; otherwise, return None. |
| """ |
| import mypy.solve |
| constraints = [] # type: List[mypy.constraints.Constraint] |
| for arg_type, target_arg_type in zip(type.arg_types, target.arg_types): |
| c = mypy.constraints.infer_constraints( |
| arg_type, target_arg_type, mypy.constraints.SUPERTYPE_OF) |
| constraints.extend(c) |
| if not ignore_return: |
| c = mypy.constraints.infer_constraints( |
| type.ret_type, target.ret_type, return_constraint_direction) |
| constraints.extend(c) |
| type_var_ids = [tvar.id for tvar in type.variables] |
| inferred_vars = mypy.solve.solve_constraints(type_var_ids, constraints) |
| if None in inferred_vars: |
| return None |
| non_none_inferred_vars = cast(List[Type], inferred_vars) |
| msg = messages.temp_message_builder() |
| applied = mypy.applytype.apply_generic_arguments(type, non_none_inferred_vars, msg, |
| context=target) |
| if msg.is_errors(): |
| return None |
| return applied |
| |
| |
| def restrict_subtype_away(t: Type, s: Type, *, ignore_promotions: bool = False) -> Type: |
| """Return t minus s. |
| |
| If we can't determine a precise result, return a supertype of the |
| ideal result (just t is a valid result). |
| |
| This is used for type inference of runtime type checks such as |
| isinstance. |
| |
| Currently this just removes elements of a union type. |
| """ |
| if isinstance(t, UnionType): |
| # Since runtime type checks will ignore type arguments, erase the types. |
| erased_s = erase_type(s) |
| # TODO: Implement more robust support for runtime isinstance() checks, |
| # see issue #3827 |
| new_items = [item for item in t.relevant_items() |
| if (not (is_proper_subtype(erase_type(item), erased_s, |
| ignore_promotions=ignore_promotions) or |
| is_proper_subtype(item, erased_s, |
| ignore_promotions=ignore_promotions)) |
| or isinstance(item, AnyType))] |
| return UnionType.make_union(new_items) |
| else: |
| return t |
| |
| |
| def is_proper_subtype(left: Type, right: Type, *, ignore_promotions: bool = False) -> bool: |
| """Is left a proper subtype of right? |
| |
| For proper subtypes, there's no need to rely on compatibility due to |
| Any types. Every usable type is a proper subtype of itself. |
| """ |
| if isinstance(right, UnionType) and not isinstance(left, UnionType): |
| return any([is_proper_subtype(left, item, ignore_promotions=ignore_promotions) |
| for item in right.items]) |
| return left.accept(ProperSubtypeVisitor(right, ignore_promotions=ignore_promotions)) |
| |
| |
| class ProperSubtypeVisitor(TypeVisitor[bool]): |
| def __init__(self, right: Type, *, ignore_promotions: bool = False) -> None: |
| self.right = right |
| self.ignore_promotions = ignore_promotions |
| self._subtype_kind = ProperSubtypeVisitor.build_subtype_kind( |
| ignore_promotions=ignore_promotions, |
| ) |
| |
| @staticmethod |
| def build_subtype_kind(*, ignore_promotions: bool = False) -> SubtypeKind: |
| return (True, ignore_promotions) |
| |
| def _is_proper_subtype(self, left: Type, right: Type) -> bool: |
| return is_proper_subtype(left, right, ignore_promotions=self.ignore_promotions) |
| |
| def visit_unbound_type(self, left: UnboundType) -> bool: |
| # This can be called if there is a bad type annotation. The result probably |
| # doesn't matter much but by returning True we simplify these bad types away |
| # from unions, which could filter out some bogus messages. |
| return True |
| |
| def visit_any(self, left: AnyType) -> bool: |
| return isinstance(self.right, AnyType) |
| |
| def visit_none_type(self, left: NoneTyp) -> bool: |
| if state.strict_optional: |
| return (isinstance(self.right, NoneTyp) or |
| is_named_instance(self.right, 'builtins.object')) |
| return True |
| |
| def visit_uninhabited_type(self, left: UninhabitedType) -> bool: |
| return True |
| |
| def visit_erased_type(self, left: ErasedType) -> bool: |
| # This may be encountered during type inference. The result probably doesn't |
| # matter much. |
| return True |
| |
| def visit_deleted_type(self, left: DeletedType) -> bool: |
| return True |
| |
| def visit_instance(self, left: Instance) -> bool: |
| right = self.right |
| if isinstance(right, Instance): |
| if TypeState.is_cached_subtype_check(self._subtype_kind, left, right): |
| return True |
| if not self.ignore_promotions: |
| for base in left.type.mro: |
| if base._promote and self._is_proper_subtype(base._promote, right): |
| TypeState.record_subtype_cache_entry(self._subtype_kind, left, right) |
| return True |
| |
| if left.type.has_base(right.type.fullname()): |
| def check_argument(leftarg: Type, rightarg: Type, variance: int) -> bool: |
| if variance == COVARIANT: |
| return self._is_proper_subtype(leftarg, rightarg) |
| elif variance == CONTRAVARIANT: |
| return self._is_proper_subtype(rightarg, leftarg) |
| else: |
| return mypy.sametypes.is_same_type(leftarg, rightarg) |
| # Map left type to corresponding right instances. |
| left = map_instance_to_supertype(left, right.type) |
| |
| nominal = all(check_argument(ta, ra, tvar.variance) for ta, ra, tvar in |
| zip(left.args, right.args, right.type.defn.type_vars)) |
| if nominal: |
| TypeState.record_subtype_cache_entry(self._subtype_kind, left, right) |
| return nominal |
| if (right.type.is_protocol and |
| is_protocol_implementation(left, right, proper_subtype=True)): |
| return True |
| return False |
| if isinstance(right, CallableType): |
| call = find_member('__call__', left, left) |
| if call: |
| return self._is_proper_subtype(call, right) |
| return False |
| return False |
| |
| def visit_type_var(self, left: TypeVarType) -> bool: |
| if isinstance(self.right, TypeVarType) and left.id == self.right.id: |
| return True |
| if left.values and self._is_proper_subtype(UnionType.make_simplified_union(left.values), |
| self.right): |
| return True |
| return self._is_proper_subtype(left.upper_bound, self.right) |
| |
| def visit_callable_type(self, left: CallableType) -> bool: |
| right = self.right |
| if isinstance(right, CallableType): |
| return is_callable_compatible(left, right, is_compat=self._is_proper_subtype) |
| elif isinstance(right, Overloaded): |
| return all(self._is_proper_subtype(left, item) |
| for item in right.items()) |
| elif isinstance(right, Instance): |
| return self._is_proper_subtype(left.fallback, right) |
| elif isinstance(right, TypeType): |
| # This is unsound, we don't check the __init__ signature. |
| return left.is_type_obj() and self._is_proper_subtype(left.ret_type, right.item) |
| return False |
| |
| def visit_tuple_type(self, left: TupleType) -> bool: |
| right = self.right |
| if isinstance(right, Instance): |
| if (is_named_instance(right, 'builtins.tuple') or |
| is_named_instance(right, 'typing.Iterable') or |
| is_named_instance(right, 'typing.Container') or |
| is_named_instance(right, 'typing.Sequence') or |
| is_named_instance(right, 'typing.Reversible')): |
| if not right.args: |
| return False |
| iter_type = right.args[0] |
| if is_named_instance(right, 'builtins.tuple') and isinstance(iter_type, AnyType): |
| # TODO: We shouldn't need this special case. This is currently needed |
| # for isinstance(x, tuple), though it's unclear why. |
| return True |
| return all(self._is_proper_subtype(li, iter_type) for li in left.items) |
| return self._is_proper_subtype(mypy.typeops.tuple_fallback(left), right) |
| elif isinstance(right, TupleType): |
| if len(left.items) != len(right.items): |
| return False |
| for l, r in zip(left.items, right.items): |
| if not self._is_proper_subtype(l, r): |
| return False |
| return self._is_proper_subtype(mypy.typeops.tuple_fallback(left), |
| mypy.typeops.tuple_fallback(right)) |
| return False |
| |
| def visit_typeddict_type(self, left: TypedDictType) -> bool: |
| right = self.right |
| if isinstance(right, TypedDictType): |
| for name, typ in left.items.items(): |
| if (name in right.items |
| and not mypy.sametypes.is_same_type(typ, right.items[name])): |
| return False |
| for name, typ in right.items.items(): |
| if name not in left.items: |
| return False |
| return True |
| return self._is_proper_subtype(left.fallback, right) |
| |
| def visit_literal_type(self, left: LiteralType) -> bool: |
| if isinstance(self.right, LiteralType): |
| return left == self.right |
| else: |
| return self._is_proper_subtype(left.fallback, self.right) |
| |
| def visit_overloaded(self, left: Overloaded) -> bool: |
| # TODO: What's the right thing to do here? |
| return False |
| |
| def visit_union_type(self, left: UnionType) -> bool: |
| return all([self._is_proper_subtype(item, self.right) for item in left.items]) |
| |
| def visit_partial_type(self, left: PartialType) -> bool: |
| # TODO: What's the right thing to do here? |
| return False |
| |
| def visit_type_type(self, left: TypeType) -> bool: |
| right = self.right |
| if isinstance(right, TypeType): |
| # This is unsound, we don't check the __init__ signature. |
| return self._is_proper_subtype(left.item, right.item) |
| if isinstance(right, CallableType): |
| # This is also unsound because of __init__. |
| return right.is_type_obj() and self._is_proper_subtype(left.item, right.ret_type) |
| if isinstance(right, Instance): |
| if right.type.fullname() == 'builtins.type': |
| # TODO: Strictly speaking, the type builtins.type is considered equivalent to |
| # Type[Any]. However, this would break the is_proper_subtype check in |
| # conditional_type_map for cases like isinstance(x, type) when the type |
| # of x is Type[int]. It's unclear what's the right way to address this. |
| return True |
| if right.type.fullname() == 'builtins.object': |
| return True |
| item = left.item |
| if isinstance(item, TypeVarType): |
| item = item.upper_bound |
| if isinstance(item, Instance): |
| metaclass = item.type.metaclass_type |
| return metaclass is not None and self._is_proper_subtype(metaclass, right) |
| return False |
| |
| |
| def is_more_precise(left: Type, right: Type, *, ignore_promotions: bool = False) -> bool: |
| """Check if left is a more precise type than right. |
| |
| A left is a proper subtype of right, left is also more precise than |
| right. Also, if right is Any, left is more precise than right, for |
| any left. |
| """ |
| # TODO Should List[int] be more precise than List[Any]? |
| if isinstance(right, AnyType): |
| return True |
| return is_proper_subtype(left, right, ignore_promotions=ignore_promotions) |