Repository navigation
self-host P1: use between modules -- pin the refusals, record the import protocol and its blockers #7378
Description
Part of #5980 (phase P1, lane 2: pub and use).
Today the core refuses every use with code 1 (use lexes as a bad word). This issue records why that stays true for now, pins the refusals as fixtures, and sets down what real imports need.
What gen-c does with use
bootstrap/src/use_resolve.rs is a source-to-source splice: it finds the specs/ root above the input, maps use a::b::c to <specs>/a/b/c.t27, takes the transitive closure of the declarations the importer names, appends them after a // ---- resolved from use (t27c) ---- header (sorted by origin, then name), and compiles the result. A use line itself writes no C byte. If the spliced text fails to compile, gen-c silently compiles the raw text instead.
Probed on the Railway lab (master cd6708d), four places where that splice is lossy or wrong while gen-c exits 0:
- A.
;prose counts as a reference: a prose line naming an imported fn splices that fn and everything it uses. (filed: gen-c use splice: identifiers in ; prose pull declarations #7379) - B. An imported const is spliced as
#define name value, so a local of the same name in the importer becomesint64_t 3 = ...; the C does not compile. (filed: gen-c use splice: imported const #define captures a same-named local, broken C with exit 0 #7380) - C. An imported module
varorletis never spliced (decl_nameknows fn, struct, enum, const and type only); the C names an undeclared global. (filed: gen-c use splice: imported module var and let are never spliced, undeclared global with exit 0 #7381) - D. A
usenaming no spec only warns (t27c gen: a use it cannot resolve exits 0 and drops the import #7176).
Why the core cannot follow yet
The core reads one module on stdin. Following gen-c needs the text of every module the closure reaches, so imports require a driver protocol (for example: the driver concatenates the importer and its resolved deps with a separator the core recognises) plus a reimplementation of resolve's selection and ordering rules in t27. Two blockers:
- Capacity. The core's source is at 65341 of a 65536-byte cap (t27core: nested arrays and list initializers, byte-identical to gen-c (Closes #7361) #7374), and its whole C output must fit OUT_MAX (65536) whatever the module split, because gen-c's splice concatenates. The cap lift the slice-3 lane is working on comes first.
- Agreement. Byte identity with gen-c would mean reproducing A to C. Those get fixed in gen-c first, per the self-host rule (refuse what gen-c gets wrong).
Splitting t27core into modules is not clean today for the same reason: t27core_ddc.t27 imports the core with use and restates its module vars, because use imports no var (C above).
This slice
Data only, no core byte, under bootstrap/tests/fixtures/core_selfhost/:
specs/selfhost_use/use_dep.t27-- the module the fixtures import. gen-c run in place finds thisspecs/dir, so each fixture reproduces its defect witht27c gen-c <fixture>.refuse/e1_use_whole_module.t27(lossless import, refused because the core reads one module),refuse/e1_use_prose_pulls.t27(A),refuse/e1_use_const_captures_local.t27(B),refuse/e1_use_module_var.t27(C),refuse/e1_use_no_spec.t27(D).
When A to C land and the cap is lifted, the next slice teaches the core the protocol above and moves e1_use_whole_module to accept/.
Activity