Exemplo n.º 1
0
def infer_constraints_if_possible(template: Type, actual: Type,
                                  direction: int) -> Optional[List[Constraint]]:
    """Like infer_constraints, but return None if the input relation is
    known to be unsatisfiable, for example if template=List[T] and actual=int.
    (In this case infer_constraints would return [], just like it would for
    an automatically satisfied relation like template=List[T] and actual=object.)
    """
    if (direction == SUBTYPE_OF and
            not mypy.subtypes.is_subtype(erase_typevars(template), actual)):
        return None
    if (direction == SUPERTYPE_OF and
            not mypy.subtypes.is_subtype(actual, erase_typevars(template))):
        return None
    return infer_constraints(template, actual, direction)
Exemplo n.º 2
0
def infer_constraints_if_possible(template: Type, actual: Type,
                                  direction: int) -> Optional[List[Constraint]]:
    """Like infer_constraints, but return None if the input relation is
    known to be unsatisfiable, for example if template=List[T] and actual=int.
    (In this case infer_constraints would return [], just like it would for
    an automatically satisfied relation like template=List[T] and actual=object.)
    """
    if (direction == SUBTYPE_OF and
            not mypy.subtypes.is_subtype(erase_typevars(template), actual)):
        return None
    if (direction == SUPERTYPE_OF and
            not mypy.subtypes.is_subtype(actual, erase_typevars(template))):
        return None
    return infer_constraints(template, actual, direction)
Exemplo n.º 3
0
def has_no_typevars(typ: Type) -> bool:
    # We test if a type contains type variables by erasing all type variables
    # and comparing the result to the original type. We use comparison by equality that
    # in turn uses `__eq__` defined for types. Note: we can't use `is_same_type` because
    # it is not safe with unresolved forward references, while this function may be called
    # before forward references resolution patch pass. Note also that it is not safe to use
    # `is` comparison because `erase_typevars` doesn't preserve type identity.
    return typ == erase_typevars(typ)
Exemplo n.º 4
0
def infer_constraints_if_possible(template: Type, actual: Type,
                                  direction: int) -> Optional[List[Constraint]]:
    """Like infer_constraints, but return None if the input relation is
    known to be unsatisfiable, for example if template=List[T] and actual=int.
    (In this case infer_constraints would return [], just like it would for
    an automatically satisfied relation like template=List[T] and actual=object.)
    """
    if (direction == SUBTYPE_OF and
            not mypy.subtypes.is_subtype(erase_typevars(template), actual)):
        return None
    if (direction == SUPERTYPE_OF and
            not mypy.subtypes.is_subtype(actual, erase_typevars(template))):
        return None
    if (direction == SUPERTYPE_OF and isinstance(template, TypeVarType) and
            not mypy.subtypes.is_subtype(actual, erase_typevars(template.upper_bound))):
        # This is not caught by the above branch because of the erase_typevars() call,
        # that would return 'Any' for a type variable.
        return None
    return infer_constraints(template, actual, direction)
Exemplo n.º 5
0
def check_self_arg(functype: FunctionLike,
                   dispatched_arg_type: Type,
                   is_classmethod: bool,
                   context: Context, name: str,
                   msg: MessageBuilder) -> FunctionLike:
    """Check that an instance has a valid type for a method with annotated 'self'.

    For example if the method is defined as:
        class A:
            def f(self: S) -> T: ...
    then for 'x.f' we check that meet(type(x), A) <: S. If the method is overloaded, we
    select only overloads items that satisfy this requirement. If there are no matching
    overloads, an error is generated.

    Note: dispatched_arg_type uses a meet to select a relevant item in case if the
    original type of 'x' is a union. This is done because several special methods
    treat union types in ad-hoc manner, so we can't use MemberContext.self_type yet.
    """
    items = functype.items
    if not items:
        return functype
    new_items = []
    if is_classmethod:
        dispatched_arg_type = TypeType.make_normalized(dispatched_arg_type)
    for item in items:
        if not item.arg_types or item.arg_kinds[0] not in (ARG_POS, ARG_STAR):
            # No positional first (self) argument (*args is okay).
            msg.no_formal_self(name, item, context)
            # This is pretty bad, so just return the original signature if
            # there is at least one such error.
            return functype
        else:
            selfarg = item.arg_types[0]
            if subtypes.is_subtype(dispatched_arg_type, erase_typevars(erase_to_bound(selfarg))):
                new_items.append(item)
            elif isinstance(selfarg, ParamSpecType):
                # TODO: This is not always right. What's the most reasonable thing to do here?
                new_items.append(item)
    if not new_items:
        # Choose first item for the message (it may be not very helpful for overloads).
        msg.incompatible_self_argument(name, dispatched_arg_type, items[0],
                                       is_classmethod, context)
        return functype
    if len(new_items) == 1:
        return new_items[0]
    return Overloaded(new_items)
