Skip to content

Commit 807bd39

Browse files
ilevkivskyikoogoro
authored andcommitted
Fix ParamSpec inference for callback protocols (#15986)
Fixes #15984 Fix is straightforward, `ParamSpec` inference special-casing should put instances with `__call__` and callable types on same ground.
1 parent d7b2451 commit 807bd39

File tree

2 files changed

+19
-0
lines changed

2 files changed

+19
-0
lines changed

mypy/checkexpr.py

+4
Original file line numberDiff line numberDiff line change
@@ -2185,6 +2185,10 @@ def get_arg_infer_passes(
21852185
# run(test, 1, 2)
21862186
# we will use `test` for inference, since it will allow to infer also
21872187
# argument *names* for P <: [x: int, y: int].
2188+
if isinstance(p_actual, Instance):
2189+
call_method = find_member("__call__", p_actual, p_actual, is_operator=True)
2190+
if call_method is not None:
2191+
p_actual = get_proper_type(call_method)
21882192
if (
21892193
isinstance(p_actual, CallableType)
21902194
and not p_actual.variables

test-data/unit/check-parameter-specification.test

+15
Original file line numberDiff line numberDiff line change
@@ -1824,3 +1824,18 @@ class C(Generic[P]): ...
18241824
c: C[int, [int, str], str] # E: Nested parameter specifications are not allowed
18251825
reveal_type(c) # N: Revealed type is "__main__.C[Any]"
18261826
[builtins fixtures/paramspec.pyi]
1827+
1828+
[case testParamSpecInferenceWithCallbackProtocol]
1829+
from typing import Protocol, Callable, ParamSpec
1830+
1831+
class CB(Protocol):
1832+
def __call__(self, x: str, y: int) -> None: ...
1833+
1834+
P = ParamSpec('P')
1835+
def g(fn: Callable[P, None], *args: P.args, **kwargs: P.kwargs) -> None: ...
1836+
1837+
cb: CB
1838+
g(cb, y=0, x='a') # OK
1839+
g(cb, y='a', x=0) # E: Argument "y" to "g" has incompatible type "str"; expected "int" \
1840+
# E: Argument "x" to "g" has incompatible type "int"; expected "str"
1841+
[builtins fixtures/paramspec.pyi]

0 commit comments

Comments
 (0)