This example was raised in Discord:
from typing import Never, cast
class A: ...
class B(A): ...
class BasisConversion[T1: A, T2: A]:
def _variance_fn_1(self, value: T1, _private: Never) -> Never:
raise NotImplementedError
def _variance_fn_2(self, value: T2, _private: Never) -> T2:
raise NotImplementedError
def ok[T: A](self: BasisConversion[T, T]) -> T2:
raise NotImplementedError
a = cast("BasisConversion[A, A]", {})
out = a.ok() # Ok
b = cast("BasisConversion[A, B]", {})
out = b.ok() # OK on pyright
We currently error on the last line, saying that BasisConversion[A, A] was expected. This line should be OK, because BasisConversion[A, B] is a subtype of BasisConversion[B, B]. (BasisConversion is contravariant in T1, invariant in T2). I verified we are inferring those variances correctly
I haven't done a deep dive, but I strongly suspect the root cause here is #2799, because we union the constraints on T in ok (treating them all as lower bounds) instead of correctly noting the contravariant constraint as an upper bound.
This example was raised in Discord:
We currently error on the last line, saying that
BasisConversion[A, A]was expected. This line should be OK, becauseBasisConversion[A, B]is a subtype ofBasisConversion[B, B]. (BasisConversionis contravariant in T1, invariant in T2). I verified we are inferring those variances correctlyI haven't done a deep dive, but I strongly suspect the root cause here is #2799, because we union the constraints on
Tinok(treating them all as lower bounds) instead of correctly noting the contravariant constraint as an upper bound.