140a0c0ef7
Pure refactor — first iter of the raw-buf milestone. The
hardcoded 18-arm match in try_emit_primitive_instance_body
(crates/ailang-codegen/src/lib.rs L2841-3147 pre-iter, ~305
lines) becomes a 6-line shim that consults a single registry
table in the new sibling module crates/ailang-codegen/src/intercepts.rs.
Zero behavioural change. The wrapper name survives, all 14
in-source comment-refs to try_emit_primitive_instance_body stay
valid pointers to the canonical dispatch entry.
What landed (5 tasks):
Task 1 — module skeleton: Intercept struct, INTERCEPTS static
table (empty), lookup(name), check_sig(intercept, params, ret).
mod intercepts; wired into lib.rs at L43.
Task 2 — populate: 18 free emit fns lifted from the legacy
match arms; INTERCEPTS populated with one entry per name. Three
Emitter fields (body, locals, block_terminated) and three helper
methods (emit_compare_ladder, emit_ordering_arm,
emit_direct_int_icmp_intercept) bumped to pub(crate) so the
sibling module can reach them. lower_ctor stayed at its existing
visibility — not consumed by sibling-module fns.
Task 3 — rewire dispatch: try_emit_primitive_instance_body body
becomes `match intercepts::lookup(fn_name) { Some(i) => {
check_sig(i, params, ret)?; (i.emit)(self)?; Ok(true) } None =>
Ok(false) }`. The 305-line match collapses to 9 lines.
Task 4 — fold wants_alwaysinline into the registry: every entry
in INTERCEPTS carries wants_alwaysinline: bool. The predicate
intercept_emit_wants_alwaysinline now consults the registry for
branch 1 (the literal 13-name list the predicate hardcoded). One
source of truth instead of two — closes the silent-drift class
recon flagged.
Task 5 — registry_contains_all_legacy_arms pin test: enumerates
all 18 legacy names + asserts each resolves to a registered
entry. A half-finished migration that drops any name becomes a
hard test fail.
Two judgement calls the implementer made (both behaviour-
preserving, both worth knowing):
(1) eq__Unit param shape: the plan named expected_params: &[]
per the recon's "params ignored" reading. Reality: the call
site delivers ["i8","i8"] (Unit lowers to i8 per codegen //!
header). The registry entry uses ["i8","i8"]; the emit fn
discards the operand SSAs and returns `ret i1 1` — semantically
equivalent to the legacy arm that checked only ret_ty and
ignored params. An inline rustdoc on the entry names the
rationale.
(2) intercept_emit_wants_alwaysinline has TWO branches, not one
as the plan inferred. Branch 1 = the literal 13-name list (which
the iter's drift-closure intent covers). Branch 2 = a stem-prefix
carve-out matching {ne|lt|le|gt|ge}__* that covers polymorphic-
body monomorphizations (lt__Bool, ne__Str, ne__MyADT, …) which
are NOT registry entries and never were. A literal "replace with
one-line registry lookup" would silently drop alwaysinline on
those names, breaking the bench-perf parity established in iter
operator-routing-eq-ord.1. Branch 2 stays as it was, with a
fresh comment naming what the registry covers vs. what branch 2
covers.
Follow-up consideration (not in this iter): extend the Intercept
variant to a predicate-only entry shape so branch 2 can fold
into the registry as well, OR accept the carve-out as the final
shape. Either is reasonable. Filed as a backlog idea (see Gitea
issue created post-commit if labelled).
Verification:
cargo test --workspace → 667 passed, 0 failed, 2 ignored
(baseline was 666 + 2 ignored;
+1 from registry_contains_all_legacy_arms)
Four E2E ratifiers GREEN (named in spec § Testing strategy
raw-buf.1):
- eq_primitives_smoke_compiles_and_runs (crates/ail/tests/e2e.rs)
- compare_primitives_smoke_prints_1_2_3_thrice (crates/ail/tests/e2e.rs)
- float_compare_smoke_prints_true_true_false
- eq_ord_polymorphic_runs_end_to_end
Alwaysinline pins GREEN (regression net for branch-2 carve-out):
- crates/ailang-codegen/tests/eq_primitives_pin.rs
- crates/ail/tests/prelude_eq_alwaysinline_ir_pin.rs
New pin GREEN:
- intercepts::tests::registry_contains_all_legacy_arms
Diff size: lib.rs −318 / +26 (net −292); intercepts.rs +488 (new
file). Net repository LOC delta: +196. The size reduction in
lib.rs is the wrong proxy — the value is the consolidation: one
table, one drift-closed predicate, one pin test enumerating the
migration surface.
The raw-buf.2 iter will rename crates/ailang-kernel-stub/ to
crates/ailang-kernel/ and reshape it as the family-crate that
hosts raw_buf alongside kernel_stub. The registry shipped here
is the substrate raw-buf.3 will plug RawBuf's 12 codegen
intercepts into.