# Lower phase — L4 and L5 status (2026-10-05) Branch **`ast-stage-c`**. All slices below are byte-verified (`cmp gen_ssa/.ssa gen_ssa/L.ssa`), gated by the suite and the self-hosting fixpoint. ## Landed | Tag | Commit | Content | | --- | --- | --- | | `v3-lower4` | `53a1d15` | builtins, `CASE`, `WITH` | | `v3-lower5-core` | `ab507e2` | records, arrays, designators, aggregate copies | | `v3-lower5-lit` | `5e23bfe` | char/real/string/set literals, `IN`, typed relations | | `v3-lower5-sets` | `081869f` | set arithmetic, string concatenation | | `v3-lower5-params` | `0b22c8a` | aggregate formals, value open arrays | Suite **191/191**; `FIXPOINT OK` (stage2 == stage3, 3,304,549 bytes). ## Design - **Unified walk.** `LowerExprFull(n, ..., asAddr)` handles both value and address contexts; `LowerExpr` is the value wrapper and `LowerDesign` the address wrapper. Selectors (`.field` / `[i]` / `^`) are walked once, then `FinalLoad` applies Fact's trailing scalar/pointer load (aggregates keep the address). - **Gate.** `CanType`/`CanDesign`/`CanCaseLabel`/`CanBuiltin` mirror the walk's supported subset; `CanLower` accepts TYPE declarations and aggregate VAR/proc types. - **Builtins** dispatch by callee name (before user calls): `ABS CAP CHR ORD SIZE/TSIZE MIN/MAX SHIFT ROTATE ADR`, statements `INC/DEC INCL/EXCL NEW/DISPOSE`. - **CASE** is a compare-chain mirroring `CaseStat/CaseAlt/CaseLabel` (value and `lo..hi` labels, ELSE arm). - **WITH** uses a `withRec`/`withTop` stack shared by the gate and the walk; bare field idents resolve through `WithField` + `QbeGen.TopWith`. - **Relations** dispatch on operand type: `IN`, pointer (`CmpL`), set (`CmpSet`), string (`StrEq`), long (`CmpLong`), else `Cmp`. - **Arithmetic** covers set `+ - * /` (`SetBinOp`) and string `+` (`StrFold`/`StrCat`), plus proper long/real result types. - **Open arrays**: a value `ARRAY OF T` formal is passed by descriptor address (`FuncParam(..., isV OR IsOpenArray(t))`), matching the grammar. ## Tests `t_lower4` (builtins/sets/pointers), `t_lower4case`, `t_lower4with`, `t_lower5` (records/arrays), `t_lower5arr` (open-array + VAR record params), `t_lower5lit` (literals/IN), `t_lower5set` (set arithmetic + string concat). ## Remaining (documented, not blocking) - **UString** literals/ops. - **Aggregate constants** (record/array CONST values). - **Qualified names / imports / class methods** — L6 territory. ## Fixed after L5 - **Nested arrays** (`ARRAY OF ARRAY` record fields): `QbeGen.ArrBodyItems` now expands array-of-record elements per element (nested `EmitRec`) when the record recursively has a nested-array field, and `ArrData` emits the matching per-element sub-descriptors (nested `EmitRecStatics`). Plain record arrays stay a compact zero blob, so `AST.arena` does not balloon. Regression: `tests/t_nestarr.mod` (was `docs/wip/nested-array-field-bug.mod`). Suite 192/192; FIXPOINT OK (3,322,779 bytes). ## Not touched `QbeGen` remains at its committed state (stride fix only); the general array-of-record array-field fix stays deferred (`docs/summary_l3_selfhost_fix.md`).