Example #1
0
 def no_variant_matches_arguments(self, overload: Overloaded,
                                   context: Context) -> None:
     if overload.name():
         self.fail('No overload variant of {} matches argument types'
                   .format(overload.name()), context)
     else:
         self.fail('No overload variant matches argument types', context)
Example #2
0
 def no_variant_matches_arguments(self, overload: Overloaded, arg_types: List[Type],
                                  context: Context) -> None:
     if overload.name():
         self.fail('No overload variant of {} matches argument types {}'
                   .format(overload.name(), arg_types), context)
     else:
         self.fail('No overload variant matches argument types {}'.format(arg_types), context)
Example #3
0
 def visit_overloaded(self, t: Overloaded) -> Type:
     items = []  # type: List[CallableType]
     for item in t.items():
         new_item = item.accept(self)
         assert isinstance(new_item, CallableType)
         items.append(new_item)
     return Overloaded(items)
Example #4
0
 def visit_overloaded(self, t: Overloaded) -> Type:
     items = []  # type: List[CallableType]
     for item in t.items():
         new = item.accept(self)
         if isinstance(new, CallableType):
             items.append(new)
         else:
             raise RuntimeError('CallableType expected, but got {}'.format(type(new)))
     return Overloaded(items=items)
Example #5
0
File: meet.py Project: chadrik/mypy
 def visit_overloaded(self, t: Overloaded) -> Type:
     # TODO: Implement a better algorithm that covers at least the same cases
     # as TypeJoinVisitor.visit_overloaded().
     s = self.s
     if isinstance(s, FunctionLike):
         if s.items() == t.items():
             return Overloaded(t.items())
         elif is_subtype(s, t):
             return s
         elif is_subtype(t, s):
             return t
         else:
             return meet_types(t.fallback, s.fallback)
     elif isinstance(self.s, Instance) and self.s.type.is_protocol:
         call = unpack_callback_protocol(self.s)
         if call:
             return meet_types(t, call)
     return meet_types(t.fallback, s)
Example #6
0
 def infer_against_overloaded(self, overloaded: Overloaded,
                              template: Callable) -> List[Constraint]:
     # Create constraints by matching an overloaded type against a template.
     # This is tricky to do in general. We cheat by only matching against
     # the first overload item, and by only matching the return type. This
     # seems to work somewhat well, but we should really use a more
     # reliable technique.
     item = overloaded.items()[0]
     return infer_constraints(template.ret_type, item.ret_type,
                              self.direction)
Example #7
0
def find_matching_overload_item(overloaded: Overloaded, template: CallableType) -> CallableType:
    """Disambiguate overload item against a template."""
    items = overloaded.items()
    for item in items:
        # Return type may be indeterminate in the template, so ignore it when performing a
        # subtype check.
        if mypy.subtypes.is_callable_subtype(item, template, ignore_return=True):
            return item
    # Fall back to the first item if we can't find a match. This is totally arbitrary --
    # maybe we should just bail out at this point.
    return items[0]
Example #8
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
Example #9
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
Example #10
0
File: join.py Project: chadrik/mypy
 def visit_overloaded(self, t: Overloaded) -> Type:
     # This is more complex than most other cases. Here are some
     # examples that illustrate how this works.
     #
     # First let's define a concise notation:
     #  - Cn are callable types (for n in 1, 2, ...)
     #  - Ov(C1, C2, ...) is an overloaded type with items C1, C2, ...
     #  - Callable[[T, ...], S] is written as [T, ...] -> S.
     #
     # We want some basic properties to hold (assume Cn are all
     # unrelated via Any-similarity):
     #
     #   join(Ov(C1, C2), C1) == C1
     #   join(Ov(C1, C2), Ov(C1, C2)) == Ov(C1, C2)
     #   join(Ov(C1, C2), Ov(C1, C3)) == C1
     #   join(Ov(C2, C2), C3) == join of fallback types
     #
     # The presence of Any types makes things more interesting. The join is the
     # most general type we can get with respect to Any:
     #
     #   join(Ov([int] -> int, [str] -> str), [Any] -> str) == Any -> str
     #
     # We could use a simplification step that removes redundancies, but that's not
     # implemented right now. Consider this example, where we get a redundancy:
     #
     #   join(Ov([int, Any] -> Any, [str, Any] -> Any), [Any, int] -> Any) ==
     #       Ov([Any, int] -> Any, [Any, int] -> Any)
     #
     # TODO: Consider more cases of callable subtyping.
     result = []  # type: List[CallableType]
     s = self.s
     if isinstance(s, FunctionLike):
         # The interesting case where both types are function types.
         for t_item in t.items():
             for s_item in s.items():
                 if is_similar_callables(t_item, s_item):
                     if is_equivalent(t_item, s_item):
                         result.append(combine_similar_callables(t_item, s_item))
                     elif is_subtype(t_item, s_item):
                         result.append(s_item)
         if result:
             # TODO: Simplify redundancies from the result.
             if len(result) == 1:
                 return result[0]
             else:
                 return Overloaded(result)
         return join_types(t.fallback, s.fallback)
     elif isinstance(s, Instance) and s.type.is_protocol:
         call = unpack_callback_protocol(s)
         if call:
             return join_types(t, call)
     return join_types(t.fallback, s)
