Compiler design / 15. Linking, entries and reachability
Compilation and activation stay separate. Entry assembly selects roots and builds a reachable function union.
Compilation and activation are different verbs.
A module can compile completely, including its dormant top-level work, and still do nothing at runtime until an entry selects it. The seed can be fully formed and still sleep. Imports do not secretly run initialisers because someone mentioned a name.
Every normal root may carry dormant top-level runtime work and page fragments. That work is parsed, type-checked, lowered, borrow-validated and locally lifetime-analysed before any entry activates it.
The compiler synthesises an implicit start for a normal root. Properties that matter:
Error! return channel)Compilation never activates start. Entry assembly may activate it once after the module already compiled.
Support roots and the project package facade have no implicit start.
In the walkthrough, @page.moth owns dormant root work and a page fragment. greeting.moth remains an imported module. Importing greet does not run page-level statements from greeting's root, because greeting is not the activated entry root.
Diagram placeholder: All modules compile before one selected root activates
Caption: exact conceptual distinction. Question: when does root work run?
Diagram placeholder: page root owns a dormant start selected by one entry
Caption: simplified root map. Question: why do imported roots stay dormant?
Fragments split into useful kinds:
start runsImported modules do not run their root work merely because a consumer imported a function. Activation is explicit and entry-scoped.
The paragraph in @page.moth enters through fragment metadata and, if needed, runtime production. It does not require the backend to re-read the .moth file.
Diagram placeholder: Folded and runtime fragments preserve source indexes
Caption: exact ordering principle simplified. Question: where does the paragraph enter?
The build system selects entry candidates and builds an EntryAssembly from existing facts: which root activates, which fragments apply, which metadata the builder needs.
Contrast ProjectPackageAssembly, which carries project-wide assembly privilege for the facade. Different job, shared taste for explicit data.
Builders consume compiled graphs and explicit plans. They do not rediscover source structure by walking directories again.
From activated start, the linker walks call edges through:
greet and other source functionsThe result is a reachable function union for the entry. Unreachable private helpers need not lower. Unsupported features in unreachable private functions need not fail target validation.
Reachability here records syntactic function and CFG reachability. It does not perform clever constant-branch tree shaking as its definition of truth. Some target checks may still inspect semantic types with the paired environment when raw reachability is not enough.
Link facts also carry capabilities and assets the entry will need.
Diagram placeholder: Reachable nodes are highlighted from start, with an unreachable helper left aside
Caption: teaching graph. Question: what reaches the backend?
The exact reachable union is also the point where local lifetime summaries can be instantiated against actual callers, entry/package roots, and builder-supplied lifecycle roots.
Project/link validation completes the lifetime topology before target assignment. Linking does not reopen source or mutate HIR.
Linking consumes compiled facts. It never triggers source compilation of a module that should have been in the graph already.
If a function is missing, the graph or artefact stage failed earlier. Link planning does not become a second compiler driver.
Target capability failures wait for the next article even when they appear adjacent in real builds.
Alternative: activate imported module initialisers automatically, or parse only the active root and discover callees late.
Choice: compile dormant work once, activate selected roots explicitly.
Benefit: imports remain predictable and entry planning stays data-driven.
Cost: the builder must carry explicit root and fragment metadata.
start, entry assembly and exact reachable union.You leave with explicit roots, a reachable function union, and a validated project/link lifetime topology. Next: target assignment.