Makes the F0.4 fixes exhaustive across every resolution / nesting path.
0083 — named-const array dimension, stateless paths. Attempt 1 fixed the
stateful resolver (direct local decls, struct fields, params, returns) but the
binding-free registration-time resolver (`type_bridge`, used for type aliases
`Arr :: [N]T` and inline union/enum field types) still resolved a named dim with
a silent `else 0`, so `Arr :: [N]s64; a : Arr` and `union { a: [N]s64 }` were
still miscompiled (garbage / bus error). Thread the module-global const table
(`ProgramIndex.module_const_map`) 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 dim on
the binding-free path, which the stateful path hard-errors) now bails LOUDLY
instead of fabricating a 0 length.
0085 — nested slice-literal elements. `lowerArrayLiteral` lowered each element
with the element type as target but appended the raw value. A nested `.[...]`
element at a slice element type (`[][]s64`) still lowers to an aggregate array
`[N]T`, so the outer aggregate held raw arrays where slice {ptr,len} headers
were expected — indexing the inner slice read a garbage pointer and segfaulted.
After lowering each element, coerce a same-element array to the slice element
type via the existing `array_to_slice` op. The coercion recurses with the
nesting, so `[][]T` and deeper materialize at every level — local-bound AND
direct-call-argument forms.
Regressions (fail-before/pass-after demonstrated on the pre-fix compiler):
examples/0140-types-named-const-array-dim.sx — extended with type-alias,
nested [N][M]T, and union-field named dims (s64 / string / struct elems)
examples/0142-types-nested-slice-literal-elements.sx — [][]s64 + [][]string,
local-bound vs direct-arg
src/ir/type_bridge.test.zig — named-const dim resolves to literal length
Gate: zig build, zig build test, bash tests/run_examples.sh (388 passed).
Issues 0083 and 0085 marked RESOLVED.
56 lines
3.2 KiB
Markdown
56 lines
3.2 KiB
Markdown
# 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).
|
||
|
||
## 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.
|