Repository navigation
Ground variant owner by expected type at each call site (§3: single authority) - #5891
Conversation
…prep)
- v1_compiler_infer.rs (ExprVar): when the scope binds a shared variant to
enum A (by import-order or alpha-sort), but the declared expected type at
the call site is a different enum B that also contains the variant, prefer
B. Both binding_kind and inferred resolved-type are updated so the emit
path sees a consistent owner without needing its own fallback.
- variant_owner_disambiguation_test.rs: two new §2 witnesses:
· shared_variant_resolves_by_expected_type_not_alpha_order — AEarlyEnum
and ZLaterEnum both define SharedVarAmbig; fn return type ZLaterEnum must
emit ZLaterEnum::SharedVarAmbig not AEarlyEnum (alpha-first default).
· shared_variant_resolves_per_site_independently — two functions in the
same module with different declared return types each get the correct
variant owner independently, proving the fix is per-site not per-module.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…t_alpha_order Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
Req 5 — genuinely-ambiguous-site fallback: stated When Why this is the correct residue (not a §5 hole): The fix grounds every site where the expected type IS propagated — function return sites, named struct field sites where
Current status: CI green at — sent from proud-bee-631 |
|
Correction on review #32785 — Rust file is hand-synced, not regenerated The review states "The Rust file is now marked generated and regenerated cleanly" — this is inaccurate and worth correcting for future readers.
Faithfulness is confirmed: the regen's two relevant hunks (the new function and the updated ExprVar branch) are behaviorally identical to the hand-sync — the regen calls The file does not carry a "Generated by v1 compiler" header — that would be inserted by regen but is absent from the hand-synced version. — sent from proud-bee-631 |
The regen activates pre-existing VariantCollision logic in 04_infer.dag (line 5815) that is a blocking diagnostic and breaks the corpus (e.g. std.cache_interface defines both AtomicityModel and CacheWriteSemantics sharing WriteThenCommit — regen fires VariantCollision there). This is a known X/Y modeling decision being escalated; the hand-sync is correct and faithful for the expected_type_override_enum grounding in this PR. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Tests 2+3 previously imported both AEarlyEnum and ZLaterEnum from a separate owner module. Since they share a variant, the pre-existing imported-both guard (curr_is_imported && prev_is_imported) fires a VariantCollision diagnostic, which would block the regen path. Fix: collapse each two-module scenario into a single module with locally- defined enums and no imports. imported_enum_names is empty → no collision possible. Discrimination is preserved via variant_locals_from_items last-write-wins: ZLaterEnum defined first, AEarlyEnum second → AEarlyEnum wins scope; the function return type (ZLaterEnum) triggers the expected- type override on the site that needs it. Verified: removing expected_type_override_enum → tests 2+3 go red (AEarlyEnum::SharedVarField emitted for make_late); restoring → green. Test 1 (local-vs-transitive, #5879 fix) unaffected. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* Restore emit-path variant-owner determinism lost in #5873 regen (#5879 grounding) Port #5879's variant-owner disambiguation back into .dag authority and hand-sync the v1 Rust seed: imported_variants (source-module local items), alpha-sorted variant_fold bindings, sorted export-set map_keys, and field-type-hint struct disambiguation. Regen in #5873 overwrote these fixes; this re-lands them on current main (#5899) without disturbing expected_type_override_enum (#5891). Co-authored-by: Cursor <cursoragent@cursor.com> * Fix #5899 func_sigs merge regression in variant-owner restore Re-land imported_variants + sorted variant_fold on top of #5899's func_sigs/all_declared_sigs path (not the reverted imported_sigs fork). Restores compile-clean hand-sync; variant_owner_disambiguation 3/3 green. Co-authored-by: Cursor <cursoragent@cursor.com> * Ground emit-path variant-owner determinism in .dag authority with pure regen. Fix imported_variants map type so regen emits valid Rust (Map<String,String> for unambiguous owners only), then regen stage0 to match .dag fixed point. Co-authored-by: Cursor <cursoragent@cursor.com> --------- Co-authored-by: Brian Searls <briansearls1@gmail.com> Co-authored-by: Cursor <cursoragent@cursor.com>
Summary
Fixes the latent §3 collision flagged as residue in #5879: when a variant name appears in two coproducts that are BOTH in scope (e.g. `WriteThenCommit` ∈ `AtomicityModel` ∩ `CacheWriteSemantics`), the correct owning enum at each emit site is determined by the declared expected/field type at that site — not by scope-order or alpha-sort.
Authority site:
src/v1/04_infer.dag—expected_type_override_enumhelper added at line 515; ExprVar branch updated to call it. The.rsseed (v1_compiler_infer.rs) is hand-synced (not full-regen — correct per emitter-nondeterminism constraint).What changed
src/v1/04_infer.dag(AUTHORITY) +v1_compiler_infer.rs(hand-synced mirror) —infer_exprExprVar branch:When the scope binds a shared variant to enum A (by import-order or alpha-sort), but:
…then enum B is used as the owner. Both
binding_kind(→VariantValueBinding { parent_enum: B }) and the inferred resolved type are updated in lockstep, so the emit path ineffective_variant_parentsees a consistent owner.This is §3 single-authority grounding applied to variant-constructor sites: the EXPECTED TYPE is the authoritative single source, not whichever enum happens to be first in the scope map.
dsl/test/claim/variant_owner_expected_type_test.dag— floor-auto-enrolled.dagdiscriminating witness:expected_type_picks_variant_owner_not_alpha_order():AEarlyOwnerandZLaterOwnerboth defineSharedVariant;make_z_variant() -> ZLaterOwner { SharedVariant }must inferZLaterOwneras owner. Without the fix, scope-order picksAEarlyOwner→ TypeMismatch → red. Verified green-by-execution.variant_owner_disambiguation_test.rs— two new §2.rswitnesses:shared_variant_resolves_by_expected_type_not_alpha_order: alpha-first default would pick the wrong owner; expected type overrides it. Red-on-revert.shared_variant_resolves_per_site_independently: two functions with different declared return types in the same module each get the correct owner — proves the fix is per-site, not per-module.Concrete corpus case fixed
In
dsl/extdeps/cache/github_actions.dag:Previously both emitted
AtomicityModel::WriteThenCommit(alpha wins) — thewrite_semanticsfield was wrong.Open residual (tracked, dissolution-gated)
Genuinely-ambiguous sites —
expected=None→ scope-order fallback (unchanged #5879 behavior):When the expected type is
None(e.g., variant used inside an anonymous record literal whererecord_lit_expanded_from_expectedreturnsnonefortype_name=Absent), the override does not fire and the code falls back toscope_parent— the alpha-first enum viabinding.resolved. This is the same deterministic scope-order behavior as #5879.Classification: §5 "wall-after-grounding" — decidable but gated on a corpus migration. The strict fix (TypeAmbiguous diagnostic when
expected=Noneand variant is shared) would break existing anonymous-record sites. Interim behavior is latent-safe: emit-host MVP smoke is green, emitted Rust is self-consistent.Dissolution trigger: corpus migration to named struct literals or qualified variant syntax at ambiguous sites (e.g.
CacheInterfaceCatalogIoSemantics { write_semantics: WriteThenCommit }instead of bare{ write_semantics: WriteThenCommit }). Once migrated, the TypeAmbiguous wall can turn on without breaking anonymous-record sites.Test plan
shared_variant_resolves_to_locally_defined_owner_not_transitive(§1 — existing, still green)shared_variant_resolves_by_expected_type_not_alpha_order(§2 new — red without fix)shared_variant_resolves_per_site_independently(§2b new — red without fix)expected_type_picks_variant_owner_not_alpha_order(.dagfloor witness — red without fix)61d6812b— compile-clean + emit-host MVP smokes passcargo fmt --checkpassescargo clippy -p v1-compiler -- -D warningspasses🤖 Generated with Claude Code