Example #11
0
 def visit_overloaded(self, left: Overloaded) -> bool:
     right = self.right
     if is_named_instance(right, 'builtins.object'):
         return True
     elif isinstance(right, Callable) 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
Example #12
0
def bind_self(method: F,
              original_type: Optional[Type] = None,
              is_classmethod: bool = False) -> F:
    """Return a copy of `method`, with the type of its first parameter (usually
    self or cls) bound to original_type.

    If the type of `self` is a generic type (T, or Type[T] for classmethods),
    instantiate every occurrence of type with original_type in the rest of the
    signature and in the return type.

    original_type is the type of E in the expression E.copy(). It is None in
    compatibility checks. In this case we treat it as the erasure of the
    declared type of self.

    This way we can express "the type of self". For example:

    T = TypeVar('T', bound='A')
    class A:
        def copy(self: T) -> T: ...

    class B(A): pass

    b = B().copy()  # type: B

    """
    if isinstance(method, Overloaded):
        return cast(
            F,
            Overloaded([bind_self(c, original_type) for c in method.items()]))
    assert isinstance(method, CallableType)
    func = method
    if not func.arg_types:
        # invalid method. return something
        return cast(F, func)
    if func.arg_kinds[0] == ARG_STAR:
        # The signature is of the form 'def foo(*args, ...)'.
        # In this case we shouldn't drop the first arg,
        # since func will be absorbed by the *args.

        # TODO: infer bounds on the type of *args?
        return cast(F, func)
    self_param_type = func.arg_types[0]
    if func.variables and (isinstance(self_param_type, TypeVarType) or
                           (isinstance(self_param_type, TypeType) and
                            isinstance(self_param_type.item, TypeVarType))):
        if original_type is None:
            # Type check method override
            # XXX value restriction as union?
            original_type = erase_to_bound(self_param_type)

        ids = [x.id for x in func.variables]
        typearg = infer_type_arguments(ids, self_param_type, original_type)[0]
        if (is_classmethod and isinstance(typearg, UninhabitedType)
                and isinstance(original_type,
                               (Instance, TypeVarType, TupleType))):
            # In case we call a classmethod through an instance x, fallback to type(x)
            # TODO: handle Union
            typearg = infer_type_arguments(ids, self_param_type,
                                           TypeType(original_type))[0]

        def expand(target: Type) -> Type:
            assert typearg is not None
            return expand_type(target, {func.variables[0].id: typearg})

        arg_types = [expand(x) for x in func.arg_types[1:]]
        ret_type = expand(func.ret_type)
        variables = func.variables[1:]
    else:
        arg_types = func.arg_types[1:]
        ret_type = func.ret_type
        variables = func.variables
    if isinstance(original_type, CallableType) and original_type.is_type_obj():
        original_type = TypeType.make_normalized(original_type.ret_type)
    res = func.copy_modified(arg_types=arg_types,
                             arg_kinds=func.arg_kinds[1:],
                             arg_names=func.arg_names[1:],
                             variables=variables,
                             ret_type=ret_type,
                             bound_args=[original_type])
    return cast(F, res)
Example #13
0
def add_class_tvars(
        t: ProperType,
        isuper: Optional[Instance],
        is_classmethod: bool,
        original_type: Type,
        original_vars: Optional[Sequence[TypeVarLikeType]] = None) -> Type:
    """Instantiate type variables during analyze_class_attribute_access,
    e.g T and Q in the following:

    class A(Generic[T]):
        @classmethod
        def foo(cls: Type[Q]) -> Tuple[T, Q]: ...

    class B(A[str]): pass
    B.foo()

    Args:
        t: Declared type of the method (or property)
        isuper: Current instance mapped to the superclass where method was defined, this
            is usually done by map_instance_to_supertype()
        is_classmethod: True if this method is decorated with @classmethod
        original_type: The value of the type B in the expression B.foo() or the corresponding
            component in case of a union (this is used to bind the self-types)
        original_vars: Type variables of the class callable on which the method was accessed
    Returns:
        Expanded method type with added type variables (when needed).
    """
    # TODO: verify consistency between Q and T

    # We add class type variables if the class method is accessed on class object
    # without applied type arguments, this matches the behavior of __init__().
    # For example (continuing the example in docstring):
    #     A       # The type of callable is def [T] () -> A[T], _not_ def () -> A[Any]
    #     A[int]  # The type of callable is def () -> A[int]
    # and
    #     A.foo       # The type is generic def [T] () -> Tuple[T, A[T]]
    #     A[int].foo  # The type is non-generic def () -> Tuple[int, A[int]]
    #
    # This behaviour is useful for defining alternative constructors for generic classes.
    # To achieve such behaviour, we add the class type variables that are still free
    # (i.e. appear in the return type of the class object on which the method was accessed).
    if isinstance(t, CallableType):
        tvars = original_vars if original_vars is not None else []
        if is_classmethod:
            t = freshen_function_type_vars(t)
            t = bind_self(t, original_type, is_classmethod=True)
            assert isuper is not None
            t = cast(CallableType, expand_type_by_instance(t, isuper))
            freeze_type_vars(t)
        return t.copy_modified(variables=list(tvars) + list(t.variables))
    elif isinstance(t, Overloaded):
        return Overloaded([
            cast(
                CallableType,
                add_class_tvars(item,
                                isuper,
                                is_classmethod,
                                original_type,
                                original_vars=original_vars))
            for item in t.items()
        ])
    if isuper is not None:
        t = cast(ProperType, expand_type_by_instance(t, isuper))
    return t
