Skip to content

false positive with assignment to contravariant typevar #3483

Description

@carljm

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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workinggenericsBugs or features relating to ty's generics implementation

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions