d64031c234
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>
232 lines
5.9 KiB
JSON
232 lines
5.9 KiB
JSON
{
|
|
"schema": "ailang/v0",
|
|
"name": "list_map_poly",
|
|
"imports": [],
|
|
"defs": [
|
|
{
|
|
"kind": "type",
|
|
"name": "List",
|
|
"vars": ["a"],
|
|
"doc": "Polymorphic singly-linked list.",
|
|
"ctors": [
|
|
{ "name": "Nil", "fields": [] },
|
|
{
|
|
"name": "Cons",
|
|
"fields": [
|
|
{ "k": "var", "name": "a" },
|
|
{
|
|
"k": "con",
|
|
"name": "List",
|
|
"args": [{ "k": "var", "name": "a" }]
|
|
}
|
|
]
|
|
}
|
|
]
|
|
},
|
|
{
|
|
"kind": "fn",
|
|
"name": "inc",
|
|
"type": {
|
|
"k": "fn",
|
|
"params": [{ "k": "con", "name": "Int" }],
|
|
"ret": { "k": "con", "name": "Int" },
|
|
"effects": []
|
|
},
|
|
"params": ["x"],
|
|
"doc": "Add 1 to an Int.",
|
|
"body": {
|
|
"t": "app",
|
|
"fn": { "t": "var", "name": "+" },
|
|
"args": [
|
|
{ "t": "var", "name": "x" },
|
|
{ "t": "lit", "lit": { "kind": "int", "value": 1 } }
|
|
]
|
|
}
|
|
},
|
|
{
|
|
"kind": "fn",
|
|
"name": "map",
|
|
"type": {
|
|
"k": "forall",
|
|
"vars": ["a", "b"],
|
|
"body": {
|
|
"k": "fn",
|
|
"params": [
|
|
{
|
|
"k": "fn",
|
|
"params": [{ "k": "var", "name": "a" }],
|
|
"ret": { "k": "var", "name": "b" },
|
|
"effects": []
|
|
},
|
|
{
|
|
"k": "con",
|
|
"name": "List",
|
|
"args": [{ "k": "var", "name": "a" }]
|
|
}
|
|
],
|
|
"ret": {
|
|
"k": "con",
|
|
"name": "List",
|
|
"args": [{ "k": "var", "name": "b" }]
|
|
},
|
|
"effects": []
|
|
}
|
|
},
|
|
"params": ["f", "xs"],
|
|
"doc": "Polymorphic map: apply f to every element, recursing on the tail.",
|
|
"body": {
|
|
"t": "match",
|
|
"scrutinee": { "t": "var", "name": "xs" },
|
|
"arms": [
|
|
{
|
|
"pat": { "p": "ctor", "ctor": "Nil", "fields": [] },
|
|
"body": {
|
|
"t": "ctor",
|
|
"type": "List",
|
|
"ctor": "Nil",
|
|
"args": []
|
|
}
|
|
},
|
|
{
|
|
"pat": {
|
|
"p": "ctor",
|
|
"ctor": "Cons",
|
|
"fields": [
|
|
{ "p": "var", "name": "h" },
|
|
{ "p": "var", "name": "t" }
|
|
]
|
|
},
|
|
"body": {
|
|
"t": "ctor",
|
|
"type": "List",
|
|
"ctor": "Cons",
|
|
"args": [
|
|
{
|
|
"t": "app",
|
|
"fn": { "t": "var", "name": "f" },
|
|
"args": [{ "t": "var", "name": "h" }]
|
|
},
|
|
{
|
|
"t": "app",
|
|
"fn": { "t": "var", "name": "map" },
|
|
"args": [
|
|
{ "t": "var", "name": "f" },
|
|
{ "t": "var", "name": "t" }
|
|
]
|
|
}
|
|
]
|
|
}
|
|
}
|
|
]
|
|
}
|
|
},
|
|
{
|
|
"kind": "fn",
|
|
"name": "print_list",
|
|
"type": {
|
|
"k": "fn",
|
|
"params": [
|
|
{
|
|
"k": "con",
|
|
"name": "List",
|
|
"args": [{ "k": "con", "name": "Int" }]
|
|
}
|
|
],
|
|
"ret": { "k": "con", "name": "Unit" },
|
|
"effects": ["IO"]
|
|
},
|
|
"params": ["xs"],
|
|
"doc": "Print each Int on its own line.",
|
|
"body": {
|
|
"t": "match",
|
|
"scrutinee": { "t": "var", "name": "xs" },
|
|
"arms": [
|
|
{
|
|
"pat": { "p": "ctor", "ctor": "Nil", "fields": [] },
|
|
"body": { "t": "lit", "lit": { "kind": "unit" } }
|
|
},
|
|
{
|
|
"pat": {
|
|
"p": "ctor",
|
|
"ctor": "Cons",
|
|
"fields": [
|
|
{ "p": "var", "name": "h" },
|
|
{ "p": "var", "name": "t" }
|
|
]
|
|
},
|
|
"body": {
|
|
"t": "seq",
|
|
"lhs": {
|
|
"t": "do",
|
|
"op": "io/print_int",
|
|
"args": [{ "t": "var", "name": "h" }]
|
|
},
|
|
"rhs": {
|
|
"t": "app",
|
|
"fn": { "t": "var", "name": "print_list" },
|
|
"args": [{ "t": "var", "name": "t" }],
|
|
"tail": true
|
|
}
|
|
}
|
|
}
|
|
]
|
|
}
|
|
},
|
|
{
|
|
"kind": "fn",
|
|
"name": "main",
|
|
"type": {
|
|
"k": "fn",
|
|
"params": [],
|
|
"ret": { "k": "con", "name": "Unit" },
|
|
"effects": ["IO"]
|
|
},
|
|
"params": [],
|
|
"doc": "Map inc over [1,2,3] via polymorphic List, then print: 2,3,4.",
|
|
"body": {
|
|
"t": "app",
|
|
"fn": { "t": "var", "name": "print_list" },
|
|
"args": [
|
|
{
|
|
"t": "app",
|
|
"fn": { "t": "var", "name": "map" },
|
|
"args": [
|
|
{ "t": "var", "name": "inc" },
|
|
{
|
|
"t": "ctor",
|
|
"type": "List",
|
|
"ctor": "Cons",
|
|
"args": [
|
|
{ "t": "lit", "lit": { "kind": "int", "value": 1 } },
|
|
{
|
|
"t": "ctor",
|
|
"type": "List",
|
|
"ctor": "Cons",
|
|
"args": [
|
|
{ "t": "lit", "lit": { "kind": "int", "value": 2 } },
|
|
{
|
|
"t": "ctor",
|
|
"type": "List",
|
|
"ctor": "Cons",
|
|
"args": [
|
|
{ "t": "lit", "lit": { "kind": "int", "value": 3 } },
|
|
{
|
|
"t": "ctor",
|
|
"type": "List",
|
|
"ctor": "Nil",
|
|
"args": []
|
|
}
|
|
]
|
|
}
|
|
]
|
|
}
|
|
]
|
|
}
|
|
]
|
|
}
|
|
]
|
|
}
|
|
}
|
|
]
|
|
}
|