fix(ir): unify named-const array-dim resolution + kill length-0 fabrication (0083)

A type alias whose dimension is a named const (`Arr :: [N]T`) resolves its
dimension eagerly during scanDecls pass 1, on the stateless registration path,
which can only read `module_const_map`. Typed consts (`N : s64 : 16`) register
only in pass 2 and a forward-declared untyped const had not registered yet, so
the stateless resolver saw an empty table, printed a non-fatal warning,
fabricated length 0, and continued — yielding a 0-byte alloca, garbage reads,
and a segfault for slice/struct elements.

- scanDecls pass 0 pre-registers every integer-valued module const before any
  type alias resolves, so typed, untyped, and forward-referenced consts all
  resolve identically.
- Both dim resolvers now share `program_index.moduleConstInt`, so the stateful
  body-lowering path and the stateless registration path cannot diverge.
- `resolveArrayLen` returns `?u32`; `resolveCompound` yields `.unresolved` on
  null instead of a 0-length array. The stateful path emits a diagnostic; the
  alias-registration path surfaces an unresolved alias as a clean compile error
  that aborts the build. The Vector lane-count `else => 0` is fixed the same way.

Regressions: examples/0143 (typed-const dim direct + via alias for s64/string/
struct, forward-ref alias, nested) and examples/1129 (an unresolvable computed
dim halts with a clean diagnostic + non-zero exit). Both fail on the pre-fix
compiler (garbage/segfault; warning+exit0) and pass after.
This commit is contained in:
agra
2026-06-04 09:39:18 +03:00
parent 1f9f944ca1
commit d2bf8f3f2d
14 changed files with 211 additions and 34 deletions

View File

@@ -0,0 +1,20 @@
// An array dimension that is not a compile-time integer constant is a hard
// error, not a silently-fabricated 0-length array. Here a type alias's
// dimension is a computed expression (`M + 1`), which the registration-time
// resolver cannot evaluate.
//
// Regression (issue 0083): the stateless resolver printed a non-fatal warning
// and fabricated length 0, then let compilation continue — producing a 0-byte
// alloca and corrupt element access. It now yields the `.unresolved` sentinel,
// which the alias registration surfaces as this diagnostic, aborting the build
// with a non-zero exit.
#import "modules/std.sx";
M :: 4;
BadArr :: [M + 1]s64;
main :: () {
a : BadArr = ---;
a[0] = 7;
print("a0={}\n", a[0]);
}