Example #14
0
 def visit_overloaded(self, left: Overloaded) -> bool:
     if isinstance(self.right, Overloaded):
         return is_same_types(left.items(), self.right.items())
     else:
         return False
Example #15
0
 def visit_overloaded(self, t: Overloaded) -> None:
     for item in t.items():
         item.accept(self)
     # Fallback can be None for overloaded types that haven't been semantically analyzed.
     if t.fallback is not None:
         t.fallback.accept(self)
Example #16
0
 def visit_overloaded(self, t: Overloaded) -> Type:
     return t.items()[0].accept(self)
Example #17
0
 def visit_overloaded(self, t: Overloaded) -> None:
     for item in t.items():
         item.accept(self)
Example #18
0
def add_class_tvars(t: ProperType, itype: Instance, isuper: Optional[Instance],
                    is_classmethod: bool, builtin_type: Callable[[str],
                                                                 Instance],
                    original_type: Type) -> Type:
    """Instantiate type variables during analyze_class_attribute_access,
    e.g T and Q in the following:

    class A(Generic[T]):
        @classmethod
        def foo(cls: Type[Q]) -> Tuple[T, Q]: ...

    class B(A[str]): pass

    B.foo()

    original_type is the value of the type B in the expression B.foo() or the corresponding
    component in case if a union (this is used to bind the self-types).
    """
    # TODO: verify consistency between Q and T
    info = itype.type  # type: TypeInfo
    if is_classmethod:
        assert isuper is not None
        t = get_proper_type(expand_type_by_instance(t, isuper))
    # We add class type variables if the class method is accessed on class object
    # without applied type arguments, this matches the behavior of __init__().
    # For example (continuing the example in docstring):
    #     A       # The type of callable is def [T] () -> A[T], _not_ def () -> A[Any]
    #     A[int]  # The type of callable is def () -> A[int]
    # and
    #     A.foo       # The type is generic def [T] () -> Tuple[T, A[T]]
    #     A[int].foo  # The type is non-generic def () -> Tuple[int, A[int]]
    #
    # This behaviour is useful for defining alternative constructors for generic classes.
    # To achieve such behaviour, we add the class type variables that are still free
    # (i.e. appear in the return type of the class object on which the method was accessed).
    free_ids = {t.id for t in itype.args if isinstance(t, TypeVarType)}

    if isinstance(t, CallableType):
        # NOTE: in practice either all or none of the variables are free, since
        # visit_type_application() will detect any type argument count mismatch and apply
        # a correct number of Anys.
        tvars = [
            TypeVarDef(n, n, i + 1, [], builtin_type('builtins.object'),
                       tv.variance)
            for (i,
                 n), tv in zip(enumerate(info.type_vars), info.defn.type_vars)
            # use 'is' to avoid id clashes with unrelated variables
            if any(tv.id is id for id in free_ids)
        ]
        if is_classmethod:
            t = bind_self(t, original_type, is_classmethod=True)
        return t.copy_modified(variables=tvars + t.variables)
    elif isinstance(t, Overloaded):
        return Overloaded([
            cast(
                CallableType,
                add_class_tvars(item, itype, isuper, is_classmethod,
                                builtin_type, original_type))
            for item in t.items()
        ])
    return t
Example #19
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):
            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):
            # Ensure each overload in the right side (the supertype) is accounted for.
            previous_match_left_index = -1
            matched_overloads = set()
            possible_invalid_overloads = set()

            for right_index, right_item in enumerate(right.items()):
                found_match = False

                for left_index, left_item in enumerate(left.items()):
                    subtype_match = is_subtype(
                        left_item,
                        right_item,
                        self.check_type_parameter,
                        ignore_pos_arg_names=self.ignore_pos_arg_names)

                    # Order matters: we need to make sure that the index of
                    # this item is at least the index of the previous one.
                    if subtype_match and previous_match_left_index <= left_index:
                        if not found_match:
                            # Update the index of the previous match.
                            previous_match_left_index = left_index
                            found_match = True
                            matched_overloads.add(left_item)
                            possible_invalid_overloads.discard(left_item)
                    else:
                        # If this one overlaps with the supertype in any way, but it wasn't
                        # an exact match, then it's a potential error.
                        if (is_callable_compatible(
                                left_item,
                                right_item,
                                is_compat=is_subtype,
                                ignore_return=True,
                                ignore_pos_arg_names=self.ignore_pos_arg_names)
                                or is_callable_compatible(
                                    right_item,
                                    left_item,
                                    is_compat=is_subtype,
                                    ignore_return=True,
                                    ignore_pos_arg_names=self.
                                    ignore_pos_arg_names)):
                            # If this is an overload that's already been matched, there's no
                            # problem.
                            if left_item not in matched_overloads:
                                possible_invalid_overloads.add(left_item)

                if not found_match:
                    return False

            if possible_invalid_overloads:
                # There were potentially invalid overloads that were never matched to the
                # supertype.
                return False
            return True
        elif isinstance(right, UnboundType):
            return True
        elif isinstance(right, TypeType):
            # All the items must have the same type object status, so
            # it's sufficient to query only (any) one of them.
            # This is unsound, we don't check all the __init__ signatures.
            return left.is_type_obj() and is_subtype(left.items()[0], right)
        else:
            return False
