Example #1
0
    def join_instances(self, t: Instance, s: Instance) -> ProperType:
        if (t, s) in self.seen_instances or (s, t) in self.seen_instances:
            return object_from_instance(t)

        self.seen_instances.append((t, s))

        # Calculate the join of two instance types
        if t.type == s.type:
            # Simplest case: join two types with the same base type (but
            # potentially different arguments).

            # Combine type arguments.
            args: List[Type] = []
            # N.B: We use zip instead of indexing because the lengths might have
            # mismatches during daemon reprocessing.
            for ta, sa, type_var in zip(t.args, s.args, t.type.defn.type_vars):
                ta_proper = get_proper_type(ta)
                sa_proper = get_proper_type(sa)
                new_type: Optional[Type] = None
                if isinstance(ta_proper, AnyType):
                    new_type = AnyType(TypeOfAny.from_another_any, ta_proper)
                elif isinstance(sa_proper, AnyType):
                    new_type = AnyType(TypeOfAny.from_another_any, sa_proper)
                elif isinstance(type_var, TypeVarType):
                    if type_var.variance == COVARIANT:
                        new_type = join_types(ta, sa, self)
                        if len(type_var.values
                               ) != 0 and new_type not in type_var.values:
                            self.seen_instances.pop()
                            return object_from_instance(t)
                        if not is_subtype(new_type, type_var.upper_bound):
                            self.seen_instances.pop()
                            return object_from_instance(t)
                    # TODO: contravariant case should use meet but pass seen instances as
                    # an argument to keep track of recursive checks.
                    elif type_var.variance in (INVARIANT, CONTRAVARIANT):
                        if not is_equivalent(ta, sa):
                            self.seen_instances.pop()
                            return object_from_instance(t)
                        # If the types are different but equivalent, then an Any is involved
                        # so using a join in the contravariant case is also OK.
                        new_type = join_types(ta, sa, self)
                else:
                    # ParamSpec type variables behave the same, independent of variance
                    if not is_equivalent(ta, sa):
                        return get_proper_type(type_var.upper_bound)
                    new_type = join_types(ta, sa, self)
                assert new_type is not None
                args.append(new_type)
            result: ProperType = Instance(t.type, args)
        elif t.type.bases and is_subtype(t, s, ignore_type_params=True):
            result = self.join_instances_via_supertype(t, s)
        else:
            # Now t is not a subtype of s, and t != s. Now s could be a subtype
            # of t; alternatively, we need to find a common supertype. This works
            # in of the both cases.
            result = self.join_instances_via_supertype(s, t)

        self.seen_instances.pop()
        return result
Example #2
0
def check_method_type(
    functype: FunctionLike, itype: Instance, is_classmethod: bool, context: Context, msg: MessageBuilder
) -> None:
    for item in functype.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.invalid_method_type(item, context)
        elif not is_classmethod:
            # Check that self argument has type 'Any' or valid instance type.
            selfarg = item.arg_types[0]
            # If this is a method of a tuple class, correct for the fact that
            # we passed to typ.fallback in analyze_member_access. See #1432.
            if isinstance(selfarg, TupleType):
                selfarg = selfarg.fallback
            if not subtypes.is_equivalent(selfarg, itype):
                msg.invalid_method_type(item, context)
        else:
            # Check that cls argument has type 'Any' or valid class type.
            # (This is sufficient for the current treatment of @classmethod,
            # but probably needs to be revisited when we implement Type[C]
            # or advanced variants of it like Type[<args>, C].)
            clsarg = item.arg_types[0]
            if isinstance(clsarg, CallableType) and clsarg.is_type_obj():
                if not subtypes.is_equivalent(clsarg.ret_type, itype):
                    msg.invalid_class_method_type(item, context)
            else:
                if not subtypes.is_equivalent(clsarg, AnyType()):
                    msg.invalid_class_method_type(item, context)