Exemplo n.º 6
0
    def make_type_object_wrapper(self, tdef: ClassDef) -> FuncDef:
        """Construct dynamically typed wrapper function for a class.

        It simple calls the type object and returns the result.
        """
        
        # TODO keyword args, default args and varargs
        # TODO overloads

        type_sig = cast(Callable, type_object_type(tdef.info, None))
        type_sig = cast(Callable, erasetype.erase_typevars(type_sig))
        
        init = cast(FuncDef, tdef.info.get_method('__init__'))
        arg_kinds = type_sig.arg_kinds

        # The wrapper function has a dynamically typed signature.
        wrapper_sig = Callable( [AnyType()] * len(arg_kinds),
                               arg_kinds, [None] * len(arg_kinds),
                               AnyType(), False)
        
        n = NameExpr(tdef.name) # TODO full name
        args = self.func_tf.call_args(
            init.args[1:],
            type_sig,
            wrapper_sig,
            True, False)
        call = CallExpr(n, args, arg_kinds)
        ret = ReturnStmt(call)
        

        fdef = FuncDef(tdef.name + self.tf.dynamic_suffix(),
                       init.args[1:],
                       arg_kinds, [None] * len(arg_kinds),
                       Block([ret]))
        
        fdef.type = wrapper_sig
        return fdef
Exemplo n.º 7
0
    def make_type_object_wrapper(self, tdef):
        """Construct dynamically typed wrapper function for a class.

        It simple calls the type object and returns the result.
        """
        
        # TODO keyword args, default args and varargs
        # TODO overloads

        type_sig = type_object_type(tdef.info, None)
        type_sig = erasetype.erase_typevars(type_sig)
        
        init = tdef.info.get_method('__init__')
        arg_kinds = type_sig.arg_kinds

        # The wrapper function has a dynamically typed signature.
        wrapper_sig = Callable( [Any()] * len(arg_kinds),
                               arg_kinds, [None] * len(arg_kinds),
                               Any(), False)
        
        n = NameExpr(tdef.name) # TODO full name
        args = self.func_tf.call_args(
            init.args[1:],
            type_sig,
            wrapper_sig,
            True, False)
        call = CallExpr(n, args, arg_kinds)
        ret = ReturnStmt(call)
        

        fdef = FuncDef(tdef.name + self.tf.dynamic_suffix(),
                       init.args[1:],
                       arg_kinds, [None] * len(arg_kinds),
                       Block([ret]))
        
        fdef.type = wrapper_sig
        return fdef
