Repository navigation
04_resolve: preserve peelable form for non-recursive coproduct-container aliases (Witness arms) - #5623
Merged
Conversation
…ner aliases A nullary alias to a generic coproduct container (e.g. Witness<C> = Holds|Violates) whose only recursion is an imported recursive type is correctly un-marked non-recursive once cross-module recursion-marking is fixed. Such an alias was then COLLAPSED during resolution, dropping its coproduct arms -> VariantNotFound at match sites (e.g. self_host.dag StageEmissionEquality = Witness<StructurallyEqual>). Fix: the children==0 lazy-return branch already preserves the peelable form for recursive types (they cannot be eagerly expanded). Extend that SAME "do not collapse a peelable form" behavior to a second structural inhabitant: a resolved alias whose target is a registered container type with a Disj (coproduct) declaration. Name-free (is_container_type = container-registry membership; resolve_generic_use_decl(...) .connective == Disj); does not touch is_witness_type_name. This is recursion-INDEPENDENCE: the non-recursive coproduct-container alias now resolves to the same peelable form the recursive case produced, so the existing downstream variant resolution fires regardless of recursion-marking. No-op on main (835/0 emit == pristine); enables the cross-module recursive-set fix (separate PR) which exposes the previously recursion-masked sites. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
Extend the
04_resolvechildren==0lazy-return branch to preserve the peelable form for non-recursive coproduct-container aliases (e.g.Witness<C> = Holds | Violates), exactly as it already does for recursive types.Why (one concept, two structural inhabitants — §3)
The lazy-return
NodeResolveResult { resolved: n }is a single "preserve the peelable form — do not collapse" behavior. It is inhabited by two structural conditions:is_recursive_type_for(n)— a recursive type cannot be eagerly expanded (pre-existing);n_target_is_coproduct_container— a non-recursive alias whose target is a registered container (is_container_type) with a Disj declaration; collapsing it drops the coproduct arms.A nullary alias to a generic coproduct container whose only recursion is an imported recursive type is correctly un-marked non-recursive once cross-module recursion-marking is fixed (separate lever PR). Before this fix, such an alias was collapsed during resolution → its
Holds/Violatesarms were dropped →VariantNotFoundat match sites (e.g.self_host.dagStageEmissionEquality = Witness<StructurallyEqual>). This change makes the non-recursive case resolve to the same peelable form the recursive case produced — recursion-independence — so existing downstream variant resolution fires regardless of recursion-marking.Name-free / §3-clean: keys on
is_container_type(=map_get(container_type_arity, name).is_present, container-registry membership) ANDresolve_generic_use_decl(target).connective == Disj. No literal"Witness";is_witness_type_nameuntouched.Genealogy (why not the broader version)
The first attempt — a blanket
|| n_is_resolved_alias(any resolved alias lazy) — over-broadened: it forced struct aliases lazy too, breaking generic-lambda field-access element-type unification. 3-way emit control:p.name/p.expression→field on type 'T')The narrow
is_container_type && Disjgate leaves struct aliases (Conj decls) on the unchanged collapse path.Proof (by execution)
VariantNotFoundatself_host.dag:51(StageEmissionEqualityHolds/Violates); with this fix → 0. The toggle is the proof.cargo test -p v1-compiler-tests—generic_alias_field_access_resolves_through_expansion✓ (the exact path the blanket version broke),list_and_freemonoid_*alias-compat ✓ (10),*coproduct*✓ (20),real_optional_coproduct_*✓.Sequencing
This is the prerequisite. The cross-module recursive-set fix (the lever) that exposes the recursion-masked sites lands as a follow-up PR rebased on this one, carrying a permanent floor witness for the resolution + its red-on-revert.
Seed mirror (
v1_compiler_infer_resolve.rs) hand-edited (no regen); gunbc builds clean.🤖 Generated with Claude Code