Example #20
0
 def visit_overloaded(self, typ: Overloaded) -> SnapshotItem:
     return ('Overloaded', snapshot_types(typ.items()))
Example #21
0
 def visit_overloaded(self, t: types.Overloaded) -> Set[str]:
     return self._visit(t.items()) | self._visit(t.fallback)
Example #22
0
def takes_callable_and_args_callback(ctx: FunctionContext) -> Type:
    """Automate the boilerplate for writing functions that accept
    arbitrary positional arguments of the same type accepted by
    a callable.

    For example, this supports writing::

        @trio_typing.takes_callable_and_args
        def start_soon(
            self,
            async_fn: Callable[[trio_typing.ArgsForCallable], None],
            *args: trio_typing.ArgsForCallable,
        ) -> None: ...

    instead of::

        T1 = TypeVar("T1")
        T2 = TypeVar("T2")
        T3 = TypeVar("T3")
        T4 = TypeVar("T4")

        @overload
        def start_soon(
            self,
            async_fn: Callable[[], None],
        ) -> None: ...

        @overload
        def start_soon(
            self,
            async_fn: Callable[[T1], None],
            __arg1: T1,
        ) -> None: ...

        @overload
        def start_soon(
            self,
            async_fn: Callable[[T1, T2], None],
            __arg1: T1,
            __arg2: T2
        ) -> None: ...

        # etc

    """
    try:
        if (not ctx.arg_types or len(ctx.arg_types[0]) != 1
                or not isinstance(ctx.arg_types[0][0], CallableType)
                or not isinstance(ctx.default_return_type, CallableType)):
            raise ValueError("must be used as a decorator")

        fn_type = ctx.arg_types[0][0]  # type: CallableType
        callable_idx = -1  # index in function arguments of the callable
        callable_args_idx = -1  # index in callable arguments of the StarArgs
        args_idx = -1  # index in function arguments of the StarArgs

        for idx, (kind,
                  ty) in enumerate(zip(fn_type.arg_kinds, fn_type.arg_types)):
            if (isinstance(ty, Instance)
                    and ty.type.fullname() == "trio_typing.ArgsForCallable"):
                if kind != ARG_STAR:
                    raise ValueError(
                        "ArgsForCallable must be used with a *args argument "
                        "in the decorated function")
                assert args_idx == -1
                args_idx = idx
            elif isinstance(ty, CallableType) and kind == ARG_POS:
                for idx_, (kind_,
                           ty_) in enumerate(zip(ty.arg_kinds, ty.arg_types)):
                    if (isinstance(ty_, Instance) and ty_.type.fullname()
                            == "trio_typing.ArgsForCallable"):
                        if kind != ARG_POS:
                            raise ValueError(
                                "ArgsForCallable must be used with a positional "
                                "argument in the callable type that the decorated "
                                "function takes")
                        if callable_idx != -1:
                            raise ValueError(
                                "ArgsForCallable may only be used once as the type "
                                "of an argument to a callable type that the "
                                "decorated function takes")
                        callable_idx = idx
                        callable_args_idx = idx_
        if args_idx == -1:
            raise ValueError("decorated function must take *args with type "
                             "trio_typing.ArgsForCallable")
        if callable_idx == -1:
            raise ValueError(
                "decorated function must take a callable that has an "
                "argument of type trio_typing.ArgsForCallable")

        expanded_fns = []  # type: List[CallableType]
        type_var_defs = []  # type: List[TypeVarDef]
        type_var_types = []  # type: List[Type]
        for arg_idx in range(1, 5):
            callable_ty = cast(CallableType, fn_type.arg_types[callable_idx])
            arg_types = list(fn_type.arg_types)
            arg_types[callable_idx] = callable_ty.copy_modified(
                arg_types=(callable_ty.arg_types[:callable_args_idx] +
                           type_var_types +
                           callable_ty.arg_types[callable_args_idx + 1:]),
                arg_kinds=(callable_ty.arg_kinds[:callable_args_idx] +
                           ([ARG_POS] * len(type_var_types)) +
                           callable_ty.arg_kinds[callable_args_idx + 1:]),
                arg_names=(callable_ty.arg_names[:callable_args_idx] +
                           ([None] * len(type_var_types)) +
                           callable_ty.arg_names[callable_args_idx + 1:]),
                variables=(callable_ty.variables + type_var_defs),
            )
            expanded_fns.append(
                fn_type.copy_modified(
                    arg_types=(arg_types[:args_idx] + type_var_types +
                               arg_types[args_idx + 1:]),
                    arg_kinds=(fn_type.arg_kinds[:args_idx] +
                               ([ARG_POS] * len(type_var_types)) +
                               fn_type.arg_kinds[args_idx + 1:]),
                    arg_names=(fn_type.arg_names[:args_idx] +
                               ([None] * len(type_var_types)) +
                               fn_type.arg_names[args_idx + 1:]),
                    variables=(fn_type.variables + type_var_defs),
                ))
            type_var_defs.append(
                TypeVarDef(
                    "__T{}".format(arg_idx),
                    "__T{}".format(arg_idx),
                    -len(fn_type.variables) - arg_idx - 1,
                    [],
                    ctx.api.named_generic_type("builtins.object", []),
                ))
            type_var_types.append(
                TypeVarType(type_var_defs[-1], ctx.context.line,
                            ctx.context.column))
        return Overloaded(expanded_fns)

    except ValueError as ex:
        ctx.api.fail("invalid use of @takes_callable_and_args: {}".format(ex),
                     ctx.context)
        return ctx.default_return_type