Example #3
0
def check_method_type(functype: FunctionLike, itype: Instance,
                      is_classmethod: bool, context: Context,
                      msg: MessageBuilder) -> None:
    for item in functype.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.invalid_method_type(item, context)
        elif not is_classmethod:
            # Check that self argument has type 'Any' or valid instance type.
            selfarg = item.arg_types[0]
            # If this is a method of a tuple class, correct for the fact that
            # we passed to typ.fallback in analyze_member_access. See #1432.
            if isinstance(selfarg, TupleType):
                selfarg = selfarg.fallback
            if not subtypes.is_subtype(selfarg, itype):
                msg.invalid_method_type(item, context)
        else:
            # Check that cls argument has type 'Any' or valid class type.
            # (This is sufficient for the current treatment of @classmethod,
            # but probably needs to be revisited when we implement Type[C]
            # or advanced variants of it like Type[<args>, C].)
            clsarg = item.arg_types[0]
            if isinstance(clsarg, CallableType) and clsarg.is_type_obj():
                if not subtypes.is_equivalent(clsarg.ret_type, itype):
                    msg.invalid_class_method_type(item, context)
            else:
                if not subtypes.is_equivalent(clsarg, AnyType()):
                    msg.invalid_class_method_type(item, context)
Example #4
0
def is_similar_callables(t: CallableType, s: CallableType) -> bool:
    """Return True if t and s are equivalent and have identical numbers of
    arguments, default arguments and varargs.
    """

    return (len(t.arg_types) == len(s.arg_types) and t.min_args == s.min_args
            and t.is_var_arg == s.is_var_arg and is_equivalent(t, s))
Example #5
0
 def visit_callable_type(self, t: CallableType) -> ProperType:
     if isinstance(self.s, CallableType) and is_similar_callables(
             t, self.s):
         if is_equivalent(t, self.s):
             return combine_similar_callables(t, self.s)
         result = meet_similar_callables(t, self.s)
         # We set the from_type_type flag to suppress error when a collection of
         # concrete class objects gets inferred as their common abstract superclass.
         if not (
             (t.is_type_obj() and t.type_object().is_abstract) or
             (self.s.is_type_obj() and self.s.type_object().is_abstract)):
             result.from_type_type = True
         if isinstance(get_proper_type(result.ret_type), UninhabitedType):
             # Return a plain None or <uninhabited> instead of a weird function.
             return self.default(self.s)
         return result
     elif isinstance(self.s,
                     TypeType) and t.is_type_obj() and not t.is_generic():
         # In this case we are able to potentially produce a better meet.
         res = meet_types(self.s.item, t.ret_type)
         if not isinstance(res, (NoneType, UninhabitedType)):
             return TypeType.make_normalized(res)
         return self.default(self.s)
     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 self.default(self.s)
Example #6
0
def callable_corresponding_argument(typ: CallableType,
                                    model: FormalArgument) -> Optional[FormalArgument]:
    """Return the argument a function that corresponds to `model`"""

    by_name = typ.argument_by_name(model.name)
    by_pos = typ.argument_by_position(model.pos)
    if by_name is None and by_pos is None:
        return None
    if by_name is not None and by_pos is not None:
        if by_name == by_pos:
            return by_name
        # If we're dealing with an optional pos-only and an optional
        # name-only arg, merge them.  This is the case for all functions
        # taking both *args and **args, or a pair of functions like so:

        # def right(a: int = ...) -> None: ...
        # def left(__a: int = ..., *, a: int = ...) -> None: ...
        from mypy.subtypes import is_equivalent

        if (not (by_name.required or by_pos.required)
                and by_pos.name is None
                and by_name.pos is None
                and is_equivalent(by_name.typ, by_pos.typ)):
            return FormalArgument(by_name.name, by_pos.pos, by_name.typ, False)
    return by_name if by_name is not None else by_pos
Example #7
0
def is_similar_callables(t: CallableType, s: CallableType) -> bool:
    """Return True if t and s are equivalent and have identical numbers of
    arguments, default arguments and varargs.
    """

    return (len(t.arg_types) == len(s.arg_types) and t.min_args == s.min_args
            and t.is_var_arg == s.is_var_arg and is_equivalent(t, s))
 def visit_callable_type(self, t: CallableType) -> ProperType:
     if isinstance(self.s, CallableType) and is_similar_callables(
             t, self.s):
         if is_equivalent(t, self.s):
             return combine_similar_callables(t, self.s)
         result = join_similar_callables(t, self.s)
         # We set the from_type_type flag to suppress error when a collection of
         # concrete class objects gets inferred as their common abstract superclass.
         if not (
             (t.is_type_obj() and t.type_object().is_abstract) or
             (self.s.is_type_obj() and self.s.type_object().is_abstract)):
             result.from_type_type = True
         if any(
                 isinstance(tp, (NoneType, UninhabitedType))
                 for tp in get_proper_types(result.arg_types)):
             # We don't want to return unusable Callable, attempt fallback instead.
             return join_types(t.fallback, self.s)
         return result
     elif isinstance(self.s, Overloaded):
         # Switch the order of arguments to that we'll get to visit_overloaded.
         return join_types(t, self.s)
     elif isinstance(self.s, Instance) and self.s.type.is_protocol:
         call = unpack_callback_protocol(self.s)
         if call:
             return join_types(t, call)
     return join_types(t.fallback, self.s)
