Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 6 additions & 8 deletions mypy/checkexpr.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
import mypy.checker
from mypy import types
from mypy.sametypes import is_same_type
from mypy.erasetype import replace_meta_vars
from mypy.erasetype import replace_meta_vars, erase_type
from mypy.messages import MessageBuilder
from mypy import messages
from mypy.infer import infer_type_arguments, infer_function_type_arguments
Expand Down Expand Up @@ -1314,14 +1314,12 @@ def infer_overload_return_type(self,
return None
elif any_causes_overload_ambiguity(matches, return_types, arg_types, arg_kinds, arg_names):
# An argument of type or containing the type 'Any' caused ambiguity.
if all(is_subtype(ret_type, return_types[-1]) and
is_subtype(return_types[-1], ret_type)
for ret_type in return_types[:-1]):
# The last match is mutually compatible with all previous ones, so it's safe
# to return that inferred type.
return return_types[-1], inferred_types[-1]
# We try returning a precise type if we can. If not, we give up and just return 'Any'.
if all_same_types(return_types):
return return_types[0], inferred_types[0]
elif all_same_types(erase_type(typ) for typ in return_types):
return erase_type(return_types[0]), erase_type(inferred_types[0])
else:
# We give up and return 'Any'.
return self.check_call(callee=AnyType(TypeOfAny.special_form),
args=args,
arg_kinds=arg_kinds,
Expand Down
20 changes: 14 additions & 6 deletions mypy/erasetype.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,19 +5,19 @@
CallableType, TupleType, TypedDictType, UnionType, Overloaded, ErasedType, PartialType,
DeletedType, TypeTranslator, UninhabitedType, TypeType, TypeOfAny
)
from mypy.nodes import ARG_STAR, ARG_STAR2


def erase_type(typ: Type) -> Type:
"""Erase any type variables from a type.

Also replace tuple types with the corresponding concrete types. Replace
callable types with empty callable types.
Also replace tuple types with the corresponding concrete types.

Examples:
A -> A
B[X] -> B[Any]
Tuple[A, B] -> tuple
Callable[...] -> Callable[[], None]
Callable[[A1, A2, ...], R] -> Callable[..., Any]
Type[X] -> Type[Any]
"""

Expand Down Expand Up @@ -57,11 +57,19 @@ def visit_type_var(self, t: TypeVarType) -> Type:

def visit_callable_type(self, t: CallableType) -> Type:
# We must preserve the fallback type for overload resolution to work.
ret_type = NoneTyp() # type: Type
return CallableType([], [], [], ret_type, t.fallback)
any_type = AnyType(TypeOfAny.special_form)
return CallableType(
arg_types=[any_type, any_type],
arg_kinds=[ARG_STAR, ARG_STAR2],
arg_names=[None, None],
ret_type=any_type,
fallback=t.fallback,
is_ellipsis_args=True,
implicit=True,
)

def visit_overloaded(self, t: Overloaded) -> Type:
return t.items()[0].accept(self)
return t.fallback.accept(self)

def visit_tuple_type(self, t: TupleType) -> Type:
return t.fallback.accept(self)
Expand Down
14 changes: 11 additions & 3 deletions mypy/test/testtypes.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
UnboundType, AnyType, CallableType, TupleType, TypeVarDef, Type, Instance, NoneTyp, Overloaded,
TypeType, UnionType, UninhabitedType, true_only, false_only, TypeVarId, TypeOfAny
)
from mypy.nodes import ARG_POS, ARG_OPT, ARG_STAR, CONTRAVARIANT, INVARIANT, COVARIANT
from mypy.nodes import ARG_POS, ARG_OPT, ARG_STAR, ARG_STAR2, CONTRAVARIANT, INVARIANT, COVARIANT
from mypy.subtypes import is_subtype, is_more_precise, is_proper_subtype
from mypy.test.typefixture import TypeFixture, InterfaceTypeFixture

Expand Down Expand Up @@ -150,11 +150,19 @@ def test_erase_with_tuple_type(self) -> None:

def test_erase_with_function_type(self) -> None:
self.assert_erase(self.fx.callable(self.fx.a, self.fx.b),
self.fx.callable_type(self.fx.nonet))
CallableType(arg_types=[self.fx.anyt, self.fx.anyt],
arg_kinds=[ARG_STAR, ARG_STAR2],
arg_names=[None, None],
ret_type=self.fx.anyt,
fallback=self.fx.function))

def test_erase_with_type_object(self) -> None:
self.assert_erase(self.fx.callable_type(self.fx.a, self.fx.b),
self.fx.callable_type(self.fx.nonet))
CallableType(arg_types=[self.fx.anyt, self.fx.anyt],
arg_kinds=[ARG_STAR, ARG_STAR2],
arg_names=[None, None],
ret_type=self.fx.anyt,
fallback=self.fx.type_type))

def test_erase_with_type_type(self) -> None:
self.assert_erase(self.fx.type_a, self.fx.type_a)
Expand Down
80 changes: 80 additions & 0 deletions test-data/unit/check-overloading.test
Original file line number Diff line number Diff line change
Expand Up @@ -1443,6 +1443,86 @@ reveal_type(f(**a)) # E: Revealed type is 'Any'

[builtins fixtures/dict.pyi]

[case testOverloadWithOverlappingItemsAndAnyArgument12]
from typing import overload, Any

@overload
def f(x: int) -> Any: ...
@overload
def f(x: str) -> str: ...
def f(x): pass

a: Any
reveal_type(f(a)) # E: Revealed type is 'Any'

[case testOverloadWithOverlappingItemsAndAnyArgument13]
from typing import Any, overload, TypeVar, Generic

class slice: pass

T = TypeVar('T')
class A(Generic[T]):
@overload
def f(self, x: int) -> T: ...
@overload
def f(self, x: slice) -> A[T]: ...
def f(self, x): ...

i: Any
a: A[Any]
reveal_type(a.f(i)) # E: Revealed type is 'Any'

[case testOverloadWithOverlappingItemsAndAnyArgument14]
from typing import Any, overload, TypeVar, Generic

T = TypeVar('T')

class Wrapper(Generic[T]): pass
class slice: pass

class A(Generic[T]):
@overload
def f(self, x: int) -> Wrapper[T]: ...
@overload
def f(self, x: slice) -> Wrapper[A[T]]: ...
def f(self, x): ...

i: Any
a: A[Any]
reveal_type(a.f(i)) # E: Revealed type is '__main__.Wrapper[Any]'

[case testOverloadWithOverlappingItemsAndAnyArgument15]
from typing import overload, Any, Union

@overload
def f(x: int) -> str: ...
@overload
def f(x: str) -> str: ...
def f(x): pass

@overload
def g(x: int) -> Union[str, int]: ...
@overload
def g(x: str) -> Union[int, str]: ...
def g(x): pass

a: Any
reveal_type(f(a)) # E: Revealed type is 'builtins.str'
reveal_type(g(a)) # E: Revealed type is 'Union[builtins.str, builtins.int]'

[case testOverloadWithOverlappingItemsAndAnyArgument16]
from typing import overload, Any, Union, Callable

@overload
def f(x: int) -> Callable[[int, int], int]: ...
@overload
def f(x: str) -> Callable[[str], str]: ...
def f(x): pass

a: Any
reveal_type(f(a)) # E: Revealed type is 'def (*Any, **Any) -> Any'
reveal_type(f(a)(a)) # E: Revealed type is 'Any'

[case testOverloadOnOverloadWithType]
from typing import Any, Type, TypeVar, overload
from mod import MyInt
Expand Down