[red-knot] Ensure differently ordered unions and intersections are understood as equivalent even inside arbitrarily nested tuples (#15740)

## Summary

On `main`, red-knot:
- Considers `P | Q` equivalent to `Q | P`
- Considered `tuple[P | Q]` equivalent to `tuple[Q | P]`
- Considers `tuple[P | tuple[P | Q]]` equivalent to `tuple[tuple[Q | P]
| P]`
- ‼️ Does _not_ consider `tuple[tuple[P | Q]]` equivalent to
`tuple[tuple[Q | P]]`

The key difference for the last one of these is that the union appears
inside a tuple that is directly nested inside another tuple.

This PR fixes this so that differently ordered unions are considered
equivalent even when they appear inside arbitrarily nested tuple types.

## Test Plan

- Added mdtests that fails on `main`
- Checked that all property tests continue to pass with this PR
This commit is contained in:
Alex Waygood 2025-01-25 16:39:07 +00:00 committed by GitHub
parent a77a32b7d4
commit f85ea1bf46
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 85 additions and 18 deletions

View file

@ -84,4 +84,26 @@ static_assert(
)
```
## Unions containing tuples containing tuples containing unions (etc.)
```py
from knot_extensions import is_equivalent_to, static_assert, Intersection
class P: ...
class Q: ...
static_assert(
is_equivalent_to(
tuple[tuple[tuple[P | Q]]] | P,
tuple[tuple[tuple[Q | P]]] | P,
)
)
static_assert(
is_equivalent_to(
tuple[tuple[tuple[tuple[tuple[Intersection[P, Q]]]]]],
tuple[tuple[tuple[tuple[tuple[Intersection[Q, P]]]]]],
)
)
```
[the equivalence relation]: https://typing.readthedocs.io/en/latest/spec/glossary.html#term-equivalent