journal: 2026-05-08 codegen split tidy
Records the four-phase reorganisation that moved 2470 lines out of lib.rs into purpose-named sibling submodules. Captures the visibility model (descendant-module privacy + selective pub(crate)), the deliberate non-extractions (lower_term, the app/call cluster), and the framing as a navigability tidy rather than a feature-driven change.
This commit is contained in:
+100
@@ -8351,3 +8351,103 @@ post-18g-tidy follow-ups: all closed. Decision 9 has been
|
|||||||
re-framed (commit `f10a77e`) to match the orchestrator's
|
re-framed (commit `f10a77e`) to match the orchestrator's
|
||||||
dual-allocator stance. Next iter is queue-driven; nothing
|
dual-allocator stance. Next iter is queue-driven; nothing
|
||||||
load-bearing is open.
|
load-bearing is open.
|
||||||
|
|
||||||
|
## 2026-05-08 — codegen split: lib.rs from 5295 → 2825 lines
|
||||||
|
|
||||||
|
User asked mid-session "wie groß ist die codebase mittlerweile?
|
||||||
|
Kannst du sie noch kontrollieren?" The honest answer was that
|
||||||
|
`crates/ailang-codegen/src/lib.rs` was the one file flagged for
|
||||||
|
navigability — 5295 lines monolithic, every codegen concern
|
||||||
|
sharing a single namespace. Decision delegated by the user
|
||||||
|
("Das musst du selbst entscheiden"). With the 18g family closed
|
||||||
|
and tests dense, the window for a mechanical move-only refactor
|
||||||
|
was as good as it gets.
|
||||||
|
|
||||||
|
Executed as four sequential commits, full
|
||||||
|
`cargo test --workspace` between each, no behaviour change.
|
||||||
|
Each phase moved a coherent cluster into a sibling submodule
|
||||||
|
under `crates/ailang-codegen/src/`:
|
||||||
|
|
||||||
|
- **Phase 1** (`84ba83d`): `synth.rs` (216 lines) +
|
||||||
|
`subst.rs` (319 lines). The free-function tail of lib.rs:
|
||||||
|
LLVM IR shaping helpers and the monomorphisation
|
||||||
|
substitution pipeline.
|
||||||
|
- **Phase 2** (`86989a7`): `drop.rs` (696 lines). All RC-
|
||||||
|
allocator drop work — per-type drop fns, per-let-close
|
||||||
|
drop dispatch, closure-pair drops.
|
||||||
|
- **Phase 3** (`86406ac`): `match_lower.rs` (935 lines).
|
||||||
|
`Term::Ctor`, `Term::ReuseAs`, `Term::Match` lowering. The
|
||||||
|
`lower_match` body (≈500 lines) is the single largest
|
||||||
|
method left in the project; moving it gave the biggest
|
||||||
|
navigability win.
|
||||||
|
- **Phase 4** (`bea5c92`): `lambda.rs` (447 lines).
|
||||||
|
`Term::Lam` + closure machinery (capture analysis, env
|
||||||
|
construction, deferred per-pair drop fns).
|
||||||
|
|
||||||
|
Final layout (lib.rs is now the Emitter setup + the
|
||||||
|
`lower_term` mass dispatcher + the lookup helpers + tests):
|
||||||
|
|
||||||
|
```
|
||||||
|
lib.rs 2825 Emitter struct, lifecycle, lower_term
|
||||||
|
dispatcher, app/eq/effect lowering,
|
||||||
|
lookup helpers, synth_arg_type,
|
||||||
|
monomorphisation entry, tests.
|
||||||
|
match_lower.rs 935 Term::Ctor / ReuseAs / Match.
|
||||||
|
escape.rs 722 escape analysis (predates split).
|
||||||
|
drop.rs 696 per-type + per-let-close drops.
|
||||||
|
lambda.rs 447 Term::Lam + closure machinery.
|
||||||
|
subst.rs 319 substitution + unification.
|
||||||
|
synth.rs 216 IR shaping helpers + builtin types.
|
||||||
|
```
|
||||||
|
|
||||||
|
### Visibility model
|
||||||
|
|
||||||
|
Rust's "private = visible to module + descendants" rule
|
||||||
|
made the split cheap. The `Emitter` struct and its private
|
||||||
|
fields stay private in `lib.rs`; submodules (drop, lambda,
|
||||||
|
match_lower) can read those fields directly through normal
|
||||||
|
descendant-module privacy. Only methods that lib.rs calls
|
||||||
|
back into the submodule needed `pub(crate)` (the entry-point
|
||||||
|
methods); helpers used only inside a submodule stayed
|
||||||
|
private. Mirroring this, a small set of lib.rs-side helpers
|
||||||
|
that submodules call back into were upgraded to
|
||||||
|
`pub(crate)`: `start_block`, `lower_term`, `fresh_ssa`,
|
||||||
|
`fresh_id`, `synth_arg_type`, `collect_owner_local_types`,
|
||||||
|
`lookup_ctor_by_type`, `lookup_ctor_in_pattern`. No fields
|
||||||
|
needed `pub(crate)`.
|
||||||
|
|
||||||
|
### What was deliberately not done
|
||||||
|
|
||||||
|
- **No behaviour change.** Not a single character of
|
||||||
|
generated IR is different. The split is purely a
|
||||||
|
reorganisation. (Verified by 66/66 e2e tests passing
|
||||||
|
byte-identically across all four commits.)
|
||||||
|
- **No method signatures changed.** Visibility upgrades only
|
||||||
|
(`fn` → `pub(crate) fn`) on helpers crossed by the new
|
||||||
|
module boundary. No parameter or return-type changes.
|
||||||
|
- **No further extraction.** `lower_term` is 395 lines of
|
||||||
|
pure dispatch into other methods; splitting its arms into
|
||||||
|
per-shape files would force every shape's dispatcher to
|
||||||
|
re-enter through a `pub(crate)` boundary and would split
|
||||||
|
the term-shape ↔ lowered-shape correspondence across
|
||||||
|
files. Kept whole. Same call for the
|
||||||
|
`lower_app`/`lower_polymorphic_call`/`emit_call`/
|
||||||
|
`emit_indirect_call` cluster — they are too tightly
|
||||||
|
coupled to the `Emitter`'s dispatch state to extract
|
||||||
|
cleanly.
|
||||||
|
|
||||||
|
### What this enables
|
||||||
|
|
||||||
|
The biggest concrete win is for `ailang-architect` and
|
||||||
|
debugging conversations: a "what does the drop emission do?"
|
||||||
|
question now reads one 696-line file instead of grepping
|
||||||
|
through five thousand lines. Same for the closure machinery,
|
||||||
|
the match lowering, and the substitution pipeline. Future
|
||||||
|
iters that touch these subsystems get a smaller working
|
||||||
|
context.
|
||||||
|
|
||||||
|
The split is not motivated by a coming feature, and no
|
||||||
|
queued iter required it. It is a tidy paid for navigability
|
||||||
|
alone — the kind of work that compounds across future
|
||||||
|
sessions without showing up in any single one's bench
|
||||||
|
numbers.
|
||||||
|
|||||||
Reference in New Issue
Block a user