python / mypy

Optional static typing for Python
https://www.mypy-lang.org/
Other
18.47k stars 2.83k forks source link

`singledispatch.register` doesn't typecheck registration of generic functions #13040

Open inducer opened 2 years ago

inducer commented 2 years ago

To Reproduce

Run mypy (no options) on this file:

:warning: See below for actual MWE. This is preserved here to preserve the flow of discussion.

from typing import TypeVar
from functools import singledispatch

T = TypeVar("T")

@singledispatch
def f(x: T) -> T:
    return x

class A:
    pass

@f.register(A)
def _f_a(x: A) -> A:
    return x

Expected Behavior

No complaint. There's no bound on T, so I feel that _f_a should be acceptable.

Actual Behavior

mypybug.py:15: error: Dispatch type "A" must be subtype of fallback function first argument "T"
Found 1 error in 1 file (checked 1 source file)

Your Environment

hauntsaninja commented 2 years ago

I don't think this is type safe. If B is a subclass of A, f(b) promises you a B, but _f_a(b) gives you an A

inducer commented 2 years ago

Thanks, fair point. Here's another attempt that, I think, addresses your concern, however mypy still complains in the same way. Arguably, it should consider the actual prototype of _f_a, unless singledispatch is to be taught about type variables (sounds unlikely?).

from typing import TypeVar
from functools import singledispatch

T = TypeVar("T")

@singledispatch
def f(x: T) -> T:
    return x

class A:
    pass

AT = TypeVar("AT", bound=A)

@f.register(A)
def _f_a(x: AT) -> AT:
    return x