[ty] Recognize exhaustive matches over finite tuples (#26132)
## Summary
Prior to this change, we could recognize exhaustive match statements
when a fixed tuple's finite combinations were written as an explicit
union, but not when those alternatives were hidden inside the tuple
element types:
```python
def f(b_1: bool, b_2: bool) -> int:
match (b_1, b_2):
case (True, True):
return 0
case (False, _):
return 1
case (_, False):
return 2
```
We now share the existing bounded type-expansion logic used during
overload resolution and use the expanded union when computing match
reachability. For `tuple[bool, bool]`, this lets each preceding case
subtract the combinations it covers until no alternatives remain.
The expanded type is used only for reachability, so subject and capture
inference remain unchanged. Tuple products remain capped at 64
alternatives; larger products keep the existing conservative behavior.
This also resolves the existing `tuple[int | str]` sequence-pattern
exhaustiveness TODO.
Closes https://github.com/astral-sh/ty/issues/3807.