Skip to content

Commit 3c23fd1

Browse files
hyperpolymathclaude
andcommitted
docs(stdlib): refresh #135 triage after slices 1-3,6 (STDLIB-AOT-TRIAGE)
Live state after 8 merged PRs (#149-#156). 9/19 stdlib files compile end-to-end. Refines remaining root causes from raw symptoms: - Slice 7 was mis-hypothesised as "empty-array literal" — that pattern compiles in isolation; the real cause is HOF `fold` instantiated monomorphically by `sum`/`product`. Reclassified, not guessed. - New sub-defects surfaced as earlier walls fell: `&mut T` ref params (option, slice 9), `as` keyword-as-param-name (collections, slice 6b), generic-extern kind-checking (effects, slice 10). - Tags each remaining slice by autonomy/risk: 6b/5 safe-bounded; 4/7/8/9/10 correctness-/grammar-critical (rigorous, not auto-rushed). Refs #128, #135. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent d0654d4 commit 3c23fd1

1 file changed

Lines changed: 69 additions & 96 deletions

File tree

docs/history/STDLIB-AOT-TRIAGE.md

Lines changed: 69 additions & 96 deletions
Original file line numberDiff line numberDiff line change
@@ -3,104 +3,77 @@
33

44
# Stdlib AOT triage — #135 punch list
55

6-
**Generated 2026-05-17**, against the compiler at `feat/135a-lambda-expr`
7-
(origin/main + #131/#134 merged, #133/PR #152 auto-merging, + #135 slice 1
8-
`fn(params) => expr`). This is the live per-file state of driving every
9-
`stdlib/*.affine` through `resolve → typecheck → codegen` (Deno-ESM).
6+
**Refreshed 2026-05-17** after merging slices 1, 2, 3, 6. Live per-file
7+
state of driving every `stdlib/*.affine` through
8+
`resolve → typecheck → codegen` (Deno-ESM).
109

11-
Methodology: `affinescript compile stdlib/<f>.affine -o /tmp/x.js
12-
--deno-esm`, first error per file, classified by pipeline stage.
10+
## Done (merged to main)
1311

14-
## Status snapshot
15-
16-
| File | Stage | Site | Root cause / slice |
12+
| Slice | What | PR |
13+
|---|---|---|
14+
| #131 | `>>` nested-generic close (keystone) | #149 |
15+
| #134 | prelude unwrap/unwrap_result soundness | #150 |
16+
| #132 | namespace ADR-011 | #151 |
17+
| #133 | single-ownership dedup | #152 |
18+
| #135 sl.1 | `fn(x) => e` anon-function expressions | #153 |
19+
| #135 sl.2 | slice/range index `e[a:b]` via `slice` builtin | #154 |
20+
| #135 sl.3 | bare `effect E;` + ADR-008 `-> T / E` row | #155 |
21+
| #135 sl.6 | `try``attempt`, `ref``make_ref` (keyword-as-ident) | #156 |
22+
23+
## Current sweep
24+
25+
| File | Stage | Site | Slice / root cause |
1726
|---|---|---|---|
1827
| `string` | ✅ OK || full pipeline |
1928
| `Core` | ✅ OK || full pipeline |
20-
| `Ajv` `Crypto` `Grammy` `Network` `Sqlite` `Vscode` `VscodeLanguageClient` | ✅ OK || full pipeline (already `module`-declared) |
21-
| `prelude` | TYPECHECK | `Unify.TypeMismatch (T, Int)` | **Slice 7** — empty-array literal `let result = []` then `result ++ [..]` not generalised |
22-
| `option` | PARSE | `238:15` `Some(list[1:])` | **Slice 2** — slice/range index `list[1:]` |
23-
| `collections` | PARSE | `24:35` `take(n-1, list[1:])` | **Slice 2** — same slice syntax |
24-
| `result` | PARSE | `221:1` `fn try<T>(...)` | **Slice 6**`try` is a reserved keyword (TRY); used as a fn name |
25-
| `effects` | PARSE | `5:8` `effect io;` | **Slice 3** — bare `effect <name>;` declaration form |
26-
| `testing` | PARSE | `302:3` `let total = ...;` then `{` | **Slice 4** — statement sequencing: `let;` followed by a block expr |
27-
| `math` | PARSE | `354:3` `let total = 0.0;` then `for` | **Slice 4** — same: `let;` followed by `for` statement |
28-
| `traits` | PARSE | `12:43` `pub fn ne(ref self, ...) -> Bool {` | **Slice 5** — trait method *default bodies* / `ref self` receiver |
29-
| `io` | RESOLVE | `Resolve.UndefinedVariable` | **Slice 8** — builtin/extern + namespace wiring; interacts with #132/#133 module model |
30-
31-
9/19 already compile end-to-end. The remaining 10 reduce to **7 distinct
32-
feature slices**, none of which is the #131 angle-bracket or #135-slice-1
33-
lambda defect (both fixed).
34-
35-
## Slices (proposed order, each its own PR)
36-
37-
Ordering rationale: do the two-for-one parser slices first (max files
38-
unblocked per change), keep the model-coupled one (Slice 8) until after
39-
#133/PR #152 lands, and the typecheck/keyword ones are independent.
40-
41-
### Slice 2 — slice/range index `list[1:]` *(unblocks `option`, `collections`)*
42-
Postfix index currently accepts `e[i]` only. Add range-index
43-
`e[a:b]` / `e[a:]` / `e[:b]` / `e[:]` to the postfix-expr rule, lowering
44-
to the existing slice/`Array` op (check `lib/parser.mly` postfix rule +
45-
how `typecheck.ml`/codegen model slices — `string` already slices, so a
46-
lowering target likely exists). Two files, one feature. Independent.
47-
48-
### Slice 3 — `effect <name>;` declaration *(unblocks `effects`)*
49-
Grammar has `effect_decl` for `effect E { ops }`; `effects.affine` uses
50-
the bare forward-declaration form `effect io;`. Add the bare form to
51-
`effect_decl` (empty-op effect) or a dedicated production. Independent;
52-
small.
53-
54-
### Slice 4 — statement sequencing: `let …;` then block/`for` *(unblocks `testing`, `math`)*
55-
Both fail where a `let …;` statement is immediately followed by another
56-
statement that is a block expr (`{ … }`) or a `for`. Root cause is in
57-
the block/statement-list rule (the `list(stmt)` vs `expr_record_body`
58-
reduce/reduce noted in the grammar). Needs the statement-sequence rule
59-
disambiguated so a trailing-semicolon `let` composes with a following
60-
block/`for`. Independent; medium (touches the known r/r conflict — do
61-
rigorously, re-check conflict counts before/after).
62-
63-
### Slice 5 — trait method default bodies + `ref self` *(unblocks `traits`)*
64-
`trait_decl` accepts method *signatures*; `traits.affine` provides
65-
*default bodies* (`pub fn ne(ref self, ref other: Self) -> Bool { … }`).
66-
Add optional `fn_body` to trait method items and accept the `ref self`
67-
receiver form. Independent; medium.
68-
69-
### Slice 6 — `try` as a value identifier *(unblocks `result`)*
70-
`try` is the TRY keyword (try/catch). `result.affine` defines
71-
`fn try<T>(…)`. Decide: (a) make `try` a contextual keyword (allow as
72-
fn name / ident), or (b) rename the stdlib function (e.g. `attempt`).
73-
(a) is the resolve-at-source fix but wider; (b) is local and safe.
74-
Recommend (b) unless `try`-as-ident is wanted broadly. Independent; small.
75-
76-
### Slice 7 — empty-array literal generalisation *(unblocks `prelude`)*
77-
`map`/`filter` do `let result = []; for x in arr { result = result ++ [f(x)] }`.
78-
`[]` is inferred at a concrete element type (`Int`) and then conflicts
79-
with `[U]`. Needs the empty-array literal to take a fresh element tyvar
80-
unified by later use (or an annotation path). Typecheck/inference, not
81-
parsing. Independent; medium — touch `typecheck.ml` array-literal rule
82-
with care + regression test.
83-
84-
### Slice 8 — `io` resolution / builtin + namespace *(unblocks `io`)***do after #133/PR #152**
85-
`io.affine` references runtime builtins (`print`, `read_file`, …) the
86-
static resolver doesn't know. This couples to the module/extern model
87-
(ADR-011 / #132) and the #133 ownership changes. Sequence it after
88-
PR #152 (#133) lands so it is solved against the real module model, not
89-
the interpreter-era flat namespace. Medium; model-coupled.
90-
91-
## After all slices
92-
93-
Then #135 closes; unblocks #136 (CI AOT smoke gate), #137 (multi-module
94-
integration test), #138 (remove b895374 band-aid). Estimated 3–5 further
95-
focused sessions for slices 2–8 (each: feature + tests + conflict
96-
re-verification), per the "rigorous over partial-hack" discipline.
97-
98-
## Done so far (this epic)
99-
100-
| Issue | PR | State |
101-
|---|---|---|
102-
| #131 `>>` nested-generic | #149 | merged |
103-
| #134 prelude unwrap soundness | #150 | merged |
104-
| #132 namespace ADR-011 | #151 | merged |
105-
| #133 single-ownership dedup | #152 | auto-merging |
106-
| #135 slice 1 (`fn(x)=>e`) | this PR | open |
29+
| `Ajv`/`Crypto`/`Grammy`/`Network`/`Sqlite`/`Vscode`/`VscodeLanguageClient` | ✅ OK || full pipeline |
30+
| `traits` | PARSE | `12:43` | **Slice 5** — trait method *default body* + `ref self` (`pub fn ne(ref self, ...) { ... }`) |
31+
| `collections` | PARSE | `40:13` | **Slice 6b**`as` used as a parameter name (`fn zip<A,B>(as: [A], ...)`); `as` is the AS keyword. Same class as slice 6 → rename (`elems`) |
32+
| `math` | PARSE | `354:3` | **Slice 4**`if cond { ... }` (no else) used as a statement between other statements; the parser commits to if-as-trailing-expr |
33+
| `testing` | PARSE | `302:3` | **Slice 4** — record literal `{ f: v }` as the block's final expression after statements (the pre-existing `list(stmt)` vs `expr_record_body` r/r) |
34+
| `option` | PARSE | `320:15` | **Slice 9**`&mut Option<T>` reference parameter type (`fn take<T>(opt: &mut Option<T>)`); flagged in #128 itself (take/get_or_insert + affine/borrow lowering) |
35+
| `result` | RESOLVE || **Slice 8** — module/`use prelude::{...}` resolution (post-#133 model) |
36+
| `io` | RESOLVE || **Slice 8** — builtin/extern + namespace resolution; model-coupled |
37+
| `prelude` | TYPECHECK | `Unify (T, Int)` | **Slice 7 (root cause refined)***not* a simple empty-array literal (that pattern compiles in isolation). Deeper type-instantiation: `fold`'s `(U,T)->U` HOF instantiated monomorphically by `sum`/`product` (`fold(arr, 0, …)` forces `0:Int`). Needs careful typecheck investigation |
38+
| `effects` | TYPECHECK | "Not implemented: Too many arguments for kind" | **Slice 10** — kind-checking of generic externs (`extern fn make_ref<T>(x: T) -> Ref<T> / state`); distinct codegen/kind defect |
39+
40+
9/19 compile end-to-end. Parse walls + deeper defects regroup into the
41+
slices below.
42+
43+
## Remaining slices — difficulty & autonomy
44+
45+
**Safe to do autonomously (bounded, low risk):**
46+
- **Slice 6b**`as` param-name in `collections.affine` → rename
47+
(`elems`/`xs`). Pure stdlib edit, zero grammar risk. ~15 min.
48+
- **Slice 5** — trait default bodies + `ref self`. `trait_item`
49+
already has `TraitFnDefault f` (line ~537); the gap is the `ref self`
50+
receiver in trait-method position. Grammar-bounded, medium; verify
51+
conflict counts.
52+
53+
**Needs care — rigorous, not auto-rushed:**
54+
- **Slice 4** (testing, math) — block/statement ambiguity. The hardest:
55+
`if`/`while`/`for` as statements vs trailing-expr, and record-literal
56+
vs block `{`. This is the grammar's pre-existing `list(stmt)` /
57+
`expr_record_body` reduce/reduce. High regression risk; needs a
58+
careful block-grammar restructure with full conflict + suite
59+
re-verification. Multi-step.
60+
- **Slice 9** (option) — `&mut T` reference parameters with
61+
reassignment. Touches affine/borrow lowering (the #128-noted hard
62+
case). Correctness-critical (ownership) — must be rigorous.
63+
- **Slice 7** (prelude) — type-checker instantiation of HOF `fold`
64+
under monomorphic `sum`/`product`. Correctness-critical typecheck
65+
code; investigate, don't guess.
66+
- **Slice 8** (result, io) — module/extern resolution against the
67+
post-#133 model (ADR-011). Model-coupled.
68+
- **Slice 10** (effects) — generic-extern kind-checking
69+
("Too many arguments for kind"). Distinct kind/codegen defect.
70+
71+
## Closure
72+
73+
#135 closes when all files compile resolve→typecheck→codegen; then
74+
#138 (remove b895374 band-aid), #136 (CI AOT smoke gate), #137
75+
(multi-module integration test). The safe slices (6b, 5) are ~1 short
76+
session; slices 4/7/8/9/10 are correctness-/grammar-critical and are
77+
each their own focused, rigorous unit (the "rigorous over partial-hack"
78+
discipline applies — no guessed changes to typecheck/borrow/block
79+
grammar).

0 commit comments

Comments
 (0)