Exemplo n.º 8
0
def analyze_class_attribute_access(
        itype: Instance,
        name: str,
        mx: MemberContext,
        override_info: Optional[TypeInfo] = None,
        original_vars: Optional[List[TypeVarDef]] = None) -> Optional[Type]:
    """Analyze access to an attribute on a class object.

    itype is the return type of the class object callable, original_type is the type
    of E in the expression E.var, original_vars are type variables of the class callable
    (for generic classes).
    """
    info = itype.type
    if override_info:
        info = override_info

    node = info.get(name)
    if not node:
        if info.fallback_to_any:
            return AnyType(TypeOfAny.special_form)
        return None

    is_decorated = isinstance(node.node, Decorator)
    is_method = is_decorated or isinstance(node.node, FuncBase)
    if mx.is_lvalue:
        if is_method:
            mx.msg.cant_assign_to_method(mx.context)
        if isinstance(node.node, TypeInfo):
            mx.msg.fail(message_registry.CANNOT_ASSIGN_TO_TYPE, mx.context)

    # If a final attribute was declared on `self` in `__init__`, then it
    # can't be accessed on the class object.
    if node.implicit and isinstance(node.node, Var) and node.node.is_final:
        mx.msg.fail(
            message_registry.CANNOT_ACCESS_FINAL_INSTANCE_ATTR.format(
                node.node.name), mx.context)

    # An assignment to final attribute on class object is also always an error,
    # independently of types.
    if mx.is_lvalue and not mx.chk.get_final_context():
        check_final_member(name, info, mx.msg, mx.context)

    if info.is_enum and not (mx.is_lvalue or is_decorated or is_method):
        enum_literal = LiteralType(name, fallback=itype)
        # When we analyze enums, the corresponding Instance is always considered to be erased
        # due to how the signature of Enum.__new__ is `(cls: Type[_T], value: object) -> _T`
        # in typeshed. However, this is really more of an implementation detail of how Enums
        # are typed, and we really don't want to treat every single Enum value as if it were
        # from type variable substitution. So we reset the 'erased' field here.
        return itype.copy_modified(erased=False, last_known_value=enum_literal)

    t = node.type
    if t:
        if isinstance(t, PartialType):
            symnode = node.node
            assert isinstance(symnode, Var)
            return mx.chk.handle_partial_var_type(t, mx.is_lvalue, symnode,
                                                  mx.context)

        # Find the class where method/variable was defined.
        if isinstance(node.node, Decorator):
            super_info = node.node.var.info  # type: Optional[TypeInfo]
        elif isinstance(node.node, (Var, SYMBOL_FUNCBASE_TYPES)):
            super_info = node.node.info
        else:
            super_info = None

        # Map the type to how it would look as a defining class. For example:
        #     class C(Generic[T]): ...
        #     class D(C[Tuple[T, S]]): ...
        #     D[int, str].method()
        # Here itype is D[int, str], isuper is C[Tuple[int, str]].
        if not super_info:
            isuper = None
        else:
            isuper = map_instance_to_supertype(itype, super_info)

        if isinstance(node.node, Var):
            assert isuper is not None
            # Check if original variable type has type variables. For example:
            #     class C(Generic[T]):
            #         x: T
            #     C.x  # Error, ambiguous access
            #     C[int].x  # Also an error, since C[int] is same as C at runtime
            if isinstance(t, TypeVarType) or has_type_vars(t):
                # Exception: access on Type[...], including first argument of class methods is OK.
                if not isinstance(get_proper_type(mx.original_type),
                                  TypeType) or node.implicit:
                    if node.node.is_classvar:
                        message = message_registry.GENERIC_CLASS_VAR_ACCESS
                    else:
                        message = message_registry.GENERIC_INSTANCE_VAR_CLASS_ACCESS
                    mx.msg.fail(message, mx.context)

            # Erase non-mapped variables, but keep mapped ones, even if there is an error.
            # In the above example this means that we infer following types:
            #     C.x -> Any
            #     C[int].x -> int
            t = erase_typevars(expand_type_by_instance(t, isuper))

        is_classmethod = (
            (is_decorated and cast(Decorator, node.node).func.is_class)
            or (isinstance(node.node, FuncBase) and node.node.is_class))
        t = get_proper_type(t)
        if isinstance(t, FunctionLike) and is_classmethod:
            t = check_self_arg(t, mx.self_type, False, mx.context, name,
                               mx.msg)
        result = add_class_tvars(t,
                                 isuper,
                                 is_classmethod,
                                 mx.self_type,
                                 original_vars=original_vars)
        if not mx.is_lvalue:
            result = analyze_descriptor_access(mx.original_type,
                                               result,
                                               mx.builtin_type,
                                               mx.msg,
                                               mx.context,
                                               chk=mx.chk)
        return result
    elif isinstance(node.node, Var):
        mx.not_ready_callback(name, mx.context)
        return AnyType(TypeOfAny.special_form)

    if isinstance(node.node, TypeVarExpr):
        mx.msg.fail(
            message_registry.CANNOT_USE_TYPEVAR_AS_EXPRESSION.format(
                info.name, name), mx.context)
        return AnyType(TypeOfAny.from_error)

    if isinstance(node.node, TypeInfo):
        return type_object_type(node.node, mx.builtin_type)

    if isinstance(node.node, MypyFile):
        # Reference to a module object.
        return mx.builtin_type('types.ModuleType')

    if (isinstance(node.node, TypeAlias)
            and isinstance(get_proper_type(node.node.target), Instance)):
        return instance_alias_type(node.node, mx.builtin_type)

    if is_decorated:
        assert isinstance(node.node, Decorator)
        if node.node.type:
            return node.node.type
        else:
            mx.not_ready_callback(name, mx.context)
            return AnyType(TypeOfAny.from_error)
    else:
        assert isinstance(node.node, FuncBase)
        typ = function_type(node.node, mx.builtin_type('builtins.function'))
        # Note: if we are accessing class method on class object, the cls argument is bound.
        # Annotated and/or explicit class methods go through other code paths above, for
        # unannotated implicit class methods we do this here.
        if node.node.is_class:
            typ = bind_self(typ, is_classmethod=True)
        return typ