Example #23
0
 def visit_overloaded(self, t: Overloaded) -> None:
     self.traverse_types(t.items())
Example #24
0
 def visit_overloaded(self, t: Overloaded) -> None:
     for item in t.items():
         item.accept(self)
     # Fallback can be None for overloaded types that haven't been semantically analyzed.
     if t.fallback is not None:
         t.fallback.accept(self)
Example #25
0
 def visit_overloaded(self, t: Overloaded) -> None:
     self.traverse_types(t.items())
Example #26
0
 def visit_overloaded(self, t: Overloaded) -> Type:
     items = []  # type: List[CallableType]
     for item in t.items():
         items.append(cast(CallableType, item.accept(self)))
     return Overloaded(items)
Example #27
0
 def visit_overloaded(self, t: types.Overloaded) -> Set[str]:
     return self._visit(*t.items()) | self._visit(t.fallback)
Example #28
0
 def visit_overloaded(self, t: Overloaded) -> T:
     return self.query_types(t.items())
Example #29
0
def takes_callable_and_args_callback(ctx: FunctionContext) -> Type:
    """Automate the boilerplate for writing functions that accept
    arbitrary positional arguments of the same type accepted by
    a callable.

    For example, this supports writing::

        @trio_typing.takes_callable_and_args
        def start_soon(
            self,
            async_fn: Callable[[VarArg()], Any],
            *args: Any,
        ) -> None: ...

    instead of::

        T1 = TypeVar("T1")
        T2 = TypeVar("T2")
        T3 = TypeVar("T3")
        T4 = TypeVar("T4")

        @overload
        def start_soon(
            self,
            async_fn: Callable[[], Any],
        ) -> None: ...

        @overload
        def start_soon(
            self,
            async_fn: Callable[[T1], Any],
            __arg1: T1,
        ) -> None: ...

        @overload
        def start_soon(
            self,
            async_fn: Callable[[T1, T2], Any],
            __arg1: T1,
            __arg2: T2
        ) -> None: ...

        # etc

    """
    try:
        if not ctx.arg_types or len(ctx.arg_types[0]) != 1:
            raise ValueError("must be used as a decorator")

        fn_type = get_proper_type(ctx.arg_types[0][0])
        if not isinstance(fn_type, CallableType) or not isinstance(
                get_proper_type(ctx.default_return_type), CallableType):
            raise ValueError("must be used as a decorator")

        callable_idx = -1  # index in function arguments of the callable
        callable_args_idx = -1  # index in callable arguments of the StarArgs
        callable_ty = None  # type: Optional[CallableType]
        args_idx = -1  # index in function arguments of the StarArgs

        for idx, (kind,
                  ty) in enumerate(zip(fn_type.arg_kinds, fn_type.arg_types)):
            ty = get_proper_type(ty)
            if isinstance(ty, AnyType) and kind == ARG_STAR:
                assert args_idx == -1
                args_idx = idx
            elif isinstance(ty, (UnionType, CallableType)) and kind == ARG_POS:
                # turn Union[Callable[..., T], Callable[[VarArg()], T]]
                # into Callable[[VarArg()], T]
                # (the union makes it not fail when the plugin is not being used)
                if isinstance(ty, UnionType):
                    for arm in get_proper_types(ty.items):
                        if (isinstance(arm, CallableType)
                                and not arm.is_ellipsis_args
                                and any(kind_ == ARG_STAR
                                        for kind_ in arm.arg_kinds)):
                            ty = arm
                            break
                    else:
                        continue

                for idx_, (kind_,
                           ty_) in enumerate(zip(ty.arg_kinds, ty.arg_types)):
                    ty_ = get_proper_type(ty_)
                    if isinstance(ty_, AnyType) and kind_ == ARG_STAR:
                        if callable_idx != -1:
                            raise ValueError(
                                "decorated function may only take one callable "
                                "that has an argument of type VarArg()")
                        callable_idx = idx
                        callable_args_idx = idx_
                        callable_ty = ty

        if args_idx == -1:
            raise ValueError("decorated function must take *args: Any")
        if callable_idx == -1 or callable_ty is None:
            raise ValueError(
                "decorated function must take a callable that has a "
                "argument of type mypy_extensions.VarArg()")

        expanded_fns = []  # type: List[CallableType]
        type_var_defs = []  # type: List[TypeVarDef]
        type_var_types = []  # type: List[Type]
        for arg_idx in range(
                1, 7):  # provides overloads for 0 through 5 arguments
            arg_types = list(fn_type.arg_types)
            arg_types[callable_idx] = callable_ty.copy_modified(
                arg_types=(callable_ty.arg_types[:callable_args_idx] +
                           type_var_types +
                           callable_ty.arg_types[callable_args_idx + 1:]),
                arg_kinds=(callable_ty.arg_kinds[:callable_args_idx] +
                           ([ARG_POS] * len(type_var_types)) +
                           callable_ty.arg_kinds[callable_args_idx + 1:]),
                arg_names=(callable_ty.arg_names[:callable_args_idx] +
                           ([None] * len(type_var_types)) +
                           callable_ty.arg_names[callable_args_idx + 1:]),
                variables=(callable_ty.variables + type_var_defs),
            )
            expanded_fns.append(
                fn_type.copy_modified(
                    arg_types=(arg_types[:args_idx] + type_var_types +
                               arg_types[args_idx + 1:]),
                    arg_kinds=(fn_type.arg_kinds[:args_idx] +
                               ([ARG_POS] * len(type_var_types)) +
                               fn_type.arg_kinds[args_idx + 1:]),
                    arg_names=(fn_type.arg_names[:args_idx] +
                               ([None] * len(type_var_types)) +
                               fn_type.arg_names[args_idx + 1:]),
                    variables=(fn_type.variables + type_var_defs),
                ))
            type_var_defs.append(
                TypeVarDef(
                    "__T{}".format(arg_idx),
                    "__T{}".format(arg_idx),
                    -len(fn_type.variables) - arg_idx - 1,
                    [],
                    ctx.api.named_generic_type("builtins.object", []),
                ))
            type_var_types.append(
                TypeVarType(type_var_defs[-1], ctx.context.line,
                            ctx.context.column))
        return Overloaded(expanded_fns)

    except ValueError as ex:
        ctx.api.fail("invalid use of @takes_callable_and_args: {}".format(ex),
                     ctx.context)
        return ctx.default_return_type
