コード例 #1
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
コード例 #2
0
ファイル: subtypes.py プロジェクト: troyboy1102/Python
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 sametypes.is_same_type(l, left) and 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
            # 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
                is_compat = is_subtype(subtype,
                                       supertype,
                                       ignore_pos_arg_names=True)
            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 proper_subtype:
        TypeState.record_proper_subtype_cache_entry(left, right)
    else:
        TypeState.record_subtype_cache_entry(left, right)
    return True