[ty] propagate visitors and constraints through has_relation_in_invariant_position (#20259)

## Summary

The sub-checks for assignability and subtyping of materializations
performed in `has_relation_in_invariant_position` and
`is_subtype_in_invariant_position` need to propagate the
`HasRelationToVisitor`, or we can stack overflow.

A side effect of this change is that we also propagate the
`ConstraintSet` through, rather than using `C::from_bool`, which I think
may also become important for correctness in cases involving type
variables (though it isn't testable yet, since we aren't yet actually
creating constraints other than always-true and always-false.)

## Test Plan

Added mdtest (derived from code found in pydantic) which
stack-overflowed before this PR.

With this change incorporated, pydantic now checks successfully on my
draft PR for PEP 613 TypeAlias support.
This commit is contained in:
Carl Meyer
2025-09-05 17:17:17 -07:00
committed by GitHub
parent a27c64811e
commit 2467c4352e
3 changed files with 74 additions and 40 deletions

View File

@@ -287,6 +287,20 @@ def _(x: C):
reveal_type(x) # revealed: () -> C | None
```
### Subtyping of materializations of cyclic aliases
```py
from ty_extensions import static_assert, is_subtype_of, Bottom, Top
type JsonValue = None | JsonDict
type JsonDict = dict[str, JsonValue]
static_assert(is_subtype_of(Top[JsonDict], Top[JsonDict]))
static_assert(is_subtype_of(Top[JsonDict], Bottom[JsonDict]))
static_assert(is_subtype_of(Bottom[JsonDict], Bottom[JsonDict]))
static_assert(is_subtype_of(Bottom[JsonDict], Top[JsonDict]))
```
### Union inside generic
#### With old-style union