Skip to content

emit_rust: a generic fn stored as a function value forwards its Clone bound (native broker 2A, rule 4) - #13160

Merged
gunbai-bot[bot] merged 11 commits into
mainfrom
session/snappy-owl-646-fn-value
Oct 4, 2026
Merged

gunbai-bot[bot] merged 11 commits into
mainfrom
session/snappy-owl-646-fn-value

Conversation

@gunbai-bot

@gunbai-bot gunbai-bot Bot commented Oct 3, 2026 •

Copy link
Copy Markdown
Contributor

Native broker 2A, rule 4: a generic fn stored as a function value forwards its Clone bound

Part of the native-broker program (owner gentle-dove-36), class A. Rule 1 landed as #13144. Rule 2 (Set-element Ord) is gunbc#13078's. Rule 3 (leaf-keyed declaration index) is lane 2K's. This PR is rule 4 only; I checked that #13078 does not cover it (its function-value change is about optional unwrapping of lambda arguments).

The defect

std.key_relation:

fn key_relation_global_scope_of<Subject>(_subject: Subject) -> GlobalKeyScope
fn key_relation_global<Relation, Subject, Key>(key_of: .., key_eq: ..) -> KeyRelation<Relation, Subject, GlobalKeyScope, Key> {
  KeyRelation { scope_of: key_relation_global_scope_of, .. }
}

Storing key_relation_global_scope_of in the arrow field instantiates it at the wrapper's Subject, exactly as a call would. The callee emits <Subject: Clone>; the wrapper emitted <Relation: 'static, Subject: 'static, Key: 'static>, so rustc refuses at Rc::new(key_relation_global_scope_of) (E0277, twice, std_key_relation.rs:106). The existing forwarding derivation only looked at calls.

Where the instantiation is read from

A call has arguments to join on. A function value has none, and two places that look like they carry the instantiation do not:

  • the reference is typed with the callee's own uninstantiated signature (v1.compiler.infer, resolved_callable_type over the callee's params);
  • the record literal's resolved type is the declaration's product with the declaration's own slot names. This was measured: a first form of this rule read the field there and bound std.key_relation correctly only because that module spells the record's slot and the wrapper's generic identically (Subject). The control, which spells them Subject and S, stayed unbounded.

So the join is read from the type the literal is checked against. At a fn's result position that is the declared return type, whose arguments are authored: the callee's i-th value parameter is a bounded callee generic; the record declaration's field is an arrow whose i-th argument is the declaration's k-th slot; the return type passes one of the fn's own generics at slot k.

Declared boundary: a record literal in result position (the body, or the tail of a let / block / if / match / return) whose type is the return type's head, with bare-slot arrow arguments. A literal elsewhere contributes nothing rather than being guessed at from the return type. Next-rung trigger: a specimen storing a generic fn in a literal outside result position, which needs the expected type carried to the literal.

The hop this manufactures, fixed in the same PR

Bounding key_relation_global made its caller owe the bound: key_resource_relation_global forwards its own fn(Subject) -> Key into it. The call-forwarding join reads a type's head and one type argument, and an arrow has neither, so that caller stayed bare and the error moved one fn up (std_key_relation.rs:138, observed in the intermediate run). v1_call_forwarding_forwarded_param_names now also joins arrow-typed parameters by argument position. Without it this rule trades one error for another, so it is not split out.

The callee's full bound (own body, what it calls, what it stores) is extracted to v1_callee_clone_bound_param_names, so the call site and the function-value site ask one derivation.

Evidence (one remote dispatch, amd64 runner, branch head b30646e plus the regenerated mirror)

Native emission control (gunbc test //gunbc/instruments:native-emission-controls, four new fn_value_* cases; callee generic T, record slot Subject, wrapper generic S, plus a control_keying_via hop):

seed emitter before the rule after
emitted control crate does not compile: E0277 S: Clone at control_keying builds with -D warnings, warning_count=0
run n/a exit 0, 10/10 held (6 from rule 1, 4 new)

Textual witness (test.claim.generic_item_clone_bound_witness, two new arms, both executed true in that dispatch via gunbc run --function): hdr_keying<S: Clone + 'static, K: 'static> and the hop hdr_keying_via<A: Clone + 'static, B: 'static>; converse arms that K / B gain no Clone and that a fn storing only the values it was handed (hdr_keying_plain) keeps S without Clone.

Regen: claim_executor --required-regen drifted on v1_compiler_emit_rust.rs only; after installing it first_generation_equal=true and --required-regen-fixed-point reports fixed_point_equal=true. No other mirror changed, so neither the function-value rule nor the arrow-argument join added a bound to any emitted seed fn.

Error delta

probe before after
std.key_relation closure (--entry dag/std/key_relation.dag, 12 files) 3 1

The remaining one is std_key_relation.rs:132 E0282 "type annotations needed", a different class and not this lane's.

Approval broker, paired (one dispatch; this head 8cb6e7f and its main base 63128f5, same runner, both with the approval_store_receipt filter hoisted locally for the probe only; errors joined by module and message with line numbers stripped):

base 63128f5 this head
emitted files 452 452
cargo check errors 887 885

Only in base: the two std_key_relation.rs E0277 Subject: Clone. Only in head: nothing. So the rule removes exactly its two class-A errors and neither it nor the arrow-argument join adds an error anywhere in the broker closure. (This base is main before lane 1A's closure cut lands, hence 887 rather than the 253 census figure.)

Class A after this PR, at this base: 13 errors, all owned elsewhere -- 10 at std_access.rs (lane 2K, leaf-keyed index) and 3 at std_authorization_profile.rs:74/85 (gunbc#13078, Set-element Ord).

🤖 Generated with Claude Code

Brian Searls and others added 5 commits October 3, 2026 21:08
… bound (WIP, mirrors not regenerated)

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…instantiated at the literal

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…esult position; join arrow-typed arguments by position

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…ding (fixed point verified at b30646e)

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@gunbai-bot
gunbai-bot Bot added this pull request to the merge queue Oct 3, 2026
@github-merge-queue
github-merge-queue Bot removed this pull request from the merge queue due to a conflict with the base branch Oct 4, 2026
Brian Searls and others added 2 commits October 4, 2026 02:36
…executor --regen-round-cost; fixed point at round 2)

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@gunbai-bot
gunbai-bot Bot added this pull request to the merge queue Oct 4, 2026
@github-merge-queue
github-merge-queue Bot removed this pull request from the merge queue due to a conflict with the base branch Oct 4, 2026
briansrls and others added 2 commits October 4, 2026 09:01
… mirror regenerated)

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
briansrls and others added 2 commits October 4, 2026 16:19
…egenerated next)

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@gunbai-bot
gunbai-bot Bot added this pull request to the merge queue Oct 4, 2026
Merged via the queue into main with commit 10ba9cc Oct 4, 2026
4 checks passed
@gunbai-bot
gunbai-bot Bot deleted the session/snappy-owl-646-fn-value branch October 4, 2026 21:02
gunbai-bot Bot pushed a commit that referenced this pull request Oct 4, 2026
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.

1 participant