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

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ module test.claim.emitted_lib_rs_module_declaration_witness_test

// Permanent regression control for the emitted `lib.rs` module list.
//
// THE DEFECT, now repaired: v1.compiler.emit_rust emit_lib_rs_from_files derived
// THE DEFECT, now repaired: v1.compiler.emit_rust emit_lib_rs_from_paths derived
// its module declarations from the files this emit actually produced, and then
// appended `pub mod v1_interpreter_dispatch_generated;` UNCONDITIONALLY from a
// hand-authored string. For the stage0 crate that module is real — a different
Expand Down
2 changes: 1 addition & 1 deletion src/v1/04_emit_info.dag
Original file line number Diff line number Diff line change
Expand Up @@ -568,4 +568,4 @@ fn add_emit_item_summary(state: EmitInfoBuildState, item: Node, source_indices:
}
}

data emit_dependency_registration_dissolve_on_note: DissolutionCondition = unbound_dissolution(description: "dissolve-on (FreeMonoid pass 2026-07-20): collect emitted cross-module type/path refs during emit into one authority; derive (a) use-lines via build_shared_types + emit_faithful_text_carrier_import_lines and (b) closure pub-mod membership via emit_lib_rs_from_files from that set. Instance-patch interim: faithful corpus emits carrier import lines per module unless locally defined (FreeMonoid/Char/NonEmptyStr/Int); closure projections (v1.compiler.closure_stub_v2_std_text_rust and closure_stub_v2_std_integer_rust) when refs exist but the real v2.std.text or v2.std.integer module is absent from narrow typed.modules — projections are NOT parallel modeling authorities (see each stub module dissolve_on_note); they dissolve when the ref set includes the real module in the closure.")
data emit_dependency_registration_dissolve_on_note: DissolutionCondition = unbound_dissolution(description: "dissolve-on (FreeMonoid pass 2026-07-20): collect emitted cross-module type/path refs during emit into one authority; derive (a) use-lines via build_shared_types + emit_faithful_text_carrier_import_lines and (b) closure pub-mod membership via emit_lib_rs_from_paths from that set. Instance-patch interim: faithful corpus emits carrier import lines per module unless locally defined (FreeMonoid/Char/NonEmptyStr/Int); closure projections (v1.compiler.closure_stub_v2_std_text_rust and closure_stub_v2_std_integer_rust) when refs exist but the real v2.std.text or v2.std.integer module is absent from narrow typed.modules — projections are NOT parallel modeling authorities (see each stub module dissolve_on_note); they dissolve when the ref set includes the real module in the closure.")
253 changes: 200 additions & 53 deletions src/v1/05_emit_rust.dag

Large diffs are not rendered by default.

31 changes: 30 additions & 1 deletion src/v1/artifact.dag
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,33 @@ type ArtifactKind
| Frontend
| GeneratedSupport

// WHICH MODULES THIS ARTIFACT RENDERS, and it is a property of the PLAN rather than of the
// emitter, because the plan is where "what is being built" is already decided.
//
// RenderEveryModule is the whole closure, byte for byte what the emitter always produced.
// RenderSelectedMirrors carries the exact derived closure of a change -- the basenames a regen
// round's affected-set bound selected -- and the emitter renders those and no others.
//
// THE SELECTION BOUNDS RENDERING AND NOTHING ELSE. Every population-denominated answer the
// emitter gives (the crate's module list, the emitted-population manifest, the closure-stub
// decision) is derived from the resolved graph or from paths, so it is identical under both
// arms. A selection that could change one of those answers would be a scope silently deciding
// what the artifact IS, rather than which of its files this round re-renders.
//
// There is no arm meaning "select nothing in particular": an empty basename list renders no
// modules, which is the honest answer for a round whose change touches no mirror, and is a
// different state from RenderEveryModule rather than a degenerate spelling of it.
type RustModuleRenderSelection
= RenderEveryModule
| RenderSelectedMirrors { basenames: List<String> }

type Artifact {
name: String
kind: ArtifactKind
target: RenderTarget
entry_modules: List<String>
dependencies: List<String>
module_selection: RustModuleRenderSelection
}

type BoundaryKind
Expand Down Expand Up @@ -54,12 +75,20 @@ type ArtifactOutput {
}

fn default_artifact_plan(root_modules: List<String>, target: RenderTarget) -> ArtifactPlan {
selected_artifact_plan(root_modules: root_modules, target: target, selection: RenderEveryModule)
}

// ONE BODY, TWO NAMED ENTRY POINTS. `default_artifact_plan` is this call with the whole-closure
// arm supplied, so a caller states which question it asks by naming it rather than by passing a
// flag, and there is no second plan constructor to drift from this one.
fn selected_artifact_plan(root_modules: List<String>, target: RenderTarget, selection: RustModuleRenderSelection) -> ArtifactPlan {
plan_artifacts(rule: Explicit { artifacts: [Artifact {
name: "default",
kind: ServiceBinary,
target: target,
entry_modules: root_modules,
dependencies: []
dependencies: [],
module_selection: selection
}] })
}

Expand Down
2 changes: 1 addition & 1 deletion src/v1/closure_stub_v2_std_integer_rust.dag
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ module v1.compiler.closure_stub_v2_std_integer_rust

// dissolve-on (FreeMonoid pass 2026-07-20): NOT a second v2.std.integer authority — a minimal
// closure projection when narrow typed.modules omits v2.std.integer but emitted refs need Int.
// Dissolves when emit_lib_rs_from_files derives pub-mod membership from the emitted ref set and
// Dissolves when emit_lib_rs_from_paths derives pub-mod membership from the emitted ref set and
// emits the real v2.std.integer module instead.

fn closure_stub_v2_std_integer_source() -> String {
Expand Down
2 changes: 1 addition & 1 deletion src/v1/closure_stub_v2_std_text_rust.dag
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ module v1.compiler.closure_stub_v2_std_text_rust

// dissolve-on (FreeMonoid pass 2026-07-20): NOT a second v2.std.text authority — a minimal closure
// projection when narrow typed.modules omits v2.std.text but emitted refs need
// crate::v2_std_text::. Dissolves when emit_lib_rs_from_files derives pub-mod membership from the
// crate::v2_std_text::. Dissolves when emit_lib_rs_from_paths derives pub-mod membership from the
// emitted ref set and emits the real v2.std.text module instead.

fn closure_stub_v2_std_text_source() -> String {
Expand Down
42 changes: 37 additions & 5 deletions src/v1/compile.dag
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ import v1.compiler.infer_types { algebra_field_kind_name }
import v1.compiler.emit_core_support { EmitResult, escape_json_string }
import v1.compiler.emit { unmodeled_file_transport_diagnostics }

import v1.compiler.emit_rust { emit_rust }
import v1.compiler.emit_rust { emit_rust_selected }

import v1.compiler.emit_python { emit_python }

Expand All @@ -84,7 +84,7 @@ import std.termination {

import v1.compiler.ownership { OwnershipProof, OwnershipDecision, SharedError, analyze_ownership }

import v1.compiler.artifact { ArtifactPlan, Artifact, RenderTarget, Dag, default_artifact_plan }
import v1.compiler.artifact { ArtifactPlan, Artifact, RenderTarget, Dag, default_artifact_plan, selected_artifact_plan, RustModuleRenderSelection, RenderEveryModule }

import v1.compiler.dag_collect_support { DagCollectAcc, json_quote, connective_name }

Expand Down Expand Up @@ -240,7 +240,7 @@ fn emit_artifact(typed: ResolvedGraph, artifact: Artifact) -> EmitResult {
return EmitResult { files: [], diagnostics: unmodeled_transports }
}
match artifact.target {
Rust => emit_rust(typed: typed)
Rust => emit_rust_selected(typed: typed, selection: artifact.module_selection)
Python => emit_python(typed: typed)
Go => emit_go(typed: typed)
Dag => emit_dag_artifact(typed: typed)
Expand Down Expand Up @@ -1199,6 +1199,18 @@ fn compile_sources(sources: List<SourceFile>, target: RenderTarget) -> PipelineR
)
}

// THE CHANGE-DENOMINATED ENTRY. Same pipeline, same resolved graph, same diagnostics -- the
// selection reaches emission only, where it decides which modules are RENDERED. A caller that
// supplies RenderEveryModule here has written `compile_sources` the long way, which is why that
// wrapper stays the name for the whole-closure question.
fn compile_sources_selected(sources: List<SourceFile>, target: RenderTarget, selection: RustModuleRenderSelection) -> PipelineResult {
emit_resolved_for_target_selected(
resolved: compile_to_resolved_with_options(sources: sources, options: default_compile_pipeline_options()),
target: target,
selection: selection
)
}

fn compile_sources_with_options(sources: List<SourceFile>, target: RenderTarget, options: CompilePipelineOptions) -> PipelineResult {
emit_resolved_for_target(
resolved: compile_to_resolved_with_options(sources: sources, options: options),
Expand Down Expand Up @@ -1319,6 +1331,25 @@ fn compile_to_resolved_with_options(sources: List<SourceFile>, options: CompileP
}

fn emit_resolved_for_target(resolved: ResolvedPipelineResult, target: RenderTarget) -> PipelineResult {
emit_resolved_for_target_selected(resolved: resolved, target: target, selection: RenderEveryModule)
}

// WHY THE REFUSAL PRECONDITION A SCOPED ROUND RESTS ON LIVES HERE, one binding down.
//
// Under RenderSelectedMirrors the emitter observes import refusals only for the modules it
// rendered, so a reader is owed why that is EXACT rather than merely cheaper. It is exact
// because of `final_files` below: an emit carrying one error diagnostic returns NO FILES AT ALL.
// A committed mirror is therefore a file some emit returned, and no emit returns a file while
// any module in the closure refuses. So a tree that exists is a tree whose whole closure emitted
// clean, and the modules a scope declined to render had nothing to say.
//
// This is a construction rather than a claim about it: the `if` below is what makes the
// implication true, and `an_emit_that_refuses_hands_back_no_files` in
// `v1_compiler.required_regen_host` is its discriminating execution -- a fixture whose emit
// refuses, asserted to produce zero files rather than the ones that did render. It runs in the
// required unit step, so deleting the `if` goes red there, which is the only form this argument
// can take that a later reader can check.
fn emit_resolved_for_target_selected(resolved: ResolvedPipelineResult, target: RenderTarget, selection: RustModuleRenderSelection) -> PipelineResult {
match emittable_graph(resolved: resolved) {
Absent =>
PipelineResult {
Expand All @@ -1331,9 +1362,10 @@ fn emit_resolved_for_target(resolved: ResolvedPipelineResult, target: RenderTarg
}
Present { value: emittable } => {
let typed = emittable.graph
let artifact_plan = default_artifact_plan(
let artifact_plan = selected_artifact_plan(
root_modules: typed.modules |> map(m => authored_name_at(source_indices: resolved.source_indices, node: m.module)),
target: target
target: target,
selection: selection
)
let _ = trace_mark("compile.emit.begin")
let emit_result = emit_from_artifact_plan(emittable: emittable, artifact_plan: artifact_plan)
Expand Down
Loading
Loading