# 0083 — fixed array with a named-constant dimension is miscompiled > **RESOLVED.** Root cause: `TypeResolver.resolveCompound`'s array arm resolved > the dimension with `if (length.data == .int_literal) ... else 0` — a named > const (`N :: 16`) hit the silent `else 0`, so `[N]T` became a 0-length / 0-byte > array and element access ran out of bounds (garbage for scalars, bus error for > slice/pointer/struct elements). Fix: the array arm now delegates the dimension > to `inner.resolveArrayLen` (symmetric with `inner.resolveInner` for the element > type). The stateful `Lowering.resolveArrayLen` evaluates the dimension as a > compile-time integer across the comptime-constant, generic-value, and > module-global const tables, and emits a diagnostic (no fabricated length) when > it isn't one. > > **Exhaustive follow-up (attempt 2).** The first fix covered every *stateful* > resolution path (direct local decls, struct fields, function params/returns), > but the *stateless* registration-time resolver (`type_bridge`, used for type > aliases `Arr :: [N]T` and inline union/enum field types) still resolved the > named dim with a silent `else 0` — so `Arr :: [N]s64; a : Arr` and > `union { a: [N]s64 }` were still miscompiled. Fix: the module-global const > table (`ProgramIndex.module_const_map`) is now threaded into `type_bridge` > alongside the alias map, so `StatelessInner.resolveArrayLen` resolves a named > module-const dim to the same length everywhere. The remaining unresolvable case > (a computed/comptime dimension on the binding-free path) bails LOUDLY instead of > fabricating a 0 length. Files: `src/ir/type_resolver.zig`, `src/ir/lower.zig`, > `src/ir/type_bridge.zig`. Regression: `examples/0140-types-named-const-array-dim.sx` > (direct + type-alias + nested `[N][M]T` + union-field dims, s64 / string / > struct element types). > > **Root-cause close-out (attempt 3).** Attempt 2 threaded the const map into > `type_bridge` but the map wasn't fully populated when an alias resolved its > dimension: type aliases (`Arr :: [N]T`) resolve EAGERLY in scanDecls pass 1, > while TYPED consts (`N : s64 : 16`) register only in pass 2 and a > forward-declared untyped const (`Arr :: [N]T; N :: 16`) hadn't registered yet > either — so the stateless resolver saw an empty table, printed a non-fatal > warning, fabricated length 0, and CONTINUED to garbage / a segfault. Three > coordinated fixes: (1) a scanDecls **pass 0** pre-registers every integer-valued > module const into `module_const_map` BEFORE any alias resolves, so typed, > untyped, and forward-referenced consts all resolve identically; (2) both the > stateful and stateless dim resolvers now share one routine > (`program_index.moduleConstInt`) so they cannot disagree again; (3) the length-0 > fabrications are GONE — `resolveArrayLen` returns `?u32`, `resolveCompound` > yields the `.unresolved` sentinel on null (never a 0-byte array), the stateful > path emits a diagnostic, and the registration path surfaces an unresolved alias > as a clean compile error that aborts the build (the `type_bridge.zig:270` > Vector-lane `else => 0` is fixed the same way). Files: > `src/ir/program_index.zig`, `src/ir/lower.zig`, `src/ir/type_bridge.zig`, > `src/ir/type_resolver.zig`. Regressions: > `examples/0143-types-typed-const-array-dim.sx` (typed-const dim direct + via > alias for s64/string/struct, forward-ref alias, nested) and > `examples/1129-diagnostics-array-dim-not-const.sx` (an unresolvable computed dim > halts with a clean diagnostic + non-zero exit, not a fabricated 0-length array). > > **Const-expression dimensions (attempt 4).** Attempts 1–3 resolved only a BARE > named-const dim (`[M]`) or a literal (`[5]`); any constant-FOLDABLE *expression* > dimension (`[M + 1]`, `[M * N]`, `[N - M]`, nested `[M + N - 1]`, parenthesised > `[(M + 1) * 2]`) was wrongly rejected as "not a compile-time integer constant" > even though every operand is compile-time-known. Such a dimension MUST be > evaluated, not rejected. Fix: the shared dim resolver now routes the dimension > through a single constant integer-expression evaluator > (`program_index.evalConstIntExpr`) that folds integer `+ - * / %` and unary > negate (parentheses carry no AST node) over literals and named/typed module > consts, recursively. The leaf-name lookup is delegated (`ctx.lookupDimName`) so > the stateful body-lowering path and the stateless registration path share the > EXACT SAME folding logic and cannot diverge — an expression dim via a type alias > resolves identically to the direct form. The no-fabrication discipline is > unchanged: a genuinely non-comptime dimension (a runtime local, a non-comptime > call, an unbound name) — or arithmetic that overflows / divides by zero — still > yields null → `.unresolved` → the same clean compile-halting diagnostic, never a > fabricated length. Files: `src/ir/program_index.zig` (+`.test.zig`), > `src/ir/lower.zig`, `src/ir/type_bridge.zig`. Regression: > `examples/0144-types-const-expr-array-dim.sx` (every expression form, direct vs > alias, scalar / string / struct element types); `1129` re-pointed at a genuinely > non-const dimension (`[get()]s64`, a runtime call) so it still proves the > stateless clean-halt. ## Symptom A fixed array whose dimension is a module-global integer constant (`N :: 16; a : [N]T`) miscompiles element access: reads/writes compute a wrong address. With `s64` elements `a[0]` returns GARBAGE (silent); with slice/pointer element types (`[N]string`) it Bus-errors. The identical program with a LITERAL dimension (`a : [16]T`) is correct. Silent-miscompile class (cf. 0079–0082). ## Reproduction ```sx #import "modules/std.sx"; N :: 16; main :: () { a : [N]s64 = ---; a[0] = 7; print("a0={}\n", a[0]); } ``` `./zig-out/bin/sx run` prints `a0=8472789232` (garbage); want `a0=7`. Replacing `[N]` with `[16]` prints `7`. ## Investigation prompt A fixed-array TYPE whose dimension is a named const (`N :: 16; [N]T`) resolves to a wrong element stride / array length in codegen — element address computation is wrong (garbage for scalars, bad pointer for slice/pointer elements). Literal dimensions are correct, so the defect is in resolving the array-type DIMENSION from a constant expression (vs a literal) — the dim likely resolves to 0/unknown or the element size is wrong. Look at array-type resolution where the length is a const-expr (type lowering / sizeof / element-stride computation). Fix so a named-const dimension yields the same layout as the literal. Verify with the repro (expect 7) + a `[N]string`/`[N]struct` case (no bus error, correct reads), and `zig build && zig build test && bash tests/run_examples.sh` green.