False negative for callable assignability
Describe the bug
Pyright reports a false negative when checking assignability between two callable types when the RHS has variadic and keyword-variadic parameters while the LHS has only standard parameter. Refer to the code example below.
Code or Screenshots
from typing import Protocol
class A(Protocol):
def __call__(self, *args: int, **kwargs: bool) -> None: ...
class B(Protocol):
def __call__(self, a: int) -> None: ...
def _(a: A):
# This should be not assignable
x: B = a
The reason is that the positional form of the standard parameter is matched against the variadic parameter and is assignable but the keyword form of the standard parameter is not assignable to kwargs because int is not assignable to bool.
Here, x(a=10) is not a valid call as the type of keyword-variadic is a bool.
mypy does report this as an error:
mypy: Incompatible types in assignment (expression has type "A", variable has type "B")
Following member(s) of "A" have conflicts:
Expected:
def __call__(self, a: int) -> None
Got:
def __call__(self, *args: int, **kwargs: bool) -> None [assignment]
VS Code extension or command-line
Command-line with version 1.1.398
Thanks for the bug report. I agree this is a false negative — both from the perspective of type theory and the formal assignability rules for callables provided in the Python typing spec. (I authored that section of the spec as well as the corresponding type checker conformance tests. I simply missed this case in the implementation.)
There's another case where instead of the keyword-variadic parameter, the example uses a keyword-only parameter with the same name as the standard parameter:
from typing import Protocol
class A(Protocol):
def __call__(self, *args: int, a: bool = False) -> None: ...
class B(Protocol):
def __call__(self, a: int) -> None: ...
def _(a: A):
# This should be not assignable
x: B = a
I think the underlying bug should probably be the same (?).