Example #9
0
File: join.py Project: alanhdu/mypy
    def join_instances(self, t: Instance, s: Instance) -> ProperType:
        if (t, s) in self.seen_instances or (s, t) in self.seen_instances:
            return object_from_instance(t)

        self.seen_instances.append((t, s))
        """Calculate the join of two instance types."""
        if t.type == s.type:
            # Simplest case: join two types with the same base type (but
            # potentially different arguments).

            # Combine type arguments.
            args: List[Type] = []
            # N.B: We use zip instead of indexing because the lengths might have
            # mismatches during daemon reprocessing.
            for ta, sa, type_var in zip(t.args, s.args, t.type.defn.type_vars):
                ta_proper = get_proper_type(ta)
                sa_proper = get_proper_type(sa)
                new_type: Optional[Type] = None
                if isinstance(ta_proper, AnyType):
                    new_type = AnyType(TypeOfAny.from_another_any, ta_proper)
                elif isinstance(sa_proper, AnyType):
                    new_type = AnyType(TypeOfAny.from_another_any, sa_proper)
                elif type_var.variance == COVARIANT:
                    new_type = join_types(ta, sa, self)
                    if len(type_var.values
                           ) != 0 and new_type not in type_var.values:
                        self.seen_instances.pop()
                        return object_from_instance(t)
                    if not is_subtype(new_type, type_var.upper_bound):
                        self.seen_instances.pop()
                        return object_from_instance(t)
                elif type_var.variance == CONTRAVARIANT:
                    new_type = meet.meet_types(ta, sa)
                    if len(type_var.values
                           ) != 0 and new_type not in type_var.values:
                        self.seen_instances.pop()
                        return object_from_instance(t)
                    # No need to check subtype, as ta and sa already have to be subtypes of
                    # upper_bound
                elif type_var.variance == INVARIANT:
                    new_type = join_types(ta, sa)
                    if not is_equivalent(ta, sa):
                        self.seen_instances.pop()
                        return object_from_instance(t)
                assert new_type is not None
                args.append(new_type)
            result: ProperType = Instance(t.type, args)
        elif t.type.bases and is_subtype_ignoring_tvars(t, s):
            result = self.join_instances_via_supertype(t, s)
        else:
            # Now t is not a subtype of s, and t != s. Now s could be a subtype
            # of t; alternatively, we need to find a common supertype. This works
            # in of the both cases.
            result = self.join_instances_via_supertype(s, t)

        self.seen_instances.pop()
        return result
Example #10
0
def check_method_type(functype, itype, context, msg):
    for item in functype.items():
        if not item.arg_types or item.arg_kinds[0] != ARG_POS:
            # No positional first (self) argument.
            msg.invalid_method_type(item, context)
        else:
            # Check that self argument has type 'any' or valid instance type.
            selfarg = item.arg_types[0]
            if not subtypes.is_equivalent(selfarg, itype):
                msg.invalid_method_type(item, context)
Example #11
0
 def visit_callable_type(self, t: CallableType) -> Type:
     if isinstance(self.s, CallableType) and is_similar_callables(t, self.s):
         if is_equivalent(t, self.s):
             return combine_similar_callables(t, self.s)
         result = meet_similar_callables(t, self.s)
         if isinstance(result.ret_type, UninhabitedType):
             # Return a plain None or <uninhabited> instead of a weird function.
             return self.default(self.s)
         return result
     else:
         return self.default(self.s)
Example #12
0
 def visit_callable_type(self, t: CallableType) -> Type:
     if isinstance(self.s, CallableType) and is_similar_callables(t, self.s):
         if is_equivalent(t, self.s):
             return combine_similar_callables(t, self.s)
         result = meet_similar_callables(t, self.s)
         if isinstance(result.ret_type, UninhabitedType):
             # Return a plain None or <uninhabited> instead of a weird function.
             return self.default(self.s)
         return result
     else:
         return self.default(self.s)
