diff --git a/mypy/constraints.py b/mypy/constraints.py index c8c3c7933b6e..a341a2f31149 100644 --- a/mypy/constraints.py +++ b/mypy/constraints.py @@ -10,7 +10,7 @@ from mypy.argmap import ArgTypeExpander from mypy.erasetype import erase_typevars from mypy.maptype import map_instance_to_supertype -from mypy.nodes import ARG_OPT, ARG_POS, CONTRAVARIANT, COVARIANT, ArgKind +from mypy.nodes import ARG_OPT, ARG_POS, CONTRAVARIANT, COVARIANT, ArgKind, FuncDef from mypy.types import ( TUPLE_LIKE_INSTANCE_NAMES, AnyType, @@ -1138,8 +1138,13 @@ def find_matching_overload_item(overloaded: Overloaded, template: CallableType) item, template, is_compat=mypy.subtypes.is_subtype, 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. + # Try to return the first item with the correct self type (fixes issue 14943). + for item in items: + if isinstance(item.definition, FuncDef) and isinstance(item.definition.type, CallableType): + if item.bound_args and item.definition.type.arg_types: + if item.bound_args[0] == item.definition.type.arg_types[0]: + return item + # Give up and just return the first of all items. return items[0] diff --git a/test-data/unit/check-protocols.test b/test-data/unit/check-protocols.test index 182745b99e40..7c7d352d9b22 100644 --- a/test-data/unit/check-protocols.test +++ b/test-data/unit/check-protocols.test @@ -4020,3 +4020,42 @@ class P(Protocol): [file lib.py] class C: ... + +[case TestOverloadedMethodWithExplictSelfTypes] +from typing import Generic, overload, Protocol, TypeVar, Union + +AnyStr = TypeVar("AnyStr", str, bytes) +T_co = TypeVar("T_co", covariant=True) +T_contra = TypeVar("T_contra", contravariant=True) + +class SupportsRead(Protocol[T_co]): + def read(self) -> T_co: ... + +class SupportsWrite(Protocol[T_contra]): + def write(self, s: T_contra) -> int: ... + +class Input(Generic[AnyStr]): + def read(self) -> AnyStr: ... + +class Output(Generic[AnyStr]): + @overload + def write(self: Output[str], s: str) -> int: ... + @overload + def write(self: Output[bytes], s: bytes) -> int: ... + def write(self, s: Union[str, bytes]) -> int: ... + +def f(src: SupportsRead[AnyStr], dst: SupportsWrite[AnyStr]) -> None: ... + +def g1(a: Input[bytes], b: Output[bytes]) -> None: + f(a, b) + +def g2(a: Input[bytes], b: Output[bytes]) -> None: + f(a, b) + +def g3(a: Input[str], b: Output[bytes]) -> None: + f(a, b) # E: Cannot infer type argument 1 of "f" + +def g4(a: Input[bytes], b: Output[str]) -> None: + f(a, b) # E: Cannot infer type argument 1 of "f" + +[builtins fixtures/tuple.pyi]