diff --git a/src/v1/05_emit_rust.dag b/src/v1/05_emit_rust.dag index d842048873b..1daae92f425 100644 --- a/src/v1/05_emit_rust.dag +++ b/src/v1/05_emit_rust.dag @@ -3391,7 +3391,71 @@ fn reference_derived_candidate_authored(module_source: String, name: String, typ || reference_derived_variant_induced_parent_spelled(module_source: module_source, enum_name: name, type_summaries: type_summaries, variant_to_enum: variant_to_enum) } -fn reference_derived_use_lines(items: List, unlisted_type_names: List, this_module_name: String, registry: Map, emit_info: EmitGraphInfo, local_type_names: List, already_imported_names: List, export_sets: Map>, typed_modules: List, source_indices: Map, module_index: ModuleIndex) -> List { + +// THE CANDIDATE PRODUCER FOR NAMES THE SOURCE NEVER SPELLS. +// +// host_realized_builtin_needs_no_import_note and reference_derived_authored_source_gate_note name +// the same terminal shape from opposite ends: derive use-lines from the EMITTED reference set, +// because a name the collector never proposes cannot be admitted by any gate decision however wide. +// This is that producer, at type grain and with no second authority: the realized names are read +// back out of render_rust_type -- the one function that decides what a type reference becomes -- +// rather than re-derived from a roster of substitutions, so a renderer change cannot leave the +// import derivation behind. +// +// The three substitution mechanisms this reaches, each measured on the 03_ingest board of +// 2026-08-23 (docs/probes/board_2026-08-23): a host carrier rewrite (Diagnostics renders as +// Option, four E0425 blocks across v2.compiler.normalized_tree and +// v2.compiler.normalize), an alias expansion (Char renders as Int in v2.std.text, EpochMs as Int +// in std.state_durability), and a leaf reduction (a qualified reference spelled +// v2.std.cross_tree.resolution.SourceRootIndex renders as the bare leaf). In every case the SOURCE +// name is imported or needs no import and the EMITTED name is the one with no provider line. +// +// It proposes only; every existing filter still decides. A proposed name must resolve through the +// registry to another module, pass provider_proven_exports_symbol, and -- the arm below -- be +// spelled in the module's own EMITTED text. That last attestation is why a misrendered candidate +// cannot fabricate a use-line: a name the emitter did not write is not attested by the artifact it +// wrote, which is a strictly stronger witness than the authored-source gate it joins. +// Splits a Rust TEXT into bare identifier tokens. Two callers with one authority: a rendered TYPE +// string (Rc>, crate::a::B) and a whole emitted MODULE source. The type caller only ever +// contains the first nine delimiters; the source caller also carries statement and block +// punctuation, and omitting those is not cosmetic -- `pub type X = Int;` would tokenize to `Int;` +// and a membership test for `Int` would answer NO for a name the emitter demonstrably wrote, +// dropping a required use-line and reproducing the E0425 class this producer exists to close. +// Adding them is expected to be a no-op for the type caller (rendered types contain none of them), +// so one tokenizer serves both rather than a second near-copy keyed to the caller. That is stated as +// UNREFUTED rather than proven: the two-arm measurement below moved 20 use-lines and every one is +// explained by the GATE, so nothing in it exhibits a producer-side change -- but nothing in it +// positively rules one out either. +fn rust_identifier_tokens(s: String) -> List { + let spaced = replace(replace(replace(replace(replace(replace(replace(replace(replace(s, + "<", " "), ">", " "), ",", " "), "(", " "), ")", " "), "[", " "), "]", " "), "&", " "), ":", " ") + let unpunctuated = replace(replace(replace(replace(replace(replace(replace(replace(replace(spaced, + ";", " "), "\{", " "), "\}", " "), ".", " "), "=", " "), "\n", " "), "\t", " "), "\r", " "), "*", " ") + let untokened = replace(replace(replace(replace(replace(unpunctuated, + "!", " "), "?", " "), "|", " "), "+", " "), "#", " ") + untokened |> split(delimiter: " ") |> map(t => trim(t)) |> filter(t => t != "") +} + +fn collect_type_node_realized_surface_names(n: Node, shared_types: Set, source_indices: Map, emit_info: EmitGraphInfo) -> List { + rust_identifier_tokens(s: render_rust_type(n: n, shared_types: shared_types, source_indices: source_indices, emit_info: emit_info)) +} + +fn collect_item_realized_surface_names(item: Node, shared_types: Set, source_indices: Map, emit_info: EmitGraphInfo) -> List { + let from_ann = match item.type_annotation { + Present { value: t } => collect_type_node_realized_surface_names(n: t, shared_types: shared_types, source_indices: source_indices, emit_info: emit_info) + Absent => [] + } + let from_params = item.params |> flat_map(p => + collect_type_node_realized_surface_names(n: param_node_type_expr(n: p), shared_types: shared_types, source_indices: source_indices, emit_info: emit_info) + ) + let from_inferred = match item.inferred { + Present { value: Resolved { node: rt } } => collect_type_node_realized_surface_names(n: rt, shared_types: shared_types, source_indices: source_indices, emit_info: emit_info) + _ => [] + } + unique_strings(items: concat(from_ann, concat(from_params, from_inferred))) +} + +fn reference_derived_use_lines(items: List, unlisted_type_names: List, this_module_name: String, registry: Map, emit_info: EmitGraphInfo, local_type_names: List, already_imported_names: List, export_sets: Map>, typed_modules: List, source_indices: Map, module_index: ModuleIndex, shared_types: Set, emitted_source: String) -> List { { let module_source = match typed_modules |> filter(tm => authored_name_at(source_indices: source_indices, node: tm.module) == this_module_name) |> first { Present { value: tm } => module_authored_source_text(module: tm.module, source_indices: source_indices) @@ -3402,10 +3466,13 @@ fn reference_derived_use_lines(items: List, unlisted_type_names: List flat_map(item => collect_anonymous_record_lit_heads(n: item, source_indices: source_indices, type_summaries: emit_info.type_summaries))) - let candidates = unique_strings(items: concat(concat(concat(concat(unlisted_type_names, value_names), type_surface_names), field_surface_names), variant_payload_structs)) + let realized_surface_names = unique_strings(items: items |> flat_map(item => collect_item_realized_surface_names(item: item, shared_types: shared_types, source_indices: source_indices, emit_info: emit_info))) + let emitted_source_tokens = rust_identifier_tokens(s: emitted_source) + let candidates = unique_strings(items: concat(concat(concat(concat(concat(unlisted_type_names, value_names), type_surface_names), field_surface_names), variant_payload_structs), realized_surface_names)) |> filter(name => reference_derived_candidate_authored(module_source: module_source, name: name, type_summaries: emit_info.type_summaries, variant_to_enum: emit_info.variant_to_enum) - || emitter_attested_anon_heads |> any(h => h == name)) + || emitter_attested_anon_heads |> any(h => h == name) + || (emitted_source_tokens |> any(t => t == name))) |> filter(name => !reference_is_host_realized_builtin(name: name)) let local_decl_names = items |> flat_map(item => let nm = authored_name_at(source_indices: source_indices, node: item) @@ -3477,6 +3544,18 @@ fn emit_module_full(typed_module: TypedModule, registry: Map, |> map(item => authored_name(env: scope.type_env, node: item)), collect_phantom_zst_marker_names(items: typed_module.items, env: scope.type_env) ) + let module_import_items = module_imports(n: m) + let this_module_name = authored_name(env: scope.type_env, node: m) + let wire_context_items = concat(typed_module.items, contracts_items_for_module(module_name: this_module_name, typed_modules: typed_modules, source_indices: scope.type_env.source_indices, module_index: module_index)) + let wire_context_imports = concat(module_import_items, contracts_imports_for_module(module_name: this_module_name, typed_modules: typed_modules, source_indices: scope.type_env.source_indices, module_index: module_index)) + let wire_contract_item = wire_context_items + |> filter(i => + is_data_def_item(item: i) + && authored_name_at(source_indices: scope.type_env.source_indices, node: i) == "wire_contract") + |> first + let items_str = typed_module.items + |> map(item => emit_typed_item(item: item, module_name: authored_name(env: scope.type_env, node: m), registry: registry, scope: scope, shared_types: shared_types, emit_info: emit_info, wire_contract_item: wire_contract_item, data_items: scoped_data_items, module_items: wire_context_items, imports: wire_context_imports, export_sets: export_sets, typed_modules: typed_modules, module_index: module_index)) + |> join(separator: "\n\n") let prelude = emit_prelude(imported_names: prelude_imported_names, local_type_names: local_type_names) let imports_str = emit_imports(imports: module_imports(n: m), emit_info: emit_info, registry: registry, local_names: local_type_names, export_sets: export_sets, typed_modules: typed_modules, source_indices: scope.type_env.source_indices, module_index: module_index, supplement_items: typed_module.items) let dag_import_lines = if imports_str == "" { [] } else { imports_str |> split(delimiter: "\n") } @@ -3510,7 +3589,9 @@ fn emit_module_full(typed_module: TypedModule, registry: Map, export_sets: export_sets, typed_modules: typed_modules, source_indices: scope.type_env.source_indices, - module_index: module_index + module_index: module_index, + shared_types: shared_types, + emitted_source: items_str ) let merged_imports = dedupe_rust_import_lines(lines: concat(concat(dag_import_lines, carrier_import_lines), reference_use_lines)) |> join(separator: "\n") let imports_section = if merged_imports == "" { "" } else { concat("\n", merged_imports) } @@ -3538,22 +3619,10 @@ fn emit_module_full(typed_module: TypedModule, registry: Map, let local_coproduct_names = typed_module.items |> filter(item => is_type_def_item(item: item) && is_coproduct_type(n: item)) |> map(item => authored_name(env: scope.type_env, node: item)) - let module_import_items = module_imports(n: m) - let this_module_name = authored_name(env: scope.type_env, node: m) - let wire_context_items = concat(typed_module.items, contracts_items_for_module(module_name: this_module_name, typed_modules: typed_modules, source_indices: scope.type_env.source_indices, module_index: module_index)) - let wire_context_imports = concat(module_import_items, contracts_imports_for_module(module_name: this_module_name, typed_modules: typed_modules, source_indices: scope.type_env.source_indices, module_index: module_index)) let coproduct_wire_contract_validations = emit_coproduct_wire_contract_validations(module_items: wire_context_items, imports: wire_context_imports, local_coproduct_names: local_coproduct_names, source_indices: scope.type_env.source_indices) let coproduct_wire_contract_validation_section = if coproduct_wire_contract_validations == "" { "" } else { concat(coproduct_wire_contract_validations, "\n\n") } let local_uses_str = if local_enum_uses |> count == 0 { "" } else { concat("\n", local_enum_uses |> join(separator: "\n")) } - let wire_contract_item = wire_context_items - |> filter(i => - is_data_def_item(item: i) - && authored_name_at(source_indices: scope.type_env.source_indices, node: i) == "wire_contract") - |> first - let items_str = typed_module.items - |> map(item => emit_typed_item(item: item, module_name: authored_name(env: scope.type_env, node: m), registry: registry, scope: scope, shared_types: shared_types, emit_info: emit_info, wire_contract_item: wire_contract_item, data_items: scoped_data_items, module_items: wire_context_items, imports: wire_context_imports, export_sets: export_sets, typed_modules: typed_modules, module_index: module_index)) - |> join(separator: "\n\n") let phantom_zst_markers = emit_module_phantom_zst_markers(items: typed_module.items, env: scope.type_env) let phantom_section = if phantom_zst_markers == "" { "" } else { concat("\n\n", phantom_zst_markers) } let raw_filename = module_to_filename(name: authored_name(env: scope.type_env, node: m)) diff --git a/src/v1/stage0/src/v1_compiler_emit_rust.rs b/src/v1/stage0/src/v1_compiler_emit_rust.rs index b71ce441aed..6eefe86e558 100644 --- a/src/v1/stage0/src/v1_compiler_emit_rust.rs +++ b/src/v1/stage0/src/v1_compiler_emit_rust.rs @@ -7448,6 +7448,189 @@ pub fn reference_derived_candidate_authored( )) } +pub fn rust_identifier_tokens(s: String) -> Rc> { + { + let spaced = v1_rt::replace( + v1_rt::replace( + v1_rt::replace( + v1_rt::replace( + v1_rt::replace( + v1_rt::replace( + v1_rt::replace( + v1_rt::replace( + v1_rt::replace(s.clone(), "<".to_string(), " ".to_string()), + ">".to_string(), + " ".to_string(), + ), + ",".to_string(), + " ".to_string(), + ), + "(".to_string(), + " ".to_string(), + ), + ")".to_string(), + " ".to_string(), + ), + "[".to_string(), + " ".to_string(), + ), + "]".to_string(), + " ".to_string(), + ), + "&".to_string(), + " ".to_string(), + ), + ":".to_string(), + " ".to_string(), + ); + let unpunctuated = v1_rt::replace( + v1_rt::replace( + v1_rt::replace( + v1_rt::replace( + v1_rt::replace( + v1_rt::replace( + v1_rt::replace( + v1_rt::replace( + v1_rt::replace( + spaced.clone(), + ";".to_string(), + " ".to_string(), + ), + "{".to_string(), + " ".to_string(), + ), + "}".to_string(), + " ".to_string(), + ), + ".".to_string(), + " ".to_string(), + ), + "=".to_string(), + " ".to_string(), + ), + "\n".to_string(), + " ".to_string(), + ), + "\t".to_string(), + " ".to_string(), + ), + "\x0d".to_string(), + " ".to_string(), + ), + "*".to_string(), + " ".to_string(), + ); + let untokened = v1_rt::replace( + v1_rt::replace( + v1_rt::replace( + v1_rt::replace( + v1_rt::replace(unpunctuated.clone(), "!".to_string(), " ".to_string()), + "?".to_string(), + " ".to_string(), + ), + "|".to_string(), + " ".to_string(), + ), + "+".to_string(), + " ".to_string(), + ), + "#".to_string(), + " ".to_string(), + ); + Rc::new({ + let mut __result = Vec::new(); + for t in Rc::new({ + let mut __result = Vec::new(); + for t in Rc::new( + untokened + .clone() + .split(&" ".to_string()) + .map(|s| s.to_string()) + .collect::>(), + ) + .iter() + .cloned() + { + __result.push(v1_rt::trim(t.clone())); + } + __result + }) + .iter() + .cloned() + { + if (t.clone() != "".to_string()) { + __result.push(t); + } + } + __result + }) + } +} + +pub fn collect_type_node_realized_surface_names( + n: Rc, + shared_types: Rc>, + source_indices: Rc>>, + emit_info: Rc, +) -> Rc> { + rust_identifier_tokens(render_rust_type( + n.clone(), + shared_types.clone(), + source_indices.clone(), + emit_info.clone(), + )) +} + +pub fn collect_item_realized_surface_names( + item: Rc, + shared_types: Rc>, + source_indices: Rc>>, + emit_info: Rc, +) -> Rc> { + { + let from_ann = match item.type_annotation.clone() { + Some(t) => collect_type_node_realized_surface_names( + t.clone(), + shared_types.clone(), + source_indices.clone(), + emit_info.clone(), + ), + None => Rc::new(vec![]), + }; + let from_params = Rc::new({ + let mut __result = Vec::new(); + for p in item.params.clone().iter().cloned() { + __result.extend( + (*collect_type_node_realized_surface_names( + param_node_type_expr(p.clone()), + shared_types.clone(), + source_indices.clone(), + emit_info.clone(), + )) + .iter() + .cloned(), + ); + } + __result + }); + let from_inferred = match item.inferred.clone().as_deref().cloned() { + Some(InferredNode::Resolved { node: rt, .. }) => { + collect_type_node_realized_surface_names( + rt.clone(), + shared_types.clone(), + source_indices.clone(), + emit_info.clone(), + ) + } + _ => Rc::new(vec![]), + }; + unique_strings(v1_rt::concat( + from_ann.clone(), + v1_rt::concat(from_params.clone(), from_inferred.clone()), + )) + } +} + pub fn reference_derived_use_lines( items: Rc>>, unlisted_type_names: Rc>, @@ -7460,6 +7643,8 @@ pub fn reference_derived_use_lines( typed_modules: Rc>>, source_indices: Rc>>, module_index: Rc, + shared_types: Rc>, + emitted_source: String, ) -> Rc> { { let module_source = match Rc::new({ @@ -7535,6 +7720,23 @@ pub fn reference_derived_use_lines( } __result })); + let realized_surface_names = unique_strings(Rc::new({ + let mut __result = Vec::new(); + for item in items.iter().cloned() { + __result.extend( + (*collect_item_realized_surface_names( + item.clone(), + shared_types.clone(), + source_indices.clone(), + emit_info.clone(), + )) + .iter() + .cloned(), + ); + } + __result + })); + let emitted_source_tokens = rust_identifier_tokens(emitted_source.clone()); let candidates = Rc::new({ let mut __result = Vec::new(); for name in Rc::new({ @@ -7542,17 +7744,20 @@ pub fn reference_derived_use_lines( for name in unique_strings(v1_rt::concat( v1_rt::concat( v1_rt::concat( - v1_rt::concat(unlisted_type_names.clone(), value_names.clone()), - type_surface_names.clone(), + v1_rt::concat( + v1_rt::concat(unlisted_type_names.clone(), value_names.clone()), + type_surface_names.clone(), + ), + field_surface_names.clone(), ), - field_surface_names.clone(), + variant_payload_structs.clone(), ), - variant_payload_structs.clone(), + realized_surface_names.clone(), )) .iter() .cloned() { - if (reference_derived_candidate_authored( + if ((reference_derived_candidate_authored( module_source.clone(), name.clone(), emit_info.type_summaries.clone(), @@ -7566,6 +7771,15 @@ pub fn reference_derived_use_lines( } } __found + }) || { + let mut __found = false; + for t in emitted_source_tokens.iter().cloned() { + if (t.clone() == name.clone()) { + __found = true; + break; + } + } + __found }) { __result.push(name); } @@ -7846,6 +8060,62 @@ pub fn emit_module_full( }), collect_phantom_zst_marker_names(typed_module.items.clone(), scope.type_env.clone()), ); + let module_import_items = module_imports(m.clone()); + let this_module_name = authored_name(scope.type_env.clone(), m.clone()); + let wire_context_items = v1_rt::concat( + typed_module.items.clone(), + contracts_items_for_module( + this_module_name.clone(), + typed_modules.clone(), + scope.type_env.clone().source_indices.clone(), + module_index.clone(), + ), + ); + let wire_context_imports = v1_rt::concat( + module_import_items.clone(), + contracts_imports_for_module( + this_module_name.clone(), + typed_modules.clone(), + scope.type_env.clone().source_indices.clone(), + module_index.clone(), + ), + ); + let wire_contract_item = Rc::new({ + let mut __result = Vec::new(); + for i in wire_context_items.iter().cloned() { + if (is_data_def_item(i.clone()) + && (authored_name_at(scope.type_env.clone().source_indices.clone(), i.clone()) + == "wire_contract".to_string())) + { + __result.push(i); + } + } + __result + }) + .first() + .cloned(); + let items_str = Rc::new({ + let mut __result = Vec::new(); + for item in typed_module.items.clone().iter().cloned() { + __result.push(emit_typed_item( + item.clone(), + authored_name(scope.type_env.clone(), m.clone()), + registry.clone(), + scope.clone(), + shared_types.clone(), + emit_info.clone(), + wire_contract_item.clone(), + scoped_data_items.clone(), + wire_context_items.clone(), + wire_context_imports.clone(), + export_sets.clone(), + typed_modules.clone(), + module_index.clone(), + )); + } + __result + }) + .join(&"\n\n".to_string()); let prelude = emit_prelude(prelude_imported_names.clone(), local_type_names.clone()); let imports_str = emit_imports( module_imports(m.clone()), @@ -7921,6 +8191,8 @@ pub fn emit_module_full( typed_modules.clone(), scope.type_env.clone().source_indices.clone(), module_index.clone(), + shared_types.clone(), + items_str.clone(), ); let merged_imports = dedupe_rust_import_lines(v1_rt::concat( v1_rt::concat(dag_import_lines.clone(), carrier_import_lines.clone()), @@ -8041,26 +8313,6 @@ pub fn emit_module_full( } __result }); - let module_import_items = module_imports(m.clone()); - let this_module_name = authored_name(scope.type_env.clone(), m.clone()); - let wire_context_items = v1_rt::concat( - typed_module.items.clone(), - contracts_items_for_module( - this_module_name.clone(), - typed_modules.clone(), - scope.type_env.clone().source_indices.clone(), - module_index.clone(), - ), - ); - let wire_context_imports = v1_rt::concat( - module_import_items.clone(), - contracts_imports_for_module( - this_module_name.clone(), - typed_modules.clone(), - scope.type_env.clone().source_indices.clone(), - module_index.clone(), - ), - ); let coproduct_wire_contract_validations = emit_coproduct_wire_contract_validations( wire_context_items.clone(), wire_context_imports.clone(), @@ -8084,42 +8336,6 @@ pub fn emit_module_full( local_enum_uses.clone().join(&"\n".to_string()), ) }; - let wire_contract_item = Rc::new({ - let mut __result = Vec::new(); - for i in wire_context_items.iter().cloned() { - if (is_data_def_item(i.clone()) - && (authored_name_at(scope.type_env.clone().source_indices.clone(), i.clone()) - == "wire_contract".to_string())) - { - __result.push(i); - } - } - __result - }) - .first() - .cloned(); - let items_str = Rc::new({ - let mut __result = Vec::new(); - for item in typed_module.items.clone().iter().cloned() { - __result.push(emit_typed_item( - item.clone(), - authored_name(scope.type_env.clone(), m.clone()), - registry.clone(), - scope.clone(), - shared_types.clone(), - emit_info.clone(), - wire_contract_item.clone(), - scoped_data_items.clone(), - wire_context_items.clone(), - wire_context_imports.clone(), - export_sets.clone(), - typed_modules.clone(), - module_index.clone(), - )); - } - __result - }) - .join(&"\n\n".to_string()); let phantom_zst_markers = emit_module_phantom_zst_markers(typed_module.items.clone(), scope.type_env.clone()); let phantom_section = if (phantom_zst_markers.clone() == "".to_string()) {