Example #13
0
def check_method_type(functype: FunctionLike, itype: Instance,
                      context: Context, msg: MessageBuilder) -> None:
    for item in functype.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.invalid_method_type(item, context)
        else:
            # Check that self argument has type 'Any' or valid instance type.
            selfarg = item.arg_types[0]
            if not subtypes.is_equivalent(selfarg, itype):
                msg.invalid_method_type(item, context)
Example #14
0
def check_method_type(functype: FunctionLike, itype: Instance,
                      context: Context, msg: MessageBuilder) -> None:
    for item in functype.items():
        if not item.arg_types or item.arg_kinds[0] != ARG_POS:
            # No positional first (self) argument.
            msg.invalid_method_type(item, context)
        else:
            # Check that self argument has type 'Any' or valid instance type.
            selfarg = item.arg_types[0]
            if not subtypes.is_equivalent(selfarg, itype):
                msg.invalid_method_type(item, context)
Example #15
0
 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 #16
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 #17
0
File: meet.py Project: chadrik/mypy
 def visit_callable_type(self, t: CallableType) -> Type:
     if isinstance(self.s, CallableType) and is_similar_callables(t, self.s):
         if is_equivalent(t, self.s):
             return combine_similar_callables(t, self.s)
         result = meet_similar_callables(t, self.s)
         if isinstance(result.ret_type, UninhabitedType):
             # Return a plain None or <uninhabited> instead of a weird function.
             return self.default(self.s)
         return result
     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 self.default(self.s)
Example #18
0
 def visit_typeddict_type(self, t: TypedDictType) -> Type:
     if isinstance(self.s, TypedDictType):
         for (_, l, r) in self.s.zip(t):
             if not is_equivalent(l, r):
                 return self.default(self.s)
         items = OrderedDict([(item_name, s_item_type or t_item_type)
                              for (item_name, s_item_type,
                                   t_item_type) in self.s.zipall(t)])
         mapping_value_type = join_type_list(list(items.values()))
         fallback = self.s.create_anonymous_fallback(
             value_type=mapping_value_type)
         return TypedDictType(items, fallback)
     else:
         return self.default(self.s)
Example #19
0
 def visit_callable_type(self, t: CallableType) -> Type:
     if isinstance(self.s, CallableType) and is_similar_callables(t, self.s):
         if is_equivalent(t, self.s):
             return combine_similar_callables(t, self.s)
         result = join_similar_callables(t, self.s)
         if any(isinstance(tp, (NoneTyp, UninhabitedType)) for tp in result.arg_types):
             # We don't want to return unusable Callable, attempt fallback instead.
             return join_types(t.fallback, self.s)
         return result
     elif isinstance(self.s, Overloaded):
         # Switch the order of arguments to that we'll get to visit_overloaded.
         return join_types(t, self.s)
     else:
         return join_types(t.fallback, self.s)
Example #20
0
 def visit_typeddict_type(self, t: TypedDictType) -> Type:
     if isinstance(self.s, TypedDictType):
         for (_, l, r) in self.s.zip(t):
             if not is_equivalent(l, r):
                 return self.default(self.s)
         items = OrderedDict([
             (item_name, s_item_type or t_item_type)
             for (item_name, s_item_type, t_item_type) in self.s.zipall(t)
         ])
         mapping_value_type = join_type_list(list(items.values()))
         fallback = self.s.create_anonymous_fallback(value_type=mapping_value_type)
         return TypedDictType(items, fallback)
     else:
         return self.default(self.s)
Example #21
0
 def visit_callable_type(self, t: CallableType) -> Type:
     if isinstance(self.s, CallableType) and is_similar_callables(t, self.s):
         if is_equivalent(t, self.s):
             return combine_similar_callables(t, self.s)
         result = join_similar_callables(t, self.s)
         if any(isinstance(tp, (NoneTyp, UninhabitedType)) for tp in result.arg_types):
             # We don't want to return unusable Callable, attempt fallback instead.
             return join_types(t.fallback, self.s)
         return result
     elif isinstance(self.s, Overloaded):
         # Switch the order of arguments to that we'll get to visit_overloaded.
         return join_types(t, self.s)
     else:
         return join_types(t.fallback, self.s)
Example #22
0
 def visit_callable_type(self, t: CallableType) -> Type:
     if isinstance(self.s, CallableType) and is_similar_callables(t, self.s):
         if is_equivalent(t, self.s):
             return combine_similar_callables(t, self.s)
         result = meet_similar_callables(t, self.s)
         if isinstance(result.ret_type, UninhabitedType):
             # Return a plain None or <uninhabited> instead of a weird function.
             return self.default(self.s)
         return result
     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 self.default(self.s)
