Skip to content

Assignability of overloaded implementation to Proto[**P](Protocol) is overload-order-sensitive #19480

@bzoracler

Description

@bzoracler

Bug Report, To Reproduce & Actual Behaviour

When matching a method signature in a protocol with an overloaded implementation, the implementation's overload order appears to matter, even when only one of the overloads match.

In the following example, only the first overload of the implementation is tried for compatibility with the protocol (which looks similar to the issue in #14070). See mypy Playground:

# mypy: disable-error-code=no-overload-impl

from typing import *

_A_contra = TypeVar("_A_contra", bound=Literal["a", "b"], contravariant=True)
_P = ParamSpec("_P")

class Callback(Protocol[_A_contra, _P]):
    def method(self, a: _A_contra, *args: _P.args, **kwargs: _P.kwargs) -> None: ...
    
class Impl:
    @overload
    def method(self, a: Literal["a"], b: int) -> None: ...
    @overload
    def method(self, a: int, b: str) -> None: ...

class Impl2:  # Overload signature order is reversed compared with `Impl`
    @overload
    def method(self, a: int, b: str) -> None: ...
    @overload
    def method(self, a: Literal["a"], b: int) -> None: ...

def accepts_callback(cb: Callback[Literal["a"], _P], *args: _P.args, **kwargs: _P.kwargs) -> int: 
    return 1

a = accepts_callback(Impl(), 1)
b = accepts_callback(Impl2(), 1)  # Error
reveal_type(a)
reveal_type(b)

Expected Behavior

No errors

Your Environment

  • Mypy version used: 1.16.1, master
  • Python version used: 3.12

Metadata

Metadata

Assignees

No one assigned

    Labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions