Commit Graph

3 Commits

Author SHA1 Message Date
Brummel 7e5c95f6c6 runtime: half-retirement of Boehm — flip CLI default to --alloc=rc
The dual-allocator policy from 2026-05-08 made Boehm the CLI default
"for general workloads", with rc selected explicitly for real-time-
sensitive code. That asymmetry contradicted Decision 10: rc + uniqueness
inference is the canonical memory model AILang's typechecker enforces,
and the CLI was teaching the opposite mental model to users and prompt-
fed LLMs.

This iter flips the asymmetry without removing Boehm:

  - main.rs: default_value gc -> rc for build/run; help text rewritten
    so rc is the canonical path and gc is the parity oracle.
  - DESIGN.md Decision 9 retitled "RC canonical, Boehm parity oracle"
    and rewritten end-to-end. Migration plan step 6 updated to a
    two-step retirement (default-flip done, full removal gated).
  - DESIGN.md pipeline diagram: rc-first, gc-as-oracle.
  - JOURNAL: 2026-05-09 entry recording the call, what shipped,
    the bug the flip surfaced, the gating condition for full
    Boehm removal.

Bug surfaced by the flip and fixed in the same iter:
codegen/drop.rs build_pair_drop_fn emitted `getelementptr inbounds
{{ ptr, ptr }}, ...` via push_str (not format!), so the doubled
braces leaked verbatim into the IR. LLVM parsed it as a struct-of-
struct, the GEP referenced a non-existent field, and clang failed.
Invisible under the old gc default (no per-type drop fns) and
invisible to the 8 explicit _with_alloc("rc") tests (none of them
escaped a closure-with-captures). Caught immediately by two corpus
tests once rc became the baseline: closure_captures_let_n,
local_rec_as_value_capture_demo. Fix: single braces. Tests stay
as the regression guard.

The episode is the canonical justification for keeping the GC arm
as a parity oracle for now — a months-old codegen bug found by
flipping the baseline column.

288 passed / 0 failed / 3 ignored, unchanged.
2026-05-09 00:14:56 +02:00
Brummel caefcf996a codegen rc: tag-conditional partial-drop helper closes 3 carve-outs
Three sibling sites previously fell back to shallow `ailang_rc_dec`
when a binder had non-empty `moved_slots` and a dynamic runtime ctor
tag: Iter B Own-param dec at fn-return (lib.rs), Iter A arm-close
pattern-binder dec (match_lower.rs), and emit_inlined_partial_drop's
non-Ctor branch (drop.rs). Shallow freed the outer cell but did not
walk the unmoved ptr fields — silent leak.

Adds `emit_partial_drop_fn_for_type`: a per-ADT helper structurally
parallel to `emit_drop_fn_for_type` but taking an i64 moved-slots
bitmask. Each ptr-field's dec is gated on the corresponding mask
bit; the outer box is dec'd at join. Emitted alongside the per-type
drop fn for every ADT under --alloc=rc.

Three call sites rewritten to resolve the partial_drop symbol from
the binder's static type and build the mask from `moved_slots`.

Three RED-then-GREEN fixtures (rc_own_param_/rc_match_arm_/
rc_app_let_partial_drop_leak) pin the carve-outs in regression
coverage; live cell counts go from 3/1/3 (pre-fix) to 0/0/0.
e2e count: 66 → 69.

The pre-existing `alloc_rc_own_param_dec_at_fn_return` IR-shape
assertion is widened to accept `partial_drop_<m>_<T>(%arg_xs,
i64 mask)` as a third valid drop shape (the canonical fu2 case).

Closes the JOURNAL queue's only remaining iter; the "wait for
organic fixture" stance from the 18g tidy is retracted — known
leaks are bugs, CLAUDE.md's TDD rule covers them autonomously.
2026-05-08 16:25:40 +02:00
Brummel 86989a7cb5 codegen tidy: extract drop emission into drop.rs
Second slice of the codegen split. Pulls every method that emits
or dispatches drop fns into a dedicated module. No behaviour
change.

Cluster A (per-type drop bodies):
  - emit_drop_fn_for_type — recursive cascade, ADT default.
  - emit_iterative_drop_fn_for_type — Iter 18e worklist variant.
  - field_is_same_type — same-ADT predicate (private to drop.rs).
  - field_drop_call — per-field drop-symbol resolver.

Cluster B (per-let-close dispatch):
  - is_rc_heap_allocated — Iter 18c.3 trackability gate, widened
    in 18g.2 to include Own-returning App.
  - synth_callee_ret_mode — ret_mode lookup helper (private).
  - drop_symbol_for_binder — picks the symbol Term::Let calls
    at scope close.
  - emit_inlined_partial_drop — partial-drop emission for
    pattern-moved slots.

Cluster C (closure drops):
  - build_env_drop_fn — env's drop fn body builder.
  - build_pair_drop_fn — pair's drop fn body builder.

Visibility: methods called from lib.rs are pub(crate);
helpers used only inside drop.rs (field_is_same_type,
synth_callee_ret_mode) stay private. Three Emitter helpers
in lib.rs that drop.rs calls back into were upgraded to
pub(crate): synth_arg_type, lookup_ctor_by_type, fresh_ssa.
Field access from drop.rs into the parent's private Emitter
fields uses the standard descendant-module privacy lane.

lib.rs drops from 4800 → 4139 lines. drop.rs is 580 lines.
cargo test --workspace clean: 66/66 e2e + 26/26 codegen +
all sibling crates pass.
2026-05-08 15:47:59 +02:00