Example #30
0
 def ov(*items: CallableType) -> Overloaded:
     return Overloaded(list(items))
Example #31
0
def translate_kind_instance(typ: Type) -> Type:  # noqa: WPS, C901
    """
    We use this ugly hack to translate ``KindN[x, y]`` into ``x[y]``.

    This is required due to the fact that ``KindN``
    can be nested in other types, like: ``List[KindN[...]]``.

    We will refactor this code after ``TypeTranslator``
    is released in ``[email protected]`` version.
    """
    typ = get_proper_type(typ)

    if isinstance(typ, _LEAF_TYPES):  # noqa: WPS223
        return typ
    elif isinstance(typ, Instance):
        last_known_value: Optional[LiteralType] = None
        if typ.last_known_value is not None:
            raw_last_known_value = translate_kind_instance(
                typ.last_known_value)
            assert isinstance(raw_last_known_value, LiteralType)
            last_known_value = raw_last_known_value
        instance = Instance(
            typ=typ.type,
            args=_translate_types(typ.args),
            line=typ.line,
            column=typ.column,
            last_known_value=last_known_value,
        )
        if typ.type.fullname == TYPED_KINDN:  # That's where we do the change
            return _process_kinded_type(instance)
        return instance

    elif isinstance(typ, CallableType):
        return typ.copy_modified(
            arg_types=_translate_types(typ.arg_types),
            ret_type=translate_kind_instance(typ.ret_type),
        )
    elif isinstance(typ, TupleType):
        return TupleType(
            _translate_types(typ.items),
            translate_kind_instance(typ.partial_fallback),  # type: ignore
            typ.line,
            typ.column,
        )
    elif isinstance(typ, TypedDictType):
        dict_items = {
            item_name: translate_kind_instance(item_type)
            for item_name, item_type in typ.items.items()
        }
        return TypedDictType(
            dict_items,
            typ.required_keys,
            translate_kind_instance(typ.fallback),  # type: ignore
            typ.line,
            typ.column,
        )
    elif isinstance(typ, LiteralType):
        fallback = translate_kind_instance(typ.fallback)
        assert isinstance(fallback, Instance)
        return LiteralType(
            value=typ.value,
            fallback=fallback,
            line=typ.line,
            column=typ.column,
        )
    elif isinstance(typ, UnionType):
        return UnionType(_translate_types(typ.items), typ.line, typ.column)
    elif isinstance(typ, Overloaded):
        functions: List[CallableType] = []
        for func in typ.items():
            new = translate_kind_instance(func)
            assert isinstance(new, CallableType)
            functions.append(new)
        return Overloaded(items=functions)
    elif isinstance(typ, TypeType):
        return TypeType.make_normalized(
            translate_kind_instance(typ.item),
            line=typ.line,
            column=typ.column,
        )
    return typ
Example #32
0
 def visit_overloaded(self, typ: Overloaded) -> List[str]:
     triggers = []
     for item in typ.items():
         triggers.extend(self.get_type_triggers(item))
     return triggers