Exemplo n.º 9
0
def analyze_class_attribute_access(itype: Instance, name: str,
                                   mx: MemberContext) -> Optional[Type]:
    """original_type is the type of E in the expression E.var"""
    node = itype.type.get(name)
    if not node:
        if itype.type.fallback_to_any:
            return AnyType(TypeOfAny.special_form)
        return None

    is_decorated = isinstance(node.node, Decorator)
    is_method = is_decorated or isinstance(node.node, FuncBase)
    if mx.is_lvalue:
        if is_method:
            mx.msg.cant_assign_to_method(mx.context)
        if isinstance(node.node, TypeInfo):
            mx.msg.fail(message_registry.CANNOT_ASSIGN_TO_TYPE, mx.context)

    # If a final attribute was declared on `self` in `__init__`, then it
    # can't be accessed on the class object.
    if node.implicit and isinstance(node.node, Var) and node.node.is_final:
        mx.msg.fail(
            message_registry.CANNOT_ACCESS_FINAL_INSTANCE_ATTR.format(
                node.node.name()), mx.context)

    # An assignment to final attribute on class object is also always an error,
    # independently of types.
    if mx.is_lvalue and not mx.chk.get_final_context():
        check_final_member(name, itype.type, mx.msg, mx.context)

    if itype.type.is_enum and not (mx.is_lvalue or is_decorated or is_method):
        return itype

    t = node.type
    if t:
        if isinstance(t, PartialType):
            symnode = node.node
            assert isinstance(symnode, Var)
            return mx.chk.handle_partial_var_type(t, mx.is_lvalue, symnode,
                                                  mx.context)

        # Find the class where method/variable was defined.
        if isinstance(node.node, Decorator):
            super_info = node.node.var.info  # type: Optional[TypeInfo]
        elif isinstance(node.node, (Var, SYMBOL_FUNCBASE_TYPES)):
            super_info = node.node.info
        else:
            super_info = None

        # Map the type to how it would look as a defining class. For example:
        #     class C(Generic[T]): ...
        #     class D(C[Tuple[T, S]]): ...
        #     D[int, str].method()
        # Here itype is D[int, str], isuper is C[Tuple[int, str]].
        if not super_info:
            isuper = None
        else:
            isuper = map_instance_to_supertype(itype, super_info)

        if isinstance(node.node, Var):
            assert isuper is not None
            # Check if original variable type has type variables. For example:
            #     class C(Generic[T]):
            #         x: T
            #     C.x  # Error, ambiguous access
            #     C[int].x  # Also an error, since C[int] is same as C at runtime
            if isinstance(t, TypeVarType) or get_type_vars(t):
                # Exception: access on Type[...], including first argument of class methods is OK.
                if not isinstance(mx.original_type, TypeType):
                    mx.msg.fail(
                        message_registry.GENERIC_INSTANCE_VAR_CLASS_ACCESS,
                        mx.context)

            # Erase non-mapped variables, but keep mapped ones, even if there is an error.
            # In the above example this means that we infer following types:
            #     C.x -> Any
            #     C[int].x -> int
            t = erase_typevars(expand_type_by_instance(t, isuper))

        is_classmethod = (
            (is_decorated and cast(Decorator, node.node).func.is_class)
            or (isinstance(node.node, FuncBase) and node.node.is_class))
        result = add_class_tvars(t, itype, isuper, is_classmethod,
                                 mx.builtin_type, mx.original_type)
        if not mx.is_lvalue:
            result = analyze_descriptor_access(mx.original_type,
                                               result,
                                               mx.builtin_type,
                                               mx.msg,
                                               mx.context,
                                               chk=mx.chk)
        return result
    elif isinstance(node.node, Var):
        mx.not_ready_callback(name, mx.context)
        return AnyType(TypeOfAny.special_form)

    if isinstance(node.node, TypeVarExpr):
        mx.msg.fail(
            message_registry.CANNOT_USE_TYPEVAR_AS_EXPRESSION.format(
                itype.type.name(), name), mx.context)
        return AnyType(TypeOfAny.from_error)

    if isinstance(node.node, TypeInfo):
        return type_object_type(node.node, mx.builtin_type)

    if isinstance(node.node, MypyFile):
        # Reference to a module object.
        return mx.builtin_type('types.ModuleType')

    if isinstance(node.node, TypeAlias) and isinstance(node.node.target,
                                                       Instance):
        return instance_alias_type(node.node, mx.builtin_type)

    if is_decorated:
        assert isinstance(node.node, Decorator)
        if node.node.type:
            return node.node.type
        else:
            mx.not_ready_callback(name, mx.context)
            return AnyType(TypeOfAny.from_error)
    else:
        return function_type(cast(FuncBase, node.node),
                             mx.builtin_type('builtins.function'))