Example #23
0
 def visit_typeddict_type(self, t: TypedDictType) -> Type:
     if isinstance(self.s, TypedDictType):
         items = OrderedDict([
             (item_name, s_item_type)
             for (item_name, s_item_type, t_item_type) in self.s.zip(t)
             if (is_equivalent(s_item_type, t_item_type) and
                 (item_name in t.required_keys) == (item_name in self.s.required_keys))
         ])
         mapping_value_type = join_type_list(list(items.values()))
         fallback = self.s.create_anonymous_fallback(value_type=mapping_value_type)
         # We need to filter by items.keys() since some required keys present in both t and
         # self.s might be missing from the join if the types are incompatible.
         required_keys = set(items.keys()) & t.required_keys & self.s.required_keys
         return TypedDictType(items, required_keys, fallback)
     elif isinstance(self.s, Instance):
         return join_types(self.s, t.fallback)
     else:
         return self.default(self.s)
Example #24
0
 def visit_callable_type(self, t: CallableType) -> ProperType:
     if isinstance(self.s, CallableType) and is_similar_callables(t, self.s):
         if is_equivalent(t, self.s):
             return combine_similar_callables(t, self.s)
         result = join_similar_callables(t, self.s)
         if any(isinstance(tp, (NoneType, UninhabitedType))
                for tp in get_proper_types(result.arg_types)):
             # We don't want to return unusable Callable, attempt fallback instead.
             return join_types(t.fallback, self.s)
         return result
     elif isinstance(self.s, Overloaded):
         # Switch the order of arguments to that we'll get to visit_overloaded.
         return join_types(t, self.s)
     elif isinstance(self.s, Instance) and self.s.type.is_protocol:
         call = unpack_callback_protocol(self.s)
         if call:
             return join_types(t, call)
     return join_types(t.fallback, self.s)
Example #25
0
File: join.py Project: zdszt/mypy
 def visit_typeddict_type(self, t: TypedDictType) -> Type:
     if isinstance(self.s, TypedDictType):
         items = OrderedDict([
             (item_name, s_item_type)
             for (item_name, s_item_type, t_item_type) in self.s.zip(t)
             if (is_equivalent(s_item_type, t_item_type) and
                 (item_name in t.required_keys) == (item_name in self.s.required_keys))
         ])
         mapping_value_type = join_type_list(list(items.values()))
         fallback = self.s.create_anonymous_fallback(value_type=mapping_value_type)
         # We need to filter by items.keys() since some required keys present in both t and
         # self.s might be missing from the join if the types are incompatible.
         required_keys = set(items.keys()) & t.required_keys & self.s.required_keys
         return TypedDictType(items, required_keys, fallback)
     elif isinstance(self.s, Instance):
         return join_types(self.s, t.fallback)
     else:
         return self.default(self.s)
Example #26
0
 def visit_typeddict_type(self, t: TypedDictType) -> Type:
     if isinstance(self.s, TypedDictType):
         for (_, l, r) in self.s.zip(t):
             if not is_equivalent(l, r):
                 return self.default(self.s)
         item_list = []  # type: List[Tuple[str, Type]]
         for (item_name, s_item_type, t_item_type) in self.s.zipall(t):
             if s_item_type is not None:
                 item_list.append((item_name, s_item_type))
             else:
                 # at least one of s_item_type and t_item_type is not None
                 assert t_item_type is not None
                 item_list.append((item_name, t_item_type))
         items = OrderedDict(item_list)
         mapping_value_type = join_type_list(list(items.values()))
         fallback = self.s.create_anonymous_fallback(
             value_type=mapping_value_type)
         return TypedDictType(items, fallback)
     else:
         return self.default(self.s)
Example #27
0
File: meet.py Project: python/mypy
 def visit_callable_type(self, t: CallableType) -> Type:
     if isinstance(self.s, CallableType) and is_similar_callables(t, self.s):
         if is_equivalent(t, self.s):
             return combine_similar_callables(t, self.s)
         result = meet_similar_callables(t, self.s)
         if isinstance(result.ret_type, UninhabitedType):
             # Return a plain None or <uninhabited> instead of a weird function.
             return self.default(self.s)
         return result
     elif isinstance(self.s, TypeType) and t.is_type_obj() and not t.is_generic():
         # In this case we are able to potentially produce a better meet.
         res = meet_types(self.s.item, t.ret_type)
         if not isinstance(res, (NoneType, UninhabitedType)):
             return TypeType.make_normalized(res)
         return self.default(self.s)
     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 self.default(self.s)
