From 786d2713a7c68ac87df11c43df0ac6bb1e1cd77f Mon Sep 17 00:00:00 2001 From: gunbc-ci-auto-heal Date: Wed, 23 Sep 2026 19:46:30 +0000 Subject: [PATCH 1/4] Pkg7d 1b: emitter use-line edges are returned typed and admitted against the stage0 crate partition v1.compiler.emit_rust returns SemanticSourceReference edges beside the use-lines it renders (emit_imports, reference_derived_use_line_plan, service imports); they ride EmitResult and PipelineResult out to required-regen, where gunbc.stage0_emitted_edge_admission refuses an edge whose target crate the source crate does not reach (E0432 class) and names a module outside the seed as NotCovered. gunbc_rust_emitted_edge moves into the std-core unit, which the first partition build demanded. v1 touched as v2 self-host work (v1_seed_standing). Co-Authored-By: Claude Opus 5.5 (1M context) --- dag/gunbc/rust_emitted_edge.dag | 12 +- .../stage0_crate_partition_generated.dag | 3 +- .../stage0/stage0_emitted_edge_admission.dag | 207 ++++++ src/v1/05_emit_core_support.dag | 4 + src/v1/05_emit_go.dag | 6 +- src/v1/05_emit_python.dag | 6 +- src/v1/05_emit_rust.dag | 150 +++-- src/v1/compile.dag | 24 +- src/v1/stage0/src/emitted_population.rs | 2 + src/v1/stage0/src/gunbc_rust_emitted_edge.rs | 13 + .../gunbc_stage0_crate_partition_generated.rs | 2 +- .../gunbc_stage0_emitted_edge_admission.rs | 420 ++++++++++++ src/v1/stage0/src/lib.rs | 6 +- src/v1/stage0/src/required_regen_host.rs | 24 + src/v1/stage0/src/v1_compiler_compile.rs | 21 + .../src/v1_compiler_emit_core_support.rs | 2 + src/v1/stage0/src/v1_compiler_emit_go.rs | 3 + src/v1/stage0/src/v1_compiler_emit_python.rs | 3 + src/v1/stage0/src/v1_compiler_emit_rust.rs | 631 +++++++++++------- .../stage0/src/v1_compiler_stage0_crates.rs | 41 +- src/v1/stage0_crates.dag | 12 +- src/v1/stage0_std_core/src/lib.rs | 3 + ...e0_emitted_edge_admission_witness_test.dag | 110 +++ src/v2/workflow/rust_crate_partition.dag | 8 +- 24 files changed, 1357 insertions(+), 356 deletions(-) create mode 100644 dag/gunbc/stage0/stage0_emitted_edge_admission.dag create mode 100644 src/v1/stage0/src/gunbc_stage0_emitted_edge_admission.rs create mode 100644 src/v2/test/claim/stage0_emitted_edge_admission_witness_test.dag diff --git a/dag/gunbc/rust_emitted_edge.dag b/dag/gunbc/rust_emitted_edge.dag index b208e274f95..796b4d65abf 100644 --- a/dag/gunbc/rust_emitted_edge.dag +++ b/dag/gunbc/rust_emitted_edge.dag @@ -13,12 +13,14 @@ import std.types { List, String } // This module lives under dag/ because the v1 emitter imports it and the v2 partition imports it: // one producer, two readers, no second list. -// Only the provenances a producer below emits are arms. The typed use-line rows (helper -// carriers, authored and reference-derived imports, service/CLI surfaces) add their arms in the -// change that lands their producer, not before it. +// Only the provenances a producer emits are arms. SemanticSourceReference is a use-line the +// emitter derives from the source: an authored import (emit_imports), a reference-derived import +// (reference_derived_use_line_plan), or a service import (emit_module_full). Helper-carrier and +// service/CLI runtime-surface arms land with their producers, not before them. type EmittedEdgeProvenance = RuntimePrelude | ReexportFacade + | SemanticSourceReference type EmittedEdgeTarget = EmittedModuleTarget { module: String } @@ -52,6 +54,10 @@ fn rust_prelude_emitted_edges(module: String) -> List { } } +fn semantic_source_reference_edge(from: String, to_module: String) -> EmittedEdge { + EmittedEdge { from: from, to: EmittedModuleTarget { module: to_module }, provenance: SemanticSourceReference } +} + fn emitted_edge_target_module(edge: EmittedEdge) -> List { match edge.to { EmittedModuleTarget { module: target } => [target] diff --git a/dag/gunbc/stage0/stage0_crate_partition_generated.dag b/dag/gunbc/stage0/stage0_crate_partition_generated.dag index 9fac5b37530..7e9fade05ff 100644 --- a/dag/gunbc/stage0/stage0_crate_partition_generated.dag +++ b/dag/gunbc/stage0/stage0_crate_partition_generated.dag @@ -75,7 +75,8 @@ data generated_partition_crate_rows: List = [ "std_literal_elaboration", "std_operator_realization", "std_import", - "v1_std_core" + "v1_std_core", + "gunbc_rust_emitted_edge" ], reexport_packages: [ "v1-stage0-runtime" diff --git a/dag/gunbc/stage0/stage0_emitted_edge_admission.dag b/dag/gunbc/stage0/stage0_emitted_edge_admission.dag new file mode 100644 index 00000000000..b97790114f8 --- /dev/null +++ b/dag/gunbc/stage0/stage0_emitted_edge_admission.dag @@ -0,0 +1,207 @@ +module gunbc.stage0_emitted_edge_admission + +import std.types { Bool, Int, List, String } +import gunbc.rust_emitted_edge { + EmittedEdge, + EmittedEdgeProvenance, + EmittedModuleTarget, + EmittedCrateRootTarget, + RuntimePrelude, + ReexportFacade, + SemanticSourceReference +} +import gunbc.stage0_crate_partition_generated { generated_partition_crate_rows } +import gunbc.stage0_partition_package_graph { + stage0_host_shell_dependency_names, + stage0_host_shell_package_name, + stage0_partition_package_dependency_names, + stage0_partition_row_is_module_bearing_package +} + +// DOES EVERY EDGE THE EMITTER WROTE RESOLVE IN THE CRATE ITS SOURCE MODULE LANDS IN. A `use +// crate::m::X;` line compiles in a partition crate only when m lives in that crate or in a package +// the crate re-exports (transitively, since each layered facade is `pub use ::*;`). The +// emitter returns each such edge beside the text it wrote (gunbc.rust_emitted_edge); this admission +// maps both endpoints through the partition's owner rows and the package graph +// (gunbc.stage0_partition_package_graph), and refuses an edge whose target package the source +// package cannot reach -- the E0432 class, named before rustc is asked. +// +// THE POPULATION IS THE STAGE0 SEED, and it is stated rather than assumed. A module is owned by the +// module-bearing partition row that lists it, else by the host shell package when the host shell's +// module roster (the caller supplies it, read from the shell's lib.rs) lists it. A module in +// neither is NOT COVERED: this admission has no crate for it, so it answers with that typed arm, +// never with a pass. Emitting a closure that is not the seed therefore reaches the not-covered arm +// by name. + +type Stage0EmittedModuleOwner + = Stage0EmittedModuleOwned { package_name: String } + | Stage0EmittedModuleNotCovered + +type Stage0EmittedEdgeCrossing { + from_module: String + to_module: String + from_package: String + to_package: String + provenance: EmittedEdgeProvenance +} + +type Stage0EmittedEdgeUncovered { + module: String + edge_from: String + provenance: EmittedEdgeProvenance +} + +type Stage0EmittedEdgeAdmission + = Stage0EmittedEdgesAdmitted { edge_count: Int } + | Stage0EmittedEdgesNotCovered { uncovered: List } + | Stage0EmittedEdgesRefused { crossings: List } + +// THE ONE ROW-OWNER LOOKUP. v1.compiler.stage0_crates stage0_lookup_module_owner_package_name reads +// this too, so the crate a lib.rs includes a module into and the crate this admission places it in +// are one answer. +fn stage0_partition_module_owner_packages(module_basename: String) -> List { + generated_partition_crate_rows + |> filter(row => + stage0_partition_row_is_module_bearing_package(row: row) + && (row.modules |> any(m => m == module_basename)) + ) + |> map(row => row.package_name) +} + +fn stage0_emitted_module_owner(module_basename: String, host_shell_modules: List) -> Stage0EmittedModuleOwner { + match stage0_partition_module_owner_packages(module_basename: module_basename) |> first { + Present { value: package_name } => Stage0EmittedModuleOwned { package_name: package_name } + Absent => + if host_shell_modules |> any(m => m == module_basename) { + Stage0EmittedModuleOwned { package_name: stage0_host_shell_package_name() } + } else { + Stage0EmittedModuleNotCovered + } + } +} + +fn stage0_package_direct_dependencies(package_name: String) -> List { + if package_name == stage0_host_shell_package_name() { + stage0_host_shell_dependency_names() + } else { + generated_partition_crate_rows + |> filter(row => row.package_name == package_name) + |> flat_map(row => stage0_partition_package_dependency_names(row: row)) + } +} + +// Bounded by the package count: each round adds every direct dependency of what is already +// reached, and a chain over n partition packages plus the shell is complete after n rounds, so the +// rows themselves are the fuel. +fn stage0_package_reachable(package_name: String) -> List { + generated_partition_crate_rows |> fold(init: [package_name], f: (reached, _row) => + reached + |> concat(reached |> flat_map(p => stage0_package_direct_dependencies(package_name: p))) + |> fold(init: [], f: (acc, p) => if acc |> any(a => a == p) { acc } else { acc |> concat([p]) }) + ) +} + +type Stage0PackageReach { + package_name: String + reachable: List +} + +// Computed once per admission, one row per package, so an edge asks a lookup rather than a closure. +fn stage0_package_reach_table() -> List { + concat([stage0_host_shell_package_name()], generated_partition_crate_rows |> map(row => row.package_name)) + |> map(p => Stage0PackageReach { package_name: p, reachable: stage0_package_reachable(package_name: p) }) +} + +fn stage0_package_reaches(reach: List, from_package: String, to_package: String) -> Bool { + from_package == to_package + || reach |> any(r => r.package_name == from_package && (r.reachable |> any(p => p == to_package))) +} + +fn stage0_emitted_edge_target_basename(edge: EmittedEdge) -> List { + match edge.to { + EmittedModuleTarget { module: target } => if target == edge.from { [] } else { [target] } + EmittedCrateRootTarget => [] + } +} + +fn stage0_emitted_edge_uncovered(edge: EmittedEdge, host_shell_modules: List) -> List { + concat([edge.from], stage0_emitted_edge_target_basename(edge: edge)) |> flat_map(m => + match stage0_emitted_module_owner(module_basename: m, host_shell_modules: host_shell_modules) { + Stage0EmittedModuleOwned { package_name: _ } => [] + Stage0EmittedModuleNotCovered => [Stage0EmittedEdgeUncovered { module: m, edge_from: edge.from, provenance: edge.provenance }] + } + ) +} + +fn stage0_emitted_edge_crossing(edge: EmittedEdge, host_shell_modules: List, reach: List) -> List { + stage0_emitted_edge_target_basename(edge: edge) |> flat_map(target => + match stage0_emitted_module_owner(module_basename: edge.from, host_shell_modules: host_shell_modules) { + Stage0EmittedModuleNotCovered => [] + Stage0EmittedModuleOwned { package_name: from_package } => + match stage0_emitted_module_owner(module_basename: target, host_shell_modules: host_shell_modules) { + Stage0EmittedModuleNotCovered => [] + Stage0EmittedModuleOwned { package_name: to_package } => + if stage0_package_reaches(reach: reach, from_package: from_package, to_package: to_package) { + [] + } else { + [Stage0EmittedEdgeCrossing { + from_module: edge.from, + to_module: target, + from_package: from_package, + to_package: to_package, + provenance: edge.provenance + }] + } + } + } + ) +} + +fn stage0_emitted_edge_admission(edges: List, host_shell_modules: List) -> Stage0EmittedEdgeAdmission { + let uncovered = edges |> flat_map(edge => stage0_emitted_edge_uncovered(edge: edge, host_shell_modules: host_shell_modules)) + let reach = stage0_package_reach_table() + let crossings = edges |> flat_map(edge => stage0_emitted_edge_crossing(edge: edge, host_shell_modules: host_shell_modules, reach: reach)) + if uncovered |> count > 0 { + Stage0EmittedEdgesNotCovered { uncovered: uncovered } + } else if crossings |> count > 0 { + Stage0EmittedEdgesRefused { crossings: crossings } + } else { + Stage0EmittedEdgesAdmitted { edge_count: edges |> count } + } +} + +fn stage0_emitted_edge_provenance_name(provenance: EmittedEdgeProvenance) -> String { + match provenance { + RuntimePrelude => "runtime-prelude" + ReexportFacade => "reexport-facade" + SemanticSourceReference => "semantic-source-reference" + } +} + +fn stage0_emitted_edge_admission_refusal(outcome: Stage0EmittedEdgeAdmission) -> String? { + match outcome { + Stage0EmittedEdgesAdmitted { edge_count: _ } => none + Stage0EmittedEdgesNotCovered { uncovered: uncovered } => + Present { + value: concat( + "Stage0EmittedEdgesNotCovered: ", + to_string(value: uncovered |> count), + " emitted edge endpoint(s) have no stage0 crate (neither a module-bearing partition row nor the host shell lists them):\n", + uncovered + |> map(u => concat(" ", u.module, " (edge from ", u.edge_from, ", ", stage0_emitted_edge_provenance_name(provenance: u.provenance), ")")) + |> join(separator: "\n") + ) + } + Stage0EmittedEdgesRefused { crossings: crossings } => + Present { + value: concat( + "Stage0EmittedEdgeCrossesCrateBoundary: ", + to_string(value: crossings |> count), + " emitted edge(s) name a module in a package their source crate does not depend on (E0432 class):\n", + crossings + |> map(c => concat(" ", c.from_module, " [", c.from_package, "] -> ", c.to_module, " [", c.to_package, "] (", stage0_emitted_edge_provenance_name(provenance: c.provenance), ")")) + |> join(separator: "\n") + ) + } + } +} diff --git a/src/v1/05_emit_core_support.dag b/src/v1/05_emit_core_support.dag index 0eb952101e3..b19d8603053 100644 --- a/src/v1/05_emit_core_support.dag +++ b/src/v1/05_emit_core_support.dag @@ -10,6 +10,7 @@ import v1.std.core { } import v1.compiler.artifact { RenderTarget } +import gunbc.rust_emitted_edge { EmittedEdge } import v1.compiler.infer_items { ResolvedGraph, TypedModule, leaf_owner_modules_from_registry } @@ -24,9 +25,12 @@ import v1.compiler.languages { language_spec_for_target, test_conventions_for_target } +// emitted_edges are the Rust realization edges (gunbc.rust_emitted_edge) of the published modules; +// every other target, and every refused emission, carries none. type EmitResult { files: List diagnostics: List + emitted_edges: List } type TestProjection { diff --git a/src/v1/05_emit_go.dag b/src/v1/05_emit_go.dag index 2c3ec783985..fb8b018aeee 100644 --- a/src/v1/05_emit_go.dag +++ b/src/v1/05_emit_go.dag @@ -118,11 +118,11 @@ fn go_v2rt_import_path() -> String { fn emit_go(typed: ResolvedGraph) -> EmitResult { let filename_collisions = module_filename_collision_diagnostics(typed: typed) if filename_collisions |> count > 0 { - return EmitResult { files: [], diagnostics: filename_collisions } + return EmitResult { files: [], diagnostics: filename_collisions, emitted_edges: [] } } let symbol_collisions = emitted_symbol_collision_diagnostics(typed: typed) if symbol_collisions |> count > 0 { - return EmitResult { files: [], diagnostics: symbol_collisions } + return EmitResult { files: [], diagnostics: symbol_collisions, emitted_edges: [] } } let registry = typed.item_registry let test_projections = extract_test_projections(typed: typed) @@ -135,7 +135,7 @@ fn emit_go(typed: ResolvedGraph) -> EmitResult { let go_mod = emit_go_mod(module_name: go_emit_module_root()) let v2rt_file = emit_go_v2rt_module() let files = concat([go_mod, v2rt_file], module_files, test_files) - EmitResult { files: files, diagnostics: [] } + EmitResult { files: files, diagnostics: [], emitted_edges: [] } } fn emit_go_v2rt_module() -> TextFile { diff --git a/src/v1/05_emit_python.dag b/src/v1/05_emit_python.dag index b97a1f0caa9..583782127b3 100644 --- a/src/v1/05_emit_python.dag +++ b/src/v1/05_emit_python.dag @@ -109,11 +109,11 @@ import v1.compiler.emit_core_support { fn emit_python(typed: ResolvedGraph) -> EmitResult { let filename_collisions = module_filename_collision_diagnostics(typed: typed) if filename_collisions |> count > 0 { - return EmitResult { files: [], diagnostics: filename_collisions } + return EmitResult { files: [], diagnostics: filename_collisions, emitted_edges: [] } } let symbol_collisions = emitted_symbol_collision_diagnostics(typed: typed) if symbol_collisions |> count > 0 { - return EmitResult { files: [], diagnostics: symbol_collisions } + return EmitResult { files: [], diagnostics: symbol_collisions, emitted_edges: [] } } let registry = typed.item_registry let test_projections = extract_test_projections(typed: typed) @@ -126,7 +126,7 @@ fn emit_python(typed: ResolvedGraph) -> EmitResult { let init_file = emit_init_py(modules: typed.modules) let requirements = emit_requirements_txt(has_services: has_service_items(typed: typed)) let files = concat([requirements, init_file], module_files, test_files) - EmitResult { files: files, diagnostics: [] } + EmitResult { files: files, diagnostics: [], emitted_edges: [] } } fn py_derive_attribute() -> String { diff --git a/src/v1/05_emit_rust.dag b/src/v1/05_emit_rust.dag index 066cd517af8..58e1b69c246 100644 --- a/src/v1/05_emit_rust.dag +++ b/src/v1/05_emit_rust.dag @@ -12,7 +12,7 @@ import std.repair_input_origin { import std.primitive_projection { primitive_identity_runtime_name, primitive_projection_row_for_declaration } -import gunbc.rust_emitted_edge { rust_prelude_emitted_edges, emitted_edge_target_module, RuntimePrelude, ReexportFacade } +import gunbc.rust_emitted_edge { EmittedEdge, rust_prelude_emitted_edges, emitted_edge_target_module, semantic_source_reference_edge, RuntimePrelude, ReexportFacade } import gunbc.reference_derived_candidate { ReferenceDerivedCandidateDisposition, CandidateSurvived, @@ -3500,19 +3500,19 @@ fn emit_rust_selected(typed: ResolvedGraph, selection: RustModuleRenderSelection let shared_types = emit_info.shared_types let anonymous_record_diags = ctx.anonymous_record_diags if anonymous_record_diags |> count > 0 { - return EmitResult { files: [], diagnostics: anonymous_record_diags } + return EmitResult { files: [], diagnostics: anonymous_record_diags, emitted_edges: [] } } let effectful_recursion_diags = ctx.effectful_recursion_diags if effectful_recursion_diags |> count > 0 { - return EmitResult { files: [], diagnostics: effectful_recursion_diags } + return EmitResult { files: [], diagnostics: effectful_recursion_diags, emitted_edges: [] } } let filename_collisions = module_filename_collision_diagnostics(typed: typed) if filename_collisions |> count > 0 { - return EmitResult { files: [], diagnostics: filename_collisions } + return EmitResult { files: [], diagnostics: filename_collisions, emitted_edges: [] } } let symbol_collisions = emitted_symbol_collision_diagnostics(typed: typed) if symbol_collisions |> count > 0 { - return EmitResult { files: [], diagnostics: symbol_collisions } + return EmitResult { files: [], diagnostics: symbol_collisions, emitted_edges: [] } } let test_projections = ctx.test_projections let module_emissions = typed.modules @@ -3590,7 +3590,7 @@ fn emit_rust_selected(typed: ResolvedGraph, selection: RustModuleRenderSelection let population_manifest = emit_emitted_population_manifest(paths: emitted_paths) let emitted_files = concat([cargo, lib_file, main_file], all_mod_files, compiler_tests_file, test_files) let files = concat(emitted_files, [population_manifest]) - EmitResult { files: files, diagnostics: module_refusals } + EmitResult { files: files, diagnostics: module_refusals, emitted_edges: published_module_emissions |> flat_map(e => e.emitted_edges) } } // THE ONE PLACE A MODULE'S EMITTED FILENAME IS DECIDED, read by the renderer and by every @@ -5178,6 +5178,7 @@ fn reference_derived_census(rows: List) -> Referen type ReferenceDerivedUseLinePlan { lines: List rows: List + edges: List } // The final use-line authority is one module's emitted item text, at exact identifier grain. @@ -5284,30 +5285,35 @@ fn reference_derived_use_line_plan(items: List, unlisted_type_names: List< } ) let providers = canonical_string_set(items: resolved |> map(b => b.provider_module)) - let lines = providers |> flat_map(provider => + let typed_lines = providers |> flat_map(provider => let names = canonical_string_set(items: resolved |> filter(b => b.provider_module == provider) |> map(b => b.name)) let plan_module_env = match map_get(module_index.by_name, this_module_name) { Present { value: tm } => Present { value: tm.type_env } Absent => none } - let block = emit_specific_import_block(import_module: provider, mod_name: module_to_filename(name: provider), filtered_names: names, type_position_names: applied_type_argument_names, emit_info: emit_info, registry: registry, local_names: local_type_names, export_sets: export_sets, typed_modules: typed_modules, source_indices: source_indices, module_index: module_index, module_env: plan_module_env) - let block_lines = if block == "" { [] } else { block |> split(delimiter: "\n") } - let emitted_here = block_lines |> flat_map(l => imported_names_in_use_line(line: l)) + let block_lines = emit_specific_import_use_lines(import_module: provider, mod_name: module_to_filename(name: provider), filtered_names: names, type_position_names: applied_type_argument_names, emit_info: emit_info, registry: registry, local_names: local_type_names, export_sets: export_sets, typed_modules: typed_modules, source_indices: source_indices, module_index: module_index, module_env: plan_module_env) + let emitted_here = block_lines |> flat_map(l => imported_names_in_use_line(line: l.text)) let fallback = names |> flat_map(nm => if (emitted_here |> any(e => e == nm)) || (is_known_variant(type_summaries: emit_info.type_summaries, name: nm) && !emit_map_has(m: type_position_set, key: nm)) { [] } else if provider_proven_exports_symbol(name: nm, provider_module: provider, export_sets: export_sets, typed_modules: typed_modules, source_indices: source_indices, module_index: module_index) { - [concat(rust_visibility_prefix(), concat("use crate::", concat(module_to_filename(name: provider), concat("::", concat(emit_import_name(owner_module: provider, n: nm, registry: registry), ";")))))] + [RustUseLine { target_module: module_to_filename(name: provider), text: concat(rust_visibility_prefix(), concat("use crate::", concat(module_to_filename(name: provider), concat("::", concat(emit_import_name(owner_module: provider, n: nm, registry: registry), ";"))))) }] } else { [] } ) concat(block_lines, fallback) ) + let lines = typed_lines |> map(l => l.text) let names_already_in_lines = lines |> flat_map(l => imported_names_in_use_line(line: l)) let qualified_rows = qualified_type_reference_rows(emit_info: emit_info, names: qualified_item_emit_surface_compatibility_names(candidates: origin_candidates) |> filter(nm => emit_map_has(m: emitted_source_token_set, key: qualified_last_segment(name: nm))), this_module_name: this_module_name, already: already, names_already_in_lines: names_already_in_lines, registry: registry, export_sets: export_sets, typed_modules: typed_modules, source_indices: source_indices, module_index: module_index) let qualified_lines = qualified_type_reference_use_lines(rows: qualified_rows, registry: registry) - ReferenceDerivedUseLinePlan { lines: concat(lines, qualified_lines), rows: concat(rows, qualified_rows) } + let this_module_filename = module_to_filename(name: this_module_name) + ReferenceDerivedUseLinePlan { + lines: concat(lines, qualified_lines |> map(l => l.text)), + rows: concat(rows, qualified_rows), + edges: rust_use_line_edges(from: this_module_filename, lines: concat(typed_lines, qualified_lines)) + } } } @@ -5388,14 +5394,17 @@ fn registry_row_is_type_declared_in(info: ItemInfo, module_name: String) -> Bool if info.module_name != module_name { false } else { match info.kind { TypeItem => true _ => false } } } -fn qualified_type_reference_use_lines(rows: List, registry: Map) -> List { - canonical_string_set(items: rows |> flat_map(r => +fn qualified_type_reference_use_lines(rows: List, registry: Map) -> List { + let typed = rows |> flat_map(r => match r.disposition { CandidateSurvived { provider_module: provider } => - [concat(rust_visibility_prefix(), "use crate::", module_to_filename(name: provider), "::", emit_import_name(owner_module: provider, n: qualified_last_segment(name: r.name), registry: registry), ";")] + [RustUseLine { target_module: module_to_filename(name: provider), text: concat(rust_visibility_prefix(), "use crate::", module_to_filename(name: provider), "::", emit_import_name(owner_module: provider, n: qualified_last_segment(name: r.name), registry: registry), ";") }] _ => [] } - )) + ) + canonical_string_set(items: typed |> map(l => l.text)) |> flat_map(text => + typed |> filter(l => l.text == text) |> take(n: 1) + ) } 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 { @@ -5412,6 +5421,7 @@ fn reference_derived_use_lines(items: List, unlisted_type_names: List + emitted_edges: List module_refusals: List } @@ -5501,7 +5511,8 @@ fn emit_module_full(typed_module: TypedModule, registry: Map, |> 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(module_name: this_module_name) - 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, module_env: Present { value: scope.type_env }) + let rendered_imports = 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, module_env: Present { value: scope.type_env }, from_module: module_to_filename(name: this_module_name)) + let imports_str = rendered_imports.text let dag_import_lines = if imports_str == "" { [] } else { imports_str |> split(delimiter: "\n") } let carrier_import_lines = if module_needs_faithful_carrier_imports( items: typed_module.items, @@ -5548,15 +5559,17 @@ fn emit_module_full(typed_module: TypedModule, registry: Map, Absent => [] } ) - let extern_svc_imports = unique_strings(items: all_svc_names) |> flat_map(sn => + let extern_svc_use_lines = unique_strings(items: all_svc_names) |> flat_map(sn => match map_get(svc_module_map, sn) { Present { value: mod_file } => if mod_file == this_mod_filename { [] } - else { [concat(rust_visibility_prefix(), "use crate::", mod_file, "::", sanitize_service_name(name: sn), ";")] } + else { [RustUseLine { target_module: mod_file, text: concat(rust_visibility_prefix(), "use crate::", mod_file, "::", sanitize_service_name(name: sn), ";") }] } Absent => [] } ) + let extern_svc_imports = extern_svc_use_lines |> map(l => l.text) let uncovered_svc_imports = service_import_lines_not_already_bound(svc_lines: extern_svc_imports, merged_lines: merged_import_lines) + let uncovered_svc_use_lines = extern_svc_use_lines |> filter(l => uncovered_svc_imports |> any(u => u == l.text)) let svc_imports_str = if uncovered_svc_imports |> count == 0 { "" } else { concat("\n", uncovered_svc_imports |> join(separator: "\n")) } let local_enum_uses = typed_module.items @@ -5583,6 +5596,12 @@ fn emit_module_full(typed_module: TypedModule, registry: Map, ModuleEmission { file: TextFile { path: module_emit_path, content: content }, reference_rows: reference_plan.rows, + emitted_edges: concat( + rust_prelude_emitted_edges(module: this_mod_filename), + rendered_imports.edges, + reference_plan.edges, + rust_use_line_edges(from: this_mod_filename, lines: uncovered_svc_use_lines) + ), module_refusals: concat( reference_derived_row_diagnostics(rows: reference_plan.rows, module_span: m.span), module_projection_refusals( @@ -6619,7 +6638,28 @@ fn import_name_resolves_to_host_realized_kernel_scalar(name: String, module_env: } } +// A use-line and the module its path names, produced together so the edge the crate partition +// reads and the text rustc reads are one value (gunbc.rust_emitted_edge SemanticSourceReference). +type RustUseLine { + target_module: String + text: String +} + +fn rust_use_lines_text(lines: List) -> String { + lines |> map(l => l.text) |> join(separator: "\n") +} + +fn rust_use_line_edges(from: String, lines: List) -> List { + canonical_string_set(items: lines |> map(l => l.target_module)) + |> filter(target => target != from) + |> map(target => semantic_source_reference_edge(from: from, to_module: target)) +} + fn emit_specific_import_block(import_module: String, mod_name: String, filtered_names: List, type_position_names: List, emit_info: EmitGraphInfo, registry: Map, local_names: List, export_sets: Map>, typed_modules: List, source_indices: Map, module_index: ModuleIndex, module_env: TypeEnv?) -> String { + rust_use_lines_text(lines: emit_specific_import_use_lines(import_module: import_module, mod_name: mod_name, filtered_names: filtered_names, type_position_names: type_position_names, emit_info: emit_info, registry: registry, local_names: local_names, export_sets: export_sets, typed_modules: typed_modules, source_indices: source_indices, module_index: module_index, module_env: module_env)) +} + +fn emit_specific_import_use_lines(import_module: String, mod_name: String, filtered_names: List, type_position_names: List, emit_info: EmitGraphInfo, registry: Map, local_names: List, export_sets: Map>, typed_modules: List, source_indices: Map, module_index: ModuleIndex, module_env: TypeEnv?) -> List { let type_summaries = emit_info.type_summaries let deduped_names = unique_strings(items: filtered_names |> filter(n => local_names |> all(ln => ln != n)) @@ -6633,7 +6673,7 @@ fn emit_specific_import_block(import_module: String, mod_name: String, filtered_ )) let non_marker_names = deduped_names |> filter(n => marker_type_names |> all(name => name != n)) if deduped_names |> count == 0 { - "" + [] } else { let import_module_enums = import_module_enum_scope(import_module: import_module, registry: registry, type_summaries: type_summaries, export_sets: export_sets, typed_modules: typed_modules, source_indices: source_indices, module_index: module_index) let top_level = non_marker_names |> filter(n => @@ -6700,7 +6740,7 @@ fn emit_specific_import_block(import_module: String, mod_name: String, filtered_ let type_direct_mods = unique_strings(items: type_direct_names |> map(n => graph_type_import_module_filename(name: n, import_module: import_module, mod_name: mod_name, typed_modules: typed_modules, export_sets: export_sets, source_indices: source_indices, module_index: module_index) )) - let type_direct_lines = type_direct_mods |> map(def_mod => + let type_direct_lines = type_direct_mods |> flat_map(def_mod => let group = type_direct_names |> filter(n => graph_type_import_module_filename(name: n, import_module: import_module, mod_name: mod_name, typed_modules: typed_modules, export_sets: export_sets, source_indices: source_indices, module_index: module_index) == def_mod ) @@ -6708,16 +6748,16 @@ fn emit_specific_import_block(import_module: String, mod_name: String, filtered_ let names_str = group |> map(n => emit_import_name(owner_module: graph_type_import_module_path(name: n, import_module: import_module, mod_name: mod_name, typed_modules: typed_modules, export_sets: export_sets, source_indices: source_indices, module_index: module_index), n: n, registry: registry) ) |> join(separator: ", ") - concat(rust_visibility_prefix(), "use crate::", def_mod, "::{", names_str, "};") - } else { "" } + [RustUseLine { target_module: def_mod, text: concat(rust_visibility_prefix(), "use crate::", def_mod, "::{", names_str, "};") }] + } else { [] } ) let other_direct_line = if other_direct_names |> count > 0 { let names_str = other_direct_names |> map(n => emit_import_name(owner_module: import_module, n: n, registry: registry) ) |> join(separator: ", ") - concat(rust_visibility_prefix(), "use crate::", mod_name, "::{", names_str, "};") - } else { "" } - let direct_lines = concat(type_direct_lines |> filter(l => l != ""), if other_direct_line != "" { [other_direct_line] } else { [] }) + [RustUseLine { target_module: mod_name, text: concat(rust_visibility_prefix(), "use crate::", mod_name, "::{", names_str, "};") }] + } else { [] } + let direct_lines = concat(type_direct_lines, other_direct_line) let parent_defining_mods = unique_strings(items: remote_parent_list |> map(p => let rep_variant = deduped_names |> filter(n => match find_variant_parent_in_module(variant_name: n, module_name: import_module, typed_modules: typed_modules, source_indices: source_indices, module_index: module_index) { @@ -6734,7 +6774,7 @@ fn emit_specific_import_block(import_module: String, mod_name: String, filtered_ Absent => item_defining_module_filename(name: p, module_index: module_index, fallback: mod_name) } )) - let parent_main_lines = parent_defining_mods |> map(def_mod => + let parent_main_lines = parent_defining_mods |> flat_map(def_mod => let group = remote_parent_list |> filter(p => let rep_variant = deduped_names |> filter(n => match find_variant_parent_in_module(variant_name: n, module_name: import_module, typed_modules: typed_modules, source_indices: source_indices, module_index: module_index) { @@ -6753,16 +6793,12 @@ fn emit_specific_import_block(import_module: String, mod_name: String, filtered_ ) if group |> count > 0 { let names_str = group |> join(separator: ", ") - concat(rust_visibility_prefix(), "use crate::", def_mod, "::{", names_str, "};") - } else { "" } + [RustUseLine { target_module: def_mod, text: concat(rust_visibility_prefix(), "use crate::", def_mod, "::{", names_str, "};") }] + } else { [] } ) - let main_lines = if direct_lines |> count > 0 { - concat(direct_lines, parent_main_lines |> filter(l => l != "")) - } else { - parent_main_lines |> filter(l => l != "") - } - let variant_lines = parent_list |> map(parent => - if is_grounded_coproduct_native_alias(name: parent) { "" } else { + let main_lines = concat(direct_lines, parent_main_lines) + let variant_lines = parent_list |> flat_map(parent => + if is_grounded_coproduct_native_alias(name: parent) { [] } else { let variants = deduped_names |> filter(n => if n == "None" || n == "Some" { false @@ -6790,20 +6826,15 @@ fn emit_specific_import_block(import_module: String, mod_name: String, filtered_ Absent => item_defining_module_filename(name: parent, module_index: module_index, fallback: mod_name) } let vars_str = variants |> join(separator: ", ") - concat("use crate::", parent_mod, "::", parent, "::{", vars_str, "};") + [RustUseLine { target_module: parent_mod, text: concat("use crate::", parent_mod, "::", parent, "::{", vars_str, "};") }] } ) let final_imported_enums = top_level |> filter(n => import_module_enums |> any(e => e == n)) let wildcard_enum_lines = final_imported_enums |> filter(en => parent_list |> any(p => p == en) == false && !is_grounded_coproduct_native_alias(name: en)) - |> map(en => concat("use crate::", mod_name, "::", en, "::*;")) - let all_lines = concat( - main_lines |> filter(l => l != ""), - variant_lines |> filter(l => l != ""), - wildcard_enum_lines - ) - all_lines |> join(separator: "\n") + |> map(en => RustUseLine { target_module: mod_name, text: concat("use crate::", mod_name, "::", en, "::*;") }) + concat(main_lines, variant_lines, wildcard_enum_lines) } } @@ -7083,16 +7114,23 @@ fn dedupe_rust_import_lines(lines: List) -> List { strip_repeated_use_symbols(lines: covered) } -fn emit_imports(imports: List, emit_info: EmitGraphInfo, registry: Map, local_names: List, export_sets: Map>, typed_modules: List, source_indices: Map, module_index: ModuleIndex, supplement_items: List, module_env: TypeEnv?) -> String { +// A renderer's use-line text and the edges its paths name, returned together (DESIGN §3: the +// crate partition reads the edge, rustc reads the text, and neither is re-derived from the other). +type RenderedUseLines { + text: String + edges: List +} + +fn emit_imports(imports: List, emit_info: EmitGraphInfo, registry: Map, local_names: List, export_sets: Map>, typed_modules: List, source_indices: Map, module_index: ModuleIndex, supplement_items: List, module_env: TypeEnv?, from_module: String) -> RenderedUseLines { if imports |> count == 0 { - "" + RenderedUseLines { text: "", edges: [] } } else { let applied_type_argument_names = unique_strings(items: supplement_items |> flat_map(item => collect_item_type_surface_occurrences(item: item, source_indices: source_indices)) |> filter(occurrence => occurrence.applied_argument) |> map(occurrence => occurrence.name)) let import_modules = unique_strings(items: imports |> map(imp => authored_name_at(source_indices: source_indices, node: imp))) - let import_lines = import_modules |> flat_map(import_module => + let import_blocks = import_modules |> map(import_module => let mod_imports = imports |> filter(imp => authored_name_at(source_indices: source_indices, node: imp) == import_module) let mod_name = module_to_filename(name: import_module) let mod_has_wildcard = mod_imports |> any(imp => import_is_all(n: imp)) @@ -7105,7 +7143,7 @@ fn emit_imports(imports: List, emit_info: EmitGraphInfo, registry: Map flat_map(imp => import_specific_names_at(n: imp, source_indices: source_indices)), reexport_surface )) - let specific_block = emit_specific_import_block( + let specific_lines = emit_specific_import_use_lines( import_module: import_module, mod_name: mod_name, filtered_names: merged_specific, @@ -7118,16 +7156,12 @@ fn emit_imports(imports: List, emit_info: EmitGraphInfo, registry: Map flat_map(imp => import_specific_names_at(n: imp, source_indices: source_indices)) let synth_for_module = module_data_field_struct_import_names(items: supplement_items, type_summaries: emit_info.type_summaries, import_module: import_module, export_sets: export_sets, typed_modules: typed_modules, source_indices: source_indices, module_index: module_index) let merged_specific = unique_strings(items: concat(specific_names, synth_for_module)) - emit_specific_import_block( + emit_specific_import_use_lines( import_module: import_module, mod_name: mod_name, filtered_names: merged_specific, @@ -7141,9 +7175,13 @@ fn emit_imports(imports: List, emit_info: EmitGraphInfo, registry: Map split(delimiter: "\n") + block ) - dedupe_rust_import_lines(lines: import_lines) |> join(separator: "\n") + let import_lines = import_blocks |> flat_map(block => rust_use_lines_text(lines: block) |> split(delimiter: "\n")) + RenderedUseLines { + text: dedupe_rust_import_lines(lines: import_lines) |> join(separator: "\n"), + edges: rust_use_line_edges(from: from_module, lines: import_blocks |> flat_map(block => block)) + } } } diff --git a/src/v1/compile.dag b/src/v1/compile.dag index 5ad77f4807c..9bbffaf2895 100644 --- a/src/v1/compile.dag +++ b/src/v1/compile.dag @@ -73,6 +73,7 @@ import v1.compiler.infer { reconcile, reconcile_with_census_extra } import v1.compiler.infer_types { algebra_field_kind_name } import v1.compiler.emit_core_support { EmitResult, escape_json_string } +import gunbc.rust_emitted_edge { EmittedEdge } import v1.compiler.emit { unmodeled_file_transport_diagnostics, unmodeled_shell_transport_diagnostics } import v1.compiler.emit_rust { emit_rust_selected } @@ -121,6 +122,7 @@ type PipelineResult { ownership: List artifact_plan: ArtifactPlan newline_indices: List + emitted_edges: List } // The authored source annotation graph rides beside the semantic result rather than inside it. @@ -668,7 +670,7 @@ fn emit_artifact(typed: ResolvedGraph, artifact: Artifact) -> EmitResult { unmodeled_file_transport_diagnostics(typed: typed, target: artifact.target), unmodeled_shell_transport_diagnostics(typed: typed, target: artifact.target)) if unmodeled_transports |> count > 0 { - return EmitResult { files: [], diagnostics: unmodeled_transports } + return EmitResult { files: [], diagnostics: unmodeled_transports, emitted_edges: [] } } match artifact.target { Rust => emit_rust_selected(typed: typed, selection: artifact.module_selection) @@ -1382,13 +1384,13 @@ fn emit_dag_artifact(typed: ResolvedGraph) -> EmitResult { let collected = collect_dag_nodes(typed: typed) let _ = trace_mark("compile.emit.dag.collect.done") if collected.collision_errors |> count > 0 { - return EmitResult { files: [], diagnostics: collected.collision_errors } + return EmitResult { files: [], diagnostics: collected.collision_errors, emitted_edges: [] } } let order = collected.order let key_to_id = build_dag_key_to_id(order: order) let ref_errors = dag_emit_ref_errors(order: order, key_to_id: key_to_id) if ref_errors |> count > 0 { - return EmitResult { files: [], diagnostics: ref_errors } + return EmitResult { files: [], diagnostics: ref_errors, emitted_edges: [] } } let source_indices = dag_graph_source_indices(typed: typed) let nodes_json = serialize_dag_nodes_table(order: order, source_indices: source_indices, key_to_id: key_to_id) @@ -1405,7 +1407,8 @@ fn emit_dag_artifact(typed: ResolvedGraph) -> EmitResult { let _ = trace_mark("compile.emit.dag.serialize.done") EmitResult { files: [TextFile { path: "dag-artifact.json", content: json }], - diagnostics: [] + diagnostics: [], + emitted_edges: [] } } @@ -1449,17 +1452,18 @@ fn emit_from_artifact_plan(emittable: EmittableGraph, artifact_plan: ArtifactPla if artifact_plan.artifacts |> count == 0 { return EmitResult { files: [], - diagnostics: [compile_bundle_error(message: "compile_sources planned no artifacts")] + diagnostics: [compile_bundle_error(message: "compile_sources planned no artifacts")], + emitted_edges: [] } } let boundary_diags = validate_boundaries(plan: artifact_plan) if boundary_diags |> count > 0 { - return EmitResult { files: [], diagnostics: boundary_diags } + return EmitResult { files: [], diagnostics: boundary_diags, emitted_edges: [] } } let results = artifact_plan.artifacts |> map(artifact => emit_artifact(typed: typed, artifact: artifact)) let all_files = results |> flat_map(r => r.files) let all_diags = results |> flat_map(r => r.diagnostics) - EmitResult { files: all_files, diagnostics: all_diags } + EmitResult { files: all_files, diagnostics: all_diags, emitted_edges: results |> flat_map(r => r.emitted_edges) } } fn collect_diagnostics(parse_results: List) -> List { @@ -1993,7 +1997,8 @@ fn emit_resolved_for_target_selected(resolved: ResolvedPipelineResult, target: R complexity: resolved.complexity, ownership: resolved.ownership, artifact_plan: empty_artifact_plan(), - newline_indices: resolved.newline_indices + newline_indices: resolved.newline_indices, + emitted_edges: [] } Present { value: emittable } => { let typed = emittable.graph @@ -2015,7 +2020,8 @@ fn emit_resolved_for_target_selected(resolved: ResolvedPipelineResult, target: R complexity: resolved.complexity, ownership: resolved.ownership, artifact_plan: artifact_plan, - newline_indices: resolved.newline_indices + newline_indices: resolved.newline_indices, + emitted_edges: if emit_errors |> count > 0 { [] } else { emit_result.emitted_edges } } } } diff --git a/src/v1/stage0/src/emitted_population.rs b/src/v1/stage0/src/emitted_population.rs index 4da63253737..69cc0a7ba53 100644 --- a/src/v1/stage0/src/emitted_population.rs +++ b/src/v1/stage0/src/emitted_population.rs @@ -35,9 +35,11 @@ // src/gunbc_namespace_reference_derived_closure_admission.rs // src/gunbc_reference_derived_candidate.rs // src/gunbc_rust_decl_type_overlay.rs +// src/gunbc_rust_emitted_edge.rs // src/gunbc_rust_source_type_bindings.rs // src/gunbc_stage0_crate_layout_generated.rs // src/gunbc_stage0_crate_partition_generated.rs +// src/gunbc_stage0_emitted_edge_admission.rs // src/gunbc_stage0_emitted_population_manifest.rs // src/gunbc_stage0_executable_assembly_generated.rs // src/gunbc_stage0_partition_package_graph.rs diff --git a/src/v1/stage0/src/gunbc_rust_emitted_edge.rs b/src/v1/stage0/src/gunbc_rust_emitted_edge.rs index f87a9a178c5..d40b34df9ea 100644 --- a/src/v1/stage0/src/gunbc_rust_emitted_edge.rs +++ b/src/v1/stage0/src/gunbc_rust_emitted_edge.rs @@ -18,6 +18,7 @@ use std::rc::Rc; pub enum EmittedEdgeProvenance { RuntimePrelude, ReexportFacade, + SemanticSourceReference, } #[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)] @@ -76,6 +77,16 @@ pub fn rust_prelude_emitted_edges(module: String) -> Rc>> { } } +pub fn semantic_source_reference_edge(from: String, to_module: String) -> Rc { + Rc::new(EmittedEdge { + from: from.clone(), + to: Rc::new(EmittedEdgeTarget::EmittedModuleTarget { + module: to_module.clone(), + }), + provenance: EmittedEdgeProvenance::SemanticSourceReference, + }) +} + pub fn emitted_edge_target_module(edge: Rc) -> Rc> { match (*edge.to.clone()).clone() { EmittedEdgeTarget::EmittedModuleTarget { module: target, .. } => { @@ -89,3 +100,5 @@ pub fn emitted_edge_target_module(edge: Rc) -> Rc> { pub struct RuntimePrelude; #[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)] pub struct ReexportFacade; +#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)] +pub struct SemanticSourceReference; diff --git a/src/v1/stage0/src/gunbc_stage0_crate_partition_generated.rs b/src/v1/stage0/src/gunbc_stage0_crate_partition_generated.rs index 058e545f0c3..dce5a96bd77 100644 --- a/src/v1/stage0/src/gunbc_stage0_crate_partition_generated.rs +++ b/src/v1/stage0/src/gunbc_stage0_crate_partition_generated.rs @@ -54,7 +54,7 @@ pub fn generated_partition_crate_rows() -> Rc package_name: "v1-stage0-std-core".to_string(), crate_dir: "src/v1/stage0_std_core".to_string(), kind: GeneratedPartitionCrateKind::GeneratedLayeredCoreCrate, - modules: Rc::new(vec!["std_content_hash".to_string(), "std_coercion".to_string(), "extdeps_currency_currency".to_string(), "std_decl_ref".to_string(), "std_keyed_row".to_string(), "std_keyed_roster".to_string(), "std_roster_frontier".to_string(), "std_dissolution".to_string(), "std_disposition".to_string(), "std_error_primitives".to_string(), "std_emit_model".to_string(), "std_magnitude".to_string(), "std_measure".to_string(), "std_types".to_string(), "std_unicode_types".to_string(), "std_algebra".to_string(), "std_nat".to_string(), "std_node".to_string(), "std_syntax".to_string(), "std_computation".to_string(), "std_termination".to_string(), "std_checked_arithmetic".to_string(), "std_induction".to_string(), "std_graph".to_string(), "extdeps_uri".to_string(), "extdeps_external_authority".to_string(), "std_process_termination".to_string(), "std_primitive_projection".to_string(), "extdeps_container_oci_digest".to_string(), "extdeps_units_dimensionless".to_string(), "extdeps_units_iec_80000_13".to_string(), "extdeps_units_iso8601".to_string(), "extdeps_units_iso_80000_3".to_string(), "std_occurrence_identity".to_string(), "std_source_annotation".to_string(), "std_target_representation".to_string(), "std_literal_elaboration".to_string(), "std_operator_realization".to_string(), "std_import".to_string(), "v1_std_core".to_string()]), + modules: Rc::new(vec!["std_content_hash".to_string(), "std_coercion".to_string(), "extdeps_currency_currency".to_string(), "std_decl_ref".to_string(), "std_keyed_row".to_string(), "std_keyed_roster".to_string(), "std_roster_frontier".to_string(), "std_dissolution".to_string(), "std_disposition".to_string(), "std_error_primitives".to_string(), "std_emit_model".to_string(), "std_magnitude".to_string(), "std_measure".to_string(), "std_types".to_string(), "std_unicode_types".to_string(), "std_algebra".to_string(), "std_nat".to_string(), "std_node".to_string(), "std_syntax".to_string(), "std_computation".to_string(), "std_termination".to_string(), "std_checked_arithmetic".to_string(), "std_induction".to_string(), "std_graph".to_string(), "extdeps_uri".to_string(), "extdeps_external_authority".to_string(), "std_process_termination".to_string(), "std_primitive_projection".to_string(), "extdeps_container_oci_digest".to_string(), "extdeps_units_dimensionless".to_string(), "extdeps_units_iec_80000_13".to_string(), "extdeps_units_iso8601".to_string(), "extdeps_units_iso_80000_3".to_string(), "std_occurrence_identity".to_string(), "std_source_annotation".to_string(), "std_target_representation".to_string(), "std_literal_elaboration".to_string(), "std_operator_realization".to_string(), "std_import".to_string(), "v1_std_core".to_string(), "gunbc_rust_emitted_edge".to_string()]), reexport_packages: Rc::new(vec!["v1-stage0-runtime".to_string()]), carries_non_empty_wrappers: false, }), Rc::new(GeneratedPartitionCrateRow { diff --git a/src/v1/stage0/src/gunbc_stage0_emitted_edge_admission.rs b/src/v1/stage0/src/gunbc_stage0_emitted_edge_admission.rs new file mode 100644 index 00000000000..017df58f440 --- /dev/null +++ b/src/v1/stage0/src/gunbc_stage0_emitted_edge_admission.rs @@ -0,0 +1,420 @@ +// Generated by v1 compiler -- do not edit. +// Source module: gunbc.stage0_emitted_edge_admission + +use self::Stage0EmittedEdgeAdmission::*; +use self::Stage0EmittedModuleOwner::*; +use crate::gunbc_rust_emitted_edge::EmittedEdgeProvenance::{ + ReexportFacade, RuntimePrelude, SemanticSourceReference, +}; +use crate::gunbc_rust_emitted_edge::EmittedEdgeTarget::{ + EmittedCrateRootTarget, EmittedModuleTarget, +}; +pub use crate::gunbc_rust_emitted_edge::{EmittedEdge, EmittedEdgeProvenance, EmittedEdgeTarget}; +pub use crate::gunbc_stage0_crate_partition_generated::generated_partition_crate_rows; +pub use crate::gunbc_stage0_crate_partition_generated::GeneratedPartitionCrateRow; +pub use crate::gunbc_stage0_partition_package_graph::{ + stage0_host_shell_dependency_names, stage0_host_shell_package_name, + stage0_partition_package_dependency_names, stage0_partition_row_is_module_bearing_package, +}; +use crate::std_types::Bool::*; +pub use crate::std_types::{Bool, List}; +use crate::v1_rt; +use crate::v1_rt::{VecCompat, VecJoin}; +use crate::NonEmptyBTreeSet; +use crate::NonEmptyVec; +use im::{vector as vec, HashMap, OrdSet as BTreeSet, Vector as Vec}; +use std::rc::Rc; + +#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)] +#[serde(tag = "_variant")] +pub enum Stage0EmittedModuleOwner { + Stage0EmittedModuleOwned { package_name: String }, + Stage0EmittedModuleNotCovered, +} +impl Stage0EmittedModuleOwner { + pub fn package_name(&self) -> String { + match self { + Stage0EmittedModuleOwner::Stage0EmittedModuleOwned { + package_name: __val, + .. + } => __val.clone(), + Stage0EmittedModuleOwner::Stage0EmittedModuleNotCovered => { + panic!("no package_name on unit variant") + } + } + } +} + +#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)] +pub struct Stage0EmittedEdgeCrossing { + pub from_module: String, + pub to_module: String, + pub from_package: String, + pub to_package: String, + pub provenance: EmittedEdgeProvenance, +} + +#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)] +pub struct Stage0EmittedEdgeUncovered { + pub module: String, + pub edge_from: String, + pub provenance: EmittedEdgeProvenance, +} + +#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)] +#[serde(tag = "_variant")] +pub enum Stage0EmittedEdgeAdmission { + Stage0EmittedEdgesAdmitted { + edge_count: i64, + }, + Stage0EmittedEdgesNotCovered { + uncovered: Rc>>, + }, + Stage0EmittedEdgesRefused { + crossings: Rc>>, + }, +} + +pub fn stage0_partition_module_owner_packages(module_basename: String) -> Rc> { + Rc::new({ + let mut __result = Vec::new(); + for row in Rc::new({ let mut __result = Vec::new(); for row in generated_partition_crate_rows().iter().cloned() { if (crate::gunbc_stage0_partition_package_graph::stage0_partition_row_is_module_bearing_package(row.clone()) && { let mut __found = false; for m in row.modules.clone().iter().cloned() { if (m.clone() == module_basename.clone()) { __found = true; break; } } __found }) { __result.push(row); } } __result }).iter().cloned() { __result.push(row.package_name.clone()); } + __result + }) +} + +pub fn stage0_emitted_module_owner( + module_basename: String, + host_shell_modules: Rc>, +) -> Rc { + match stage0_partition_module_owner_packages(module_basename.clone()) + .first() + .cloned() + { + Some(package_name) => Rc::new(Stage0EmittedModuleOwner::Stage0EmittedModuleOwned { + package_name: package_name.clone(), + }), + std::option::Option::None => { + if { + let mut __found = false; + for m in host_shell_modules.iter().cloned() { + if (m.clone() == module_basename.clone()) { + __found = true; + break; + } + } + __found + } { + Rc::new(Stage0EmittedModuleOwner::Stage0EmittedModuleOwned { + package_name: + crate::gunbc_stage0_partition_package_graph::stage0_host_shell_package_name( + ), + }) + } else { + Rc::new(Stage0EmittedModuleOwner::Stage0EmittedModuleNotCovered) + } + } + } +} + +pub fn stage0_package_direct_dependencies(package_name: String) -> Rc> { + if (package_name.clone() + == crate::gunbc_stage0_partition_package_graph::stage0_host_shell_package_name()) + { + crate::gunbc_stage0_partition_package_graph::stage0_host_shell_dependency_names() + } else { + Rc::new({ + let mut __result = Vec::new(); + for row in Rc::new({ + let mut __result = Vec::new(); + for row in generated_partition_crate_rows().iter().cloned() { + if (row.package_name.clone() == package_name.clone()) { + __result.push(row); + } + } + __result + }) + .iter() + .cloned() + { + __result.extend((*crate::gunbc_stage0_partition_package_graph::stage0_partition_package_dependency_names(row.clone())).iter().cloned()); + } + __result + }) + } +} + +pub fn stage0_package_reachable(package_name: String) -> Rc> { + generated_partition_crate_rows().iter().cloned().fold( + Rc::new(vec![package_name.clone()]), + |reached: Rc>, _row: Rc| { + v1_rt::concat( + reached.clone(), + Rc::new({ + let mut __result = Vec::new(); + for p in reached.iter().cloned() { + __result.extend( + (*stage0_package_direct_dependencies(p.clone())) + .iter() + .cloned(), + ); + } + __result + }), + ) + .iter() + .cloned() + .fold(Rc::new(vec![]), |acc: _, p: String| { + if { + let mut __found = false; + for a in acc.iter().cloned() { + if (a.clone() == p.clone()) { + __found = true; + break; + } + } + __found + } { + acc.clone() + } else { + v1_rt::concat(acc.clone(), Rc::new(vec![p.clone()])) + } + }) + }, + ) +} + +#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)] +pub struct Stage0PackageReach { + pub package_name: String, + pub reachable: Rc>, +} + +pub fn stage0_package_reach_table() -> Rc>> { + Rc::new({ + let mut __result = Vec::new(); + for p in v1_rt::concat( + Rc::new(vec![ + crate::gunbc_stage0_partition_package_graph::stage0_host_shell_package_name(), + ]), + Rc::new({ + let mut __result = Vec::new(); + for row in generated_partition_crate_rows().iter().cloned() { + __result.push(row.package_name.clone()); + } + __result + }), + ) + .iter() + .cloned() + { + __result.push(Rc::new(Stage0PackageReach { + package_name: p.clone(), + reachable: stage0_package_reachable(p.clone()), + })); + } + __result + }) +} + +pub fn stage0_package_reaches( + reach: Rc>>, + from_package: String, + to_package: String, +) -> bool { + ((from_package.clone() == to_package.clone()) || { + let mut __found = false; + for r in reach.iter().cloned() { + if ((r.package_name.clone() == from_package.clone()) && { + let mut __found = false; + for p in r.reachable.clone().iter().cloned() { + if (p.clone() == to_package.clone()) { + __found = true; + break; + } + } + __found + }) { + __found = true; + break; + } + } + __found + }) +} + +pub fn stage0_emitted_edge_target_basename(edge: Rc) -> Rc> { + match (*edge.to.clone()).clone() { + EmittedEdgeTarget::EmittedModuleTarget { module: target, .. } => { + if (target.clone() == edge.from.clone()) { + Rc::new(vec![]) + } else { + Rc::new(vec![target.clone()]) + } + } + EmittedEdgeTarget::EmittedCrateRootTarget => Rc::new(vec![]), + } +} + +pub fn stage0_emitted_edge_uncovered( + edge: Rc, + host_shell_modules: Rc>, +) -> Rc>> { + Rc::new({ + let mut __result = Vec::new(); + for m in v1_rt::concat( + Rc::new(vec![edge.from.clone()]), + stage0_emitted_edge_target_basename(edge.clone()), + ) + .iter() + .cloned() + { + __result.extend( + (*match (*stage0_emitted_module_owner(m.clone(), host_shell_modules.clone())) + .clone() + { + Stage0EmittedModuleOwner::Stage0EmittedModuleOwned { + package_name: _, .. + } => Rc::new(vec![]), + Stage0EmittedModuleOwner::Stage0EmittedModuleNotCovered => { + Rc::new(vec![Rc::new(Stage0EmittedEdgeUncovered { + module: m.clone(), + edge_from: edge.from.clone(), + provenance: edge.provenance.clone(), + })]) + } + }) + .iter() + .cloned(), + ); + } + __result + }) +} + +pub fn stage0_emitted_edge_crossing( + edge: Rc, + host_shell_modules: Rc>, + reach: Rc>>, +) -> Rc>> { + Rc::new({ + let mut __result = Vec::new(); + for target in stage0_emitted_edge_target_basename(edge.clone()) + .iter() + .cloned() + { + __result.extend( + (*match (*stage0_emitted_module_owner( + edge.from.clone(), + host_shell_modules.clone(), + )) + .clone() + { + Stage0EmittedModuleOwner::Stage0EmittedModuleNotCovered => Rc::new(vec![]), + Stage0EmittedModuleOwner::Stage0EmittedModuleOwned { + package_name: from_package, + .. + } => match (*stage0_emitted_module_owner( + target.clone(), + host_shell_modules.clone(), + )) + .clone() + { + Stage0EmittedModuleOwner::Stage0EmittedModuleNotCovered => Rc::new(vec![]), + Stage0EmittedModuleOwner::Stage0EmittedModuleOwned { + package_name: to_package, + .. + } => { + if stage0_package_reaches( + reach.clone(), + from_package.clone(), + to_package.clone(), + ) { + Rc::new(vec![]) + } else { + Rc::new(vec![Rc::new(Stage0EmittedEdgeCrossing { + from_module: edge.from.clone(), + to_module: target.clone(), + from_package: from_package.clone(), + to_package: to_package.clone(), + provenance: edge.provenance.clone(), + })]) + } + } + }, + }) + .iter() + .cloned(), + ); + } + __result + }) +} + +pub fn stage0_emitted_edge_admission( + edges: Rc>>, + host_shell_modules: Rc>, +) -> Rc { + { + let uncovered = Rc::new({ + let mut __result = Vec::new(); + for edge in edges.iter().cloned() { + __result.extend( + (*stage0_emitted_edge_uncovered(edge.clone(), host_shell_modules.clone())) + .iter() + .cloned(), + ); + } + __result + }); + let reach = stage0_package_reach_table(); + let crossings = Rc::new({ + let mut __result = Vec::new(); + for edge in edges.iter().cloned() { + __result.extend( + (*stage0_emitted_edge_crossing( + edge.clone(), + host_shell_modules.clone(), + reach.clone(), + )) + .iter() + .cloned(), + ); + } + __result + }); + if ((uncovered.clone().len() as i64) > 0) { + Rc::new(Stage0EmittedEdgeAdmission::Stage0EmittedEdgesNotCovered { + uncovered: uncovered.clone(), + }) + } else { + if ((crossings.clone().len() as i64) > 0) { + Rc::new(Stage0EmittedEdgeAdmission::Stage0EmittedEdgesRefused { + crossings: crossings.clone(), + }) + } else { + Rc::new(Stage0EmittedEdgeAdmission::Stage0EmittedEdgesAdmitted { + edge_count: (edges.clone().len() as i64), + }) + } + } + } +} + +pub fn stage0_emitted_edge_provenance_name(provenance: EmittedEdgeProvenance) -> String { + match provenance.clone() { + EmittedEdgeProvenance::RuntimePrelude => "runtime-prelude".to_string(), + EmittedEdgeProvenance::ReexportFacade => "reexport-facade".to_string(), + EmittedEdgeProvenance::SemanticSourceReference => "semantic-source-reference".to_string(), + } +} + +pub fn stage0_emitted_edge_admission_refusal( + outcome: Rc, +) -> Option { + match (*outcome.clone()).clone() { + Stage0EmittedEdgeAdmission::Stage0EmittedEdgesAdmitted { edge_count: _, .. } => std::option::Option::None, + Stage0EmittedEdgeAdmission::Stage0EmittedEdgesNotCovered { uncovered: uncovered, .. } => Some(v1_rt::concat(v1_rt::concat(v1_rt::concat("Stage0EmittedEdgesNotCovered: ".to_string(), ((uncovered.clone().len() as i64)).to_string()), " emitted edge endpoint(s) have no stage0 crate (neither a module-bearing partition row nor the host shell lists them):\n".to_string()), Rc::new({ let mut __result = Vec::new(); for u in uncovered.iter().cloned() { __result.push(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(" ".to_string(), u.module.clone()), " (edge from ".to_string()), u.edge_from.clone()), ", ".to_string()), stage0_emitted_edge_provenance_name(u.provenance.clone())), ")".to_string())); } __result }).join(&"\n".to_string()))), + Stage0EmittedEdgeAdmission::Stage0EmittedEdgesRefused { crossings: crossings, .. } => Some(v1_rt::concat(v1_rt::concat(v1_rt::concat("Stage0EmittedEdgeCrossesCrateBoundary: ".to_string(), ((crossings.clone().len() as i64)).to_string()), " emitted edge(s) name a module in a package their source crate does not depend on (E0432 class):\n".to_string()), Rc::new({ let mut __result = Vec::new(); for c in crossings.iter().cloned() { __result.push(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(" ".to_string(), c.from_module.clone()), " [".to_string()), c.from_package.clone()), "] -> ".to_string()), c.to_module.clone()), " [".to_string()), c.to_package.clone()), "] (".to_string()), stage0_emitted_edge_provenance_name(c.provenance.clone())), ")".to_string())); } __result }).join(&"\n".to_string()))), +} +} diff --git a/src/v1/stage0/src/lib.rs b/src/v1/stage0/src/lib.rs index e15242140c3..b548ade19f8 100644 --- a/src/v1/stage0/src/lib.rs +++ b/src/v1/stage0/src/lib.rs @@ -169,7 +169,7 @@ pub mod gunbc_rust_decl_type_overlay; suspicious_double_ref_op, clippy::all )] -pub mod gunbc_rust_emitted_edge; +pub mod gunbc_stage0_crate_layout_generated; #[allow( unused_imports, unused_variables, @@ -180,7 +180,7 @@ pub mod gunbc_rust_emitted_edge; suspicious_double_ref_op, clippy::all )] -pub mod gunbc_stage0_crate_layout_generated; +pub mod gunbc_stage0_crate_partition_generated; #[allow( unused_imports, unused_variables, @@ -191,7 +191,7 @@ pub mod gunbc_stage0_crate_layout_generated; suspicious_double_ref_op, clippy::all )] -pub mod gunbc_stage0_crate_partition_generated; +pub mod gunbc_stage0_emitted_edge_admission; #[allow( unused_imports, unused_variables, diff --git a/src/v1/stage0/src/required_regen_host.rs b/src/v1/stage0/src/required_regen_host.rs index 26a2a0999b9..f94a0c8d87d 100644 --- a/src/v1/stage0/src/required_regen_host.rs +++ b/src/v1/stage0/src/required_regen_host.rs @@ -1115,6 +1115,30 @@ fn compile_stage0( { return Err(message); } + // EVERY EDGE THE EMITTER WROTE MUST RESOLVE IN THE CRATE ITS MODULE LANDS IN. The emitter + // returns its use-line and prelude edges beside the text (`gunbc.rust_emitted_edge`), and + // `gunbc.stage0_emitted_edge_admission` maps both ends through the partition rows and the + // package graph. This is the one emission whose population IS the stage0 seed, so the host + // shell's module roster is read from its lib.rs and supplied; a module in neither the rows + // nor the shell refuses as not covered rather than passing. + let host_shell_modules = super::emitted_closure_compile_host::closure_modules( + &workspace_root().join("src/v1/stage0/src/lib.rs"), + )?; + let admission = crate::gunbc_stage0_emitted_edge_admission::stage0_emitted_edge_admission( + result.emitted_edges.clone(), + Rc::new(host_shell_modules.into_iter().collect()), + ); + if let crate::gunbc_stage0_emitted_edge_admission::Stage0EmittedEdgeAdmission::Stage0EmittedEdgesAdmitted { + edge_count, + } = &*admission + { + eprintln!("required-regen: emitted-edge admission admitted edges={edge_count}"); + } + if let Some(message) = + crate::gunbc_stage0_emitted_edge_admission::stage0_emitted_edge_admission_refusal(admission) + { + return Err(message); + } let mut out = HashMap::new(); for file in result.files.iter() { out.insert(file.path.clone(), file.content.clone()); diff --git a/src/v1/stage0/src/v1_compiler_compile.rs b/src/v1/stage0/src/v1_compiler_compile.rs index 2c31d2f89ec..1c56dc7972a 100644 --- a/src/v1/stage0/src/v1_compiler_compile.rs +++ b/src/v1/stage0/src/v1_compiler_compile.rs @@ -6,6 +6,7 @@ use self::CensusModuleRetention::*; use self::CorpusScope::*; use self::TestReferenceRowScope::*; pub use crate::extdeps_languages_dag_syntax::dag_parse_environment; +pub use crate::gunbc_rust_emitted_edge::EmittedEdge; pub use crate::std_compiler_entry::CompilerEntryDriver; use crate::std_compiler_entry::CompilerEntryDriver::RetainedHostCliKernel; pub use crate::std_computation::ShrinkFactor; @@ -157,6 +158,7 @@ pub struct PipelineResult { pub ownership: Rc>>, pub artifact_plan: Rc, pub newline_indices: Rc>>, + pub emitted_edges: Rc>>, } #[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)] @@ -1346,6 +1348,7 @@ pub fn emit_artifact(typed: Rc, artifact: Rc) -> Rc) -> Rc { return Rc::new(EmitResult { files: Rc::new(vec![]), diagnostics: collected.collision_errors.clone(), + emitted_edges: Rc::new(vec![]), }); } let order = collected.order.clone(); @@ -3275,6 +3279,7 @@ pub fn emit_dag_artifact(typed: Rc) -> Rc { return Rc::new(EmitResult { files: Rc::new(vec![]), diagnostics: ref_errors.clone(), + emitted_edges: Rc::new(vec![]), }); } let source_indices = dag_graph_source_indices(typed.clone()); @@ -3341,6 +3346,7 @@ pub fn emit_dag_artifact(typed: Rc) -> Rc { content: json.clone(), })]), diagnostics: Rc::new(vec![]), + emitted_edges: Rc::new(vec![]), }) } } @@ -3446,6 +3452,7 @@ pub fn emit_from_artifact_plan( diagnostics: Rc::new(vec![compile_bundle_error( "compile_sources planned no artifacts".to_string(), )]), + emitted_edges: Rc::new(vec![]), }); } let boundary_diags = validate_boundaries(artifact_plan.clone()); @@ -3453,6 +3460,7 @@ pub fn emit_from_artifact_plan( return Rc::new(EmitResult { files: Rc::new(vec![]), diagnostics: boundary_diags.clone(), + emitted_edges: Rc::new(vec![]), }); } let results = Rc::new({ @@ -3479,6 +3487,13 @@ pub fn emit_from_artifact_plan( Rc::new(EmitResult { files: all_files.clone(), diagnostics: all_diags.clone(), + emitted_edges: Rc::new({ + let mut __result = Vec::new(); + for r in results.iter().cloned() { + __result.extend((*r.emitted_edges.clone()).iter().cloned()); + } + __result + }), }) } } @@ -4191,6 +4206,7 @@ pub fn emit_resolved_for_target_selected( ownership: resolved.ownership.clone(), artifact_plan: empty_artifact_plan(), newline_indices: resolved.newline_indices.clone(), + emitted_edges: Rc::new(vec![]), }), Some(emittable) => { let typed = emittable.graph(); @@ -4234,6 +4250,11 @@ pub fn emit_resolved_for_target_selected( ownership: resolved.ownership.clone(), artifact_plan: artifact_plan.clone(), newline_indices: resolved.newline_indices.clone(), + emitted_edges: if ((emit_errors.clone().len() as i64) > 0) { + Rc::new(vec![]) + } else { + emit_result.emitted_edges.clone() + }, }) } } diff --git a/src/v1/stage0/src/v1_compiler_emit_core_support.rs b/src/v1/stage0/src/v1_compiler_emit_core_support.rs index 607f0a0161b..e60916a12ac 100644 --- a/src/v1/stage0/src/v1_compiler_emit_core_support.rs +++ b/src/v1/stage0/src/v1_compiler_emit_core_support.rs @@ -1,6 +1,7 @@ // Generated by v1 compiler -- do not edit. // Source module: v1.compiler.emit_core_support +pub use crate::gunbc_rust_emitted_edge::EmittedEdge; pub use crate::v1_compiler_artifact::RenderTarget; use crate::v1_compiler_artifact::RenderTarget::*; pub use crate::v1_compiler_infer_env::TypeEnv; @@ -32,6 +33,7 @@ use std::rc::Rc; pub struct EmitResult { pub files: Rc>>, pub diagnostics: Rc>>, + pub emitted_edges: Rc>>, } #[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)] diff --git a/src/v1/stage0/src/v1_compiler_emit_go.rs b/src/v1/stage0/src/v1_compiler_emit_go.rs index ad91acd5f4e..18fd1ae5a00 100644 --- a/src/v1/stage0/src/v1_compiler_emit_go.rs +++ b/src/v1/stage0/src/v1_compiler_emit_go.rs @@ -126,6 +126,7 @@ pub fn emit_go(typed: Rc) -> Rc { return Rc::new(EmitResult { files: Rc::new(vec![]), diagnostics: filename_collisions.clone(), + emitted_edges: Rc::new(vec![]), }); } let symbol_collisions = @@ -136,6 +137,7 @@ pub fn emit_go(typed: Rc) -> Rc { return Rc::new(EmitResult { files: Rc::new(vec![]), diagnostics: symbol_collisions.clone(), + emitted_edges: Rc::new(vec![]), }); } let registry = typed.item_registry.clone(); @@ -197,6 +199,7 @@ pub fn emit_go(typed: Rc) -> Rc { Rc::new(EmitResult { files: files.clone(), diagnostics: Rc::new(vec![]), + emitted_edges: Rc::new(vec![]), }) } } diff --git a/src/v1/stage0/src/v1_compiler_emit_python.rs b/src/v1/stage0/src/v1_compiler_emit_python.rs index c93a7fc2ced..36821e30cfa 100644 --- a/src/v1/stage0/src/v1_compiler_emit_python.rs +++ b/src/v1/stage0/src/v1_compiler_emit_python.rs @@ -114,6 +114,7 @@ pub fn emit_python(typed: Rc) -> Rc { return Rc::new(EmitResult { files: Rc::new(vec![]), diagnostics: filename_collisions.clone(), + emitted_edges: Rc::new(vec![]), }); } let symbol_collisions = @@ -124,6 +125,7 @@ pub fn emit_python(typed: Rc) -> Rc { return Rc::new(EmitResult { files: Rc::new(vec![]), diagnostics: symbol_collisions.clone(), + emitted_edges: Rc::new(vec![]), }); } let registry = typed.item_registry.clone(); @@ -186,6 +188,7 @@ pub fn emit_python(typed: Rc) -> Rc { Rc::new(EmitResult { files: files.clone(), diagnostics: Rc::new(vec![]), + emitted_edges: Rc::new(vec![]), }) } } diff --git a/src/v1/stage0/src/v1_compiler_emit_rust.rs b/src/v1/stage0/src/v1_compiler_emit_rust.rs index 95a40e7ea76..bd1bedd64fc 100644 --- a/src/v1/stage0/src/v1_compiler_emit_rust.rs +++ b/src/v1/stage0/src/v1_compiler_emit_rust.rs @@ -47,9 +47,11 @@ pub use crate::gunbc_reference_derived_candidate::{ ReferenceDerivedCandidateDisposition, ReferenceDerivedCandidateRow, }; pub use crate::gunbc_rust_decl_type_overlay::rust_decl_type_container_overlay_is_admitted; -pub use crate::gunbc_rust_emitted_edge::EmittedEdgeProvenance; use crate::gunbc_rust_emitted_edge::EmittedEdgeProvenance::{ReexportFacade, RuntimePrelude}; -pub use crate::gunbc_rust_emitted_edge::{emitted_edge_target_module, rust_prelude_emitted_edges}; +pub use crate::gunbc_rust_emitted_edge::{ + emitted_edge_target_module, rust_prelude_emitted_edges, semantic_source_reference_edge, +}; +pub use crate::gunbc_rust_emitted_edge::{EmittedEdge, EmittedEdgeProvenance}; pub use crate::gunbc_stage0_crate_layout_generated::generated_pub_mod_block; pub use crate::gunbc_stage0_crate_partition_generated::generated_partition_crate_rows; pub use crate::gunbc_stage0_crate_partition_generated::GeneratedPartitionCrateRow; @@ -6767,6 +6769,7 @@ pub fn emit_rust_selected( return Rc::new(EmitResult { files: Rc::new(vec![]), diagnostics: anonymous_record_diags.clone(), + emitted_edges: Rc::new(vec![]), }); } let effectful_recursion_diags = ctx.effectful_recursion_diags.clone(); @@ -6774,6 +6777,7 @@ pub fn emit_rust_selected( return Rc::new(EmitResult { files: Rc::new(vec![]), diagnostics: effectful_recursion_diags.clone(), + emitted_edges: Rc::new(vec![]), }); } let filename_collisions = @@ -6784,6 +6788,7 @@ pub fn emit_rust_selected( return Rc::new(EmitResult { files: Rc::new(vec![]), diagnostics: filename_collisions.clone(), + emitted_edges: Rc::new(vec![]), }); } let symbol_collisions = @@ -6794,6 +6799,7 @@ pub fn emit_rust_selected( return Rc::new(EmitResult { files: Rc::new(vec![]), diagnostics: symbol_collisions.clone(), + emitted_edges: Rc::new(vec![]), }); } let test_projections = ctx.test_projections.clone(); @@ -7144,6 +7150,13 @@ pub fn emit_rust_selected( Rc::new(EmitResult { files: files.clone(), diagnostics: module_refusals.clone(), + emitted_edges: Rc::new({ + let mut __result = Vec::new(); + for e in published_module_emissions.iter().cloned() { + __result.extend((*e.emitted_edges.clone()).iter().cloned()); + } + __result + }), }) } } @@ -9893,6 +9906,7 @@ pub fn reference_derived_census( pub struct ReferenceDerivedUseLinePlan { pub lines: Rc>, pub rows: Rc>>, + pub edges: Rc>>, } #[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)] @@ -10265,7 +10279,7 @@ pub fn reference_derived_use_line_plan( } __result })); - let lines = Rc::new({ + let typed_lines = Rc::new({ let mut __result = Vec::new(); for provider in providers.iter().cloned() { __result.extend((*{ @@ -10274,18 +10288,16 @@ let plan_module_env = match v1_rt::map_get(&module_index.by_name.clone(), this_m Some(tm) => Some(tm.type_env.clone()), std::option::Option::None => std::option::Option::None, }; -let block = emit_specific_import_block(provider.clone(), crate::v1_compiler_emit_core_support::module_to_filename(provider.clone()), names.clone(), applied_type_argument_names.clone(), emit_info.clone(), registry.clone(), local_type_names.clone(), export_sets.clone(), typed_modules.clone(), source_indices.clone(), module_index.clone(), plan_module_env.clone()); -let block_lines = if (block.clone() == "".to_string()) { - Rc::new(vec![]) - } else { - Rc::new(block.clone().split(&"\n".to_string()).map(|s| s.to_string()).collect::>()) - }; -let emitted_here = Rc::new({ let mut __result = Vec::new(); for l in block_lines.iter().cloned() { __result.extend((*imported_names_in_use_line(l.clone())).iter().cloned()); } __result }); +let block_lines = emit_specific_import_use_lines(provider.clone(), crate::v1_compiler_emit_core_support::module_to_filename(provider.clone()), names.clone(), applied_type_argument_names.clone(), emit_info.clone(), registry.clone(), local_type_names.clone(), export_sets.clone(), typed_modules.clone(), source_indices.clone(), module_index.clone(), plan_module_env.clone()); +let emitted_here = Rc::new({ let mut __result = Vec::new(); for l in block_lines.iter().cloned() { __result.extend((*imported_names_in_use_line(l.text.clone())).iter().cloned()); } __result }); let fallback = Rc::new({ let mut __result = Vec::new(); for nm in names.iter().cloned() { __result.extend((*if ({ let mut __found = false; for e in emitted_here.iter().cloned() { if (e.clone() == nm.clone()) { __found = true; break; } } __found } || (crate::v1_compiler_infer_emit_info::is_known_variant(emit_info.type_summaries.clone(), nm.clone()) && !crate::v1_compiler_infer_types::emit_map_has(type_position_set.clone(), nm.clone()))) { Rc::new(vec![]) } else { if provider_proven_exports_symbol(nm.clone(), provider.clone(), export_sets.clone(), typed_modules.clone(), source_indices.clone(), module_index.clone()) { - Rc::new(vec![v1_rt::concat(rust_visibility_prefix(), v1_rt::concat("use crate::".to_string(), v1_rt::concat(crate::v1_compiler_emit_core_support::module_to_filename(provider.clone()), v1_rt::concat("::".to_string(), v1_rt::concat(emit_import_name(provider.clone(), nm.clone(), registry.clone()), ";".to_string())))))]) + Rc::new(vec![Rc::new(RustUseLine { + target_module: crate::v1_compiler_emit_core_support::module_to_filename(provider.clone()), + text: v1_rt::concat(rust_visibility_prefix(), v1_rt::concat("use crate::".to_string(), v1_rt::concat(crate::v1_compiler_emit_core_support::module_to_filename(provider.clone()), v1_rt::concat("::".to_string(), v1_rt::concat(emit_import_name(provider.clone(), nm.clone(), registry.clone()), ";".to_string()))))), +})]) } else { Rc::new(vec![]) } @@ -10295,6 +10307,13 @@ v1_rt::concat(block_lines.clone(), fallback.clone()) } __result }); + let lines = Rc::new({ + let mut __result = Vec::new(); + for l in typed_lines.iter().cloned() { + __result.push(l.text.clone()); + } + __result + }); let names_already_in_lines = Rc::new({ let mut __result = Vec::new(); for l in lines.iter().cloned() { @@ -10333,9 +10352,24 @@ v1_rt::concat(block_lines.clone(), fallback.clone()) ); let qualified_lines = qualified_type_reference_use_lines(qualified_rows.clone(), registry.clone()); + let this_module_filename = + crate::v1_compiler_emit_core_support::module_to_filename(this_module_name.clone()); Rc::new(ReferenceDerivedUseLinePlan { - lines: v1_rt::concat(lines.clone(), qualified_lines.clone()), + lines: v1_rt::concat( + lines.clone(), + Rc::new({ + let mut __result = Vec::new(); + for l in qualified_lines.iter().cloned() { + __result.push(l.text.clone()); + } + __result + }), + ), rows: v1_rt::concat(rows.clone(), qualified_rows.clone()), + edges: rust_use_line_edges( + this_module_filename.clone(), + v1_rt::concat(typed_lines.clone(), qualified_lines.clone()), + ), }) } } @@ -10521,45 +10555,56 @@ pub fn registry_row_is_type_declared_in(info: Rc, module_name: String) pub fn qualified_type_reference_use_lines( rows: Rc>>, registry: Rc>>, -) -> Rc> { - canonical_string_set(Rc::new({ - let mut __result = Vec::new(); - for r in rows.iter().cloned() { - __result.extend( - (*match (*r.disposition.clone()).clone() { - ReferenceDerivedCandidateDisposition::CandidateSurvived { - provider_module: provider, - .. - } => Rc::new(vec![v1_rt::concat( - v1_rt::concat( - v1_rt::concat( - v1_rt::concat( - v1_rt::concat( - rust_visibility_prefix(), - "use crate::".to_string(), - ), - crate::v1_compiler_emit_core_support::module_to_filename( - provider.clone(), - ), - ), - "::".to_string(), - ), - emit_import_name( - provider.clone(), - crate::v1_std_core::qualified_last_segment(r.name.clone()), - registry.clone(), - ), - ), - ";".to_string(), - )]), - _ => Rc::new(vec![]), - }) - .iter() - .cloned(), - ); - } - __result - })) +) -> Rc>> { + { + let typed = Rc::new({ + let mut __result = Vec::new(); + for r in rows.iter().cloned() { + __result.extend((*match (*r.disposition.clone()).clone() { + ReferenceDerivedCandidateDisposition::CandidateSurvived { provider_module: provider, .. } => Rc::new(vec![Rc::new(RustUseLine { + target_module: crate::v1_compiler_emit_core_support::module_to_filename(provider.clone()), + text: v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(rust_visibility_prefix(), "use crate::".to_string()), crate::v1_compiler_emit_core_support::module_to_filename(provider.clone())), "::".to_string()), emit_import_name(provider.clone(), crate::v1_std_core::qualified_last_segment(r.name.clone()), registry.clone())), ";".to_string()), +})]), + _ => Rc::new(vec![]), +}).iter().cloned()); + } + __result + }); + Rc::new({ + let mut __result = Vec::new(); + for text in canonical_string_set(Rc::new({ + let mut __result = Vec::new(); + for l in typed.iter().cloned() { + __result.push(l.text.clone()); + } + __result + })) + .iter() + .cloned() + { + __result.extend( + (*Rc::new( + Rc::new({ + let mut __result = Vec::new(); + for l in typed.iter().cloned() { + if (l.text.clone() == text.clone()) { + __result.push(l); + } + } + __result + }) + .iter() + .cloned() + .take(1 as usize) + .collect::>(), + )) + .iter() + .cloned(), + ); + } + __result + }) + } } pub fn reference_derived_use_lines( @@ -10601,6 +10646,7 @@ pub fn reference_derived_use_lines( pub struct ModuleEmission { pub file: Rc, pub reference_rows: Rc>>, + pub emitted_edges: Rc>>, pub module_refusals: Rc>>, } @@ -10792,7 +10838,7 @@ pub fn emit_module_full( }) .join(&"\n\n".to_string()); let prelude = emit_prelude(this_module_name.clone()); - let imports_str = emit_imports( + let rendered_imports = emit_imports( crate::v1_std_core::module_imports(m.clone()), emit_info.clone(), registry.clone(), @@ -10803,7 +10849,9 @@ pub fn emit_module_full( module_index.clone(), typed_module.items.clone(), Some(scope.type_env.clone()), + crate::v1_compiler_emit_core_support::module_to_filename(this_module_name.clone()), ); + let imports_str = rendered_imports.text.clone(); let dag_import_lines = if (imports_str.clone() == "".to_string()) { Rc::new(vec![]) } else { @@ -10910,43 +10958,30 @@ pub fn emit_module_full( } __result }); - let extern_svc_imports = Rc::new({ + let extern_svc_use_lines = Rc::new({ let mut __result = Vec::new(); for sn in crate::v1_compiler_emit_core_support::unique_strings(all_svc_names.clone()) .iter() .cloned() { - __result.extend( - (*match v1_rt::map_get(&svc_module_map, sn.clone()) { - Some(mod_file) => { - if (mod_file.clone() == this_mod_filename.clone()) { - Rc::new(vec![]) - } else { - Rc::new(vec![v1_rt::concat( - v1_rt::concat( - v1_rt::concat( - v1_rt::concat( - v1_rt::concat( - rust_visibility_prefix(), - "use crate::".to_string(), - ), - mod_file.clone(), - ), - "::".to_string(), - ), - crate::v1_compiler_emit_core_support::sanitize_service_name( - sn.clone(), - ), - ), - ";".to_string(), - )]) - } - } - std::option::Option::None => Rc::new(vec![]), - }) - .iter() - .cloned(), - ); + __result.extend((*match v1_rt::map_get(&svc_module_map, sn.clone()) { + Some(mod_file) => if (mod_file.clone() == this_mod_filename.clone()) { + Rc::new(vec![]) + } else { + Rc::new(vec![Rc::new(RustUseLine { + target_module: mod_file.clone(), + text: v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(rust_visibility_prefix(), "use crate::".to_string()), mod_file.clone()), "::".to_string()), crate::v1_compiler_emit_core_support::sanitize_service_name(sn.clone())), ";".to_string()), +})]) + }, + std::option::Option::None => Rc::new(vec![]), +}).iter().cloned()); + } + __result + }); + let extern_svc_imports = Rc::new({ + let mut __result = Vec::new(); + for l in extern_svc_use_lines.iter().cloned() { + __result.push(l.text.clone()); } __result }); @@ -10954,6 +10989,24 @@ pub fn emit_module_full( extern_svc_imports.clone(), merged_import_lines.clone(), ); + let uncovered_svc_use_lines = Rc::new({ + let mut __result = Vec::new(); + for l in extern_svc_use_lines.iter().cloned() { + if { + let mut __found = false; + for u in uncovered_svc_imports.iter().cloned() { + if (u.clone() == l.text.clone()) { + __found = true; + break; + } + } + __found + } { + __result.push(l); + } + } + __result + }); let svc_imports_str = if ((uncovered_svc_imports.clone().len() as i64) == 0) { "".to_string() } else { @@ -11069,6 +11122,18 @@ pub fn emit_module_full( content: content.clone(), }), reference_rows: reference_plan.rows.clone(), + emitted_edges: v1_rt::concat( + v1_rt::concat( + v1_rt::concat( + crate::gunbc_rust_emitted_edge::rust_prelude_emitted_edges( + this_mod_filename.clone(), + ), + rendered_imports.edges.clone(), + ), + reference_plan.edges.clone(), + ), + rust_use_line_edges(this_mod_filename.clone(), uncovered_svc_use_lines.clone()), + ), module_refusals: v1_rt::concat( reference_derived_row_diagnostics(reference_plan.rows.clone(), m.span.clone()), module_projection_refusals( @@ -13505,6 +13570,61 @@ pub fn import_name_resolves_to_host_realized_kernel_scalar( } } +#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)] +pub struct RustUseLine { + pub target_module: String, + pub text: String, +} + +pub fn rust_use_lines_text(lines: Rc>>) -> String { + Rc::new({ + let mut __result = Vec::new(); + for l in lines.iter().cloned() { + __result.push(l.text.clone()); + } + __result + }) + .join(&"\n".to_string()) +} + +pub fn rust_use_line_edges( + from: String, + lines: Rc>>, +) -> Rc>> { + Rc::new({ + let mut __result = Vec::new(); + for target in Rc::new({ + let mut __result = Vec::new(); + for target in canonical_string_set(Rc::new({ + let mut __result = Vec::new(); + for l in lines.iter().cloned() { + __result.push(l.target_module.clone()); + } + __result + })) + .iter() + .cloned() + { + if (target.clone() != from.clone()) { + __result.push(target); + } + } + __result + }) + .iter() + .cloned() + { + __result.push( + crate::gunbc_rust_emitted_edge::semantic_source_reference_edge( + from.clone(), + target.clone(), + ), + ); + } + __result + }) +} + pub fn emit_specific_import_block( import_module: String, mod_name: String, @@ -13519,6 +13639,36 @@ pub fn emit_specific_import_block( module_index: Rc, module_env: Option>, ) -> String { + rust_use_lines_text(emit_specific_import_use_lines( + import_module.clone(), + mod_name.clone(), + filtered_names.clone(), + type_position_names.clone(), + emit_info.clone(), + registry.clone(), + local_names.clone(), + export_sets.clone(), + typed_modules.clone(), + source_indices.clone(), + module_index.clone(), + module_env.clone(), + )) +} + +pub fn emit_specific_import_use_lines( + import_module: String, + mod_name: String, + filtered_names: Rc>, + type_position_names: Rc>, + emit_info: Rc, + registry: Rc>>, + local_names: Rc>, + export_sets: Rc>>>, + typed_modules: Rc>>, + source_indices: Rc>>, + module_index: Rc, + module_env: Option>, +) -> Rc>> { { let type_summaries = emit_info.type_summaries.clone(); let deduped_names = crate::v1_compiler_emit_core_support::unique_strings(Rc::new({ @@ -13593,7 +13743,7 @@ pub fn emit_specific_import_block( __result }); if ((deduped_names.clone().len() as i64) == 0) { - "".to_string() + Rc::new(vec![]) } else { { let import_module_enums = import_module_enum_scope( @@ -13910,68 +14060,75 @@ pub fn emit_specific_import_block( let type_direct_lines = Rc::new({ let mut __result = Vec::new(); for def_mod in type_direct_mods.iter().cloned() { - __result.push({ - let group = Rc::new({ - let mut __result = Vec::new(); - for n in type_direct_names.iter().cloned() { - if (graph_type_import_module_filename( - n.clone(), - import_module.clone(), - mod_name.clone(), - typed_modules.clone(), - export_sets.clone(), - source_indices.clone(), - module_index.clone(), - ) == def_mod.clone()) - { - __result.push(n); + __result.extend( + (*{ + let group = Rc::new({ + let mut __result = Vec::new(); + for n in type_direct_names.iter().cloned() { + if (graph_type_import_module_filename( + n.clone(), + import_module.clone(), + mod_name.clone(), + typed_modules.clone(), + export_sets.clone(), + source_indices.clone(), + module_index.clone(), + ) == def_mod.clone()) + { + __result.push(n); + } } - } - __result - }); - if ((group.clone().len() as i64) > 0) { - { - let names_str = Rc::new({ - let mut __result = Vec::new(); - for n in group.iter().cloned() { - __result.push(emit_import_name( - graph_type_import_module_path( + __result + }); + if ((group.clone().len() as i64) > 0) { + { + let names_str = Rc::new({ + let mut __result = Vec::new(); + for n in group.iter().cloned() { + __result.push(emit_import_name( + graph_type_import_module_path( + n.clone(), + import_module.clone(), + mod_name.clone(), + typed_modules.clone(), + export_sets.clone(), + source_indices.clone(), + module_index.clone(), + ), n.clone(), - import_module.clone(), - mod_name.clone(), - typed_modules.clone(), - export_sets.clone(), - source_indices.clone(), - module_index.clone(), - ), - n.clone(), - registry.clone(), - )); - } - __result - }) - .join(&", ".to_string()); - v1_rt::concat( - v1_rt::concat( - v1_rt::concat( + registry.clone(), + )); + } + __result + }) + .join(&", ".to_string()); + Rc::new(vec![Rc::new(RustUseLine { + target_module: def_mod.clone(), + text: v1_rt::concat( v1_rt::concat( v1_rt::concat( - rust_visibility_prefix(), - "use crate::".to_string(), + v1_rt::concat( + v1_rt::concat( + rust_visibility_prefix(), + "use crate::".to_string(), + ), + def_mod.clone(), + ), + "::{".to_string(), ), - def_mod.clone(), + names_str.clone(), ), - "::{".to_string(), + "};".to_string(), ), - names_str.clone(), - ), - "};".to_string(), - ) + })]) + } + } else { + Rc::new(vec![]) } - } else { - "".to_string() - } - }); + }) + .iter() + .cloned(), + ); } __result }); @@ -13989,42 +14146,31 @@ pub fn emit_specific_import_block( __result }) .join(&", ".to_string()); - v1_rt::concat( - v1_rt::concat( + Rc::new(vec![Rc::new(RustUseLine { + target_module: mod_name.clone(), + text: v1_rt::concat( v1_rt::concat( v1_rt::concat( v1_rt::concat( - rust_visibility_prefix(), - "use crate::".to_string(), + v1_rt::concat( + rust_visibility_prefix(), + "use crate::".to_string(), + ), + mod_name.clone(), ), - mod_name.clone(), + "::{".to_string(), ), - "::{".to_string(), + names_str.clone(), ), - names_str.clone(), + "};".to_string(), ), - "};".to_string(), - ) + })]) } } else { - "".to_string() + Rc::new(vec![]) }; - let direct_lines = v1_rt::concat( - Rc::new({ - let mut __result = Vec::new(); - for l in type_direct_lines.iter().cloned() { - if (l.clone() != "".to_string()) { - __result.push(l); - } - } - __result - }), - if (other_direct_line.clone() != "".to_string()) { - Rc::new(vec![other_direct_line.clone()]) - } else { - Rc::new(vec![]) - }, - ); + let direct_lines = + v1_rt::concat(type_direct_lines.clone(), other_direct_line.clone()); let parent_defining_mods = crate::v1_compiler_emit_core_support::unique_strings(Rc::new({ let mut __result = Vec::new(); @@ -14089,7 +14235,7 @@ pub fn emit_specific_import_block( let parent_main_lines = Rc::new({ let mut __result = Vec::new(); for def_mod in parent_defining_mods.iter().cloned() { - __result.push({ + __result.extend((*{ let group = Rc::new({ let mut __result = Vec::new(); for p in remote_parent_list.iter().cloned() { if { let rep_variant = Rc::new({ let mut __result = Vec::new(); for n in deduped_names.iter().cloned() { if match find_variant_parent_in_module(n.clone(), import_module.clone(), typed_modules.clone(), source_indices.clone(), module_index.clone()) { Some(found) => (found.clone() == p.clone()), @@ -14106,44 +14252,24 @@ match rep_variant.clone() { if ((group.clone().len() as i64) > 0) { { let names_str = group.clone().join(&", ".to_string()); -v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(rust_visibility_prefix(), "use crate::".to_string()), def_mod.clone()), "::{".to_string()), names_str.clone()), "};".to_string()) +Rc::new(vec![Rc::new(RustUseLine { + target_module: def_mod.clone(), + text: v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(rust_visibility_prefix(), "use crate::".to_string()), def_mod.clone()), "::{".to_string()), names_str.clone()), "};".to_string()), +})]) } } else { - "".to_string() + Rc::new(vec![]) } -}); +}).iter().cloned()); } __result }); - let main_lines = if ((direct_lines.clone().len() as i64) > 0) { - v1_rt::concat( - direct_lines.clone(), - Rc::new({ - let mut __result = Vec::new(); - for l in parent_main_lines.iter().cloned() { - if (l.clone() != "".to_string()) { - __result.push(l); - } - } - __result - }), - ) - } else { - Rc::new({ - let mut __result = Vec::new(); - for l in parent_main_lines.iter().cloned() { - if (l.clone() != "".to_string()) { - __result.push(l); - } - } - __result - }) - }; + let main_lines = v1_rt::concat(direct_lines.clone(), parent_main_lines.clone()); let variant_lines = Rc::new({ let mut __result = Vec::new(); for parent in parent_list.iter().cloned() { - __result.push(if is_grounded_coproduct_native_alias(parent.clone()) { - "".to_string() + __result.extend((*if is_grounded_coproduct_native_alias(parent.clone()) { + Rc::new(vec![]) } else { { let variants = Rc::new({ let mut __result = Vec::new(); for n in deduped_names.iter().cloned() { if if ((n.clone() == "None".to_string()) || (n.clone() == "Some".to_string())) { @@ -14173,9 +14299,12 @@ let parent_mod = match variants.clone().first().cloned() { std::option::Option::None => item_defining_module_filename(parent.clone(), module_index.clone(), mod_name.clone()), }; let vars_str = variants.clone().join(&", ".to_string()); -v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat("use crate::".to_string(), parent_mod.clone()), "::".to_string()), parent.clone()), "::{".to_string()), vars_str.clone()), "};".to_string()) +Rc::new(vec![Rc::new(RustUseLine { + target_module: parent_mod.clone(), + text: v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat("use crate::".to_string(), parent_mod.clone()), "::".to_string()), parent.clone()), "::{".to_string()), vars_str.clone()), "};".to_string()), +})]) } - }); + }).iter().cloned()); } __result }); @@ -14222,43 +14351,26 @@ v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::con .iter() .cloned() { - __result.push(v1_rt::concat( - v1_rt::concat( + __result.push(Rc::new(RustUseLine { + target_module: mod_name.clone(), + text: v1_rt::concat( v1_rt::concat( - v1_rt::concat("use crate::".to_string(), mod_name.clone()), - "::".to_string(), + v1_rt::concat( + v1_rt::concat("use crate::".to_string(), mod_name.clone()), + "::".to_string(), + ), + en.clone(), ), - en.clone(), + "::*;".to_string(), ), - "::*;".to_string(), - )); + })); } __result }); - let all_lines = v1_rt::concat( - v1_rt::concat( - Rc::new({ - let mut __result = Vec::new(); - for l in main_lines.iter().cloned() { - if (l.clone() != "".to_string()) { - __result.push(l); - } - } - __result - }), - Rc::new({ - let mut __result = Vec::new(); - for l in variant_lines.iter().cloned() { - if (l.clone() != "".to_string()) { - __result.push(l); - } - } - __result - }), - ), + v1_rt::concat( + v1_rt::concat(main_lines.clone(), variant_lines.clone()), wildcard_enum_lines.clone(), - ); - all_lines.clone().join(&"\n".to_string()) + ) } } } @@ -14870,6 +14982,12 @@ pub fn dedupe_rust_import_lines(lines: Rc>) -> Rc> { } } +#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)] +pub struct RenderedUseLines { + pub text: String, + pub edges: Rc>>, +} + pub fn emit_imports( imports: Rc>>, emit_info: Rc, @@ -14881,9 +14999,13 @@ pub fn emit_imports( module_index: Rc, supplement_items: Rc>>, module_env: Option>, -) -> String { + from_module: String, +) -> Rc { if ((imports.clone().len() as i64) == 0) { - "".to_string() + Rc::new(RenderedUseLines { + text: "".to_string(), + edges: Rc::new(vec![]), + }) } else { { let applied_type_argument_names = @@ -14931,10 +15053,10 @@ pub fn emit_imports( } __result })); - let import_lines = Rc::new({ + let import_blocks = Rc::new({ let mut __result = Vec::new(); for import_module in import_modules.iter().cloned() { - __result.extend((*{ + __result.push({ let mod_imports = Rc::new({ let mut __result = Vec::new(); for imp in imports.iter().cloned() { if (crate::v1_std_core::authored_name_at(source_indices.clone(), imp.clone()) == import_module.clone()) { __result.push(imp); } } __result }); let mod_name = crate::v1_compiler_emit_core_support::module_to_filename(import_module.clone()); let mod_has_wildcard = { let mut __found = false; for imp in mod_imports.iter().cloned() { if crate::v1_std_core::import_is_all(imp.clone()) { __found = true; break; } } __found }; @@ -14943,27 +15065,54 @@ let block = if mod_has_wildcard.clone() { let wildcard_line = v1_rt::concat(v1_rt::concat("use crate::".to_string(), mod_name.clone()), "::*;".to_string()); let reexport_surface = wildcard_reexport_surface_names(import_module.clone(), export_sets.clone(), typed_modules.clone(), source_indices.clone(), module_index.clone()); let merged_specific = crate::v1_compiler_emit_core_support::unique_strings(v1_rt::concat(Rc::new({ let mut __result = Vec::new(); for imp in Rc::new({ let mut __result = Vec::new(); for imp in mod_imports.iter().cloned() { if (crate::v1_std_core::import_is_all(imp.clone()) == false) { __result.push(imp); } } __result }).iter().cloned() { __result.extend((*crate::v1_std_core::import_specific_names_at(imp.clone(), source_indices.clone())).iter().cloned()); } __result }), reexport_surface.clone())); -let specific_block = emit_specific_import_block(import_module.clone(), mod_name.clone(), merged_specific.clone(), applied_type_argument_names.clone(), emit_info.clone(), registry.clone(), local_names.clone(), export_sets.clone(), typed_modules.clone(), source_indices.clone(), module_index.clone(), module_env.clone()); -if (specific_block.clone() != "".to_string()) { - v1_rt::concat(v1_rt::concat(wildcard_line.clone(), "\n".to_string()), specific_block.clone()) - } else { - wildcard_line.clone() - } +let specific_lines = emit_specific_import_use_lines(import_module.clone(), mod_name.clone(), merged_specific.clone(), applied_type_argument_names.clone(), emit_info.clone(), registry.clone(), local_names.clone(), export_sets.clone(), typed_modules.clone(), source_indices.clone(), module_index.clone(), module_env.clone()); +v1_rt::concat(Rc::new(vec![Rc::new(RustUseLine { + target_module: mod_name.clone(), + text: wildcard_line.clone(), +})]), specific_lines.clone()) } } else { { let specific_names = Rc::new({ let mut __result = Vec::new(); for imp in mod_imports.iter().cloned() { __result.extend((*crate::v1_std_core::import_specific_names_at(imp.clone(), source_indices.clone())).iter().cloned()); } __result }); let synth_for_module = module_data_field_struct_import_names(supplement_items.clone(), emit_info.type_summaries.clone(), import_module.clone(), export_sets.clone(), typed_modules.clone(), source_indices.clone(), module_index.clone()); let merged_specific = crate::v1_compiler_emit_core_support::unique_strings(v1_rt::concat(specific_names.clone(), synth_for_module.clone())); -emit_specific_import_block(import_module.clone(), mod_name.clone(), merged_specific.clone(), applied_type_argument_names.clone(), emit_info.clone(), registry.clone(), local_names.clone(), export_sets.clone(), typed_modules.clone(), source_indices.clone(), module_index.clone(), module_env.clone()) +emit_specific_import_use_lines(import_module.clone(), mod_name.clone(), merged_specific.clone(), applied_type_argument_names.clone(), emit_info.clone(), registry.clone(), local_names.clone(), export_sets.clone(), typed_modules.clone(), source_indices.clone(), module_index.clone(), module_env.clone()) } }; -Rc::new(block.clone().split(&"\n".to_string()).map(|s| s.to_string()).collect::>()) -}).iter().cloned()); +block.clone() +}); } __result }); - dedupe_rust_import_lines(import_lines.clone()).join(&"\n".to_string()) + let import_lines = Rc::new({ + let mut __result = Vec::new(); + for block in import_blocks.iter().cloned() { + __result.extend( + (*Rc::new( + rust_use_lines_text(block.clone()) + .split(&"\n".to_string()) + .map(|s| s.to_string()) + .collect::>(), + )) + .iter() + .cloned(), + ); + } + __result + }); + Rc::new(RenderedUseLines { + text: dedupe_rust_import_lines(import_lines.clone()).join(&"\n".to_string()), + edges: rust_use_line_edges( + from_module.clone(), + Rc::new({ + let mut __result = Vec::new(); + for block in import_blocks.iter().cloned() { + __result.extend((*block.clone()).iter().cloned()); + } + __result + }), + ), + }) } } } diff --git a/src/v1/stage0/src/v1_compiler_stage0_crates.rs b/src/v1/stage0/src/v1_compiler_stage0_crates.rs index 5e6b78c1ef0..7ab54b18e7d 100644 --- a/src/v1/stage0/src/v1_compiler_stage0_crates.rs +++ b/src/v1/stage0/src/v1_compiler_stage0_crates.rs @@ -35,9 +35,8 @@ use crate::gunbc_stage0_crate_partition_generated::GeneratedPartitionCrateKind:: pub use crate::gunbc_stage0_crate_partition_generated::{ GeneratedPartitionCrateKind, GeneratedPartitionCrateRow, }; -pub use crate::gunbc_stage0_partition_package_graph::{ - stage0_partition_package_dependency_names, stage0_partition_row_is_module_bearing_package, -}; +pub use crate::gunbc_stage0_emitted_edge_admission::stage0_partition_module_owner_packages; +pub use crate::gunbc_stage0_partition_package_graph::stage0_partition_package_dependency_names; pub use crate::std_dissolution::unbound_dissolution; pub use crate::std_dissolution::DissolutionCondition; use crate::std_dissolution::DissolutionCondition::*; @@ -308,29 +307,19 @@ pub fn stage0_lookup_module_owner_package_name( module_basename: String, ) -> Rc { { - let matches = Rc::new({ - let mut __result = Vec::new(); - for row in generated_partition_crate_rows().iter().cloned() { - if (crate::gunbc_stage0_partition_package_graph::stage0_partition_row_is_module_bearing_package(row.clone()) && { let mut __found = false; for m in row.modules.clone().iter().cloned() { if (m.clone() == module_basename.clone()) { __found = true; break; } } __found }) { __result.push(row); } - } - __result - }); - let package_name = Rc::new({ - let mut __result = Vec::new(); - for row in matches.iter().cloned() { - __result.push(row.package_name.clone()); - } - __result - }) - .iter() - .cloned() - .fold("".to_string(), |acc: String, pkg: String| { - if (acc.clone() == "".to_string()) { - pkg.clone() - } else { - acc.clone() - } - }); + let package_name = + crate::gunbc_stage0_emitted_edge_admission::stage0_partition_module_owner_packages( + module_basename.clone(), + ) + .iter() + .cloned() + .fold("".to_string(), |acc: String, pkg: String| { + if (acc.clone() == "".to_string()) { + pkg.clone() + } else { + acc.clone() + } + }); if (package_name.clone() == "".to_string()) { Rc::new(Stage0ModuleOwnerLookup::Stage0ModuleOwnerRefused { cause: Rc::new(Stage0ModuleOwnerRefusalCause::Stage0ModuleOwnerMissing { diff --git a/src/v1/stage0_crates.dag b/src/v1/stage0_crates.dag index 38e10133c3c..5c48ac0a911 100644 --- a/src/v1/stage0_crates.dag +++ b/src/v1/stage0_crates.dag @@ -17,9 +17,9 @@ import gunbc.rust_crate_package_ident { rust_crate_package_idents } import gunbc.stage0_partition_package_graph { - stage0_partition_package_dependency_names, - stage0_partition_row_is_module_bearing_package + stage0_partition_package_dependency_names } +import gunbc.stage0_emitted_edge_admission { stage0_partition_module_owner_packages } import gunbc.stage0_crate_partition_generated { GeneratedEmitCoreCrate, GeneratedFoundationCrate, @@ -185,13 +185,7 @@ type Stage0CrateBoundaryEmitOutcome | Stage0CrateBoundaryEmitRefused { cause: Stage0CrateBoundaryEmitRefusalCause } fn stage0_lookup_module_owner_package_name(module_basename: String) -> Stage0ModuleOwnerLookup { - let matches = generated_partition_crate_rows - |> filter(row => - stage0_partition_row_is_module_bearing_package(row: row) - && (row.modules |> any(m => m == module_basename)) - ) - let package_name = matches - |> map(row => row.package_name) + let package_name = stage0_partition_module_owner_packages(module_basename: module_basename) |> fold(init: "", f: fn(acc, pkg) { if acc == "" { pkg } else { acc } }) if package_name == "" { Stage0ModuleOwnerRefused { diff --git a/src/v1/stage0_std_core/src/lib.rs b/src/v1/stage0_std_core/src/lib.rs index 7738a2f8aba..851f07809be 100644 --- a/src/v1/stage0_std_core/src/lib.rs +++ b/src/v1/stage0_std_core/src/lib.rs @@ -140,3 +140,6 @@ pub mod std_import; #[rustfmt::skip] #[path = "../../stage0/src/v1_std_core.rs"] pub mod v1_std_core; +#[rustfmt::skip] +#[path = "../../stage0/src/gunbc_rust_emitted_edge.rs"] +pub mod gunbc_rust_emitted_edge; diff --git a/src/v2/test/claim/stage0_emitted_edge_admission_witness_test.dag b/src/v2/test/claim/stage0_emitted_edge_admission_witness_test.dag new file mode 100644 index 00000000000..dc40722899e --- /dev/null +++ b/src/v2/test/claim/stage0_emitted_edge_admission_witness_test.dag @@ -0,0 +1,110 @@ +module test.claim.stage0_emitted_edge_admission_witness + +import std.types { Bool } +import gunbc.rust_emitted_edge { rust_prelude_emitted_edges, semantic_source_reference_edge } +import gunbc.stage0_emitted_edge_admission { + Stage0EmittedEdgesAdmitted, + Stage0EmittedEdgesNotCovered, + Stage0EmittedEdgesRefused, + stage0_emitted_edge_admission, + stage0_emitted_edge_admission_refusal +} + +// ── ONE ADMISSION, SUPPLIED EDGES, THE REAL PARTITION ROWS ──────────────────────────────────── +// +// The subject is gunbc.stage0_emitted_edge_admission: given the edges the emitter returned and the +// host shell's module roster, does every edge land in a package its source crate reaches. The rows +// and package graph are the committed ones (gunbc.stage0_crate_partition_generated), so the module +// names below are real members of real crates: v1_rt in the runtime foundation, std_types in +// std-core, v1_compiler_infer in v1-infer. The edges are supplied, because the claim is about the +// admission, not about what one emission happened to produce. The real producer is exercised by the +// required generated-artifact phase, which runs this admission over the whole seed emission in +// required_regen_host compile_stage0 and refuses the regen on any arm but Admitted. + +// RED: a foundation crate re-exports nothing, so an edge out of the runtime into v1-infer names a +// module its crate cannot see -- the E0432 a partition build would report, refused here by name. +test fn an_edge_out_of_the_foundation_into_a_higher_crate_is_refused() -> Bool { + match stage0_emitted_edge_admission( + edges: [semantic_source_reference_edge(from: "v1_rt", to_module: "v1_compiler_infer")], + host_shell_modules: [] + ) { + Stage0EmittedEdgesRefused { crossings: crossings } => + (crossings |> count) == 1 + && crossings |> all(c => + c.from_module == "v1_rt" + && c.to_module == "v1_compiler_infer" + && c.from_package == "v1-stage0-runtime" + && c.to_package == "v1-stage0-v1-infer") + _ => false + } +} + +// RED, the direction that actually bites: a partition crate naming a host-shell module. The shell +// depends on the partition, never the reverse. +test fn an_edge_from_a_partition_crate_into_the_host_shell_is_refused() -> Bool { + match stage0_emitted_edge_admission( + edges: [semantic_source_reference_edge(from: "v1_compiler_infer", to_module: "cli_run")], + host_shell_modules: ["cli_run"] + ) { + Stage0EmittedEdgesRefused { crossings: crossings } => + (crossings |> count) == 1 + && crossings |> all(c => c.from_package == "v1-stage0-v1-infer" && c.to_package == "v1-compiler") + _ => false + } +} + +// CONTROL for both REDs: the same admission over edges down the layering admits. v1-infer reaches +// std-core through its facade, and the shell reaches v1-infer through its one dependency. +test fn edges_down_the_layering_are_admitted() -> Bool { + match stage0_emitted_edge_admission( + edges: [ + semantic_source_reference_edge(from: "v1_compiler_infer", to_module: "std_types"), + semantic_source_reference_edge(from: "cli_run", to_module: "v1_compiler_infer"), + semantic_source_reference_edge(from: "cli_run", to_module: "v1_rt") + ], + host_shell_modules: ["cli_run"] + ) { + Stage0EmittedEdgesAdmitted { edge_count: n } => n == 3 + _ => false + } +} + +// The emitter's own prelude rows, as the emitter produces them for a v1-infer module, admit: the +// runtime edge reaches the foundation and the facade edge names the crate root. +test fn the_emitter_prelude_rows_for_a_partition_module_are_admitted() -> Bool { + match stage0_emitted_edge_admission( + edges: rust_prelude_emitted_edges(module: "v1_compiler_infer"), + host_shell_modules: [] + ) { + Stage0EmittedEdgesAdmitted { edge_count: _ } => true + _ => false + } +} + +// NOT COVERED is its own arm: a module in neither a partition row nor the shell roster has no +// crate here, which is what emitting a closure other than the seed looks like. It never passes. +test fn a_module_outside_the_seed_is_not_covered_rather_than_admitted() -> Bool { + match stage0_emitted_edge_admission( + edges: [semantic_source_reference_edge(from: "fixture_closure_module", to_module: "std_types")], + host_shell_modules: ["cli_run"] + ) { + Stage0EmittedEdgesNotCovered { uncovered: uncovered } => + (uncovered |> count) == 1 + && uncovered |> all(u => u.module == "fixture_closure_module" && u.edge_from == "fixture_closure_module") + _ => false + } +} + +// The refusal the regen prints is located: it names both modules, both packages and the provenance. +test fn the_refusal_names_modules_packages_and_provenance() -> Bool { + match stage0_emitted_edge_admission_refusal( + outcome: stage0_emitted_edge_admission( + edges: [semantic_source_reference_edge(from: "v1_rt", to_module: "v1_compiler_infer")], + host_shell_modules: [] + ) + ) { + Present { value: message } => + string_contains(s: message, pattern: "v1_rt [v1-stage0-runtime] -> v1_compiler_infer [v1-stage0-v1-infer] (semantic-source-reference)") + Absent => false + } +} diff --git a/src/v2/workflow/rust_crate_partition.dag b/src/v2/workflow/rust_crate_partition.dag index cfe3b9031e1..d312998d954 100644 --- a/src/v2/workflow/rust_crate_partition.dag +++ b/src/v2/workflow/rust_crate_partition.dag @@ -313,6 +313,9 @@ fn stage0_std_primitive_modules() -> List { ] } +// gunbc_rust_emitted_edge is here because v1_compiler_emit_core_support (v1-infer unit) carries +// its EmittedEdge on EmitResult, and a crate:: path from that unit resolves only into a package it +// re-exports; the module names only std_types, so the lowest unit that reaches it is this one. fn stage0_std_core_modules() -> List { stage0_std_primitive_modules() |> concat([ @@ -340,7 +343,8 @@ fn stage0_std_core_modules() -> List { "std_literal_elaboration", "std_operator_realization", "std_import", - "v1_std_core" + "v1_std_core", + "gunbc_rust_emitted_edge" ]) } @@ -606,6 +610,8 @@ fn stage0_cross_unit_import_edges() -> List { stage0_module_dag_edge(from: "v1_compiler_parse", to: "std_types"), stage0_module_dag_edge(from: "v1_compiler_parse", to: "extdeps_languages_dag_syntax"), stage0_module_dag_edge(from: "v1_compiler_parse", to: "v1_std_core"), + stage0_module_dag_edge(from: "gunbc_rust_emitted_edge", to: "std_types"), + stage0_module_dag_edge(from: "v1_compiler_emit_core_support", to: "gunbc_rust_emitted_edge"), ] } From de37e00dd2361ab531fdfc6981e401b07a3b5b6b Mon Sep 17 00:00:00 2001 From: gunbc-ci-auto-heal Date: Wed, 23 Sep 2026 20:06:08 +0000 Subject: [PATCH 2/4] Emit-core re-exports gunbc_rust_emitted_edge: its #[path] copy of emit_core_support names it at the crate root Co-Authored-By: Claude Opus 5.5 (1M context) --- dag/gunbc/stage0/stage0_crate_partition_generated.dag | 1 + src/v1/stage0/src/gunbc_stage0_crate_partition_generated.rs | 2 +- src/v1/stage0_emit_core/src/lib.rs | 4 ++++ src/v2/workflow/rust_crate_partition.dag | 1 + 4 files changed, 7 insertions(+), 1 deletion(-) diff --git a/dag/gunbc/stage0/stage0_crate_partition_generated.dag b/dag/gunbc/stage0/stage0_crate_partition_generated.dag index 7e9fade05ff..1d5308abe2a 100644 --- a/dag/gunbc/stage0/stage0_crate_partition_generated.dag +++ b/dag/gunbc/stage0/stage0_crate_partition_generated.dag @@ -188,6 +188,7 @@ data generated_partition_crate_rows: List = [ crate_dir: "src/v1/stage0_emit_core", kind: GeneratedEmitCoreCrate, modules: [ + "gunbc_rust_emitted_edge", "v1_compiler_artifact", "v1_compiler_infer_env", "v1_compiler_infer_items", diff --git a/src/v1/stage0/src/gunbc_stage0_crate_partition_generated.rs b/src/v1/stage0/src/gunbc_stage0_crate_partition_generated.rs index dce5a96bd77..0e76177cceb 100644 --- a/src/v1/stage0/src/gunbc_stage0_crate_partition_generated.rs +++ b/src/v1/stage0/src/gunbc_stage0_crate_partition_generated.rs @@ -89,7 +89,7 @@ pub fn generated_partition_crate_rows() -> Rc package_name: "v1-stage0-emit-core".to_string(), crate_dir: "src/v1/stage0_emit_core".to_string(), kind: GeneratedPartitionCrateKind::GeneratedEmitCoreCrate, - modules: Rc::new(vec!["v1_compiler_artifact".to_string(), "v1_compiler_infer_env".to_string(), "v1_compiler_infer_items".to_string(), "v1_compiler_infer_service".to_string(), "v1_compiler_infer_types".to_string(), "v1_compiler_languages".to_string(), "v1_compiler_parse".to_string(), "v1_rt".to_string(), "v1_std_core".to_string()]), + modules: Rc::new(vec!["gunbc_rust_emitted_edge".to_string(), "v1_compiler_artifact".to_string(), "v1_compiler_infer_env".to_string(), "v1_compiler_infer_items".to_string(), "v1_compiler_infer_service".to_string(), "v1_compiler_infer_types".to_string(), "v1_compiler_languages".to_string(), "v1_compiler_parse".to_string(), "v1_rt".to_string(), "v1_std_core".to_string()]), reexport_packages: Rc::new(vec![]), carries_non_empty_wrappers: false, })]) diff --git a/src/v1/stage0_emit_core/src/lib.rs b/src/v1/stage0_emit_core/src/lib.rs index f61a0826388..0fb332f6a31 100644 --- a/src/v1/stage0_emit_core/src/lib.rs +++ b/src/v1/stage0_emit_core/src/lib.rs @@ -20,6 +20,10 @@ pub use v1_stage0_runtime::{NonEmptyBTreeSet, NonEmptyVec}; +pub mod gunbc_rust_emitted_edge { + pub use v1_stage0_std_core::gunbc_rust_emitted_edge::*; +} + pub mod v1_compiler_artifact { pub use v1_stage0_v1_artifact::v1_compiler_artifact::*; } diff --git a/src/v2/workflow/rust_crate_partition.dag b/src/v2/workflow/rust_crate_partition.dag index d312998d954..a4a9b340ffd 100644 --- a/src/v2/workflow/rust_crate_partition.dag +++ b/src/v2/workflow/rust_crate_partition.dag @@ -454,6 +454,7 @@ fn stage0_v1_artifact_modules() -> List { fn stage0_r3_emit_reexport_surface_modules() -> List { [ + "gunbc_rust_emitted_edge", "v1_compiler_artifact", "v1_compiler_infer_env", "v1_compiler_infer_items", From 0ccd6b34580928b270aa69031ac9e38222df1864 Mon Sep 17 00:00:00 2001 From: gunbc-ci-auto-heal Date: Wed, 23 Sep 2026 20:48:47 +0000 Subject: [PATCH 3/4] Enroll the emitted-edge admission witnesses on the required gate (named-module row) The REDs and controls execute over fixtures on every required run; the admission over the real seed emission still runs only at author regen, under gunbc.rung_drop witness_floor_off_the_required_gate. Co-Authored-By: Claude Opus 5.5 (1M context) --- .../stage0_emitted_edge_admission_witness_test.dag | 3 +++ src/v2/workflow/required_floor.dag | 11 +++++++++++ 2 files changed, 14 insertions(+) diff --git a/src/v2/test/claim/stage0_emitted_edge_admission_witness_test.dag b/src/v2/test/claim/stage0_emitted_edge_admission_witness_test.dag index dc40722899e..366386665e0 100644 --- a/src/v2/test/claim/stage0_emitted_edge_admission_witness_test.dag +++ b/src/v2/test/claim/stage0_emitted_edge_admission_witness_test.dag @@ -2,6 +2,7 @@ module test.claim.stage0_emitted_edge_admission_witness import std.types { Bool } import gunbc.rust_emitted_edge { rust_prelude_emitted_edges, semantic_source_reference_edge } +import v2.std.live_tree { LiveTreeDisposition, SubstrateInputsOnly } import gunbc.stage0_emitted_edge_admission { Stage0EmittedEdgesAdmitted, Stage0EmittedEdgesNotCovered, @@ -21,6 +22,8 @@ import gunbc.stage0_emitted_edge_admission { // required generated-artifact phase, which runs this admission over the whole seed emission in // required_regen_host compile_stage0 and refuses the regen on any arm but Admitted. +data live_tree_disposition: LiveTreeDisposition = SubstrateInputsOnly + // RED: a foundation crate re-exports nothing, so an edge out of the runtime into v1-infer names a // module its crate cannot see -- the E0432 a partition build would report, refused here by name. test fn an_edge_out_of_the_foundation_into_a_higher_crate_is_refused() -> Bool { diff --git a/src/v2/workflow/required_floor.dag b/src/v2/workflow/required_floor.dag index 8f70ae904e5..d033fb32da4 100644 --- a/src/v2/workflow/required_floor.dag +++ b/src/v2/workflow/required_floor.dag @@ -724,11 +724,22 @@ fn required_gate_prefixes() -> List { // DeclinedOutsideRequiredGate and a broken line would stay green. ADMITTED BY OPERATOR DEFAULT-APPROVAL on a 15-minute timeout, 2026-09-23 (escalation msg_731e354b, relayed by stern-carp-604), NOT a deliberated ruling -- the same standing as the allowance ruling itself, and to be weighed as a default. The module declares // SubstrateInputsOnly, and its only preparation growth is extdeps.languages.yaml, which the // policy module itself now imports. +// +// THE FOURTH ROW IS THE STAGE0 EMITTED-EDGE ADMISSION'S WITNESSES (gunbc#12171, parent ruling msg_7d7e1845 from loyal-swift-608). The +// admission itself runs over the real seed emission inside required-regen, which is the +// generated-artifact phase, off this gate under `gunbc.rung_drop` +// `witness_floor_off_the_required_gate`. What this row buys is narrower and stated as such: the +// admission's discriminating REDs and controls execute over supplied edges and the committed +// partition rows on every required run, so a regression in the ADMISSION is caught at merge. The +// admission over the REAL emission still runs only at author regen, and rides that drop. The +// module declares SubstrateInputsOnly and adds no preparation beyond gunbc.rust_emitted_edge and +// the stage0 partition rows. fn required_gate_authored_modules() -> List { [ "test.claim.runner_capacity_plan_witness", "test.claim.runner_capacity_realize_witness", "test.claim.corpus_census_allowance_witness_test", + "test.claim.stage0_emitted_edge_admission_witness", ] } From 8320a904d0917fae4a00630c1a2fde62371f0345 Mon Sep 17 00:00:00 2001 From: gunbc-ci-auto-heal Date: Thu, 24 Sep 2026 04:07:10 +0000 Subject: [PATCH 4/4] Emitted edges are returned only for use-lines the file carries; merge origin/main Import edges were taken before dedupe_rust_import_lines, so a line dedupe dropped still reached the partition as an edge -- measured as EmitterReverseEdge std_content_hash -> v2_std_node over the v2.compiler.compile closure, with no such line in the emitted file. rust_use_line_edges_surviving keeps a typed edge only when a surviving line names its target module. Co-Authored-By: Claude Opus 5.5 (1M context) --- src/v1/stage0/src/emitted_population.rs | 1 + src/v1/stage0/src/v1_compiler_emit_rust.rs | 214 ++++++++++++++++++--- 2 files changed, 187 insertions(+), 28 deletions(-) diff --git a/src/v1/stage0/src/emitted_population.rs b/src/v1/stage0/src/emitted_population.rs index 69cc0a7ba53..3a587ab768e 100644 --- a/src/v1/stage0/src/emitted_population.rs +++ b/src/v1/stage0/src/emitted_population.rs @@ -34,6 +34,7 @@ // src/gunbc_cli_dispatch_surface.rs // src/gunbc_namespace_reference_derived_closure_admission.rs // src/gunbc_reference_derived_candidate.rs +// src/gunbc_rust_crate_package_ident.rs // src/gunbc_rust_decl_type_overlay.rs // src/gunbc_rust_emitted_edge.rs // src/gunbc_rust_source_type_bindings.rs diff --git a/src/v1/stage0/src/v1_compiler_emit_rust.rs b/src/v1/stage0/src/v1_compiler_emit_rust.rs index 5b3b58c6e52..97e8c23036a 100644 --- a/src/v1/stage0/src/v1_compiler_emit_rust.rs +++ b/src/v1/stage0/src/v1_compiler_emit_rust.rs @@ -80,7 +80,6 @@ pub use crate::std_decl_ref::{DeclField, DeclarationRef}; use crate::std_induction::SubValueRelation::SubValueUnknown; pub use crate::std_induction::{InductiveField, SubValueRelation}; pub use crate::std_measure::millisecond_count; -pub use crate::std_measure::second; pub use crate::std_nat::Nat; pub use crate::std_occurrence_identity::NodeOccurrenceIdentity; use crate::std_occurrence_identity::NodeOccurrenceIdentity::OccurrenceSynthetic; @@ -122,7 +121,6 @@ pub use crate::std_target_representation::ExactBindingResolution; use crate::std_target_representation::ExactBindingResolution::{ ExactBindingAbsent, ExactBindingAmbiguous, ExactSourceIdentityUnavailable, ResolvedExactBinding, }; -pub use crate::std_types::NonEmptyStr; pub use crate::std_types::SourceSpan; pub use crate::std_types::{container_template_algebra, is_container_type, is_kernel_type}; use crate::v1_compiler_artifact::RenderTarget::Rust; @@ -132,7 +130,6 @@ use crate::v1_compiler_artifact::RustModuleRenderSelection::{ pub use crate::v1_compiler_artifact::{RenderTarget, RustModuleRenderSelection}; pub use crate::v1_compiler_closure_stub_v2_std_integer_rust::closure_stub_v2_std_integer_source; pub use crate::v1_compiler_closure_stub_v2_std_text_rust::closure_stub_v2_std_text_source; -pub use crate::v1_compiler_coercion::literal_suffix; pub use crate::v1_compiler_coercion::{ coerce_primitive_type, declaration_realization, declaration_realizes_natively_on_rust, is_copy, provenance_declares_structurally, realization_host_numeric_spelling, @@ -210,25 +207,25 @@ pub use crate::v1_compiler_infer_emit_info::{ use crate::v1_compiler_infer_env::GlobalBareLookupState::{ GlobalBareAmbiguousBinding, GlobalBareUniqueBinding, }; +use crate::v1_compiler_infer_env::UnitVariantPhantomLookup::{ + UnitVariantPhantomAbsent, UnitVariantPhantomEvidenceUnavailable, UnitVariantPhantomPresent, +}; pub use crate::v1_compiler_infer_env::{ - authored_name, binding_declares_span, empty_symbol_index, lookup_type_by_name, lookup_type_for, + authored_name, binding_declares_span, empty_symbol_index, lookup_binding_by_name, + lookup_type_by_name, lookup_type_for, lookup_unit_variant_phantom_type, type_reference_declaration_ref, }; -pub use crate::v1_compiler_infer_env::{GlobalBareLookupState, TypeBinding, TypeEnv}; -pub use crate::v1_compiler_infer_items::item_kind; +pub use crate::v1_compiler_infer_env::{ + GlobalBareLookupState, TypeBinding, TypeEnv, UnitVariantPhantomLookup, +}; use crate::v1_compiler_infer_items::ItemKind::{DataItem, OtherItem, TypeItem}; use crate::v1_compiler_infer_items::ItemLookup::{ItemFound, ItemLeafAmbiguous, ItemNotFound}; +pub use crate::v1_compiler_infer_items::{item_is_effectful_callee, item_kind}; pub use crate::v1_compiler_infer_items::{ ItemInfo, ItemKind, ItemLookup, ResolvedGraph, TypedModule, }; pub use crate::v1_compiler_infer_method::infer_builtin_call_type; -pub use crate::v1_compiler_infer_resolve::UnitVariantPhantomLookup; -use crate::v1_compiler_infer_resolve::UnitVariantPhantomLookup::{ - UnitVariantPhantomAbsent, UnitVariantPhantomEvidenceUnavailable, UnitVariantPhantomPresent, -}; -pub use crate::v1_compiler_infer_resolve::{ - is_width_nat_type_literal, lookup_unit_variant_phantom_type, resolve_node, -}; +pub use crate::v1_compiler_infer_resolve::{is_width_nat_type_literal, resolve_node}; pub use crate::v1_compiler_infer_service::{ extract_typed_service_name, is_typed_service_call_receiver, }; @@ -2020,7 +2017,7 @@ pub fn rust_type_arg_identity_spelling( } { std::option::Option::None } else { - match (*crate::v1_compiler_infer_resolve::lookup_unit_variant_phantom_type( + match (*crate::v1_compiler_infer_env::lookup_unit_variant_phantom_type( env.clone(), name.clone(), )) @@ -11123,16 +11120,19 @@ pub fn emit_module_full( }), reference_rows: reference_plan.rows.clone(), emitted_edges: v1_rt::concat( - v1_rt::concat( + crate::gunbc_rust_emitted_edge::rust_prelude_emitted_edges( + this_mod_filename.clone(), + ), + rust_use_line_edges_surviving( v1_rt::concat( - crate::gunbc_rust_emitted_edge::rust_prelude_emitted_edges( + v1_rt::concat(rendered_imports.edges.clone(), reference_plan.edges.clone()), + rust_use_line_edges( this_mod_filename.clone(), + uncovered_svc_use_lines.clone(), ), - rendered_imports.edges.clone(), ), - reference_plan.edges.clone(), + v1_rt::concat(merged_import_lines.clone(), uncovered_svc_imports.clone()), ), - rust_use_line_edges(this_mod_filename.clone(), uncovered_svc_use_lines.clone()), ), module_refusals: v1_rt::concat( reference_derived_row_diagnostics(reference_plan.rows.clone(), m.span.clone()), @@ -13071,7 +13071,7 @@ pub fn type_item_has_rust_nominal_shell_authority( } pub fn is_phantom_unit_variant_type_arg(env: Rc, variant_name: String) -> bool { - match (*crate::v1_compiler_infer_resolve::lookup_unit_variant_phantom_type( + match (*crate::v1_compiler_infer_env::lookup_unit_variant_phantom_type( env.clone(), variant_name.clone(), )) @@ -13625,6 +13625,156 @@ pub fn rust_use_line_edges( }) } +pub fn authored_import_binds_provider_declaration( + name: String, + import_module: String, + module_env: Option>, + typed_modules: Rc>>, + export_sets: Rc>>>, + source_indices: Rc>>, + module_index: Rc, +) -> bool { + match module_env.clone() { + std::option::Option::None => false, + Some(env) => { + match crate::v1_compiler_infer_env::lookup_binding_by_name(env.clone(), name.clone()) { + std::option::Option::None => false, + Some(binding) => { + let defining_module = match reexport_source_module_name( + name.clone(), + import_module.clone(), + typed_modules.clone(), + export_sets.clone(), + source_indices.clone(), + module_index.clone(), + ) { + Some(src) => src.clone(), + std::option::Option::None => import_module.clone(), + }; + match typed_module_by_name( + defining_module.clone(), + typed_modules.clone(), + source_indices.clone(), + module_index.clone(), + ) { + std::option::Option::None => false, + Some(tm) => { + let mut __found = false; + for item in tm.items.clone().iter().cloned() { + if (((crate::v1_std_core::authored_name_at( + source_indices.clone(), + item.clone(), + ) == name.clone()) + && ((crate::v1_compiler_emit_core_support::is_type_def_item( + item.clone(), + ) + || crate::v1_compiler_emit_core_support::is_type_alias_item( + item.clone(), + source_indices.clone(), + )) + || crate::v1_compiler_emit_core_support::is_type_decl_item( + item.clone(), + source_indices.clone(), + ))) + && match item.ident_span.clone() { + Some(sp) => { + crate::v1_compiler_infer_env::binding_declares_span( + binding.clone(), + sp.clone(), + ) + } + std::option::Option::None => false, + }) + { + __found = true; + break; + } + } + __found + } + } + } + } + } + } +} + +pub fn rust_use_line_edges_surviving( + edges: Rc>>, + final_lines: Rc>, +) -> Rc>> { + { + let named = Rc::new({ + let mut __result = Vec::new(); + for rest in Rc::new({ + let mut __result = Vec::new(); + for rest in Rc::new({ + let mut __result = Vec::new(); + for l in final_lines.iter().cloned() { + __result.push(rust_use_after_crate(l.clone())); + } + __result + }) + .iter() + .cloned() + { + if (rest.clone() != "".to_string()) { + __result.push(rest); + } + } + __result + }) + .iter() + .cloned() + { + __result.push( + match Rc::new( + rest.clone() + .split(&"::".to_string()) + .map(|s| s.to_string()) + .collect::>(), + ) + .first() + .cloned() + { + Some(m) => m.clone(), + std::option::Option::None => "".to_string(), + }, + ); + } + __result + }) + .iter() + .cloned() + .fold( + v1_rt::rc_empty_map::(), + |acc: Rc>, m: String| v1_rt::rc_map_insert(acc, m.clone(), true), + ); + Rc::new({ + let mut __result = Vec::new(); + for e in edges.iter().cloned() { + if { + let mut __all = true; + for m in crate::gunbc_rust_emitted_edge::emitted_edge_target_module(e.clone()) + .iter() + .cloned() + { + if !(crate::v1_compiler_infer_types::emit_map_has(named.clone(), m.clone())) + { + __all = false; + break; + } + } + __all + } { + __result.push(e); + } + } + __result + }) + } +} + pub fn emit_specific_import_block( import_module: String, mod_name: String, @@ -13876,10 +14026,19 @@ pub fn emit_specific_import_use_lines( { false } else { - if crate::v1_compiler_infer_emit_info::is_known_variant( + if (crate::v1_compiler_infer_emit_info::is_known_variant( type_summaries.clone(), n.clone(), - ) { + ) && (authored_import_binds_provider_declaration( + n.clone(), + import_module.clone(), + module_env.clone(), + typed_modules.clone(), + export_sets.clone(), + source_indices.clone(), + module_index.clone(), + ) == false)) + { { let mut __found = false; for e in import_module_enums.iter().cloned() { @@ -16163,8 +16322,7 @@ pub fn emit_typed_item( }), ) { Some(info) => { - (((info.service_names.clone().len() as i64) > 0) - || ((info.resource_names.clone().len() as i64) > 0)) + crate::v1_compiler_infer_items::item_is_effectful_callee(info.clone()) } std::option::Option::None => false, }; @@ -25762,8 +25920,8 @@ pub fn emit_typed_call( }); let extra_args = match callee.clone() { Some(info) => { - let has_effects = (((info.service_names.clone().len() as i64) > 0) - || ((info.resource_names.clone().len() as i64) > 0)); + let has_effects = + crate::v1_compiler_infer_items::item_is_effectful_callee(info.clone()); if has_effects.clone() { { let resource_args = Rc::new({ @@ -25928,8 +26086,8 @@ pub fn emit_typed_call( }; match callee.clone() { Some(info) => { - let has_effects = (((info.service_names.clone().len() as i64) > 0) - || ((info.resource_names.clone().len() as i64) > 0)); + let has_effects = + crate::v1_compiler_infer_items::item_is_effectful_callee(info.clone()); if has_effects.clone() { v1_rt::concat(call_str.clone(), ".await?".to_string()) } else {