Skip to content

False-positive no-matching-overload on constructor when a covariant generic class is passed to a function expecting a parameterized-protocol instantiation #3236

@posita

Description

@posita

UPDATE: This might be fixed. I can repro with 0.62.0 and Python 3.11.15, but not in the sandbox. I'm not sure how to tell what commit the sandbox is running. Apologies if this is obvious and I missed it.

Describe the Bug

Description

When a covariant generic class H[_T_co] has a concrete __init__ overload typed as self: H[int] / init_val: int, and a function accepts H[CanAdd[_AddWithT, _ResultT]] (a two-TypeVar protocol), pyrefly raises no-matching-overload on the bare constructor call H(10).

The call should be semantically valid:

  • H(10) resolves to H[int] via the int overload.
  • int structurally satisfies CanAdd[int, int]
    (int.__add__(int) -> int).
  • Because _T_co is covariant, H[int] is a subtype of
    H[CanAdd[int, int]].
  • Type-variable unification therefore yields _AddWithT = int,
    _ResultT = int, and the return type is H[int].

mypy (--strict), pyright, and ty all accept this code without errors.

The error message itself also seems misleading: pyrefly blames H.__init__ for not accepting Literal[10], but Literal[10] is obviously a subtype of int. The real issue appears to be that pyrefly propagates the expected type H[CanAdd[...]] backwards into overload selection before solving the free TypeVars, finds no overload whose self annotation exactly matches H[CanAdd[...]], and raises the error at the inner H(10) constructor rather than at the outer explode_n call.

Versions

pyrefly 0.62.0 → 1 error
mypy 1.x --strict → 0 errors
pyright → 0 errors
ty → 0 errors

from typing import Generic, Never, Protocol, TypeVar, overload

_T = TypeVar("_T")
_T_co = TypeVar("_T_co", covariant=True)
_AddWithT_contra = TypeVar("_AddWithT_contra", contravariant=True)
_ResultT_co = TypeVar("_ResultT_co", covariant=True)
_AddWithT = TypeVar("_AddWithT")
_ResultT = TypeVar("_ResultT")

class CanAdd(Protocol[_AddWithT_contra, _ResultT_co]):
    def __add__(self, other: _AddWithT_contra, /) -> _ResultT_co: ...

class H(Generic[_T_co]):
    @overload
    def __init__(self: "H[Never]", init_val: dict[Never, int], /) -> None: ...
    @overload
    def __init__(self: "H[_T]", init_val: dict[_T, int], /) -> None: ...
    @overload
    def __init__(self: "H[int]", init_val: int, /) -> None: ...
    def __init__(self, init_val: object, /) -> None: ...

def explode_n(source: "H[CanAdd[_AddWithT, _ResultT]]") -> "H[_ResultT]":
    raise NotImplementedError

# pyrefly 0.62.0 raises:
#   ERROR No matching overload found for function `H.__init__`
#         called with arguments: (Literal[10]) [no-matching-overload]
# mypy --strict, pyright, ty: no errors
result: "H[int]" = explode_n(H(10))

Sandbox Link

https://pyrefly.org/sandbox/?project=N4IgZglgNgpgziAXKOBDAdgEwEYHsAeAdAA4CeS4ATrgLYAEALqcROgOZ0Q3G6UN0BxGOhiUIAYwA0dAHIwAbqOkAFag1zjcUaQBVmMAGqpK03IspRcqTAB10dgPo66AXjp7ih4wAobIJ34AlI46Dpqu7vpGlL7%2BoZp%2B0pryxhAYDC46lACuMMHoDgCCmJgA6hAMABbxuOgMlKgRHl4xfkUl5VU1dQ2JdJo9qCli6Zk5eY4ASvDZUAw1TVE%2BbdNws-NhuH3JqaNZufntZRXVi57RsUed1UFTM3PObs0XK-fzt-bo4lCocHB0AGEMMVMN5VLh1JooABtK4nbr1VDSByrdY1AC6gUQdjouLomBgYDoDgc1kwJO8cBgUDApiqokQxJB1wRDWkAHpAnQALQAPmJqIem0ZhFFdjs31%2B-wAEt4hCIxOJYRisTi8QABMyiSzWNW4glEkmsCoUqk0xl%2BaXQuTmdF9Y0MBwpKCMzASBjWhRKTh1dEcrl82S1GAisXoPF0TXmHW2cN4g3EhwO03UsAWkBWpx2kDSZPO13u5W533%2Bnn8mTB0OEPWRrUWKyxiMJo3oE0OSmp9NW1gMbPFk35n0MUuBisiKs15tJ1uO9tm2k%2BgeoF10XDYABWMHEw7onLLQfHdFF1c%2BCZg%2BGIlgJDnQlNw2Uo4hDdEt0KB6BBsOZ8ORgvm6OzAN%2BVfFE3h0bNsTjXEGggKkgwYABJbhYBoYQGBgTAAFFKGoShxXQABiOgyEoQkoFIOgAAZCAANgAJkISi6Bgqk4EgojcUwyZJgAeUmIM6BoVAGHESpWA4OsYzoMB7ywaTeGk7IvgYCBajoAADaVCBbNt1LsDiIzxcRl1gTA6AAdxOOhjDYbJULqNi6G8AAZCpRGXaEAEZKMxOhoXQXBuSEkSxPYblJIbO1CME5gKO5bk4Hqd1pBIiA2EqHcmEZAK6FEXC4DsUi1jmLtoR7bMInPS9cGvW9ZW8wJAhzEASLI0hCHUGgoAoIjlFIUiwHIug0CwPB8H6WpIFshoVNqE8iIAZRgGA6AyhhiDY9l2Vawb2t4Nh2WEdlMA0OB2QGKaH2E1T0HZeTKGslJoFQbBYAm9BLpmm7V2IWb0DgE8yCqWpuXMOBvrcPwAGZCE8ui-DsaE8t4OAoqUrgeD4DDuTdUjtwgRQIgAcjSgLSKJuwAoYblSIAR2yCBSMwbkAGsYFIblUHEJ8-mJ8zjHQCn0BAABfSQQC5lTFAAMWgGAKBGnACBIcgRaAA

(Only applicable for extension issues) IDE Information

No response

Metadata

Metadata

Assignees

Type

No fields configured for Bug.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions