Skip to content

Commit 222b104

Browse files
Show Protocol __call__ for arguments with incompatible types (#18214)
Fixes issue #17840 Check if callee_type.is_protocol if so calls find_member like before on the callee_type and then calls self.note_call() to report the note.
1 parent 54ff364 commit 222b104

File tree

3 files changed

+28
-13
lines changed

3 files changed

+28
-13
lines changed

mypy/messages.py

+4-1
Original file line numberDiff line numberDiff line change
@@ -870,7 +870,10 @@ def incompatible_argument_note(
870870
)
871871
if call:
872872
self.note_call(original_caller_type, call, context, code=code)
873-
873+
if isinstance(callee_type, Instance) and callee_type.type.is_protocol:
874+
call = find_member("__call__", callee_type, callee_type, is_operator=True)
875+
if call:
876+
self.note_call(callee_type, call, context, code=code)
874877
self.maybe_note_concatenate_pos_args(original_caller_type, callee_type, context, code)
875878

876879
def maybe_note_concatenate_pos_args(

test-data/unit/check-inference.test

+8-4
Original file line numberDiff line numberDiff line change
@@ -3677,7 +3677,8 @@ def f(x: Call[T]) -> Tuple[T, T]: ...
36773677

36783678
def g(__x: str) -> None: pass
36793679
reveal_type(f(g)) # N: Revealed type is "Tuple[Never, Never]" \
3680-
# E: Argument 1 to "f" has incompatible type "Callable[[str], None]"; expected "Call[Never]"
3680+
# E: Argument 1 to "f" has incompatible type "Callable[[str], None]"; expected "Call[Never]" \
3681+
# N: "Call[Never].__call__" has type "Callable[[NamedArg(Never, 'x')], None]"
36813682
[builtins fixtures/list.pyi]
36823683

36833684
[case testCallableInferenceAgainstCallableNamedVsPosOnly]
@@ -3693,7 +3694,8 @@ def f(x: Call[T]) -> Tuple[T, T]: ...
36933694

36943695
def g(*, x: str) -> None: pass
36953696
reveal_type(f(g)) # N: Revealed type is "Tuple[Never, Never]" \
3696-
# E: Argument 1 to "f" has incompatible type "Callable[[NamedArg(str, 'x')], None]"; expected "Call[Never]"
3697+
# E: Argument 1 to "f" has incompatible type "Callable[[NamedArg(str, 'x')], None]"; expected "Call[Never]" \
3698+
# N: "Call[Never].__call__" has type "Callable[[Never], None]"
36973699
[builtins fixtures/list.pyi]
36983700

36993701
[case testCallableInferenceAgainstCallablePosOnlyVsKwargs]
@@ -3709,7 +3711,8 @@ def f(x: Call[T]) -> Tuple[T, T]: ...
37093711

37103712
def g(**x: str) -> None: pass
37113713
reveal_type(f(g)) # N: Revealed type is "Tuple[Never, Never]" \
3712-
# E: Argument 1 to "f" has incompatible type "Callable[[KwArg(str)], None]"; expected "Call[Never]"
3714+
# E: Argument 1 to "f" has incompatible type "Callable[[KwArg(str)], None]"; expected "Call[Never]" \
3715+
# N: "Call[Never].__call__" has type "Callable[[Never], None]"
37133716
[builtins fixtures/list.pyi]
37143717

37153718
[case testCallableInferenceAgainstCallableNamedVsArgs]
@@ -3725,7 +3728,8 @@ def f(x: Call[T]) -> Tuple[T, T]: ...
37253728

37263729
def g(*args: str) -> None: pass
37273730
reveal_type(f(g)) # N: Revealed type is "Tuple[Never, Never]" \
3728-
# E: Argument 1 to "f" has incompatible type "Callable[[VarArg(str)], None]"; expected "Call[Never]"
3731+
# E: Argument 1 to "f" has incompatible type "Callable[[VarArg(str)], None]"; expected "Call[Never]" \
3732+
# N: "Call[Never].__call__" has type "Callable[[NamedArg(Never, 'x')], None]"
37293733
[builtins fixtures/list.pyi]
37303734

37313735
[case testInferenceAgainstTypeVarActualBound]

test-data/unit/check-protocols.test

+16-8
Original file line numberDiff line numberDiff line change
@@ -2473,7 +2473,8 @@ def func(caller: Caller) -> None:
24732473
pass
24742474

24752475
func(call)
2476-
func(bad) # E: Argument 1 to "func" has incompatible type "Callable[[int, VarArg(str)], None]"; expected "Caller"
2476+
func(bad) # E: Argument 1 to "func" has incompatible type "Callable[[int, VarArg(str)], None]"; expected "Caller" \
2477+
# N: "Caller.__call__" has type "Callable[[Arg(str, 'x'), VarArg(int)], None]"
24772478
[builtins fixtures/tuple.pyi]
24782479
[out]
24792480

@@ -2510,7 +2511,8 @@ def func(caller: Caller) -> None:
25102511
pass
25112512

25122513
func(call)
2513-
func(bad) # E: Argument 1 to "func" has incompatible type "Callable[[int], int]"; expected "Caller"
2514+
func(bad) # E: Argument 1 to "func" has incompatible type "Callable[[int], int]"; expected "Caller" \
2515+
# N: "Caller.__call__" has type "Callable[[Arg(T, 'x')], T]"
25142516
[builtins fixtures/tuple.pyi]
25152517
[out]
25162518

@@ -2530,7 +2532,8 @@ def func(caller: Caller) -> None:
25302532
pass
25312533

25322534
func(call)
2533-
func(bad) # E: Argument 1 to "func" has incompatible type "Callable[[T], Tuple[T, T]]"; expected "Caller"
2535+
func(bad) # E: Argument 1 to "func" has incompatible type "Callable[[T], Tuple[T, T]]"; expected "Caller" \
2536+
# N: "Caller.__call__" has type "Callable[[Arg(int, 'x')], int]"
25342537
[builtins fixtures/tuple.pyi]
25352538
[out]
25362539

@@ -2557,7 +2560,8 @@ def func(caller: Caller) -> None:
25572560
pass
25582561

25592562
func(call)
2560-
func(bad) # E: Argument 1 to "func" has incompatible type "Callable[[Union[int, str]], Union[int, str]]"; expected "Caller"
2563+
func(bad) # E: Argument 1 to "func" has incompatible type "Callable[[Union[int, str]], Union[int, str]]"; expected "Caller" \
2564+
# N: "Caller.__call__" has type overloaded function
25612565
[out]
25622566

25632567
[case testCallableImplementsProtocolExtraNote]
@@ -2596,7 +2600,8 @@ def anon(caller: CallerAnon) -> None:
25962600

25972601

25982602
func(call)
2599-
func(bad) # E: Argument 1 to "func" has incompatible type "Callable[[str], None]"; expected "Caller"
2603+
func(bad) # E: Argument 1 to "func" has incompatible type "Callable[[str], None]"; expected "Caller" \
2604+
# N: "Caller.__call__" has type "Callable[[Arg(str, 'x')], None]"
26002605
anon(bad)
26012606
[out]
26022607

@@ -2619,7 +2624,8 @@ a: Other
26192624
b: Bad
26202625

26212626
func(a)
2622-
func(b) # E: Argument 1 to "func" has incompatible type "Bad"; expected "One"
2627+
func(b) # E: Argument 1 to "func" has incompatible type "Bad"; expected "One" \
2628+
# N: "One.__call__" has type "Callable[[Arg(str, 'x')], None]"
26232629
[out]
26242630

26252631
[case testJoinProtocolCallback]
@@ -3589,7 +3595,8 @@ test(C) # E: Argument 1 to "test" has incompatible type "Type[C]"; expected "P"
35893595
# N: Expected: \
35903596
# N: def __call__(x: int, y: int) -> Any \
35913597
# N: Got: \
3592-
# N: def __init__(x: int, y: str) -> C
3598+
# N: def __init__(x: int, y: str) -> C \
3599+
# N: "P.__call__" has type "Callable[[Arg(int, 'x'), Arg(int, 'y')], Any]"
35933600

35943601
[case testProtocolClassObjectPureCallback]
35953602
from typing import Any, ClassVar, Protocol
@@ -3610,7 +3617,8 @@ test(C) # E: Argument 1 to "test" has incompatible type "Type[C]"; expected "P"
36103617
# N: Expected: \
36113618
# N: def __call__(x: int, y: int) -> Any \
36123619
# N: Got: \
3613-
# N: def __init__(x: int, y: str) -> C
3620+
# N: def __init__(x: int, y: str) -> C \
3621+
# N: "P.__call__" has type "Callable[[Arg(int, 'x'), Arg(int, 'y')], Any]"
36143622
[builtins fixtures/type.pyi]
36153623

36163624
[case testProtocolClassObjectCallableError]

0 commit comments

Comments
 (0)