Example #28
0
 def visit_callable_type(self, t: CallableType) -> Type:
     if isinstance(self.s, CallableType) and is_similar_callables(t, self.s):
         if is_equivalent(t, self.s):
             return combine_similar_callables(t, self.s)
         result = meet_similar_callables(t, self.s)
         if isinstance(result.ret_type, UninhabitedType):
             # Return a plain None or <uninhabited> instead of a weird function.
             return self.default(self.s)
         return result
     elif isinstance(self.s, TypeType) and t.is_type_obj() and not t.is_generic():
         # In this case we are able to potentially produce a better meet.
         res = meet_types(self.s.item, t.ret_type)
         if not isinstance(res, (NoneType, UninhabitedType)):
             return TypeType.make_normalized(res)
         return self.default(self.s)
     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 self.default(self.s)
Example #29
0
File: meet.py Project: chadrik/mypy
 def visit_typeddict_type(self, t: TypedDictType) -> Type:
     if isinstance(self.s, TypedDictType):
         for (name, l, r) in self.s.zip(t):
             if (not is_equivalent(l, r) or
                     (name in t.required_keys) != (name in self.s.required_keys)):
                 return self.default(self.s)
         item_list = []  # type: List[Tuple[str, Type]]
         for (item_name, s_item_type, t_item_type) in self.s.zipall(t):
             if s_item_type is not None:
                 item_list.append((item_name, s_item_type))
             else:
                 # at least one of s_item_type and t_item_type is not None
                 assert t_item_type is not None
                 item_list.append((item_name, t_item_type))
         items = OrderedDict(item_list)
         mapping_value_type = join_type_list(list(items.values()))
         fallback = self.s.create_anonymous_fallback(value_type=mapping_value_type)
         required_keys = t.required_keys | self.s.required_keys
         return TypedDictType(items, required_keys, fallback)
     else:
         return self.default(self.s)
Example #30
0
 def visit_typeddict_type(self, t: TypedDictType) -> ProperType:
     if isinstance(self.s, TypedDictType):
         for (name, l, r) in self.s.zip(t):
             if (not is_equivalent(l, r) or
                     (name in t.required_keys) != (name in self.s.required_keys)):
                 return self.default(self.s)
         item_list: List[Tuple[str, Type]] = []
         for (item_name, s_item_type, t_item_type) in self.s.zipall(t):
             if s_item_type is not None:
                 item_list.append((item_name, s_item_type))
             else:
                 # at least one of s_item_type and t_item_type is not None
                 assert t_item_type is not None
                 item_list.append((item_name, t_item_type))
         items = OrderedDict(item_list)
         fallback = self.s.create_anonymous_fallback()
         required_keys = t.required_keys | self.s.required_keys
         return TypedDictType(items, required_keys, fallback)
     elif isinstance(self.s, Instance) and is_subtype(t, self.s):
         return t
     else:
         return self.default(self.s)
Example #31
0
    def check_override(self, override, original, name, supertype, node):
        """Check a method override with given signatures.

        Arguments:
          override:  The signature of the overriding method.
          original:  The signature of the original supertype method.
          name:      The name of the subtype. This and the next argument are
                     only used for generating error messages.
          supertype: The name of the supertype.
        """
        if (isinstance(override, Overloaded) or
                isinstance(original, Overloaded) or
                len((override).arg_types) !=
                    len((original).arg_types) or
                (override).min_args !=
                    (original).min_args):
            if not is_subtype(override, original):
                self.msg.signature_incompatible_with_supertype(
                    name, supertype, node)
            return
        else:
            # Give more detailed messages for the common case of both
            # signatures having the same number of arguments and no
            # intersection types.
            
            coverride = override
            coriginal = original
            
            for i in range(len(coverride.arg_types)):
                if not is_equivalent(coriginal.arg_types[i],
                                     coverride.arg_types[i]):
                    self.msg.argument_incompatible_with_supertype(
                        i + 1, name, supertype, node)
            
            if not is_subtype(coverride.ret_type, coriginal.ret_type):
                self.msg.return_type_incompatible_with_supertype(
                    name, supertype, node)
Example #32
0
        # Found a getter or a setter.
        raise NotImplementedError()
    
    # Could not find the member.
    if is_super:
        msg.undefined_in_superclass(name, node)
        return Any()
    else:
        return msg.has_no_member(itype, name, node)


