Regarding Eric's example, consider:
```
def func1(a: T | list[T]) -> T:
if a and isinstance(a, list):
return a[0]
return a
```
That seems like a valid, correctly typed function, so I'm surprised that a type checker would infer that the return type when called with a list[int] would be int, when it may return the empty list.
Naively I would have assumed an inference of `list[INT] | int` (in either order), since that's all that can be proved from the types + context.
Danny
I'm not familiar with any documentation (in PEP 484 or elsewhere) that explicitly states that unions in the Python type system are unordered, but I have made that assumption in Pyright. I think mypy makes a similar assumption.
In type theory, it makes sense that unions would be order-independent and fully commutative — i.e. `X | Y` should be equivalent to `Y | X`.
There are a few places where this comes up. One is when determining whether two types are compatible, especially when a union is used for the specialization of an invariant type parameter. I think we can agree that the following is type safe and should be allowed.
```python
def func(a: list[str | int]):
b: list[int | str] = a
```
Another place where union ordering becomes important is in the constraint solver. Martin, I'm guessing this is the case that you're referring to?
The way I solve the union ordering problem in the constraint solver in Pyright is to attempt type matches for each subtype within the union and "score" each successful match. The score represents the "simplicity" of the solution. I choose the one with the simplest solution. For example:
```python
from typing import TypeVar
T = TypeVar("T")
def func1(a: T | list[T]) -> T: ...
def func2(a: list[T] | T) -> T: ...
def test(val: list[int]):
reveal_type(func1(val)) # int
reveal_type(func2(val)) # int
```
In this example, the constraint solver attempts to match `list[int]` against both `list[T]` and `T`. Both of these are valid solutions given the constraints, but the simplest solution is `T = int` (versus `T = list[int]`). The "simplicity calculation" is a heuristic, and I've needed to tune it over time to achieve the best results, but it seems to work well and produce deterministic results that do not depend on union ordering — unless two solutions happen to result in exactly the same simplicity score.
Interestingly, mypy emits false positive errors for the above example.
-Eric
--
Eric Traut
Contributor to Pyright & Pylance
Microsoft
_______________________________________________
Typing-sig mailing list -- typing-sig@python.org
To unsubscribe send an email to typing-sig-leave@python.org
https://mail.python.org/mailman3/lists/typing-sig.python.org/
Member address: diabolo.dan@gmail.com