python / python/mypy

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

Offen
#13,864 2 Kommentare 0 Reaktionen 0 zugewiesene Personen Auf GitHub ansehen

Dieses Issue hat noch niemand übernommen.

bug
Vorherrschende Sprache
Python
Sterne
20.6k
Forks
3.3k
PR-Merge-Kennzahlen
PR-Kennzahlen ausstehend

Beschreibung

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.

Beitragsleitfaden

Beitragsleitfaden öffnen

Erste Schritte

  1. Lies das ganze Issue und danach den Beitragsleitfaden des Projekts.
  2. Schreib ins Issue, dass du es übernimmst — das erspart doppelte Arbeit.
  3. Forke das Repository und arbeite in einem Branch.
  4. Öffne einen Pull Request, der die Issue-Nummer nennt.

Rechercherichtung

Beginne damit, den bereitgestellten Reproducer mit der aktuellen mypy-Version auszuführen und die Inferenz für foo nachzuverfolgen, insbesondere den Self-ähnlichen SupportsComparison-Parameter und die ge-Methoden. Finde die relevanten Typinferenztests oder füge für das Beispiel einen Regressionstest hinzu; als erledigt gilt die Aufgabe, wenn reveal_type tuple[float, float] statt tuple[Fraction, float] meldet.

Vom Indexierungsmodell aus dem Issue-Text verfasst.

Bewertung

Tech-Stack
python
Bereich
devtools
Issue-Typ
Bug
Schwierigkeit
4/5
Geschätzter Aufwand
3-5 Tage
Aktivitätsstatus
Veraltet
Klarheit
Größtenteils klar
Anfängerfreundlichkeit
28/100

Neue Issues direkt in Ihr Postfach

Eine kurze Übersicht über anfängerfreundliche GitHub-Issues.