SymNode lookup_member_var_or_accessor(TypeInfo info, str name, bool is_lvalue):
    """Find the attribute/accessor node that refers to a member of a type."""
    if is_lvalue:
        return info.get_var_or_setter(name)
    else:
        return info.get_var_or_getter(name)


void check_method_type(FunctionLike functype, Instance itype, Context context,
                       MessageBuilder msg):
    for item in functype.items():
        if not item.arg_types or item.arg_kinds[0] != ARG_POS:
            # No positional first (self) argument.
            msg.invalid_method_type(item, context)
        else:
            # Check that self argument has type 'any' or valid instance type.
            selfarg = item.arg_types[0]
            if not subtypes.is_equivalent(selfarg, itype):
                msg.invalid_method_type(item, context)
        def process_gql_schema(ctx: AttributeContext) -> Type:
            """
            Actually perform the type-checking logic for each graphene `ObjectType` child class.
            The plugin is invoked at type-checking time.
            """

            assert isinstance(ctx.type, Instance)
            object_info = self._graphene_objects[ctx.type.type.fullname]
            all_fields = object_info.all_fields if isinstance(
                object_info, ObjectTypeInfo) else object_info.fields

            # Check that resolver methods are annotated with the correct types
            for resolver in object_info.resolvers.values():
                gql_field = all_fields.get(resolver.field_name)

                if not gql_field:
                    if isinstance(
                            object_info,
                            InterfaceInfo) and resolver.field_name == 'type':
                        # This is not a field resolver. It is the special `Interface` resolver that determines which
                        # `ObjectType` to use at runtime.
                        continue

                    ctx.api.fail(
                        f'No field with name "{resolver.field_name}" defined',
                        resolver.context)
                    continue

                # Check that the resolver's "previous" (first) argument has the correct type
                if not is_equivalent(resolver.previous_argument.type,
                                     object_info.runtime_type):
                    ctx.api.fail(
                        _get_type_mismatch_error_message(
                            resolver.previous_argument.name,
                            graphene_type=object_info.runtime_type,
                            resolver_type=resolver.previous_argument.type,
                        ),
                        resolver.previous_argument.context,
                    )
                    continue

                # Check that the resolver returns the correct type
                if not is_subtype(resolver.return_type, gql_field.type):
                    ctx.api.fail(
                        f'Resolver returns type {resolver.return_type}, expected type {gql_field.type}',
                        resolver.context,
                    )
                    continue

                for field_argument in gql_field.arguments.values():
                    resolver_argument = resolver.arguments.get(
                        field_argument.name)

                    # Check that the resolver has an argument for each argument the `Field()` defines
                    if not resolver_argument:
                        ctx.api.fail(
                            f'Parameter "{field_argument.name}" of type {field_argument.type} is missing,'
                            ' but required in resolver definition',
                            resolver.context,
                        )
                        continue

                    # Check that the resolver's argument has the correct type annotation
                    if not is_equivalent(field_argument.type,
                                         resolver_argument.type):
                        ctx.api.fail(
                            _get_type_mismatch_error_message(
                                field_argument.name,
                                graphene_type=field_argument.type,
                                resolver_type=resolver_argument.type,
                            ),
                            resolver_argument.context,
                        )
                        continue

            # If no resolver function is defined, type-check the behavior of the graphene default resolver
            if isinstance(object_info, ObjectTypeInfo):
                # The default resolver doesn't apply to `Interface`s because the `ObjectType`s that implement them could
                # have resolvers for their fields.
                # TODO: Detect if any of an `Interface`'s `ObjectType`s do _not_ define their own resolver for this
                # field. In that case, we _do_ want to type-check the default resolver.
                fields_without_resolver_names = set(
                    object_info.fields.keys()) - set(
                        object_info.resolvers.keys())
                for name in fields_without_resolver_names:
                    gql_field = object_info.fields[name]
                    # Note: `analyze_member_access` will call `ctx.api.fail()` if the provided type doesn't have
                    # a member with the given name at all. So our code only needs to do the subtype check.
                    default_resolver_return_type = analyze_member_access(
                        gql_field.name,
                        object_info.runtime_type,
                        gql_field.context,
                        False,  # is_lvalue
                        False,  # is_super
                        False,  # is_operator
                        ctx.api.msg,
                        original_type=object_info.runtime_type,
                        chk=cast(TypeChecker, ctx.api),
                    )
                    if not is_subtype(default_resolver_return_type,
                                      gql_field.type):
                        ctx.api.fail(
                            f'Field expects type {gql_field.type} but {object_info.runtime_type}.{gql_field.name} has '
                            f'type {default_resolver_return_type}',
                            gql_field.context,
                        )
                    continue

            return ctx.default_attr_type
Example #34
0
 def check_type_equivalency(self, t1, t2, node, msg=messages.INCOMPATIBLE_TYPES):
     """Generate an error if the types are not equivalent. The
     dynamic type is equivalent with all types.
     """
     if not is_equivalent(t1, t2):
         self.fail(msg, node)
Example #35
0
def enum_value_callback(ctx: 'mypy.plugin.AttributeContext') -> Type:
    """This plugin refines the 'value' attribute in enums to refer to
    the original underlying value. For example, suppose we have the
    following:

        class SomeEnum:
            FOO = A()
            BAR = B()

    By default, mypy will infer that 'SomeEnum.FOO.value' and
    'SomeEnum.BAR.value' both are of type 'Any'. This plugin refines
    this inference so that mypy understands the expressions are
    actually of types 'A' and 'B' respectively. This better reflects
    the actual runtime behavior.

    This plugin works simply by looking up the original value assigned
    to the enum. For example, when this plugin sees 'SomeEnum.BAR.value',
    it will look up whatever type 'BAR' had in the SomeEnum TypeInfo and
    use that as the inferred type of the overall expression.

    This plugin assumes that the provided context is an attribute access
    matching one of the strings found in 'ENUM_VALUE_ACCESS'.
    """
    enum_field_name = _extract_underlying_field_name(ctx.type)
    if enum_field_name is None:
        # We do not know the enum field name (perhaps it was passed to a
        # function and we only know that it _is_ a member).  All is not lost
        # however, if we can prove that the all of the enum members have the
        # same value-type, then it doesn't matter which member was passed in.
        # The value-type is still known.
        if isinstance(ctx.type, Instance):
            info = ctx.type.type

            # As long as mypy doesn't understand attribute creation in __new__,
            # there is no way to predict the value type if the enum class has a
            # custom implementation
            if _implements_new(info):
                return ctx.default_attr_type

            stnodes = (info.get(name) for name in info.names)

            # Enums _can_ have methods and instance attributes.
            # Omit methods and attributes created by assigning to self.*
            # for our value inference.
            node_types = (get_proper_type(n.type) if n else None
                          for n in stnodes if n is None or not n.implicit)
            proper_types = list(
                _infer_value_type_with_auto_fallback(ctx, t)
                for t in node_types
                if t is None or not isinstance(t, CallableType))
            underlying_type = _first(proper_types)
            if underlying_type is None:
                return ctx.default_attr_type

            # At first we try to predict future `value` type if all other items
            # have the same type. For example, `int`.
            # If this is the case, we simply return this type.
            # See https://github.com/python/mypy/pull/9443
            all_same_value_type = all(
                proper_type is not None and proper_type == underlying_type
                for proper_type in proper_types)
            if all_same_value_type:
                if underlying_type is not None:
                    return underlying_type

            # But, after we started treating all `Enum` values as `Final`,
            # we start to infer types in
            # `item = 1` as `Literal[1]`, not just `int`.
            # So, for example types in this `Enum` will all be different:
            #
            #  class Ordering(IntEnum):
            #      one = 1
            #      two = 2
            #      three = 3
            #
            # We will infer three `Literal` types here.
            # They are not the same, but they are equivalent.
            # So, we unify them to make sure `.value` prediction still works.
            # Result will be `Literal[1] | Literal[2] | Literal[3]` for this case.
            all_equivalent_types = all(
                proper_type is not None
                and is_equivalent(proper_type, underlying_type)
                for proper_type in proper_types)
            if all_equivalent_types:
                return make_simplified_union(cast(Sequence[Type],
                                                  proper_types))
        return ctx.default_attr_type

    assert isinstance(ctx.type, Instance)
    info = ctx.type.type

    # As long as mypy doesn't understand attribute creation in __new__,
    # there is no way to predict the value type if the enum class has a
    # custom implementation
    if _implements_new(info):
        return ctx.default_attr_type

    stnode = info.get(enum_field_name)
    if stnode is None:
        return ctx.default_attr_type

    underlying_type = _infer_value_type_with_auto_fallback(
        ctx, get_proper_type(stnode.type))
    if underlying_type is None:
        return ctx.default_attr_type

    return underlying_type