Iter 7: first-class function references (no capture)
Top-level fn names are now usable as values, fn-typed parameters can be called as `f(args)`. KISS slice of "closures + HOFs + TIR": no TIR, no heap, no ABI shift — that bundle stays in Iter 8 where closure-with-capture and lambdas land together. Codegen: - Type::Fn lowers to LLVM `ptr`; sig travels via a per-fn-body `ssa_fn_sigs` sidetable on `Emitter`. - Term::Var falls through to `resolve_top_level_fn` when the name is not a local; emits `@ail_<m>_<def>` and registers the sig. - Term::App splits: static callee (builtin / current-module / qualified) keeps the existing direct path; otherwise lower the callee, look up the sig, emit indirect `call <ret> (<param-tys>) %fn(args...)`. - emit_fn registers fn-typed params in the sidetable on entry. - If branches propagate a fn-pointer sig to their phi when both arms match. Typechecker: unchanged. It already accepted `synth(callee)` against Type::Fn; the only blocker was codegen rejecting non-Var callees. Tests: 48 green (was 47). New `examples/hof.ail.json` and e2e `higher_order_apply_inc` exercise `apply(inc, 41) == 42` end-to-end. DESIGN.md: "What is not (yet) supported" rewritten — closures-with- capture and lambdas remain pending, first-class fn-refs added as positive bullet. Smoke-test list extended with `hof.ail.json`. JOURNAL.md: Iter 7 entry with rationale, scope choice, architecture self-check, Iter 8 plan. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
+15
-5
@@ -229,11 +229,13 @@ ail build <module> — full pipeline → binary
|
||||
|
||||
## What is not (yet) supported
|
||||
|
||||
Snapshot of the boundary at the end of Iter 6. Items move out of this list
|
||||
Snapshot of the boundary at the end of Iter 7. Items move out of this list
|
||||
as iterations land; the JOURNAL records the exact iteration.
|
||||
|
||||
- No closures / higher-order functions. Will require a typed IR stage (TIR)
|
||||
before lowering.
|
||||
- No closures with capture / no anonymous lambdas. Both will require a
|
||||
typed IR stage (TIR) and closure conversion in lowering. First-class
|
||||
function references (top-level fns as values, fn-typed parameters,
|
||||
indirect calls) **are** supported as of Iter 7 — see below.
|
||||
- No effect handlers — only the built-in IO and Diverge ops.
|
||||
- No refinements / SMT escalation.
|
||||
- No cross-module ADTs. ADTs are local to a module; ctor names must be
|
||||
@@ -253,6 +255,14 @@ What **is** supported (and used as the smoke test for the pipeline):
|
||||
pattern are restricted to `Var` / `Wild`.
|
||||
- **Imports + qualified cross-module references** via dotted names
|
||||
(Iter 5).
|
||||
- **First-class function references** (Iter 7). A top-level fn name (or
|
||||
qualified `prefix.def`) used as a `Term::Var` is a fn-pointer value of
|
||||
AILang type `Type::Fn { ... }` and LLVM type `ptr`. Fn-typed parameters
|
||||
may be called directly as `f(args)`. No capture, no lambdas — the only
|
||||
way to construct a fn-value is to refer to a top-level def.
|
||||
|
||||
Pipeline regression smoke test: `examples/sum.ail.json` produces a
|
||||
binary that prints 55.
|
||||
Pipeline regression smoke tests:
|
||||
|
||||
- `examples/sum.ail.json` → prints 55 (recursion, arithmetic).
|
||||
- `examples/list.ail.json` → prints 42 (ADTs + match).
|
||||
- `examples/hof.ail.json` → prints 42 (first-class fn-refs, indirect call).
|
||||
|
||||
Reference in New Issue
Block a user