Lenient handling of *tuple[Any, ...] (part 3) - #22014
ilevkivskyi wants to merge 3 commits into
Conversation
This comment has been minimized.
This comment has been minimized.
| reveal_type(get_first(X())) # N: Revealed type is "builtins.int" | ||
| [builtins fixtures/tuple.pyi] | ||
|
|
||
| [case testInferAgainstVariadicPrefixSuffix] |
There was a problem hiding this comment.
This case isn't covered by tests and the behavior looks wrong:
from typing import Any
def f[T1, T2, *Ts](x: tuple[T1, T2, *Ts]) -> tuple[T1, T2, tuple[*Ts]]: ...
a: tuple[str, *tuple[Any, ...], bytes, float]
reveal_type(f(a)) # tuple[str, *tuple[Any, ...], tuple[bytes, float]]There was a problem hiding this comment.
This was already broken before (but in a different way). Most likely this should be an easy fix with the new logic.
There was a problem hiding this comment.
Oh wow, this uncovered (a quite embarrassing) bug in split_with_prefix_and_suffix(), which is like ultra-foundation in the whole TypeVarTuple story. I am surprised it didn't cause other problems so far.
To give some more context, initially I prohibited partial overlap for variadic unpacks:
class C[T1, *Ts, T2]: ...
c: C[str, bool, *tuple[int, ...]]at instance creation level. But relatively late in the process I decided to lift this restriction (and keep it only for the cases where partial overlap is genuinely ambiguous, e.g. where actual type arguments have *Us). The reason is that, unlike in "type dynamics" (i.e. is_subtype()), in "type kinematics" (i.e. expand_type()) there is no ambiguity w.r.t. what *tuple[X, ...] actually means (i.e. there is no strict vs lenient story).
However, now we need to be more careful in situations where split_with_prefix_and_suffix() is called with synthetic/ad-hoc type lists, i.e. those not directly coming from instance arguments. A more prudent way would be to either add an assert or make return type of split_with_prefix_and_suffix() optional. I however don't like either. I will probably just spot-check the most important call sites (and update if needed).
There was a problem hiding this comment.
OK, I think I handled everything except meet/join (I will handle those in a separate PR to limit the scope):
- Fix a benign off-by-2 error in
constraints.pywith a test. - Change in
checkpattern.pyshould be a pure refactoring (as it was hard to reason about).
There was a problem hiding this comment.
Actually it looks like meet/join do not need anything (i.e. I don't see any bugs, and no places where Any requires special handling now). There are still couple TODOs (because we infer object/Never where we can infer something more precise), but those are quite tedious, so I would do this if/when someone asks about it.
|
According to mypy_primer, this change doesn't affect type check results on a corpus of open source code. ✅ |
Fixes #20771 (it already worked, but I am now adding a regression test)
Fixes #20651
This handles various edge cases related to inference with variadic unpacks (including
Any). Interestingly, after properly handling some missing edge cases, I realized that the variadic case can be "merged in the main branch" of the inference logic, so that the final diff is very simple.cc @JukkaL