python / python/mypy

Assigning to intermediate variable changes type checking results

Aperta
#19,304 9 commenti 2 reazioni 0 assegnatari Vedi su GitHub

Nessuno ha ancora preso questa issue.

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

Descrizione

Bug Report

  • Assigning to an intermediate variable can change inference results.
  • Incorrect inference when inside a function call.

mypy-playground

# mypy: disable-error-code=empty-body
# fmt: off
from typing import Iterable, Iterator

class Vec[T]:  # proxy for list[T]
    def getitem(self, i: int) -> T: ...            # ensure invariance of T
    def setitem(self, i: int, v: T) -> None: ...   # ensure invariance of T
    def __init__(self, iterable: Iterable[T], /) -> None: ...
    def __iter__(self) -> Iterator[T]: ...
    def __add__[S](self, value: "Vec[S]", /) -> "Vec[S | T]": ...

def fmt(arg: Iterable[int | str]) -> None: ...  # <-- union plays a role

l1: Vec[int] = Vec([1])
l2: Vec[int] = Vec([1])
fmt(l1 + l2)  # ❌ Unsupported operand types for + ("Vec[int]" and "Vec[int]")

dummy = l1 + l2
fmt(dummy)  # ✅
Same example without PEP 695

https://mypy-play.net/?mypy=latest&python=3.12&gist=43a91e52a767ac27f2706795d45bdef1

# mypy: disable-error-code=empty-body
# fmt: off
from typing import TypeVar, Generic, Iterable, Iterator

T = TypeVar("T")
S = TypeVar("S")

class Vec(Generic[T]):
    def getitem(self, i: int) -> T: ...            # ensure invariance of T
    def setitem(self, i: int, v: T) -> None: ...   # ensure invariance of T
    def __init__(self, iterable: Iterable[T], /) -> None: ...
    def __iter__(self) -> Iterator[T]: ...
    def __add__(self, value: "Vec[S]", /) -> "Vec[S | T]": ...

def fmt(arg: Iterable[int | str]) -> None: ...

l1: Vec[int] = Vec([1])
l2: Vec[int] = Vec([1])
fmt(l1 + l2)  # ❌ Unsupported operand types for + ("Vec[int]" and "Vec[int]")

dummy = l1 + l2
fmt(dummy)  # ✅
original bug report

Bug Report

I was testing this PR (https://github.com/python/typeshed/issues/14283) for typeshed that simplifies list.__add__ from

@overload
def __add__(self, value: list[_T], /) -> list[_T]: ...
@overload
def __add__(self, value: list[_S], /) -> list[_S | _T]: ...

to

def __add__(self, value: list[_S], /) -> list[_S | _T]: ...

This seems to work generally, but there are some weird circumstances when it bugs out. It seems most of them appear when a concatenation is given as an argument to another function.

As an example, this is one of the lines that gets flagged:

https://github.com/python/mypy/blob/5081c59b9c0c7ebe7070c62a4aeaf3d0de203a24/mypyc/crash.py#L29

However, mypy stops complaing if it is changed to

dummy = tb + tb2
for s in traceback.format_list(dummy):

Assigning to an intermediate variable changed the type checking results (!)

I couldn't reproduce this behavior using a custom class, which makes me believe this is probably due to some weird special casing for builtins.

To Reproduce

git clone --branch polymorphic_overload_test https://github.com/randolf-scholz/typeshed.git
git clone https://github.com/python/mypy.git
cd typeshed
uv venv --seed
source .venv/bin/activate
uv pip install -r requirements-tests.txt
mkdir tmp
cp ../mypy/mypyc/crash.py tmp/tmp.py
python -m mypy.stubtest --custom-typeshed-dir=../typeshed tmp

Expected Behavior

Assigning to an intermediate variable shouldn't affect type inference.

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 con gli esempi nell’issue e riproduci il comportamento usando i link mypy-playground forniti. Poi esegui il comando stubtest indicato con mypyc/crash.py, confrontando la chiamata diretta alla funzione con la versione che usa una variabile intermedia. Il lavoro è completato quando l’assegnazione del risultato intermedio non cambia più l’esito del controllo dei tipi.

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

Valutazione

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

Ricevi le nuove issue nella tua casella

Un breve riepilogo di issue GitHub adatte ai principianti.