Compiler design / 16. Target planning and validation
Per-function target assignment and validation catch capability mismatches before any backend emits code.
Target planning receives an already-validated lifetime topology. It assigns targets and checks capabilities; it does not change region ownership or source legality.
Semantically valid Moth can still be unhostable on a chosen target. A function that touches the DOM does not belong in a pure Wasm partition that has no DOM. A backend should learn that before it emits half a module and shrugs.
Target planning assigns functions. Target validation checks the assignment against capabilities.
The build system supplies validation roots and candidate assignments from entry or package link planning. The compiler owns validation semantics over those inputs.
Distinguish two ideas people conflate:
A function can be perfectly typed and still require a capability its assigned target lacks.
For the greeting walkthrough, start, greet and any template runtime work arrive with link facts and capability requirements. Even a humble string page teaches the machinery that larger apps need for DOM and friends.
Diagram placeholder: Each function carries capability facts and target affinity
Caption: simplified link input. Question: what constrains assignment?
Some functions are born with affinity. A JavaScript-owned start that must orchestrate page lifecycle wants the JS side. A DOM-touching helper wants JS. Neutral pure computation may default toward Wasm where the design supports it.
Requirements propagate backwards along call edges. If a callee needs the DOM, callers that must reach it inherit the constraint under the accepted propagation rules. Neutral callees can still sit in Wasm when callers bridge correctly.
Diagram placeholder: A DOM requirement travels from callee to callers
Caption: accepted propagation rule. Question: why does a caller move targets?
A clean mental loop:
Determinism matters. The same program should not flip partitions because a hash map iterated differently at breakfast.
Diagram placeholder: One reachable union splits into target-labelled functions
Caption: conceptual assignment. Question: where does each function run?
Mixed output needs bridges.
JavaScript-to-Wasm calls may use wrappers under explicit ABI rules.
Wasm-to-JavaScript Moth calls remain prohibited after propagation in the accepted model. The planner should push the JS requirement outward rather than leave a forbidden reverse edge for emission to discover.
That asymmetry is deliberate engineering, not an accident of today's engine.
Diagram placeholder: JS-to-Wasm wrapper is allowed while Wasm-to-JS edge is rejected
Caption: exact edge rule simplified. Question: which bridge is legal?
Partitioning is entry-specific. Different entries may need different physical variants of shared logic when their capability sets differ. Variant keys make those physical artefacts addressable.
The check command plans and validates, then stops before writing a full page output set. Tooling overlays extend analysis. They do not become a second artefact builder competing with HTML output.
Unsupported features in unreachable private functions should not fail validation.
Alternative: compile a whole page to one target, or let emission discover unsupported calls mid-write.
Choice: per-function deterministic partitioning with explicit validation.
Benefit: mixed output can keep browser work in JavaScript and neutral work in Wasm.
Cost: wrappers, ABI rules and assignment reasons add planning machinery.
html_project_backend_wasm_final_implementation_plan.md.You leave with validated target assignments, capabilities, imports and physical variants. Next: how lowerers turn these explicit inputs into JavaScript and Wasm without reopening source.