python / python/mypy

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

Aperta
#13,864 2 commenti 0 reazioni 0 assegnatari Vedi su GitHub

Nessuno ha ancora preso questa issue.

bug
Lingua principale
Python
Stelle
20.6k
Fork
3.3k
Metriche di merge delle PR
Metriche PR in attesa

Descrizione

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.

Guida per i contributori

Apri la guida per i contributori

Come iniziare

  1. Leggi tutta la issue e poi la guida ai contributi del progetto.
  2. Commenta sulla issue per dire che te ne occupi tu — evita che due persone facciano lo stesso lavoro.
  3. Fai un fork del repository e lavora su un branch.
  4. Apri una pull request che faccia riferimento al numero della issue.

Direzione di ricerca

Inizia eseguendo il reproducer fornito con la versione corrente di mypy e tracciando l’inferenza per foo, in particolare il parametro SupportsComparison simile a Self e i metodi ge. Individua i test pertinenti sull’inferenza dei tipi oppure aggiungi un test di regressione per l’esempio; il lavoro è completato quando reveal_type segnala tuple[float, float] invece di tuple[Fraction, float].

Scritto dal modello di indicizzazione a partire dal testo della issue.

Valutazione

Stack tecnologico
python
Ambito
devtools
Tipo di issue
Bug
Difficoltà
4/5
Tempo stimato
3-5 giorni
Stato di attività
Ferma
Chiarezza
Abbastanza chiara
Idoneità per principianti
28/100

Ricevi le nuove issue nella tua casella

Un breve riepilogo di issue GitHub adatte ai principianti.