Files
AILang/examples/local_rec_capture.ailx
T
Brummel d5f63bc3e5 Iter 16b.2 — LetRec captures of fn-params (path-1 safe subset)
Lift 16b.1's no-capture restriction. The desugar pass's `scope`
becomes a `BTreeMap<String, ScopeEntry>` carrying `KnownType` for
fn/Lam-params, sentinels for Let-/Match-bindings. LetRec captures
of `KnownType` names are lifted: the synthetic top-level fn's
signature gets the capture types appended, and every call site of
the LetRec name is rewritten via `subst_call_with_extras` to pass
the captures positionally. Captures from let-bindings, match-arm
patterns, polymorphic enclosing fns, and name-as-value uses are
rejected at desugar with panics pointing at 16b.3-16b.7.

Demo: `sum_below(n)` recurses via `(let-rec loop (params i) ...
(body ... uses n ...) (in (app loop 1)))`. Lifts to
`loop$lr_0(i: Int, n: Int) -> Int` with `(app loop X)` rewritten
to `(app loop$lr_0 X n)`. Outputs 0, 10, 45.

Tests: 103 -> 106 (+1 e2e local_rec_capture_demo, +2 desugar unit;
the 16b.1 capture-panic test was repurposed into the positive
fn-param-capture test).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-07 21:00:49 +02:00

36 lines
1.3 KiB
Plaintext

; Iter 16b.2 — LetRec captures of fn-params (path-1 safe subset).
; `sum_below(n)` returns the sum of integers from 1 up to but not
; including n. The recursive helper `loop` captures the upper
; bound `n` from `sum_below`'s param list and recurses on its own
; counter `i`. The 16b.2 desugar pass lifts `loop` to a synthetic
; top-level fn `loop$lr_0(i: Int, n: Int) -> Int` (capture appended)
; and rewrites every `(app loop ARGS)` to `(app loop$lr_0 ARGS n)`.
;
; Expected stdout (one per line): 0 (sum below 1), 10 (1+2+3+4),
; 45 (1+2+...+9).
(module local_rec_capture
(fn sum_below
(doc "Sum 1 + 2 + ... + (n-1). Helper captures n from the enclosing scope.")
(type (fn-type (params (con Int)) (ret (con Int))))
(params n)
(body
(let-rec loop
(params i)
(type (fn-type (params (con Int)) (ret (con Int))))
(body
(if (app >= i n)
0
(app + i (app loop (app + i 1)))))
(in (app loop 1)))))
(fn main
(doc "Drive sum_below at 1, 5, 10. Expected (per line): 0, 10, 45.")
(type (fn-type (params) (ret (con Unit)) (effects IO)))
(params)
(body
(seq (do io/print_int (app sum_below 1))
(seq (do io/print_int (app sum_below 5))
(do io/print_int (app sum_below 10)))))))