Example #33
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):
            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):
            # Ensure each overload in the right side (the supertype) is accounted for.
            previous_match_left_index = -1
            matched_overloads = set()
            possible_invalid_overloads = set()

            for right_index, right_item in enumerate(right.items()):
                found_match = False

                for left_index, left_item in enumerate(left.items()):
                    subtype_match = is_subtype(left_item, right_item, self.check_type_parameter,
                                               ignore_pos_arg_names=self.ignore_pos_arg_names)

                    # Order matters: we need to make sure that the index of
                    # this item is at least the index of the previous one.
                    if subtype_match and previous_match_left_index <= left_index:
                        if not found_match:
                            # Update the index of the previous match.
                            previous_match_left_index = left_index
                            found_match = True
                            matched_overloads.add(left_item)
                            possible_invalid_overloads.discard(left_item)
                    else:
                        # If this one overlaps with the supertype in any way, but it wasn't
                        # an exact match, then it's a potential error.
                        if (is_callable_subtype(left_item, right_item, ignore_return=True,
                                            ignore_pos_arg_names=self.ignore_pos_arg_names) or
                                is_callable_subtype(right_item, left_item, ignore_return=True,
                                                ignore_pos_arg_names=self.ignore_pos_arg_names)):
                            # If this is an overload that's already been matched, there's no
                            # problem.
                            if left_item not in matched_overloads:
                                possible_invalid_overloads.add(left_item)

                if not found_match:
                    return False

            if possible_invalid_overloads:
                # There were potentially invalid overloads that were never matched to the
                # supertype.
                return False
            return True
        elif isinstance(right, UnboundType):
            return True
        elif isinstance(right, TypeType):
            # All the items must have the same type object status, so
            # it's sufficient to query only (any) one of them.
            # This is unsound, we don't check all the __init__ signatures.
            return left.is_type_obj() and is_subtype(left.items()[0], right)
        else:
            return False
Example #34
0
 def visit_overloaded(self, left: Overloaded) -> bool:
     if isinstance(self.right, Overloaded):
         return is_same_types(left.items(), self.right.items())
     else:
         return False
Example #35
0
def _curry_hook(context: FunctionContext) -> Type:
    arg_type = context.arg_types[0][0]
    function = _get_callable_type(arg_type, context)

    if function is None:
        # argument was not callable type or function
        return context.default_return_type

    if len(function.arg_types) < 2:
        # nullary or unary function: nothing to do
        return function

    type_vars = {var.fullname: var for var in function.variables}

    def get_variables(*types):
        def collect_variables(*ts):
            variables = []
            for type_ in ts:
                if isinstance(type_, TypeVarType):
                    variables.append(type_)
                if hasattr(type_, 'args'):
                    variables += get_variables(*type_.args)
                if isinstance(type_, CallableType):
                    variables += get_variables(type_.ret_type,
                                               *type_.arg_types)
                if isinstance(type_, UnionType):
                    variables += get_variables(*type_.items)
            return variables

        return set(type_vars[v.fullname] for v in collect_variables(*types))

    args = tuple(
        zip(function.arg_types, function.arg_kinds, function.arg_names))
    optional_args = tuple(
        filter(lambda a: a[1] in (ARG_OPT, ARG_NAMED_OPT, ARG_STAR2), args))
    positional_args = tuple(
        filter(lambda a: a[1] in (ARG_POS, ARG_NAMED, ARG_STAR), args))

    if not positional_args:
        # no positional args: nothing to do
        return function
    opt_arg_types, opt_arg_kinds, opt_arg_names = (tuple(zip(
        *optional_args)) if optional_args else ((), (), ()))
    pos_arg_types, pos_arg_kinds, pos_arg_names = tuple(zip(*positional_args))
    arg_type, *arg_types = pos_arg_types
    arg_name, *arg_names = pos_arg_names
    arg_kind, *arg_kinds = pos_arg_kinds
    return_type = function.ret_type

    opt_variables = get_variables(*opt_arg_types)
    variables = get_variables(arg_type)
    if len(pos_arg_types) == 1:
        variables |= get_variables(return_type)
        ret_type = return_type
    else:
        ret_type = AnyType(TypeOfAny.special_form)
    functions = [
        CallableType(arg_types=[arg_type],
                     arg_kinds=[arg_kind],
                     arg_names=[arg_name],
                     ret_type=ret_type,
                     fallback=function.fallback,
                     variables=list(variables))
    ]

    remaining_args = zip(arg_types, arg_kinds, arg_names)
    for i, (arg_type, kind, name) in enumerate(remaining_args):
        variables = get_variables(arg_type)
        if i == len(arg_types) - 1:
            variables |= get_variables(return_type)
            ret_type = return_type
        else:
            ret_type = AnyType(TypeOfAny.special_form)
        variables -= set.union(*[set(f.variables) for f in functions])
        if kind == ARG_STAR:
            last_f = functions[i]
            functions[i] = last_f.copy_modified(
                arg_types=last_f.arg_types + [arg_type],
                arg_kinds=last_f.arg_kinds + [kind],
                arg_names=last_f.arg_names + [name],
                variables=list(sorted(variables, key=str)),
                ret_type=ret_type)
        else:
            functions.append(
                CallableType(arg_types=[arg_type],
                             arg_kinds=[kind],
                             arg_names=[name],
                             ret_type=ret_type,
                             fallback=function.fallback,
                             variables=list(sorted(variables, key=str))))

    def merge(fs):
        if len(fs) == 1:
            return fs[0]
        first, next_, *rest = fs
        first.ret_type = next_
        for f in rest:
            next_.ret_type = f
            next_ = f
        return first

    merged = merge(functions)
    if optional_args:
        mod_functions = [
            f.copy_modified(variables=list(
                sorted(set(f.variables) - opt_variables, key=str)))
            for f in functions
        ]
        mod_merged = merge(mod_functions)
        with_opts = CallableType(arg_types=list(opt_arg_types),
                                 arg_kinds=list(opt_arg_kinds),
                                 arg_names=list(opt_arg_names),
                                 ret_type=mod_merged,
                                 fallback=function.fallback,
                                 variables=list(sorted(opt_variables,
                                                       key=str)))
        return Overloaded([merged, function, with_opts])
    return Overloaded([merged, function])
