# Session 2026-10-22 — corpus triage: three conforming clusters Branch **`master`**. Continues `summary_session-2026-10-19.md`; the only plan source was its "Remaining" list (corpus `LANG` triage). ## Numbers | gate | session start | end | | --- | --- | --- | | suite (`compiler/run_tests.sh`) | 249/249 | **252/252** | | fixpoint (`bootstrap/fixpoint.sh`) | OK (3,882,337 B) | **OK (3,906,044 B)** | | corpus (`tools/v3-corpus/corpus.sh`) | 467/612 | **485/612, 0 crashes** | Reproduce: ```sh cd compiler && ./build.sh && ./run_tests.sh # 252/252 cd .. && TMP="$PWD/.scratch/fixpoint" ./bootstrap/fixpoint.sh tools/v3-corpus/corpus.sh # 485 OK, 0 crash ``` ## Triage method The 118 `LANG` entries were compiled one at a time (a single-file version of `corpus.sh`), and each first diagnostic was read against its source line. They fall into these buckets: | bucket | count | verdict | | --- | --- | --- | | imports `libc` but uses a libc function as a value (`printf`/`malloc`) | ~48 | **libc prototypes missing**; V3's permissive `FROM libc IMPORT` has no result type, so expression use is `invalid call` | | declaration order (type/const/var used before its declaration) | ~25 | correctly rejected (`docs/gaps/`); not a target | | gm2 extensions (`ASM`, `''` NUL char, `666B`, absolute `VAR [addr]`) | ~7 | not a target unless chosen | | ISO features actually missing | ~20 | sized SYSTEM types (`WORD32`/`BITSET32`/qualified `SYSTEM.CARDINAL8`), `PACKEDSET`, exceptions/`UNIQUE`, `__FUNCTION__`, `PROC` as a result type | | **conforming** clusters: arrays, subranges, ordinal `FOR`, empty string | 18 | **fixed this session** | ## What landed ### PIM/ISO multi-index arrays — `compiler/src/M2.atg` `ARRAY [0..1], [0..2] OF T` is the standard spelling (17 corpus files use it; none use V3's single-bracket comma list). `ArrayType` now parses one bracket group per dimension (`{ "," "[" ... "]" }`) and appends every group's bounds before the element type; nesting stays inside-out, so the layout matches `ARRAY [0..1] OF ARRAY [0..2] OF T`. The old `ARRAY [0..1, 0..2] OF` form still works. Corpus **+6**: `arraybool`, `assignment2`, `foo`, `recordarray2`, `tinyarray4/5`. Regression `t_multidim`. ### Subranges keep their ordinal base — `SymTab`, grammar A subrange was always `FSub` with no base descriptor, so `ClassOf` returned `ClInt` for `['A'..'Z']` and `[red..blue]`: assigning a `CHAR`/enum literal (or comparing with one) failed. `SymTab.NewSubB` stores the base when both bounds have the same type; `ClassOf`, `SubBounds`, `SetSpan`/`BaseSpanOk` and the set-span check now follow it. `Assignable`/`EqCheck`/`OrdCheck` accept a base value against a subrange of the same `CHAR`/`BOOLEAN`/enum base (two different enums stay incompatible). Corpus **+3**: `subrange16`, `subrange17`, `enum3`. Regression `t_subrange`. Assignment range checks remain (future) — V3 is already lenient for the integer family. ### `FOR` over ordinals + typed `MIN`/`MAX` of sets — grammar `FOR` accepted only the integer family. It now accepts any ordinal control variable (bounds must be assignment-compatible with it), which covers enums and `CHAR`. `MIN`/`MAX` of a `SET` now yields the set's base type instead of `INTEGER`, so `FOR i := MIN(S) TO MAX(S)` binds (the bound was previously `INTEGER` against an enum `i`). Corpus **+3**: `forloop2`, `smallset4`, `minmax`. ### ISO empty string literal — `SymTab` + grammar + `Lower` ISO makes the empty string literal (`""` / `''`) length 0 and compatible with `CHAR`, where its value is the terminator. V3 typed it as an ordinary string, so `ch := ""`, `ch = ""`, `CASE ch OF ""`, `FOR ch := "" TO …`, a `CHAR` formal actual, and `RETURN ""` either failed (`incompatible assignment`/`comparison`, `invalid Fact`) or stored a descriptor address. `SymTab.NewEmptyStr` marks the literal's type (`tlo = -2`); it is still `ClStr`, so `ARRAY OF CHAR` contexts keep working (`s := ""`, `s = ""`, `t_strempty`). `Assignable`/`EqCheck` accept it against `CHAR`, and `Lower` substitutes the value `0` when the context is a character (assignment, relation, `CASE` label, `FOR` bound, value actual, `RETURN`). Corpus **+6**: `arraychar`, `arraychar2`, `arraychar3`, `nulcharcase`, `nulcharvar`, `forloopnulchar`. Regression `t_emptychar`. ## Remaining (for a next session) 1. **`libc.def`** — the single biggest corpus bucket (~48 files). A minimal definition module (`exit`, `printf`, `malloc`, `write`, …) needs the grammar to prefer it over the permissive `FROM libc IMPORT` path, plus a varargs marker for `printf`. This is library work with a real payoff. 2. **ISO SYSTEM sized types** — `WORD32`/`WORD16`/`WORD8` and `BITSET8/16/32/64` are missing, and qualified `SYSTEM.CARDINAL8` does not resolve (predefs live in the global scope, not a SYSTEM module). ~8 files. 3. **`PACKEDSET`**, ISO exceptions/`UNIQUE`, `__FUNCTION__` — each one or two files; larger or gm2-flavoured. 4. **Runtime subrange range checks** — the remaining conformance difference from this session's subrange work. 5. `STATUS.md` "what remains" is the live list.