Iter 14e: explicit, verified tail calls
Decision 8 ships. Term::App and Term::Do gain tail: bool with serde-default false and skip-when-false serialisation. New typecheck pass verify_tail_positions enforces tail-position rules (Scheme-style propagation through match arms, seq.rhs, let body, lam body). Codegen emits musttail call for marked App calls. Hash invariance verified: only the two migrated print_list defs (list_map_poly.print_list, sort.print_list) changed hashes; all other defs across all 18 fixtures kept bit-identical hashes — confirms the skip-when-false serialisation rule works. Tests 76 -> 79: tail_call_in_non_tail_position_is_rejected, tail_call_in_tail_position_is_accepted, plus an IR-grep e2e test asserting that print_list's recursive call site emits musttail in the lowered IR. Existing 25 e2e tests unchanged in behaviour (map -> [2,3,4], sort -> sorted list). IR evidence at the recursive site: %v7 = musttail call i8 @ail_list_map_poly_print_list(ptr %v6) ret i8 %v7 Two deviations called out in the implementer report and JOURNAL: 1. tail-do uses tail call, not musttail. Cross-type return (runtime helpers return i32, AILang Unit is i8) would have LLVM reject musttail. Path is implemented but not exercised by any current fixture; proper fix is runtime-helper signature change, punted. 2. block_terminated flag in codegen so tail-call emit (musttail call + ret) doesn't get a duplicate trailing ret from surrounding code (match-arm phi, fn-body, lambda thunk). Internal plumbing; required for IR well-formedness. Form (A) productions now at ~30, exactly the constraint-1 budget. Future surface additions need to retire something or explicit-budget-rebalance in DESIGN.md. GC notes from implementer survey land in JOURNAL: - Allocations cluster in lower_ctor; every term-ctor does malloc(8+8n). - Tail recursion does not reduce alloc pressure, only stack. For map-style ctor-blocked recursions, allocation IS the bottleneck. - Per-fn arena is sound only when fn return type contains no boxed ADT. Most current fixtures violate this. Plan 14f: Boehm conservative GC (GC_malloc, -lgc) as a first cut. Single-iter integration, no AST/schema change. Stress test: build a 100k Cons list, observe RSS doesn't blow up. After 14f the language is feature-complete enough for stdlib work (15a). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -164,7 +164,8 @@
|
||||
"rhs": {
|
||||
"t": "app",
|
||||
"fn": { "t": "var", "name": "print_list" },
|
||||
"args": [{ "t": "var", "name": "t" }]
|
||||
"args": [{ "t": "var", "name": "t" }],
|
||||
"tail": true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -47,7 +47,7 @@
|
||||
(case (pat-ctor Cons h t)
|
||||
(seq
|
||||
(do io/print_int h)
|
||||
(app print_list t))))))
|
||||
(tail-app print_list t))))))
|
||||
|
||||
(fn main
|
||||
(doc "Map inc over [1,2,3] via polymorphic List, then print: 2,3,4.")
|
||||
|
||||
@@ -204,7 +204,8 @@
|
||||
"rhs": {
|
||||
"t": "app",
|
||||
"fn": { "t": "var", "name": "print_list" },
|
||||
"args": [{ "t": "var", "name": "t" }]
|
||||
"args": [{ "t": "var", "name": "t" }],
|
||||
"tail": true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user