SIGN IN SIGN UP

subtype: use static `var_occurs_invariant` in env_unchanged check (#61791)

The diagonal rule was changed to semi-static in #34272 — it uses
`var_occurs_invariant(u->body, u->var)` (a structural check on the
UnionAll body) rather than the dynamic `occurs_inv` counter, since the
latter only reflects whichever invariant positions were actually
traversed. The recently-added diagonality-change check in
`env_unchanged` (#61503), however, still tested `v->occurs_inv == 0`, so
it could spuriously flag a variable as "newly diagonal" when its body
has T only in branches the algorithm never visited.

Cache `var_occurs_invariant(u->body, u->var)` once at varbinding
creation as `body_occurs_inv` and use it in `env_unchanged` (and at the
existing recompute sites in `subtype_unionall` and
`intersect_unionall`).

The two checks can be made to diverge by hiding a `Ref{T}` in a Union
branch that is never picked dynamically (added as a regression test);
However, the divergence only changes how much `exists_subtype`
exploration is performed after `sub == true` and not the boolean result
or the chosen ∃-bindings. As a result, this is a performance fix, but
not a correctness fix.

Co-authored-by: Keno Fischer <Keno@users.noreply.github.com>
Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
K
Keno Fischer committed
421d01287c6c0eeb6b65c536bf7bc44b47e9bb12
Parent: 48ff18f
Committed by GitHub <noreply@github.com> on 5/14/2026, 3:33:36 PM