Example #36
0
 def visit_overloaded(self, template: Overloaded) -> List[Constraint]:
     res = []  # type: List[Constraint]
     for t in template.items():
         res.extend(infer_constraints(t, self.actual, self.direction))
     return res
Example #37
0
 def ov(*items):
     return Overloaded(items)
Example #38
0
 def visit_overloaded(self, t: Overloaded) -> Type:
     return t.items()[0].accept(self)
Example #39
0
 def visit_overloaded(self, t: Overloaded) -> None:
     for item in t.items():
         item.accept(self)
Example #40
0
 def visit_overloaded(self, typ: Overloaded) -> SnapshotItem:
     return ('Overloaded', snapshot_types(typ.items()))
Example #41
0
 def visit_overloaded(self, t: Overloaded) -> ProperType:
     return self.copy_common(t, Overloaded(items=t.items))
Example #42
0
 def visit_overloaded(self, t: Overloaded) -> Type:
     items = [] # type: List[Callable]
     for item in t.items():
         items.append(cast(Callable, item.accept(self)))
     return Overloaded(items)
Example #43
0
File: fixup.py Project: lamby/mypy
 def visit_overloaded(self, t: Overloaded) -> None:
     for ct in t.items():
         ct.accept(self)
Example #44
0
File: deps.py Project: sixolet/mypy
 def visit_overloaded(self, typ: Overloaded) -> List[str]:
     triggers = []
     for item in typ.items():
         triggers.extend(get_type_triggers(item))
     return triggers
Example #45
0
 def visit_overloaded(self, template: Overloaded) -> List[Constraint]:
     res = []  # type: List[Constraint]
     for t in template.items():
         res.extend(infer_constraints(t, self.actual, self.direction))
     return res
Example #46
0
 def visit_overloaded(self, t: Overloaded) -> None:
     for ct in t.items():
         ct.accept(self)
Example #47
0
def bind_self(method: F,
              original_type: Optional[Type] = None,
              is_classmethod: bool = False) -> F:
    """Return a copy of `method`, with the type of its first parameter (usually
    self or cls) bound to original_type.

    If the type of `self` is a generic type (T, or Type[T] for classmethods),
    instantiate every occurrence of type with original_type in the rest of the
    signature and in the return type.

    original_type is the type of E in the expression E.copy(). It is None in
    compatibility checks. In this case we treat it as the erasure of the
    declared type of self.

    This way we can express "the type of self". For example:

    T = TypeVar('T', bound='A')
    class A:
        def copy(self: T) -> T: ...

    class B(A): pass

    b = B().copy()  # type: B

    """
    from mypy.infer import infer_type_arguments

    if isinstance(method, Overloaded):
        return cast(
            F,
            Overloaded([
                bind_self(c, original_type, is_classmethod)
                for c in method.items()
            ]))
    assert isinstance(method, CallableType)
    func = method
    if not func.arg_types:
        # Invalid method, return something.
        return cast(F, func)
    if func.arg_kinds[0] == ARG_STAR:
        # The signature is of the form 'def foo(*args, ...)'.
        # In this case we shouldn't drop the first arg,
        # since func will be absorbed by the *args.

        # TODO: infer bounds on the type of *args?
        return cast(F, func)
    self_param_type = get_proper_type(func.arg_types[0])

    variables = []  # type: Sequence[TypeVarLikeDef]
    if func.variables and supported_self_type(self_param_type):
        if original_type is None:
            # TODO: type check method override (see #7861).
            original_type = erase_to_bound(self_param_type)
        original_type = get_proper_type(original_type)

        all_ids = func.type_var_ids()
        typeargs = infer_type_arguments(all_ids,
                                        self_param_type,
                                        original_type,
                                        is_supertype=True)
        if (is_classmethod
                # TODO: why do we need the extra guards here?
                and any(
                    isinstance(get_proper_type(t), UninhabitedType)
                    for t in typeargs) and isinstance(
                        original_type, (Instance, TypeVarType, TupleType))):
            # In case we call a classmethod through an instance x, fallback to type(x)
            typeargs = infer_type_arguments(all_ids,
                                            self_param_type,
                                            TypeType(original_type),
                                            is_supertype=True)

        ids = [
            tid for tid in all_ids
            if any(tid == t.id for t in get_type_vars(self_param_type))
        ]

        # Technically, some constrains might be unsolvable, make them <nothing>.
        to_apply = [
            t if t is not None else UninhabitedType() for t in typeargs
        ]

        def expand(target: Type) -> Type:
            return expand_type(target,
                               {id: to_apply[all_ids.index(id)]
                                for id in ids})

        arg_types = [expand(x) for x in func.arg_types[1:]]
        ret_type = expand(func.ret_type)
        variables = [v for v in func.variables if v.id not in ids]
    else:
        arg_types = func.arg_types[1:]
        ret_type = func.ret_type
        variables = func.variables

    original_type = get_proper_type(original_type)
    if isinstance(original_type, CallableType) and original_type.is_type_obj():
        original_type = TypeType.make_normalized(original_type.ret_type)
    res = func.copy_modified(arg_types=arg_types,
                             arg_kinds=func.arg_kinds[1:],
                             arg_names=func.arg_names[1:],
                             variables=variables,
                             ret_type=ret_type,
                             bound_args=[original_type])
    return cast(F, res)