python / python/mypy

Union type narrowing behaves differently depending on argument position

Offen
#16,401 0 Kommentare 0 Reaktionen 0 zugewiesene Personen Auf GitHub ansehen

Dieses Issue hat noch niemand übernommen.

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

Beschreibung

Bug Report

In the following example the type narrowing of the union types works as expected if it appears in the first or second argument position, but breaks if it appears in position three (or later).

This issue probably falls into the topic-join-v-union.

To Reproduce

Example on mypy playground

from typing import Callable, TypeVar

T = TypeVar("T")

def func(
    a: Callable[[], T],
    b: Callable[[], T],
    c: Callable[[], T],
) -> T:
    raise NotImplementedError()
        

class Foo:
    ...
    
class Bar:
    ...

def make_foo() -> Foo:
    raise NotImplementedError()
    
def make_bar() -> Bar:
    raise NotImplementedError()
    
def make_foo_or_bar() -> Foo | Bar:
    raise NotImplementedError()

x1: Foo | Bar = func(a=make_foo_or_bar, b=make_foo, c=make_bar)
x2: Foo | Bar = func(a=make_foo, b=make_foo_or_bar, c=make_bar)
x3: Foo | Bar = func(a=make_foo, b=make_bar, c=make_foo_or_bar)

Expected Behavior

The example should type check properly.

Actual Behavior

Inferring the return type works properly for x1 and x2, but it fails for x3 with:

Incompatible types in assignment (expression has type "object", variable has type "Foo | Bar")  [assignment]

Considering that the code is fully valid and symmetric, there should not be a difference in the behavior.

Side note: The issue cannot be work-around at call site by just swapping the order of a and c in the func(...) call. Apparently it has to do with the order in which they appear in the function signature.

Your Environment

  • Mypy version used: 1.6.1
  • Mypy command-line flags: none
  • Mypy configuration options from mypy.ini (and other config files): none
  • Python version used: 3.10, 3.11

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 dem Reproducer im Issue und führe ihn mit mypy 1.6.1 oder der aktuellen Version aus, um den Positionsunterschied zu bestätigen. Verfolge die Typinferenz der Callable-Argumente für func und untersuche, warum der dritte Parameter object erzeugt; abgeschlossen, wenn x1, x2 und x3 alle konsistent typgeprüft werden.

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
Klar beschrieben
Anfängerfreundlichkeit
35/100

Neue Issues direkt in Ihr Postfach

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