Description
In the code below, Pyright infers the first lambda as (x: int) -> int which fails to assign to either union member.
import typing
class Fail1:
def __call__(self, *, kwarg: int) -> typing.Self: ...
f1: typing.Callable[[Fail1], Fail1] | Fail1 = lambda x: x # ERROR
f0: typing.Callable[[Fail1], Fail1] = lambda x: x # OK
$ pyright repro.py
repro.py:7:40 - error: Type "(x: int) -> int" is not assignable to declared type "((Fail1) -> Fail1) | Fail1"
Type "(x: int) -> int" is not assignable to type "((Fail1) -> Fail1) | Fail1"
Type "(x: int) -> int" is not assignable to type "(Fail1) -> Fail1"
Parameter 1: type "Fail1" is incompatible with type "int"
"Fail1" is not assignable to "int"
Function return type "int" is incompatible with type "Fail1"
"int" is not assignable to "Fail1"
"FunctionType" is not assignable to "Fail1" (reportAssignmentType)
1 error, 0 warnings, 0 notes
Expected behavior
Both lambdas are inferred as (x: Fail1) -> Fail1 and the code type-checks, as it does with mypy (v2.3.0).
VS Code extension or command-line
pyright CLI v1.1.411
More info
I'm guessing (x: int) -> int comes from trying to unify the lambda with (*, kwarg: int) -> Fail1.
Here are some variations I tried when looking for minimal repro:
Code sample in pyright playground
from typing import Self
from collections.abc import Callable
class Fail1:
def __call__(self, *, kwarg: int) -> Self: ...
f1: Callable[[Fail1], Fail1] | Fail1 = lambda x: x
# It should be inferred as this.
f0: Callable[[Fail1], Fail1] = lambda x: x
class Fail2:
def __call__(self, *, kwarg1: int, kwarg2: int) -> Self: ...
f2: Callable[[Fail2], Fail2] | Fail2 = lambda x: x
class Pass1:
def __call__(self, *, kwarg: int) -> int: ...
p1: Callable[[Pass1], Pass1] | Pass1 = lambda x: x
class Pass2:
def __call__(self, arg: int) -> Self: ...
p2: Callable[[Pass2], Pass2] | Pass2 = lambda x: x
class Pass3:
def __call__(self, *kwarg: int, **kwargs: int) -> Self: ...
p3: Callable[[Pass3], Pass3] | Pass3 = lambda x: x
class Pass4:
def __call__(self) -> Self: ...
p4: Callable[[Pass4], Pass4] | Pass4 = lambda x: x
Description
In the code below, Pyright infers the first lambda as
(x: int) -> intwhich fails to assign to either union member.Expected behavior
Both lambdas are inferred as
(x: Fail1) -> Fail1and the code type-checks, as it does with mypy (v2.3.0).VS Code extension or command-line
pyright CLI v1.1.411
More info
I'm guessing
(x: int) -> intcomes from trying to unify the lambda with(*, kwarg: int) -> Fail1.Here are some variations I tried when looking for minimal repro:
Code sample in pyright playground