; 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 the runtime allocator. The 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 allocates a Box on the heap; 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))))))))