Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 28 additions & 0 deletions dag/test/claim/trait_bound_witness_test.dag
Original file line number Diff line number Diff line change
Expand Up @@ -18,3 +18,31 @@ fn w_current_defect_reproduces_bare_generic_no_clone_impl() -> Bool {
test fn current_defect_reproduces_bare_generic_no_clone_impl() -> Bool {
w_current_defect_reproduces_bare_generic_no_clone_impl()
}

data call_forwarding_clone_bound_witness_note: String = "gunbc dashboard node://adhoc-574e999b-39c, Row 1b. Proves v1_call_forwarding_clone_bound_param_names / v1_call_forwarding_clone_bound_wrapper_param_names (src/v1/trait_bound_witness.dag, TraitBoundWitnessScope BoundedToDirectSingleCallLambdaBody) through the real emit pipeline via compile_dag_rust_emit_check, same discipline as the sibling RC-match witness above -- no v1.compiler import. Fixture is traced to reproduce src/v2/std/staging.dag's real cached_stage<A, B> shape (compound-arity CacheProbe<B> forwarded from a wrapper's lambda body directly into an already-derived-Clone-bounded callee, resolve_probe<A, B>), one of the census's 51-error board rows (docs/probes/materialization_carriers_rebaseline_2026-08-19.md). w_call_forwarding_derives_clone_bound_from_callee asserts the fixed emitted shape `fn cached_stage<A: Clone, B: Clone>(` and the absence of the pre-fix bare `fn cached_stage<A, B>(`, confirmed against a live gunbc compile of the real staging.dag module this session (v2_std_staging.rs). w_call_forwarding_scope_excludes_match_wrapped_body is the declared-boundary negative control (DESIGN.md S4b rung honesty, S6 no hypothetical generality): a function whose body is a lambda wrapping a MATCH whose arm is the call (not a lambda whose body IS directly the call) stays bare -- reproducing src/v2/compiler/materialization_carriers.dag's real cached_stage_governed<A, B> shape, confirmed unbounded against a live compile this session. That residual gap does not manifest as a rustc error in the census entrypoint's dependency closure (cached_stage_governed has zero callers there, and its own generic body never itself requires A: Clone / B: Clone to typecheck), so it is recorded here as a declared, non-silent scope boundary rather than fixed -- fixing it would require the same recursive body-walker (mirroring emit_rust_expr_if/emit_rust_expr_let's accessor shapes) that BoundedToDirectSingleCallLambdaBody's own note already names as its next-rung trigger, and is deliberately not built in this PR (DESIGN.md S6)."

fn w_call_forwarding_derives_clone_bound_from_callee() -> Bool {
compile_dag_rust_emit_check(
"module fn_clone_bound_witness.call_forwarding\ntype CacheProbe<B>\n = Miss\n | Hit { value: B }\n\nfn resolve_probe<A, B>(probe: CacheProbe<B>, stage: fn(A) -> B, x: A) -> B {\n match probe {\n Hit { value: hit } => hit\n Miss => stage(x)\n }\n}\n\nfn cached_stage<A, B>(lookup: fn(A) -> CacheProbe<B>, stage: fn(A) -> B) -> fn(A) -> B {\n fn(x) {\n resolve_probe(probe: lookup(x), stage: stage, x: x)\n }\n}\n",
"src/fn_clone_bound_witness_call_forwarding.rs",
["fn cached_stage<A: Clone, B: Clone>("],
["fn cached_stage<A, B>("]
)
}

test fn call_forwarding_derives_clone_bound_from_callee() -> Bool {
w_call_forwarding_derives_clone_bound_from_callee()
}

fn w_call_forwarding_scope_excludes_match_wrapped_body() -> Bool {
compile_dag_rust_emit_check(
"module fn_clone_bound_witness.call_forwarding_match_wrapped\ntype CacheProbe<B>\n = Miss\n | Hit { value: B }\n\nfn resolve_probe<A, B>(probe: CacheProbe<B>, stage: fn(A) -> B, x: A) -> B {\n match probe {\n Hit { value: hit } => hit\n Miss => stage(x)\n }\n}\n\nfn cached_stage_governed<A, B>(governed: Bool, lookup: fn(A) -> CacheProbe<B>, stage: fn(A) -> B) -> fn(A) -> B {\n fn(x) {\n match governed {\n true => resolve_probe(probe: lookup(x), stage: stage, x: x)\n false => stage(x)\n }\n }\n}\n",
"src/fn_clone_bound_witness_call_forwarding_match_wrapped.rs",
["fn cached_stage_governed<A, B>("],
["fn cached_stage_governed<A: Clone, B: Clone>("]
)
}

test fn call_forwarding_scope_excludes_match_wrapped_body() -> Bool {
w_call_forwarding_scope_excludes_match_wrapped_body()
}
28 changes: 26 additions & 2 deletions src/v1/04_emit_info.dag
Original file line number Diff line number Diff line change
Expand Up @@ -72,9 +72,12 @@ fn collect_type_node_import_surface_names(n: Node, source_indices: Map<String, N
dedupe_nonempty_strings(items: concat(own, concat(child_names, inferred_names)))
}

data emit_graph_fn_decl_items_note: String = "fn_decl_items mirrors type_decl_items (dashboard node adhoc-574e999b-39c): a fn-name-keyed lookup into the SAME typed (post-04_infer, .inferred-populated) module items build_emit_graph_info already folds over, so a caller-side Clone-bound derivation (v1.compiler.trait_bound_witness) can resolve a callee-by-name and re-run emit_fn_def's own derivation on the callee's real declaration Node — never a second, parallel re-parse or re-inference of the callee."

type EmitGraphInfo {
type_summaries: Map<String, TypeSummary>
type_decl_items: Map<String, Node>
fn_decl_items: Map<String, Node>
recursive_type_set: Set<String>
fielded_variants: Set<String>
positional_payload_variants: Set<String>
Expand All @@ -101,6 +104,7 @@ type EmitGraphInfo {
type EmitInfoBuildState {
type_summaries: Map<String, TypeSummary>
type_decl_items: Map<String, Node>
fn_decl_items: Map<String, Node>
}

data empty_emit_graph_info_ord_fallback_note: String = "Conservatism: render paths without EmitGraphInfo pass empty_emit_graph_info(); bare-ref BTreeSet Ord eligibility fails closed (lookup_emit_type_decl -> Absent) and surfaces compile_error! at probe time — nine call sites inherit this, loud not silent widen."
Expand All @@ -109,6 +113,7 @@ fn empty_emit_graph_info() -> EmitGraphInfo {
EmitGraphInfo {
type_summaries: empty_map(),
type_decl_items: empty_map(),
fn_decl_items: empty_map(),
recursive_type_set: empty_set(),
fielded_variants: empty_set(),
positional_payload_variants: empty_set(),
Expand All @@ -133,6 +138,7 @@ fn emit_info_with_fn_type_context(emit_info: EmitGraphInfo, generic_param_names:
EmitGraphInfo {
type_summaries: emit_info.type_summaries,
type_decl_items: emit_info.type_decl_items,
fn_decl_items: emit_info.fn_decl_items,
recursive_type_set: emit_info.recursive_type_set,
fielded_variants: emit_info.fielded_variants,
positional_payload_variants: emit_info.positional_payload_variants,
Expand All @@ -156,6 +162,7 @@ fn emit_info_with_fn_return(emit_info: EmitGraphInfo, fn_return_type: Node?) ->
EmitGraphInfo {
type_summaries: emit_info.type_summaries,
type_decl_items: emit_info.type_decl_items,
fn_decl_items: emit_info.fn_decl_items,
recursive_type_set: emit_info.recursive_type_set,
fielded_variants: emit_info.fielded_variants,
positional_payload_variants: emit_info.positional_payload_variants,
Expand Down Expand Up @@ -203,6 +210,12 @@ fn emit_graph_records_type_decl(item: Node, source_indices: Map<String, NewlineI
}
}

data emit_graph_records_fn_decl_note: String = "Same criterion as v1.compiler.emit_core_support's is_function_item (05_emit_rust.dag's top-level item dispatch), duplicated here rather than imported: this module (v1.compiler.infer_emit_info) is upstream of v1.compiler.emit_core_support in the DAG (04_emit_info.dag has no import of 05_emit_core_support.dag today), and emit_graph_records_type_decl beside it already establishes the precedent of a locally-scoped duplicate one-line item-shape predicate at this stage rather than reaching downstream for one (DESIGN.md S3 -- a fact's home is its layer, and both predicates answer 'what item shape reaches this stage's fold', not 'what does emit_core_support export')."

fn emit_graph_records_fn_decl(item: Node) -> Bool {
item.body != none && item.type_annotation == none
}

fn derive_variant_to_enum(type_summaries: Map<String, TypeSummary>) -> Map<String, String> {
map_values(type_summaries) |> fold(init: empty_map(), f: (acc, summary) =>
match summary.repr {
Expand Down Expand Up @@ -439,7 +452,17 @@ fn add_emit_item_summary(state: EmitInfoBuildState, item: Node, source_indices:
let state = if decl_name != "" && emit_graph_records_type_decl(item: item, source_indices: source_indices) {
EmitInfoBuildState {
type_summaries: state.type_summaries,
type_decl_items: map_insert(state.type_decl_items, decl_name, item)
type_decl_items: map_insert(state.type_decl_items, decl_name, item),
fn_decl_items: state.fn_decl_items
}
} else {
state
}
let state = if decl_name != "" && emit_graph_records_fn_decl(item: item) {
EmitInfoBuildState {
type_summaries: state.type_summaries,
type_decl_items: state.type_decl_items,
fn_decl_items: map_insert(state.fn_decl_items, decl_name, item)
}
} else {
state
Expand Down Expand Up @@ -476,7 +499,8 @@ fn add_emit_item_summary(state: EmitInfoBuildState, item: Node, source_indices:
let next_summaries = map_insert(with_variants, summary.name, summary)
EmitInfoBuildState {
type_summaries: next_summaries,
type_decl_items: state.type_decl_items
type_decl_items: state.type_decl_items,
fn_decl_items: state.fn_decl_items
}
Absent => state
}
Expand Down
6 changes: 4 additions & 2 deletions src/v1/04_infer.dag
Original file line number Diff line number Diff line change
Expand Up @@ -9647,14 +9647,15 @@ fn build_enum_variant_shape_sets(modules: List<TypedModule>, type_summaries: Map
fn build_emit_graph_info(modules: List<TypedModule>) -> EmitGraphInfo {
let init = EmitInfoBuildState {
type_summaries: empty_map(),
type_decl_items: empty_map()
type_decl_items: empty_map(),
fn_decl_items: empty_map()
}
let built_raw = modules |> fold(init: init, f: (state, typed_module) =>
typed_module.items |> fold(init: state, f: (inner_state, item) =>
add_emit_item_summary(state: inner_state, item: item, source_indices: typed_module.type_env.source_indices)
)
)
let built = EmitInfoBuildState { type_summaries: close_fn_fields(summaries: built_raw.type_summaries), type_decl_items: built_raw.type_decl_items }
let built = EmitInfoBuildState { type_summaries: close_fn_fields(summaries: built_raw.type_summaries), type_decl_items: built_raw.type_decl_items, fn_decl_items: built_raw.fn_decl_items }
let all_recursive = modules |> fold(init: empty_set(), f: (acc, m) =>
fold(map_keys(m.type_env.recursive_type_set), init: acc, f: (inner, ident) =>
set_insert(inner, intern_str(table: m.type_env.intern_table, id: ident))
Expand All @@ -9665,6 +9666,7 @@ fn build_emit_graph_info(modules: List<TypedModule>) -> EmitGraphInfo {
EmitGraphInfo {
type_summaries: built.type_summaries,
type_decl_items: built.type_decl_items,
fn_decl_items: built.fn_decl_items,
recursive_type_set: all_recursive,
fielded_variants: variant_shapes.fielded,
positional_payload_variants: variant_shapes.positional_payload,
Expand Down
Loading