Exemplo n.º 10
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 []
Exemplo n.º 11
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 []
Exemplo n.º 12
0
def has_no_typevars(typ: Type) -> bool:
    return is_same_type(typ, erase_typevars(typ))
Exemplo n.º 13
0
def has_no_typevars(typ: Type) -> bool:
    return is_same_type(typ, erase_typevars(typ))
Exemplo n.º 14
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 []
Exemplo n.º 15
0
def analyze_class_attribute_access(itype: Instance,
                                   name: str,
                                   mx: MemberContext) -> Optional[Type]:
    """original_type is the type of E in the expression E.var"""
    node = itype.type.get(name)
    if not node:
        if itype.type.fallback_to_any:
            return AnyType(TypeOfAny.special_form)
        return None

    is_decorated = isinstance(node.node, Decorator)
    is_method = is_decorated or isinstance(node.node, FuncBase)
    if mx.is_lvalue:
        if is_method:
            mx.msg.cant_assign_to_method(mx.context)
        if isinstance(node.node, TypeInfo):
            mx.msg.fail(message_registry.CANNOT_ASSIGN_TO_TYPE, mx.context)

    # If a final attribute was declared on `self` in `__init__`, then it
    # can't be accessed on the class object.
    if node.implicit and isinstance(node.node, Var) and node.node.is_final:
        mx.msg.fail(message_registry.CANNOT_ACCESS_FINAL_INSTANCE_ATTR
                    .format(node.node.name()), mx.context)

    # An assignment to final attribute on class object is also always an error,
    # independently of types.
    if mx.is_lvalue and not mx.chk.get_final_context():
        check_final_member(name, itype.type, mx.msg, mx.context)

    if itype.type.is_enum and not (mx.is_lvalue or is_decorated or is_method):
        return itype

    t = node.type
    if t:
        if isinstance(t, PartialType):
            symnode = node.node
            assert isinstance(symnode, Var)
            return mx.chk.handle_partial_var_type(t, mx.is_lvalue, symnode, mx.context)

        # Find the class where method/variable was defined.
        if isinstance(node.node, Decorator):
            super_info = node.node.var.info  # type: Optional[TypeInfo]
        elif isinstance(node.node, (Var, SYMBOL_FUNCBASE_TYPES)):
            super_info = node.node.info
        else:
            super_info = None

        # Map the type to how it would look as a defining class. For example:
        #     class C(Generic[T]): ...
        #     class D(C[Tuple[T, S]]): ...
        #     D[int, str].method()
        # Here itype is D[int, str], isuper is C[Tuple[int, str]].
        if not super_info:
            isuper = None
        else:
            isuper = map_instance_to_supertype(itype, super_info)

        if isinstance(node.node, Var):
            assert isuper is not None
            # Check if original variable type has type variables. For example:
            #     class C(Generic[T]):
            #         x: T
            #     C.x  # Error, ambiguous access
            #     C[int].x  # Also an error, since C[int] is same as C at runtime
            if isinstance(t, TypeVarType) or get_type_vars(t):
                # Exception: access on Type[...], including first argument of class methods is OK.
                if not isinstance(mx.original_type, TypeType):
                    mx.msg.fail(message_registry.GENERIC_INSTANCE_VAR_CLASS_ACCESS, mx.context)

            # Erase non-mapped variables, but keep mapped ones, even if there is an error.
            # In the above example this means that we infer following types:
            #     C.x -> Any
            #     C[int].x -> int
            t = erase_typevars(expand_type_by_instance(t, isuper))

        is_classmethod = ((is_decorated and cast(Decorator, node.node).func.is_class)
                          or (isinstance(node.node, FuncBase) and node.node.is_class))
        result = add_class_tvars(t, itype, isuper, is_classmethod, mx.builtin_type,
                                 mx.original_type)
        if not mx.is_lvalue:
            result = analyze_descriptor_access(mx.original_type, result, mx.builtin_type,
                                               mx.msg, mx.context, chk=mx.chk)
        return result
    elif isinstance(node.node, Var):
        mx.not_ready_callback(name, mx.context)
        return AnyType(TypeOfAny.special_form)

    if isinstance(node.node, TypeVarExpr):
        mx.msg.fail(message_registry.CANNOT_USE_TYPEVAR_AS_EXPRESSION.format(
                    itype.type.name(), name), mx.context)
        return AnyType(TypeOfAny.from_error)

    if isinstance(node.node, TypeInfo):
        return type_object_type(node.node, mx.builtin_type)

    if isinstance(node.node, MypyFile):
        # Reference to a module object.
        return mx.builtin_type('types.ModuleType')

    if isinstance(node.node, TypeAlias) and isinstance(node.node.target, Instance):
        return instance_alias_type(node.node, mx.builtin_type)

    if is_decorated:
        assert isinstance(node.node, Decorator)
        if node.node.type:
            return node.node.type
        else:
            mx.not_ready_callback(name, mx.context)
            return AnyType(TypeOfAny.from_error)
    else:
        return function_type(cast(FuncBase, node.node), mx.builtin_type('builtins.function'))
Exemplo n.º 16
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 []
Exemplo n.º 17
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 []
Exemplo n.º 18
0
        tvar = translate_runtime_type_vars_locally(tvar)
        
        # Build the rvalue (initializer) expression
        return TypeExpr(tvar)

    FuncDef make_type_object_wrapper(self, TypeDef tdef):
        """Construct dynamically typed wrapper function for a class.

        It simple calls the type object and returns the result.
        """
        
        # TODO keyword args, default args and varargs
        # TODO overloads

        type_sig = (Callable)type_object_type(tdef.info, None)
        type_sig = (Callable)erasetype.erase_typevars(type_sig)
        
        init = (FuncDef)tdef.info.get_method('__init__')
        arg_kinds = type_sig.arg_kinds

        # The wrapper function has a dynamically typed signature.
        wrapper_sig = Callable(<Type> [Any()] * len(arg_kinds),
                               arg_kinds,
                               <str> [None] * len(arg_kinds),
                               Any(), False)
        
        n = NameExpr(tdef.name) # TODO full name
        args = self.func_tf.call_args(
            init.args[1:],
            type_sig,
            wrapper_sig,