You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Subtyping and inference of user defined variadic types (#16076)
The second part of support for user defined variadic types comes as a
single PR, it was hard to split into smaller parts. This part covers
subtyping and inference (and relies on the first part: type analysis,
normalization, and expansion, concluded by
#15991). Note btw that the third (and
last) part that covers actually using all the stuff in `checkexpr.py`
will likely come as several smaller PRs.
Some comments on this PR:
* First good news: it looks like instances subtyping/inference can be
handled in a really simple way, we just need to find correct type
arguments mapping for each type variable, and perform procedures
argument by argument (note this heavily relies on the normalization).
Also callable subtyping inference for variadic items effectively defers
to corresponding tuple types. This way all code paths will ultimately go
through variadic tuple subtyping/inference (there is still a bunch of
boilerplate to do the mapping, but it is quite simple).
* Second some bad news: a lot of edge cases involving `*tuple[X, ...]`
were missing everywhere (even couple cases in the code I touched
before). I added all that were either simple or important. We can handle
more if users will ask, since it is quite tricky.
* Note that I handle variadic tuples essentially as infinite unions, the
core of the logic for this (and for most of this PR FWIW) is in
`variadic_tuple_subtype()`.
* Previously `Foo[*tuple[int, ...]]` was considered a subtype of
`Foo[int, int]`. I think this is wrong. I didn't find where this is
required in the PEP (see one case below however), and mypy currently
considers `tuple[int, ...]` not a subtype of `tuple[int, int]` (vice
versa are subtypes), and similarly `(*args: int)` vs `(x: int, y: int)`
for callables. Because of the logic I described in the first comment,
the same logic now uniformly applies to instances as well.
* Note however the PEP requires special casing of `Foo[*tuple[Any,
...]]` (equivalent to bare `Foo`), and I agree we should do this. I
added a minimal special case for this. Note we also do this for
callables as well (`*args: Any` is very different from `*args: object`).
And I think we should special case `tuple[Any, ...] <: tuple[int, int]`
as well. In the future we can even extend the special casing to
`tuple[int, *tuple[Any, ...], int]` in the spirit of
#15913
* In this PR I specifically only handle the PEP required item from above
for instances. For plain tuples I left a TODO, @hauntsaninja may
implement it since it is needed for other unrelated PR.
* I make the default upper bound for `TypeVarTupleType` to be
`tuple[object, ...]`. I think it can never be `object` (and this
simplifies some subtyping corner cases).
* TBH I didn't look into callables subtyping/inference very deeply
(unlike instances and tuples), if needed we can improve their handling
later.
* Note I remove some failing unit tests because they test non-nomralized
forms that should never appear now. We should probably add some more unit
tests, but TBH I am quite tired now.
0 commit comments