Beispiel #1
0
 def visit_tuple_type(self, left: TupleType) -> bool:
     right = self.right
     if isinstance(right, Instance):
         if is_named_instance(right, 'builtins.object'):
             return True
         if is_named_instance(right, 'builtins.tuple'):
             target_item_type = right.args[0]
             return all(is_subtype(item, target_item_type)
                        for item in left.items)
         elif (is_named_instance(right, 'typing.Iterable') or
               is_named_instance(right, 'typing.Sequence') or
               is_named_instance(right, 'typing.Reversible')):
             iter_type = right.args[0]
             return all(is_subtype(li, iter_type) for li in left.items)
         return False
     elif isinstance(right, TupleType):
         if len(left.items) != len(right.items):
             return False
         for i in range(len(left.items)):
             if not is_subtype(left.items[i], right.items[i], self.check_type_parameter):
                 return False
         if not is_subtype(left.fallback, right.fallback, self.check_type_parameter):
             return False
         return True
     else:
         return False
Beispiel #2
0
 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 right.fallback.type.is_enum:
         return is_subtype(left, right.fallback)
     if isinstance(right, Instance):
         if TypeState.is_cached_subtype_check(left, right):
             return True
         # NOTE: left.type.mro may be None in quick mode if there
         # was an error somewhere.
         if left.type.mro is not None:
             for base in left.type.mro:
                 # TODO: Also pass recursively ignore_declared_variance
                 if base._promote and is_subtype(
                         base._promote, self.right, self.check_type_parameter,
                         ignore_pos_arg_names=self.ignore_pos_arg_names):
                     TypeState.record_subtype_cache_entry(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(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 = item.fallback
         if is_named_instance(left, 'builtins.type'):
             return 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 is_subtype(call, right)
         return False
     else:
         return False
Beispiel #3
0
 def visit_tuple_type(self, left: TupleType) -> bool:
     right = self.right
     if isinstance(right, Instance):
         if is_named_instance(right, 'builtins.object'):
             return True
         if is_named_instance(right, 'builtins.tuple'):
             target_item_type = right.args[0]
             return all(
                 is_subtype(item, target_item_type) for item in left.items)
         elif (is_named_instance(right, 'typing.Iterable')
               or is_named_instance(right, 'typing.Sequence')
               or is_named_instance(right, 'typing.Reversible')):
             iter_type = right.args[0]
             return all(is_subtype(li, iter_type) for li in left.items)
         return False
     elif isinstance(right, TupleType):
         if len(left.items) != len(right.items):
             return False
         for i in range(len(left.items)):
             if not is_subtype(left.items[i], right.items[i],
                               self.check_type_parameter):
                 return False
         if not is_subtype(left.fallback, right.fallback,
                           self.check_type_parameter):
             return False
         return True
     else:
         return False
Beispiel #4
0
 def visit_instance(self, left: Instance) -> bool:
     if left.type.fallback_to_any:
         return True
     right = self.right
     if isinstance(right, TupleType) and right.fallback.type.is_enum:
         return is_subtype(left, right.fallback)
     if isinstance(right, Instance):
         if right.type.is_cached_subtype_check(left, right):
             return True
         # NOTE: left.type.mro may be None in quick mode if there
         # was an error somewhere.
         if left.type.mro is not None:
             for base in left.type.mro:
                 # TODO: Also pass recursively ignore_declared_variance
                 if base._promote and is_subtype(
                         base._promote, self.right, self.check_type_parameter,
                         ignore_pos_arg_names=self.ignore_pos_arg_names):
                     right.type.record_subtype_cache_entry(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:
                 right.type.record_subtype_cache_entry(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 = item.fallback
         if is_named_instance(left, 'builtins.type'):
             return is_subtype(TypeType(AnyType(TypeOfAny.special_form)), right)
         if left.type.is_metaclass():
             if isinstance(item, AnyType):
                 return True
             if isinstance(item, Instance):
                 # Special-case enum since we don't have better way of expressing it
                 if (is_named_instance(left, 'enum.EnumMeta')
                         and is_named_instance(item, 'enum.Enum')):
                     return True
                 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 is_subtype(call, right)
         return False
     else:
         return False
Beispiel #5
0
 def visit_instance(self, left: Instance) -> bool:
     if left.type.fallback_to_any:
         return True
     right = self.right
     if isinstance(right, TupleType) and right.fallback.type.is_enum:
         return is_subtype(left, right.fallback)
     if isinstance(right, Instance):
         if right.type.is_cached_subtype_check(left, right):
             return True
         # NOTE: left.type.mro may be None in quick mode if there
         # was an error somewhere.
         if left.type.mro is not None:
             for base in left.type.mro:
                 # TODO: Also pass recursively ignore_declared_variance
                 if base._promote and is_subtype(
                         base._promote, self.right, self.check_type_parameter,
                         ignore_pos_arg_names=self.ignore_pos_arg_names):
                     right.type.record_subtype_cache_entry(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:
                 right.type.record_subtype_cache_entry(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 = item.fallback
         if is_named_instance(left, 'builtins.type'):
             return is_subtype(TypeType(AnyType(TypeOfAny.special_form)), right)
         if left.type.is_metaclass():
             if isinstance(item, AnyType):
                 return True
             if isinstance(item, Instance):
                 # Special-case enum since we don't have better way of expressing it
                 if (is_named_instance(left, 'enum.EnumMeta')
                         and is_named_instance(item, 'enum.Enum')):
                     return True
                 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 is_subtype(call, right)
         return False
     else:
         return False
Beispiel #6
0
 def visit_callable_type(self, left: CallableType) -> bool:
     right = self.right
     if isinstance(right, CallableType):
         return is_callable_subtype(left, right)
     elif isinstance(right, Overloaded):
         return all(is_subtype(left, item) for item in right.items())
     elif is_named_instance(right, 'builtins.object'):
         return True
     elif (is_named_instance(right, 'builtins.type') and
           left.is_type_obj()):
         return True
     else:
         return False
Beispiel #7
0
 def visit_callable_type(self, left: CallableType) -> bool:
     right = self.right
     if isinstance(right, CallableType):
         return is_callable_subtype(left, right)
     elif isinstance(right, Overloaded):
         return all(is_subtype(left, item) for item in right.items())
     elif is_named_instance(right, 'builtins.object'):
         return True
     elif (is_named_instance(right, 'builtins.type') and
           left.is_type_obj()):
         return True
     else:
         return False
Beispiel #8
0
 def visit_instance(self, template: Instance) -> List[Constraint]:
     actual = self.actual
     res = []  # type: List[Constraint]
     if isinstance(actual, CallableType) and actual.fallback is not None:
         actual = actual.fallback
     if isinstance(actual, TypedDictType):
         actual = actual.as_anonymous().fallback
     if isinstance(actual, Instance):
         instance = actual
         if (self.direction == SUBTYPE_OF
                 and template.type.has_base(instance.type.fullname())):
             mapped = map_instance_to_supertype(template, instance.type)
             for i in range(len(instance.args)):
                 # The constraints for generic type parameters are
                 # invariant. Include constraints from both directions
                 # to achieve the effect.
                 res.extend(
                     infer_constraints(mapped.args[i], instance.args[i],
                                       self.direction))
                 res.extend(
                     infer_constraints(mapped.args[i], instance.args[i],
                                       neg_op(self.direction)))
             return res
         elif (self.direction == SUPERTYPE_OF
               and instance.type.has_base(template.type.fullname())):
             mapped = map_instance_to_supertype(instance, template.type)
             for j in range(len(template.args)):
                 # The constraints for generic type parameters are
                 # invariant.
                 res.extend(
                     infer_constraints(template.args[j], mapped.args[j],
                                       self.direction))
                 res.extend(
                     infer_constraints(template.args[j], mapped.args[j],
                                       neg_op(self.direction)))
             return res
     if isinstance(actual, AnyType):
         # IDEA: Include both ways, i.e. add negation as well?
         return self.infer_against_any(template.args, actual)
     if (isinstance(actual, TupleType)
             and (is_named_instance(template, 'typing.Iterable')
                  or is_named_instance(template, 'typing.Container')
                  or is_named_instance(template, 'typing.Sequence')
                  or is_named_instance(template, 'typing.Reversible'))
             and self.direction == SUPERTYPE_OF):
         for item in actual.items:
             cb = infer_constraints(template.args[0], item, SUPERTYPE_OF)
             res.extend(cb)
         return res
     else:
         return []
Beispiel #9
0
def is_subtype(
        left: Type,
        right: Type,
        type_parameter_checker: TypeParameterChecker = check_type_parameter,
        *,
        ignore_pos_arg_names: 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,
                       type_parameter_checker,
                       ignore_pos_arg_names=ignore_pos_arg_names)
            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
    # Treat builtins.type the same as Type[Any]
    elif is_named_instance(left, 'builtins.type'):
        return is_subtype(TypeType(AnyType()), right)
    elif is_named_instance(right, 'builtins.type'):
        return is_subtype(left, TypeType(AnyType()))
    return left.accept(
        SubtypeVisitor(right,
                       type_parameter_checker,
                       ignore_pos_arg_names=ignore_pos_arg_names))
Beispiel #10
0
 def visit_overloaded(self, left: Overloaded) -> bool:
     right = self.right
     if isinstance(right, Instance):
         return is_subtype(left.fallback, right)
     elif isinstance(right, CallableType) or is_named_instance(
             right, 'builtins.type'):
         for item in left.items():
             if is_subtype(item, right, self.check_type_parameter,
                           ignore_pos_arg_names=self.ignore_pos_arg_names):
                 return True
         return False
     elif isinstance(right, Overloaded):
         # TODO: this may be too restrictive
         if len(left.items()) != len(right.items()):
             return False
         for i in range(len(left.items())):
             if not is_subtype(left.items()[i], right.items()[i], self.check_type_parameter,
                               ignore_pos_arg_names=self.ignore_pos_arg_names):
                 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 the __init__ signature.
         return left.is_type_obj() and is_subtype(left.items()[0].ret_type, right.item)
     else:
         return False
Beispiel #11
0
 def visit_none_type(self, left: NoneTyp) -> bool:
     if experiments.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
Beispiel #12
0
 def visit_none_type(self, left: NoneTyp) -> bool:
     if experiments.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
Beispiel #13
0
    def visit_instance(self, left: Instance) -> bool:
        if left.type.fallback_to_any:
            return True
        right = self.right
        if isinstance(right, TupleType) and right.fallback.type.is_enum:
            return is_subtype(left, right.fallback)
        if isinstance(right, Instance):
            # NOTO: left.type.mro may be None in quick mode if there
            # was an error somewhere.
            if left.type.mro is not None:
                for base in left.type.mro:
                    if base._promote and is_subtype(
                            base._promote,
                            self.right,
                            self.check_type_parameter,
                            ignore_pos_arg_names=self.ignore_pos_arg_names):
                        return True
            rname = right.type.fullname()
            if not left.type.has_base(rname) and rname != 'builtins.object':
                return False

            # Map left type to corresponding right instances.
            t = map_instance_to_supertype(left, right.type)

            return 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 isinstance(right, TypeType):
            item = right.item
            if isinstance(item, TupleType):
                item = item.fallback
            if is_named_instance(left, 'builtins.type'):
                return is_subtype(TypeType(AnyType()), right)
            if left.type.is_metaclass():
                if isinstance(item, AnyType):
                    return True
                if isinstance(item, Instance):
                    # Special-case enum since we don't have better way of expressing it
                    if (is_named_instance(left, 'enum.EnumMeta')
                            and is_named_instance(item, 'enum.Enum')):
                        return True
                    return is_named_instance(item, 'builtins.object')
        return False
Beispiel #14
0
 def visit_instance(self, template: Instance) -> List[Constraint]:
     actual = self.actual
     res = []  # type: List[Constraint]
     if isinstance(actual, Instance):
         instance = actual
         if (self.direction == SUBTYPE_OF and
                 template.type.has_base(instance.type.fullname())):
             mapped = map_instance_to_supertype(template, instance.type)
             for i in range(len(instance.args)):
                 # The constraints for generic type parameters are
                 # invariant. Include constraints from both directions
                 # to achieve the effect.
                 res.extend(infer_constraints(
                     mapped.args[i], instance.args[i], self.direction))
                 res.extend(infer_constraints(
                     mapped.args[i], instance.args[i], neg_op(self.direction)))
             return res
         elif (self.direction == SUPERTYPE_OF and
                 instance.type.has_base(template.type.fullname())):
             mapped = map_instance_to_supertype(instance, template.type)
             for j in range(len(template.args)):
                 # The constraints for generic type parameters are
                 # invariant.
                 res.extend(infer_constraints(
                     template.args[j], mapped.args[j], self.direction))
                 res.extend(infer_constraints(
                     template.args[j], mapped.args[j], neg_op(self.direction)))
             return res
     if isinstance(actual, AnyType):
         # IDEA: Include both ways, i.e. add negation as well?
         return self.infer_against_any(template.args)
     if (isinstance(actual, TupleType) and
         (is_named_instance(template, 'typing.Iterable') or
          is_named_instance(template, 'typing.Container') or
          is_named_instance(template, 'typing.Sequence') or
          is_named_instance(template, 'typing.Reversible'))
             and self.direction == SUPERTYPE_OF):
         for item in actual.items:
             cb = infer_constraints(template.args[0], item, SUPERTYPE_OF)
             res.extend(cb)
         return res
     else:
         return []
Beispiel #15
0
 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(is_proper_subtype(li, iter_type) for li in left.items)
         return is_proper_subtype(left.fallback, 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 is_proper_subtype(l, r):
                 return False
         return is_proper_subtype(left.fallback, right.fallback)
     return False
Beispiel #16
0
 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()
             return all(is_subtype(li, iter_type) for li in left.items)
         elif is_subtype(left.fallback, right, self.check_type_parameter):
             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 is_subtype(l, r, self.check_type_parameter):
                 return False
         if not is_subtype(left.fallback, right.fallback, self.check_type_parameter):
             return False
         return True
     else:
         return False
Beispiel #17
0
 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(is_proper_subtype(li, iter_type) for li in left.items)
         return is_proper_subtype(left.fallback, 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 is_proper_subtype(l, r):
                 return False
         return is_proper_subtype(left.fallback, right.fallback)
     return False
Beispiel #18
0
 def visit_overloaded(self, left: Overloaded) -> bool:
     right = self.right
     if is_named_instance(right, 'builtins.object'):
         return True
     elif isinstance(right, CallableType) or is_named_instance(
             right, 'builtins.type'):
         for item in left.items():
             if is_subtype(item, right):
                 return True
         return False
     elif isinstance(right, Overloaded):
         # TODO: this may be too restrictive
         if len(left.items()) != len(right.items()):
             return False
         for i in range(len(left.items())):
             if not is_subtype(left.items()[i], right.items()[i]):
                 return False
         return True
     elif isinstance(right, UnboundType):
         return True
     else:
         return False
Beispiel #19
0
 def visit_overloaded(self, left: Overloaded) -> bool:
     right = self.right
     if is_named_instance(right, 'builtins.object'):
         return True
     elif isinstance(right, CallableType) or is_named_instance(
             right, 'builtins.type'):
         for item in left.items():
             if is_subtype(item, right):
                 return True
         return False
     elif isinstance(right, Overloaded):
         # TODO: this may be too restrictive
         if len(left.items()) != len(right.items()):
             return False
         for i in range(len(left.items())):
             if not is_subtype(left.items()[i], right.items()[i]):
                 return False
         return True
     elif isinstance(right, UnboundType):
         return True
     else:
         return False
def is_subtype(
        left: Type,
        right: Type,
        type_parameter_checker: TypeParameterChecker = check_type_parameter,
        *,
        ignore_pos_arg_names: 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):
        return any(
            is_subtype(left,
                       item,
                       type_parameter_checker,
                       ignore_pos_arg_names=ignore_pos_arg_names)
            for item in right.items)
    # Treat builtins.type the same as Type[Any]
    elif is_named_instance(left, 'builtins.type'):
        return is_subtype(TypeType(AnyType()), right)
    elif is_named_instance(right, 'builtins.type'):
        return is_subtype(left, TypeType(AnyType()))
    else:
        return left.accept(
            SubtypeVisitor(right,
                           type_parameter_checker,
                           ignore_pos_arg_names=ignore_pos_arg_names))
Beispiel #21
0
 def visit_overloaded(self, left: Overloaded) -> bool:
     right = self.right
     if isinstance(right, Instance):
         return is_subtype(left.fallback, right)
     elif isinstance(right, CallableType) or is_named_instance(right, "builtins.type"):
         for item in left.items():
             if is_subtype(item, right, self.check_type_parameter):
                 return True
         return False
     elif isinstance(right, Overloaded):
         # TODO: this may be too restrictive
         if len(left.items()) != len(right.items()):
             return False
         for i in range(len(left.items())):
             if not is_subtype(left.items()[i], right.items()[i], self.check_type_parameter):
                 return False
         return True
     elif isinstance(right, UnboundType):
         return True
     else:
         return False
Beispiel #22
0
 def visit_type_var(self, left: TypeVarType) -> bool:
     right = self.right
     if isinstance(right, TypeVarType):
         return left.id == right.id
     else:
         return is_named_instance(self.right, 'builtins.object')
Beispiel #23
0
 def visit_instance(self, template: Instance) -> List[Constraint]:
     original_actual = actual = self.actual
     res = []  # type: List[Constraint]
     if isinstance(actual, CallableType) and actual.fallback is not None:
         actual = actual.fallback
     if isinstance(actual, TypedDictType):
         actual = actual.as_anonymous().fallback
     if isinstance(actual, Instance):
         instance = actual
         # We always try nominal inference if possible,
         # it is much faster than the structural one.
         if (self.direction == SUBTYPE_OF
                 and template.type.has_base(instance.type.fullname())):
             mapped = map_instance_to_supertype(template, instance.type)
             for i in range(len(instance.args)):
                 # The constraints for generic type parameters are
                 # invariant. Include constraints from both directions
                 # to achieve the effect.
                 res.extend(
                     infer_constraints(mapped.args[i], instance.args[i],
                                       self.direction))
                 res.extend(
                     infer_constraints(mapped.args[i], instance.args[i],
                                       neg_op(self.direction)))
             return res
         elif (self.direction == SUPERTYPE_OF
               and instance.type.has_base(template.type.fullname())):
             mapped = map_instance_to_supertype(instance, template.type)
             for j in range(len(template.args)):
                 # The constraints for generic type parameters are
                 # invariant.
                 res.extend(
                     infer_constraints(template.args[j], mapped.args[j],
                                       self.direction))
                 res.extend(
                     infer_constraints(template.args[j], mapped.args[j],
                                       neg_op(self.direction)))
             return res
         if (template.type.is_protocol and self.direction == SUPERTYPE_OF
                 and
                 # We avoid infinite recursion for structural subtypes by checking
                 # whether this type already appeared in the inference chain.
                 # This is a conservative way break the inference cycles.
                 # It never produces any "false" constraints but gives up soon
                 # on purely structural inference cycles, see #3829.
                 not any(
                     is_same_type(template, t)
                     for t in template.type.inferring)
                 and mypy.subtypes.is_subtype(instance,
                                              erase_typevars(template))):
             template.type.inferring.append(template)
             self.infer_constraints_from_protocol_members(
                 res, instance, template, original_actual, template)
             template.type.inferring.pop()
             return res
         elif (instance.type.is_protocol and self.direction == SUBTYPE_OF
               and
               # We avoid infinite recursion for structural subtypes also here.
               not any(
                   is_same_type(instance, i)
                   for i in instance.type.inferring)
               and mypy.subtypes.is_subtype(erase_typevars(template),
                                            instance)):
             instance.type.inferring.append(instance)
             self.infer_constraints_from_protocol_members(
                 res, instance, template, template, instance)
             instance.type.inferring.pop()
             return res
     if isinstance(actual, AnyType):
         # IDEA: Include both ways, i.e. add negation as well?
         return self.infer_against_any(template.args, actual)
     if (isinstance(actual, TupleType)
             and (is_named_instance(template, 'typing.Iterable')
                  or is_named_instance(template, 'typing.Container')
                  or is_named_instance(template, 'typing.Sequence')
                  or is_named_instance(template, 'typing.Reversible'))
             and self.direction == SUPERTYPE_OF):
         for item in actual.items:
             cb = infer_constraints(template.args[0], item, SUPERTYPE_OF)
             res.extend(cb)
         return res
     elif isinstance(actual, TupleType) and self.direction == SUPERTYPE_OF:
         return infer_constraints(template, actual.fallback, self.direction)
     else:
         return []
Beispiel #24
0
 def visit_instance(self, template: Instance) -> List[Constraint]:
     original_actual = actual = self.actual
     res = []  # type: List[Constraint]
     if isinstance(actual, CallableType) and actual.fallback is not None:
         actual = actual.fallback
     if isinstance(actual, TypedDictType):
         actual = actual.as_anonymous().fallback
     if isinstance(actual, Instance):
         instance = actual
         # We always try nominal inference if possible,
         # it is much faster than the structural one.
         if (self.direction == SUBTYPE_OF and
                 template.type.has_base(instance.type.fullname())):
             mapped = map_instance_to_supertype(template, instance.type)
             for i in range(len(instance.args)):
                 # The constraints for generic type parameters are
                 # invariant. Include constraints from both directions
                 # to achieve the effect.
                 res.extend(infer_constraints(
                     mapped.args[i], instance.args[i], self.direction))
                 res.extend(infer_constraints(
                     mapped.args[i], instance.args[i], neg_op(self.direction)))
             return res
         elif (self.direction == SUPERTYPE_OF and
                 instance.type.has_base(template.type.fullname())):
             mapped = map_instance_to_supertype(instance, template.type)
             for j in range(len(template.args)):
                 # The constraints for generic type parameters are
                 # invariant.
                 res.extend(infer_constraints(
                     template.args[j], mapped.args[j], self.direction))
                 res.extend(infer_constraints(
                     template.args[j], mapped.args[j], neg_op(self.direction)))
             return res
         if (template.type.is_protocol and self.direction == SUPERTYPE_OF and
                 # We avoid infinite recursion for structural subtypes by checking
                 # whether this type already appeared in the inference chain.
                 # This is a conservative way break the inference cycles.
                 # It never produces any "false" constraints but gives up soon
                 # on purely structural inference cycles, see #3829.
                 not any(is_same_type(template, t) for t in template.type.inferring) and
                 mypy.subtypes.is_subtype(instance, erase_typevars(template))):
             template.type.inferring.append(template)
             self.infer_constraints_from_protocol_members(res, instance, template,
                                                          original_actual, template)
             template.type.inferring.pop()
             return res
         elif (instance.type.is_protocol and self.direction == SUBTYPE_OF and
               # We avoid infinite recursion for structural subtypes also here.
               not any(is_same_type(instance, i) for i in instance.type.inferring) and
               mypy.subtypes.is_subtype(erase_typevars(template), instance)):
             instance.type.inferring.append(instance)
             self.infer_constraints_from_protocol_members(res, instance, template,
                                                          template, instance)
             instance.type.inferring.pop()
             return res
     if isinstance(actual, AnyType):
         # IDEA: Include both ways, i.e. add negation as well?
         return self.infer_against_any(template.args, actual)
     if (isinstance(actual, TupleType) and
         (is_named_instance(template, 'typing.Iterable') or
          is_named_instance(template, 'typing.Container') or
          is_named_instance(template, 'typing.Sequence') or
          is_named_instance(template, 'typing.Reversible'))
             and self.direction == SUPERTYPE_OF):
         for item in actual.items:
             cb = infer_constraints(template.args[0], item, SUPERTYPE_OF)
             res.extend(cb)
         return res
     elif isinstance(actual, TupleType) and self.direction == SUPERTYPE_OF:
         return infer_constraints(template, actual.fallback, self.direction)
     else:
         return []
Beispiel #25
0
 def visit_none_type(self, left: NoneTyp) -> bool:
     if experiments.STRICT_OPTIONAL:
         return (isinstance(self.right, NoneTyp) or
                 is_named_instance(self.right, 'builtins.object'))
     else:
         return not isinstance(self.right, Void)
Beispiel #26
0
 def visit_instance(self, template: Instance) -> List[Constraint]:
     original_actual = actual = self.actual
     res: List[Constraint] = []
     if isinstance(
             actual,
         (CallableType, Overloaded)) and template.type.is_protocol:
         if template.type.protocol_members == ['__call__']:
             # Special case: a generic callback protocol
             if not any(
                     mypy.sametypes.is_same_type(template, t)
                     for t in template.type.inferring):
                 template.type.inferring.append(template)
                 call = mypy.subtypes.find_member('__call__',
                                                  template,
                                                  actual,
                                                  is_operator=True)
                 assert call is not None
                 if mypy.subtypes.is_subtype(actual, erase_typevars(call)):
                     subres = infer_constraints(call, actual,
                                                self.direction)
                     res.extend(subres)
                 template.type.inferring.pop()
                 return res
     if isinstance(actual, CallableType) and actual.fallback is not None:
         actual = actual.fallback
     if isinstance(actual, Overloaded) and actual.fallback is not None:
         actual = actual.fallback
     if isinstance(actual, TypedDictType):
         actual = actual.as_anonymous().fallback
     if isinstance(actual, LiteralType):
         actual = actual.fallback
     if isinstance(actual, Instance):
         instance = actual
         erased = erase_typevars(template)
         assert isinstance(erased, Instance)  # type: ignore
         # We always try nominal inference if possible,
         # it is much faster than the structural one.
         if (self.direction == SUBTYPE_OF
                 and template.type.has_base(instance.type.fullname)):
             mapped = map_instance_to_supertype(template, instance.type)
             tvars = mapped.type.defn.type_vars
             # N.B: We use zip instead of indexing because the lengths might have
             # mismatches during daemon reprocessing.
             for tvar, mapped_arg, instance_arg in zip(
                     tvars, mapped.args, instance.args):
                 # TODO: ParamSpecType
                 if isinstance(tvar, TypeVarType):
                     # The constraints for generic type parameters depend on variance.
                     # Include constraints from both directions if invariant.
                     if tvar.variance != CONTRAVARIANT:
                         res.extend(
                             infer_constraints(mapped_arg, instance_arg,
                                               self.direction))
                     if tvar.variance != COVARIANT:
                         res.extend(
                             infer_constraints(mapped_arg, instance_arg,
                                               neg_op(self.direction)))
             return res
         elif (self.direction == SUPERTYPE_OF
               and instance.type.has_base(template.type.fullname)):
             mapped = map_instance_to_supertype(instance, template.type)
             tvars = template.type.defn.type_vars
             # N.B: We use zip instead of indexing because the lengths might have
             # mismatches during daemon reprocessing.
             for tvar, mapped_arg, template_arg in zip(
                     tvars, mapped.args, template.args):
                 # TODO: ParamSpecType
                 if isinstance(tvar, TypeVarType):
                     # The constraints for generic type parameters depend on variance.
                     # Include constraints from both directions if invariant.
                     if tvar.variance != CONTRAVARIANT:
                         res.extend(
                             infer_constraints(template_arg, mapped_arg,
                                               self.direction))
                     if tvar.variance != COVARIANT:
                         res.extend(
                             infer_constraints(template_arg, mapped_arg,
                                               neg_op(self.direction)))
             return res
         if (template.type.is_protocol and self.direction == SUPERTYPE_OF
                 and
                 # We avoid infinite recursion for structural subtypes by checking
                 # whether this type already appeared in the inference chain.
                 # This is a conservative way to break the inference cycles.
                 # It never produces any "false" constraints but gives up soon
                 # on purely structural inference cycles, see #3829.
                 # Note that we use is_protocol_implementation instead of is_subtype
                 # because some type may be considered a subtype of a protocol
                 # due to _promote, but still not implement the protocol.
                 not any(
                     mypy.sametypes.is_same_type(template, t)
                     for t in template.type.inferring)
                 and mypy.subtypes.is_protocol_implementation(
                     instance, erased)):
             template.type.inferring.append(template)
             res.extend(
                 self.infer_constraints_from_protocol_members(
                     instance, template, original_actual, template))
             template.type.inferring.pop()
             return res
         elif (instance.type.is_protocol and self.direction == SUBTYPE_OF
               and
               # We avoid infinite recursion for structural subtypes also here.
               not any(
                   mypy.sametypes.is_same_type(instance, i)
                   for i in instance.type.inferring)
               and mypy.subtypes.is_protocol_implementation(
                   erased, instance)):
             instance.type.inferring.append(instance)
             res.extend(
                 self.infer_constraints_from_protocol_members(
                     instance, template, template, instance))
             instance.type.inferring.pop()
             return res
     if isinstance(actual, AnyType):
         return self.infer_against_any(template.args, actual)
     if (isinstance(actual, TupleType)
             and is_named_instance(template, TUPLE_LIKE_INSTANCE_NAMES)
             and self.direction == SUPERTYPE_OF):
         for item in actual.items:
             cb = infer_constraints(template.args[0], item, SUPERTYPE_OF)
             res.extend(cb)
         return res
     elif isinstance(actual, TupleType) and self.direction == SUPERTYPE_OF:
         return infer_constraints(template,
                                  mypy.typeops.tuple_fallback(actual),
                                  self.direction)
     elif isinstance(actual, TypeVarType):
         if not actual.values:
             return infer_constraints(template, actual.upper_bound,
                                      self.direction)
         return []
     else:
         return []
Beispiel #27
0
 def visit_instance(self, template: Instance) -> List[Constraint]:
     original_actual = actual = self.actual
     res = []  # type: List[Constraint]
     if isinstance(
             actual,
         (CallableType, Overloaded)) and template.type.is_protocol:
         if template.type.protocol_members == ['__call__']:
             # Special case: a generic callback protocol
             if not any(
                     mypy.sametypes.is_same_type(template, t)
                     for t in template.type.inferring):
                 template.type.inferring.append(template)
                 call = mypy.subtypes.find_member('__call__', template,
                                                  actual)
                 assert call is not None
                 if mypy.subtypes.is_subtype(actual, erase_typevars(call)):
                     subres = infer_constraints(call, actual,
                                                self.direction)
                     res.extend(subres)
                 template.type.inferring.pop()
                 return res
     if isinstance(actual, CallableType) and actual.fallback is not None:
         actual = actual.fallback
     if isinstance(actual, Overloaded) and actual.fallback is not None:
         actual = actual.fallback
     if isinstance(actual, TypedDictType):
         actual = actual.as_anonymous().fallback
     if isinstance(actual, Instance):
         instance = actual
         erased = erase_typevars(template)
         assert isinstance(erased, Instance)
         # We always try nominal inference if possible,
         # it is much faster than the structural one.
         if (self.direction == SUBTYPE_OF
                 and template.type.has_base(instance.type.fullname())):
             mapped = map_instance_to_supertype(template, instance.type)
             tvars = mapped.type.defn.type_vars
             for i in range(len(instance.args)):
                 # The constraints for generic type parameters depend on variance.
                 # Include constraints from both directions if invariant.
                 if tvars[i].variance != CONTRAVARIANT:
                     res.extend(
                         infer_constraints(mapped.args[i], instance.args[i],
                                           self.direction))
                 if tvars[i].variance != COVARIANT:
                     res.extend(
                         infer_constraints(mapped.args[i], instance.args[i],
                                           neg_op(self.direction)))
             return res
         elif (self.direction == SUPERTYPE_OF
               and instance.type.has_base(template.type.fullname())):
             mapped = map_instance_to_supertype(instance, template.type)
             tvars = template.type.defn.type_vars
             for j in range(len(template.args)):
                 # The constraints for generic type parameters depend on variance.
                 # Include constraints from both directions if invariant.
                 if tvars[j].variance != CONTRAVARIANT:
                     res.extend(
                         infer_constraints(template.args[j], mapped.args[j],
                                           self.direction))
                 if tvars[j].variance != COVARIANT:
                     res.extend(
                         infer_constraints(template.args[j], mapped.args[j],
                                           neg_op(self.direction)))
             return res
         if (template.type.is_protocol and self.direction == SUPERTYPE_OF
                 and
                 # We avoid infinite recursion for structural subtypes by checking
                 # whether this type already appeared in the inference chain.
                 # This is a conservative way break the inference cycles.
                 # It never produces any "false" constraints but gives up soon
                 # on purely structural inference cycles, see #3829.
                 # Note that we use is_protocol_implementation instead of is_subtype
                 # because some type may be considered a subtype of a protocol
                 # due to _promote, but still not implement the protocol.
                 not any(
                     mypy.sametypes.is_same_type(template, t)
                     for t in template.type.inferring)
                 and mypy.subtypes.is_protocol_implementation(
                     instance, erased)):
             template.type.inferring.append(template)
             self.infer_constraints_from_protocol_members(
                 res, instance, template, original_actual, template)
             template.type.inferring.pop()
             return res
         elif (instance.type.is_protocol and self.direction == SUBTYPE_OF
               and
               # We avoid infinite recursion for structural subtypes also here.
               not any(
                   mypy.sametypes.is_same_type(instance, i)
                   for i in instance.type.inferring)
               and mypy.subtypes.is_protocol_implementation(
                   erased, instance)):
             instance.type.inferring.append(instance)
             self.infer_constraints_from_protocol_members(
                 res, instance, template, template, instance)
             instance.type.inferring.pop()
             return res
     if isinstance(actual, AnyType):
         # IDEA: Include both ways, i.e. add negation as well?
         return self.infer_against_any(template.args, actual)
     if (isinstance(actual, TupleType)
             and (is_named_instance(template, 'typing.Iterable')
                  or is_named_instance(template, 'typing.Container')
                  or is_named_instance(template, 'typing.Sequence')
                  or is_named_instance(template, 'typing.Reversible'))
             and self.direction == SUPERTYPE_OF):
         for item in actual.items:
             cb = infer_constraints(template.args[0], item, SUPERTYPE_OF)
             res.extend(cb)
         return res
     elif isinstance(actual, TupleType) and self.direction == SUPERTYPE_OF:
         return infer_constraints(template,
                                  mypy.typeops.tuple_fallback(actual),
                                  self.direction)
     else:
         return []
Beispiel #28
0
 def visit_type_var(self, left: TypeVarType) -> bool:
     right = self.right
     if isinstance(right, TypeVarType):
         return left.id == right.id
     else:
         return is_named_instance(self.right, 'builtins.object')
Beispiel #29
0
 def visit_instance(self, template: Instance) -> List[Constraint]:
     original_actual = actual = self.actual
     res = []  # type: List[Constraint]
     if isinstance(actual, (CallableType, Overloaded)) and template.type.is_protocol:
         if template.type.protocol_members == ['__call__']:
             # Special case: a generic callback protocol
             if not any(is_same_type(template, t) for t in template.type.inferring):
                 template.type.inferring.append(template)
                 call = mypy.subtypes.find_member('__call__', template, actual)
                 assert call is not None
                 if mypy.subtypes.is_subtype(actual, erase_typevars(call)):
                     subres = infer_constraints(call, actual, self.direction)
                     res.extend(subres)
                 template.type.inferring.pop()
                 return res
     if isinstance(actual, CallableType) and actual.fallback is not None:
         actual = actual.fallback
     if isinstance(actual, Overloaded) and actual.fallback is not None:
         actual = actual.fallback
     if isinstance(actual, TypedDictType):
         actual = actual.as_anonymous().fallback
     if isinstance(actual, Instance):
         instance = actual
         erased = erase_typevars(template)
         assert isinstance(erased, Instance)
         # We always try nominal inference if possible,
         # it is much faster than the structural one.
         if (self.direction == SUBTYPE_OF and
                 template.type.has_base(instance.type.fullname())):
             mapped = map_instance_to_supertype(template, instance.type)
             tvars = mapped.type.defn.type_vars
             for i in range(len(instance.args)):
                 # The constraints for generic type parameters depend on variance.
                 # Include constraints from both directions if invariant.
                 if tvars[i].variance != CONTRAVARIANT:
                     res.extend(infer_constraints(
                         mapped.args[i], instance.args[i], self.direction))
                 if tvars[i].variance != COVARIANT:
                     res.extend(infer_constraints(
                         mapped.args[i], instance.args[i], neg_op(self.direction)))
             return res
         elif (self.direction == SUPERTYPE_OF and
                 instance.type.has_base(template.type.fullname())):
             mapped = map_instance_to_supertype(instance, template.type)
             tvars = template.type.defn.type_vars
             for j in range(len(template.args)):
                 # The constraints for generic type parameters depend on variance.
                 # Include constraints from both directions if invariant.
                 if tvars[j].variance != CONTRAVARIANT:
                     res.extend(infer_constraints(
                         template.args[j], mapped.args[j], self.direction))
                 if tvars[j].variance != COVARIANT:
                     res.extend(infer_constraints(
                         template.args[j], mapped.args[j], neg_op(self.direction)))
             return res
         if (template.type.is_protocol and self.direction == SUPERTYPE_OF and
                 # We avoid infinite recursion for structural subtypes by checking
                 # whether this type already appeared in the inference chain.
                 # This is a conservative way break the inference cycles.
                 # It never produces any "false" constraints but gives up soon
                 # on purely structural inference cycles, see #3829.
                 # Note that we use is_protocol_implementation instead of is_subtype
                 # because some type may be considered a subtype of a protocol
                 # due to _promote, but still not implement the protocol.
                 not any(is_same_type(template, t) for t in template.type.inferring) and
                 mypy.subtypes.is_protocol_implementation(instance, erased)):
             template.type.inferring.append(template)
             self.infer_constraints_from_protocol_members(res, instance, template,
                                                          original_actual, template)
             template.type.inferring.pop()
             return res
         elif (instance.type.is_protocol and self.direction == SUBTYPE_OF and
               # We avoid infinite recursion for structural subtypes also here.
               not any(is_same_type(instance, i) for i in instance.type.inferring) and
               mypy.subtypes.is_protocol_implementation(erased, instance)):
             instance.type.inferring.append(instance)
             self.infer_constraints_from_protocol_members(res, instance, template,
                                                          template, instance)
             instance.type.inferring.pop()
             return res
     if isinstance(actual, AnyType):
         # IDEA: Include both ways, i.e. add negation as well?
         return self.infer_against_any(template.args, actual)
     if (isinstance(actual, TupleType) and
         (is_named_instance(template, 'typing.Iterable') or
          is_named_instance(template, 'typing.Container') or
          is_named_instance(template, 'typing.Sequence') or
          is_named_instance(template, 'typing.Reversible'))
             and self.direction == SUPERTYPE_OF):
         for item in actual.items:
             cb = infer_constraints(template.args[0], item, SUPERTYPE_OF)
             res.extend(cb)
         return res
     elif isinstance(actual, TupleType) and self.direction == SUPERTYPE_OF:
         return infer_constraints(template, actual.fallback, self.direction)
     else:
         return []