julia
146a8bc6 - subtype: harden deferred-narrowing covariant intersection

Commit
118 days ago
subtype: harden deferred-narrowing covariant intersection Rebase of the deferred-narrowing covariant intersection (#61787) onto current master, incorporating the `Intersect` meet nodes of #61940 and the covariant-occurrence scope tracking of the Type{} refactor, plus fixes for the correctness issues found in review: - Never mutate typevar objects in place. The witness unification now records on the binding when one exists and otherwise substitutes the variable away everywhere (bounds, result, and the innervars arrays via the new `swap_innervar_entries`), re-creating the canonical witness when its bound needs tightening. The previous in-place writes lacked write barriers (matching the GC-corruption crash in this PR's earlier CI run) and corrupted types shared with earlier intersection results. - Prevent and detect bound-reference cycles. Witness lower-bound joins and the constraintkind-1 fast path refuse to record self-referential bounds, and `finish_unionall`'s innervar re-sort now skips moves that would close a reference cycle (checked transitively through the flattened env), restoring the termination bound. Two intersections that previously hung forever in the re-sort loop now terminate. - `diagonal_bound_meet` uses `simple_meet`'s over-approximation mode instead of the exact mode, which now allocates internal `Intersect` nodes that must not escape into result typevars (this broke the Base bootstrap), and unwraps trivial `S where S<:U` bounds so the witness meet can see through the wrapping `finish_unionall` produces. The meet of Vararg tuple bounds falls back to the whole-tuple over-approximation instead of under-approximating to `Union{}`, which wrongly emptied nonempty intersections such as `Tuple{T,T} where T` ∩ `Tuple{Tuple{Vararg{Int}}, Tuple{Int}}`. - A covariant var∩var witness is recorded on both variables' lower bounds (gated on the second variable being in diagonal-collapse mode), so a diagonal pop sees witnesses from every occurrence regardless of which side the dispatch picked. - The `iub == vb->var` case in `finish_unionall` falls back to the old bound-widening behavior when the single-covariant-occurrence guard does not apply, instead of routing through the UnionAll-wrap machinery, which degraded unrelated bounds and split variables. - Re-intersection rounds that switch to constraintkind 1 start from the variable's original bounds and an empty innervars list so residue from the discarded round cannot masquerade as diagonal witnesses. - `diagonal_leaf_witness` resolves through the env binding rather than the stale typevar field, and `intersect_var` no longer resolves typevar upper-bound chains before the meet, which dropped `b<:S` constraints (e.g. `Tuple{T4,S3,S3} where {S3,T4<:S3}` ∩ `Tuple{Int,String,String}` returned a non-subtype result instead of `Union{}`). Five tightness assertions that the pre-rebase branch enabled are restored to `@test_broken`: the covariant-occurrence scoping changes on master mean the machinery no longer tightens `T<:Tuple{S}`-style bounds to equality in those cases; the results are sound but not subtypes of one input. Fixes #61773. This commit was written with the assistance of generative AI (Claude). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Author
Parents
Loading