python / python/mypy

Assigning to intermediate variable changes type checking results

Offen
#19,304 9 Kommentare 2 Reaktionen 0 zugewiesene Personen Auf GitHub ansehen

Dieses Issue hat noch niemand übernommen.

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

Beschreibung

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.

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 mit den Beispielen im Issue und reproduziere das Verhalten anhand der bereitgestellten mypy-playground-Links. Führe dann den aufgeführten stubtest-Befehl mit mypyc/crash.py aus und vergleiche den direkten Funktionsaufruf mit der Version mit einer Zwischenvariable. Erledigt ist es, wenn das Zuweisen des Zwischenergebnisses das Ergebnis der Typprüfung nicht mehr verändert.

Vom Indexierungsmodell aus dem Issue-Text verfasst.

Bewertung

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

Neue Issues direkt in Ihr Postfach

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