Skip to content

Incorrect type inferencing when parameterizing with Self-like type variable involving __ge__ #13864

@SimpleArt

Description

@SimpleArt

Found a very strange bug involving self-like type variables while using __ge__ and similar methods. The following example defines:

  • a parameterized protocol SupportsComparison which takes Self as its first parameter and the type being compared to with its other parameter,
  • a protocol SupportsRadd which allows type-hinting type(t + supports_radd) == type(t),
  • a function foo should then accept foo(x, y, z) where x supports comparison with y and z supports radd with x and returns (x, y).

In the example, foo(float, float, Fraction) -> tuple[float, float] is the expected result, since:

  • float supports comparison with float and self should be float, meaning x: SupportsComparison[float, float],
  • Fraction supports radd with float, meaning z: SupportsRadd[float].

However, the result given by reveal_type(...) gives tuple[Fraction, float]. How is this the case?

from typing import Any, Protocol, TypeVar

T = TypeVar("T")
T_con = TypeVar("T_con", contravariant=True)

Self = TypeVar("Self", bound="SupportsComparison[Any, Any]", covariant=True)


class SupportsComparison(Protocol[Self, T_con]):

    def __ge__(self: Self, other: T_con) -> bool: ...
    def __gt__(self: Self, other: T_con) -> bool: ...
    def __le__(self: Self, other: T_con) -> bool: ...
    def __lt__(self: Self, other: T_con) -> bool: ...


class SupportsRadd(Protocol[T]):

    def __radd__(self, other: T) -> T: ...


X = TypeVar("X", bound=SupportsComparison[Any, Any])
Y = TypeVar("Y")
Z = TypeVar("Z", bound=SupportsRadd[Any])

def foo(
    x: SupportsComparison[X, Y],
    y: Y,
    z: SupportsRadd[X],
) -> tuple[X, Y]:
    return (x, y)

from fractions import Fraction

reveal_type(foo(float(), float(), Fraction()))  # Revealed type is "Tuple[fractions.Fraction*, builtins.float*]"
  • Mypy version: 0.942.
  • Python version used: 3.10.0.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugmypy got something wrong

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions