python / python/typing

Allow returning `AnyOf` rather than `Any` for amiguous overloads.

Offen
#2,196 4 Kommentare 0 Reaktionen 0 zugewiesene Personen Auf GitHub ansehen

Dieses Issue hat noch niemand übernommen.

topic: feature topic: typing spec
Vorherrschende Sprache
Python
Sterne
1.8k
Forks
302
Ø Merge
23 Std.
Gemergte PRs (30 T.)
8

Beschreibung

Currently, the typing spec for overloads, step 5, states that

Once this filtering process is applied for all arguments, examine the return types of the remaining overloads. If these return types include type variables, they should be replaced with their solved types. If the resulting return types for all remaining overloads are equivalent, proceed to step 6.

If the return types are not equivalent, overload matching is ambiguous. In this case, assume a return type of Any and stop.

However, couldn't this rule be relaxed to returning the union of the return type of all matching overloads? For instance, consider this example derived from a real world use case (numpy scalar ops)

from typing import Any, overload, assert_type

class A[T]:  # covariant
    def get(self) -> T: ...

@overload
def op(l: A[None], r: A[None]) -> A[None]: ...
@overload
def op(l: A[None], r: A[Any]) -> A[None]: ...
@overload
def op(l: A[Any], r: A[None]) -> A[None]: ...
@overload
def op(l: A[Any], r: A[Any]) -> A[Any]: ...

def test(x: A[None], y: A[Any]) -> None:
    assert_type(op(x, x), A[None])  # spec: ✅️ 
    assert_type(op(x, y), A[None])  # spec: ✅️
    assert_type(op(y, x), A[None])  # spec: ✅️
    assert_type(op(y, y), A[Any] | A[None])     # spec: ❌️ (expected Any)

According to the rule stated above, op(A[Any], A[Any]) should be inferred to as Any, because the overloads are ambious and A[Any] is not equivalent to A[None] as not all materializations of A[Any] can be assigned to A[None].

However inferring Any loses deducible information: we know that no matter what, the return type must be an A. So in principle the return type should be A[Any] | A[None], because if either the left argument or the right argument materializes to A[None], then we get A[None] and otherwise if they materialize to something else we get A[Any].

Beitragsleitfaden

Für dieses Repository ist kein Beitragsleitfaden indexiert

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 Schritt 5 der Overload-Spezifikation und der im Issue verlinkten Glossardefinition von equivalent. Analysiere das Beispiel A[Any] und A[None] und bestimme, ob mehrdeutige Overloads eine Union beibehalten sollten, statt zu Any zu werden. Die Aufgabe ist abgeschlossen, wenn die Typing-Spezifikation eine entschiedene, dokumentierte Regel für diesen Fall enthält und das Beispiel diese Regel widerspiegelt.

Vom Indexierungsmodell aus dem Issue-Text verfasst.

Bewertung

Tech-Stack
python
Bereich
documentation
Issue-Typ
Feature
Schwierigkeit
5/5
Geschätzter Aufwand
Über eine Woche
Aktivitätsstatus
Veraltet
Klarheit
Größtenteils klar
Anfängerfreundlichkeit
30/100

Neue Issues direkt in Ihr Postfach

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