Skip to content

Derive Ord bound for fn-generics reaching set_union: audience_subset/audience_join - #8761

Closed
gunbai-bot[bot] wants to merge 2 commits into
mainfrom
session/tidy-otter-493
Closed

gunbai-bot[bot] wants to merge 2 commits into
mainfrom
session/tidy-otter-493

Conversation

@gunbai-bot

@gunbai-bot gunbai-bot Bot commented Aug 21, 2026

Copy link
Copy Markdown
Contributor

Summary

  • v1's fn-generic bound-inference mechanism (v1.trait_derive_emit / v1.compiler.trait_bound_witness) only ever derived Clone bounds for generic function parameters. A generic reaching the set_union builtin — which lowers to v1_rt::rc_set_union::<T: Ord + Clone> — emitted without its own P: Ord, producing E0277 at the call site.
  • audience_subset<P> and audience_join<P> in dag/std/authorization_profile.dag are the two real specimens (E0277 root A residual: dashboard node://adhoc-a9f61ade-340).
  • Adds a narrowly-scoped third trigger alongside the existing Clone-bound machinery: a pure decision core (v1_set_union_ord_bound_param_names, trait_bound_witness.dag), a Node-consuming body walker locating set_union call sites and resolving their element-type argument names (05_emit_rust.dag, mirroring ownership.dag's collect_callable_refs, plus an ExprBinOp arm that precedent lacks — needed because audience_subset's set_union call sits inside a == comparison), and a sibling renderer (v1_emit_type_params_with_clone_and_ord_bounds, trait_derive_emit.dag) wired into emit_fn_def alongside the existing Clone-only renderer.
  • Scoped to the set_union builtin's known lowering only — not a general trait-bound inference system, and does not touch the separate Root A Ord-5 population on EnumeratedAudience's own struct derive (different root, out of scope here).

Verification

Since the built gunbc binary compiles v1's own .dag sources ahead-of-time (it does not interpret src/v1/*.dag at runtime), verifying this required the full self-host regen + rebuild loop:

  1. claim_executor --required-regen against these .dag edits (writes a candidate stage0 Rust mirror reflecting the change — reports drift, as expected, since the committed mirror predates this fix).
  2. Swapped the candidate mirror in for src/v1/stage0/src, rebuilt gunbc from it.
  3. Ran the candidate gunbc compile --target rust on dag/std/authorization_profile.dag.

Result: audience_subset<P: Ord + Clone> and audience_join<P: Ord + Clone> now emit correctly. All other Clone-only generic signatures reachable in the same import closure (ordering_fold, effect_access_request, list_length, disclosure_access_request, etc.) are unchanged — no regression on the existing 25-site Clone population.

The committed stage0 mirror itself is not touched by this PR — it is expected to converge via the normal CI regen gate post-merge, per the committed-mirrors-are-the-bootstrap-base-case pattern.

Test plan

  • Regenerated v1's own compiler from the edited .dag sources and re-emitted the specimen file through the candidate gunbc; confirmed P: Ord + Clone on both target functions.
  • Confirmed no change to Clone-only signatures elsewhere in the import closure.
  • Confirmed the worktree carries only the three intended .dag source edits (no stray generated-mirror changes).
  • CI's own regen gate (post-merge) converges the committed stage0 mirror.

🤖 Generated with Claude Code

Brian Searls and others added 2 commits August 21, 2026 13:00
…audience_join

v1's fn-generic bound-inference mechanism only ever derived Clone bounds
for generic function parameters, so a generic reaching the set_union
builtin (which lowers to rc_set_union<T: Ord + Clone>) emitted without
its own P: Ord, producing E0277 at the call site. audience_subset and
audience_join in dag/std/authorization_profile.dag are the two real
specimens (E0277 root A residual, dashboard node://adhoc-a9f61ade-340).

Adds a narrowly-scoped third trigger alongside the existing Clone-bound
machinery: a pure decision core (v1_set_union_ord_bound_param_names in
trait_bound_witness.dag), a Node-consuming body walker that locates
set_union call sites and resolves their element-type argument names
(05_emit_rust.dag, mirroring ownership.dag's collect_callable_refs, plus
an ExprBinOp arm that precedent lacks -- needed because audience_subset's
set_union call sits inside a == comparison), and a sibling renderer
(v1_emit_type_params_with_clone_and_ord_bounds in trait_derive_emit.dag)
wired into emit_fn_def alongside the existing Clone-only renderer.

Scoped to the set_union builtin's known lowering only -- not a general
trait-bound inference system, and does not touch the separate Root A
Ord-5 population on EnumeratedAudience's own struct derive.

Verified by regenerating v1's own compiler from these .dag sources and
re-emitting dag/std/authorization_profile.dag through the candidate
gunbc: audience_subset and audience_join now emit <P: Ord + Clone>; all
other Clone-only generic signatures in the import closure (ordering_fold,
effect_access_request, list_length, etc.) are unchanged.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Commits the src/v1/stage0/src/*.rs mirror produced by
--required-regen for the three .dag edits in dde8ac2. Closes
PR #8761's CI regen-drift failure: the prior commit only carried
the .dag sources, not their regenerated Rust mirror, so
required-regen (and its downstream receipt phase) correctly
flagged drift on v1_compiler_emit_rust.rs,
v1_compiler_trait_bound_witness.rs, and
v1_compiler_trait_derive_emit.rs.

Verified: sha256 of each mirror file matches the candidate
produced by target/stage0-regen-candidate/src (built from a
gunbc compiled against these committed .dag sources), and the
diffs are exactly the new Ord-bound rendering/decision-core
additions plus the ExprBinOp walker case, no unrelated drift.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@gunbai-bot

gunbai-bot Bot commented Aug 21, 2026

Copy link
Copy Markdown
Contributor Author

Closing in favor of a subsuming fix, not because this is wrong.

This PR's set_union call-site walker correctly emits <P: Ord + Clone> on audience_subset/audience_join, but it does so by name-recognizing the set_union builtin at call sites -- a heuristic where a structural fact turns out to be available: both real specimens (the only two generic call sites reaching set_union anywhere in dag/ or src/v1/) name AudienceSet<P> at value-param position, and quick-boar-406's lane (adhoc-1e0dee2d-68f) generalizes the existing item-level well-formedness propagation to be bound-trait-parameterized, so a fn naming an Ord-bounded declared type earns P: Ord the same way it already earns P: Clone -- no walker, no builtin name, needed. Per DESIGN.md §4 ("a heuristic is never necessary in a closed system") and §6 (bare-minimum-cost / no generalized machinery for a population of one), the general rule is the right owner once it lands.

Verified before closing: I found no counter-specimen where a fn reaches an Ord-requiring builtin without naming an Ord-bounded declared type in its own signature (checked by grep across the whole tree). If one turns up later, this branch's mechanism (and its ExprBinOp walker-precedent fix, real independent of this PR's outcome) is preserved in history rather than deleted.

— sent from tidy-otter-493

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

0 participants