Files
AILang/docs/journals/2026-05-14-iter-rpe.1.md
T
Brummel 6fdb45d2f2 iter rpe.1: retire per-type print effect-ops
Single iter shipping the post-milestone-24 follow-up named in
docs/specs/2026-05-14-retire-per-type-print-effects.md. After this
iter the only surviving direct-output effect-op is `io/print_str`;
all per-type print primitives are replaced by the polymorphic
`print` helper (prelude, iter 24.3).

Components:
- 92 examples/*.ail fixtures migrated (do io/print_<T> x) →
  (app print x); 6 .prose.txt snapshots regenerated via `ail prose`.
- Four-site lockstep compiler deletion: crates/ailang-check/src/builtins.rs
  (3 effect_ops.insert blocks + 3 list() rows + the
  install_io_print_float_signature test + module + EffectOpSig
  doc-comments); crates/ailang-codegen/src/lib.rs lower_app
  (3 arms + lowers_io_print_float test); crates/ailang-codegen/src/synth.rs
  builtin_effect_op_ret match-arm pattern. Dead `intern_string`
  helper removed as a follow-up.
- Five incidental test-body migrations (ailang-check x2, ailang-core
  spec_drift + design_schema_drift, ailang-surface/src/lex.rs,
  ailang-prose/src/lib.rs round-trip test).
- Cat B test-harness patch: six IR-shape tests in
  crates/ail/tests/e2e.rs gained a monomorphise_workspace call
  before lower_workspace_with_alloc so they follow the same
  pipeline as `ail build` (the home-rolled desugar+lift loop
  stayed because mono's precondition is "already lifted"; mono
  inserts after lift).
- Six doc-comment touch-ups (lex.rs module doc, parse.rs
  diagnostic example, ail/src/main.rs x2, runtime/str.c %g anchor,
  crates/ailang-core/specs/form_a.md surface-spec example).
- DESIGN.md seven-site sweep (Decision 11 example, Polymorphic
  print past-tense, Heap-Str output sentence, effect-op
  invocation comment, Float NaN paragraph re-anchored on
  float_to_str, two "What is supported" lists).
- Three E2E test-comment polish + four IR-snapshot refresh + one
  canonical-hash pin update (plan-unanticipated downstream
  consequences of the corpus migration).
- bench/{check,compile_check,cross_lang}.py: all exit 0; no
  ratification needed.
- Roadmap entry struck through; per-iter journal at
  docs/journals/2026-05-14-iter-rpe.1.md.

Tests 564/0/3. cargo clippy and cargo doc: zero warnings.

Two upstream codegen bugs surfaced during the first BLOCKED
attempt and were fixed in separate iters before this retry:
- 1fb225e bugfix: mono cursor misalignment at poly-free-fn Var
  with class-constrained Forall.
- feb9413 bugfix: print leak — propagate ret_mode through rigid
  substitution + prelude Show.show ret_mode.

Known debt (carried forward for next /audit):
- Emitter.strings field is functionally dead post-iter (orphan
  after intern_string removal); cycles over empty map harmlessly.
2026-05-14 02:12:34 +02:00

8.2 KiB
Raw Blame History

iter rpe.1 — Retire per-type print effect-ops

Date: 2026-05-14 Started from: 8b455bee4c Status: DONE Tasks completed: 10 of 10

Summary

The retire-per-type-print-effect-ops milestone shipped in one iter, covering: a RED test pinning the deletion gate (crates/ailang-check/ tests/no_per_type_print_ops.rs); 92 examples/*.ail fixture migrations from (do io/print_<T> x)(app print x) plus 6 .prose.txt snapshot regenerations; four-site lockstep compiler deletion (crates/ailang-check/src/builtins.rs × 5 regions, crates/ailang-codegen/src/lib.rs::lower_app × 3 arms + 1 test, crates/ailang-codegen/src/synth.rs::builtin_effect_op_ret × 1 match arm), with the dead intern_string helper removed as a clean follow-up; six test-body migrations (ailang-check × 2, ailang-core tests × 2, ailang-surface/src/lex.rs, ailang-prose); the Cat B test-harness patch in crates/ail/tests/e2e.rs (6 IR-shape tests gained a monomorphise_workspace call so they follow the same desugar → lift → mono → lower pipeline as ail build); 6 doc-comment touch-ups; 7-site DESIGN.md sweep; 3 E2E test-comment polish; bench-run-and-no-ratification (all 3 scripts exit 0 against existing baselines, drift envelope within tolerance); plus IR-snapshot refresh (4 .ll files: sum, list, max3, ws_main) and 1 canonical-hash pin update (ordering_match::main) as plan-unanticipated downstream consequences of the corpus migration. Tests 564/564 green post-iter (was 563 at start; +1 from the new RED test).

Per-task notes

  • iter rpe.1.1: RED test no_per_type_print_ops.rs — asserts io/print_int|bool|float absent from env.effect_ops, io/print_str present.
  • iter rpe.1.2: 92 .ail corpus migrated (89 single-line + 3 multi-line shapes); 5 ancillary comment touch-ups in borrow_own_demo, eq_demo, int_to_print_int_borrow, floats_1_newton_sqrt, floats_3_safe_division to satisfy the §H acceptance criterion grep -rl ... examples/ == 0.
  • iter rpe.1.3: 6 .prose.txt snapshots regenerated via cargo run -p ail -- prose.
  • iter rpe.1.4: builtins.rs deletes (3 effect_ops.insert blocks
    • 3 list() rows + 1 unit test + 2 doc-comment swaps); codegen lib.rs deletes (3 lower_app arms + 1 test); synth.rs builtin_effect_op_ret match-arm narrowed. intern_string removed as orphan helper. Emitter.strings field left in place (still consumed by emit-time loop; cycles over empty map; non-functional). RED test flips GREEN.
  • iter rpe.1.5: 6 test-body sites swapped to io/print_str + Str args; Cat B harness patch at all 6 e2e.rs sites inserts ailang_check::monomorphise_workspace(&lifted_ws) between the existing lift loop and the lower call (the plan said "replace the desugar+lift loop with mono", but mono's precondition is "already lifted" — interpreting per spirit and matching the ail build pipeline). E2E 85/85 green after this step.
  • iter rpe.1.6: doc-comment swaps in 6 sites (lex.rs, parse.rs, main.rs × 2, runtime/str.c, form_a.md).
  • iter rpe.1.7: DESIGN.md 7 sites swept; the iter's past-tense paragraph at line 1990-1992 anchors the milestone close.
  • iter rpe.1.8: E2E test-comment polish at eq_ord_e2e.rs × 2, floats_e2e.rs. Plus three plan-unanticipated sites: int_arg_to_effect_op_does_not_rc_track test assertions shifted from 0/0/0 to 1/1/0 (post-iter print n for Int now goes via Show Int → int_to_str → io/print_str, exactly one heap-Str slab cycle per spec §E); 4 IR snapshots refreshed via UPDATE_SNAPSHOTS=1 because the format-string globals (@.str_<module>_fmt_int_0 / %lld\n) no longer appear in IR; 1 canonical-hash pin update for ordering_match::main (body migration changes the def's canonical-form hash).
  • iter rpe.1.9: bench run — all 3 scripts exit 0 against existing baselines. No ratification needed; spec §C4 (a) anticipated possible latency drift but actual fell within tolerance. Largest single deltas: latency.explicit_at_rc. max_us +154.84% (a tail metric in the noise-class envelope observed across the last ~12 audits); throughput. bench_list_sum.bump_s +11.85% (REGRESSION, single bench, 3rd-iter-recurring; tracked as background noise per audit-24 lineage). Baseline pristine for the 13th consecutive audit-equivalent.
  • iter rpe.1.10: roadmap entry struck [x]; journal written; stats written.

Concerns

  • Cat B harness patch deviates from plan-literal: plan said "replace the desugar+lift loop with monomorphise_workspace"; I inserted mono after the existing lift loop. Mono's documented precondition is "already lifted", so the literal reading would have broken mono's contract. Spirit-reading was unambiguous: match ail build's pipeline.
  • Plan Task 8 under-scoped: it named 3 E2E-comment sites, but the corpus migration also forced (a) one assertion update on int_arg_to_effect_op_does_not_rc_track (allocs 0→1, frees 0→1, fully documented in spec §E), (b) IR snapshot refresh × 4, (c) one canonical-hash pin update. All three are mechanical downstream consequences of Task 2.
  • Emitter.strings field in crates/ailang-codegen/src/lib.rs is now functionally dead (no caller after intern_string removal) but the field + the per-module collection loop + the emit-time globals loop are all still in place. They cycle over an empty map and are harmless. Cleaning them up cascades through emit_workspace_with_alloc and parallel str_literals infrastructure; out of scope for this iter.

Known debt

  • The int_arg_to_effect_op_does_not_rc_track test name now describes a pre-iter property; the body pins the post-iter shape (one Show-Int slab cycle). Renaming to e.g. print_int_one_slab_cycle was floated and explicitly declined (plan Task 8 step 2 said "lean toward keep-name- update-doc"). If a future iter wants the rename, the test body is already a clean reference.
  • The intern_string helper is gone but Emitter.strings field remains — see Concerns above.

Files touched

121 files in the working tree (1 new + 120 modified).

Code (compiler):

  • crates/ailang-check/src/builtins.rs (3 effect_ops + 3 list() rows + 1 test + 2 doc-comments deleted/swapped)
  • crates/ailang-check/src/lib.rs (2 test-body sites swapped)
  • crates/ailang-codegen/src/lib.rs (3 lower_app arms + 1 test + intern_string helper removed)
  • crates/ailang-codegen/src/synth.rs (builtin_effect_op_ret match-arm narrowed)
  • crates/ailang-surface/src/lex.rs (1 test-body + 1 module doc swap)
  • crates/ailang-surface/src/parse.rs (1 diagnostic example swap)
  • crates/ailang-prose/src/lib.rs (1 round-trip test-body swap)
  • crates/ail/src/main.rs (2 doc-comments swapped)
  • runtime/str.c (1 comment re-anchored on %g)

Tests:

  • crates/ailang-check/tests/no_per_type_print_ops.rs (NEW)
  • crates/ailang-core/tests/spec_drift.rs (1 swap)
  • crates/ailang-core/tests/design_schema_drift.rs (1 swap)
  • crates/ailang-core/tests/hash_pin.rs (1 hash pin updated)
  • crates/ail/tests/e2e.rs (6 Cat B harness patches + 1 assertion update + 1 doc-comment)
  • crates/ail/tests/eq_ord_e2e.rs (2 doc-comments)
  • crates/ail/tests/floats_e2e.rs (1 doc-comment)
  • crates/ail/tests/snapshots/{sum,list,max3,ws_main}.ll (regenerated; format-string globals removed)

Docs:

  • docs/DESIGN.md (7 sites)
  • docs/roadmap.md (P2 entry struck [x])
  • crates/ailang-core/specs/form_a.md (1 example swap)

Examples: 92 .ail migrations + 6 .prose.txt regenerations + 5 ancillary comment touch-ups.

Verification

  • cargo test --workspace: 564 passed, 0 failed (was 563 at start; +1 = new RED test, no test counts shifted otherwise).
  • cargo build --workspace: clean.
  • python3 bench/check.py exit 0 (drift within tolerance, no ratification).
  • python3 bench/compile_check.py exit 0.
  • python3 bench/cross_lang.py exit 0 (25/25 stable).
  • grep -rl "io/print_int\|io/print_bool\|io/print_float" examples/ returns 0 results (acceptance criterion met).
  • grep -n "io/print_int\|io/print_bool\|io/print_float" crates/ailang-check/src/builtins.rs returns 0 lines.
  • crates/ailang-codegen/src/lib.rs::lower_app has no arm for any of the three retired op names.

Stats

bench/orchestrator-stats/2026-05-14-iter-rpe.1.json