Write each package's build artifacts flat to lib/rescript
Why
Every artifact existed in lib/bs, nested like the sources, and again in lib/ocaml, flat, and lib/bs also held copies of the sources and the generated JavaScript (#9151). The build now writes one flat lib/rescript.
modifiedLayout artifact directory of a package
text
text
modifiedPublication a compiled module's ASTs, interface and typed tree
text
modifiedFreshness Build_freshness, Compiler_info, namespace maps
representation
The compiler keeps early cutoff with one copy of each interface: it replaces an interface it cannot read instead of failing, and a .cmj cut short after its digest no longer counts as unchanged. Stale public JavaScript is removed when an AST proves the build generated it; the JS mirror and the build.ninja marker are gone. Clean empties lib/rescript but for the lock files.
Review
- Why hold ASTs as well as interfaces? A failed parse used to leave its AST in lib/bs only; with one copy it would look current and the next build would skip the parse and lose the error.
- Why rename into place, with an in-place write only as a fallback? A build killed during an in-place write leaves a truncated file, and a truncated typed tree with a fresh time counts as compiled for good. On Windows the rename fails while an editor has the file open without delete sharing, so the file is then written in place.
- Why date an AST back instead of removing it? A later compile of the same build or watch session may still read it. Time 1 is below any real source time except the epoch, which is why such an AST is always parsed again.
- What about a removed module's working .cmi, which cleanup deferred? It went to lib/bs, outside the include path. In lib/rescript it would let dependents compile against a deleted module, so it is removed at once.