Files
AILang/examples/escape_local_demo.ail
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

58 lines
2.0 KiB
Plaintext

; Iter 17a — first fixture exercising the per-fn arena (alloca for
; non-escaping allocations).
;
; `peek` builds a Box(n) and immediately matches on it, returning
; a literal Int that does not depend on the box's payload. The
; box's value is fully consumed by the local match — it never
; flows to a fn arg, never becomes a ctor field, never returns.
; Iter 17a's escape analysis flags the `(term-ctor Box MkBox n)`
; allocation as non-escaping; codegen lowers it to LLVM `alloca`
; instead of `@GC_malloc`. Boehm's heap is not touched at all by
; this fn.
;
; `count` repeats the same pattern under recursion: each call to
; `count` builds a fresh Box(_), matches it, and returns either 0
; or 1 + (count rest). Without the alloca optimisation, each
; recursive frame leaks a Box onto the GC heap until collection;
; with the optimisation, each frame's Box dies with its frame.
;
; Expected stdout (one per line):
; 42 — peek(0) returns the literal 42 from the only arm
; 42 — peek(123) ditto (the input value never reaches stdout)
; 5 — count(5)
; 0 — count(0)
(module escape_local_demo
(data Box (vars a)
(ctor MkBox a))
(fn peek
(doc "Build a Box(n), discard the payload, return 42. The Box is non-escaping.")
(type (fn-type (params (con Int)) (ret (con Int))))
(params n)
(body
(let b (term-ctor Box MkBox n)
(match b
(case (pat-ctor MkBox _) 42)))))
(fn count
(doc "Recurse n times; each call builds a temporary Box, discards its payload via _, and returns 0 if n<=0, else 1 + count(n-1).")
(type (fn-type (params (con Int)) (ret (con Int))))
(params n)
(body
(if (app <= n 0)
0
(let b (term-ctor Box MkBox n)
(match b
(case (pat-ctor MkBox _) (app + 1 (app count (app - n 1)))))))))
(fn main
(type (fn-type (params) (ret (con Unit)) (effects IO)))
(params)
(body
(seq (app print (app peek 0))
(seq (app print (app peek 123))
(seq (app print (app count 5))
(app print (app count 0))))))))