Surface rename of the signed integer family: s1..s64 become i1..i64
(u1..u64, usize, isize unchanged). 'string' keeps the s-prefix arm in
name classification; width parsing moves to the i-prefix arm next to
isize.
Internal TypeId tags follow the surface (.s8/.s16/.s32/.s64 ->
.i8/.i16/.i32/.i64), as do mono-key mangle fragments (ptr_i64,
tu_i64_bool) and all display/diagnostic formatting (i{d}).
Migrated in the same sweep: stdlib + examples + issue repros + FFI C
companions (shared symbol names like ffi_id_i64), expected
stdout/stderr/ir snapshots, specs.md, readme.md, CLAUDE.md/AGENTS.md,
implementation_plan.md, docs/, issue writeups. Vendored stb_image and
historical flow state left untouched.
zig build test: 426/426; examples suite: 595/595.
4.5 KiB
0080 - global array of struct literals silently zero-initializes
RESOLVED. Root cause:
Lowering.constExprValue(src/ir/lower.zig) — the constant- aggregate serializer for global initializers — handled primitive and nested- array leaves but had no.struct_literalarm. A module-global[N]Structinitialized with struct literals reachedconstArrayLiteral→constExprValueper element; each struct-literal element returnednull, collapsing the whole array initializer tonull.globalInitValuethen emitted no payload, so the LLVM backend zero-initialized the global (@pairs = ... zeroinitializer), silently dropping every declared field — the same silent-zero class as 0071/0072, one level inside an array literal. (A global struct literal and a struct-with-array already worked, becauseconstStructLiteralexisted and was reached directly; the gap was specifically struct literals as array elements.) Fix: makeconstExprValuetype-aware — thread the destination element/fieldTypeIdso a.struct_literalleaf routes throughconstStructLiteraland a nested.array_literalthroughconstArrayLiteralwith the correct element type.constArrayLiteralderives its element type from the arrayTypeId;constStructLiteralpasses each field's type. A global aggregate initializer that still does not fully reduce to a compile-time constant is now rejected loudly (diagnoseNonConstGlobal) instead of falling through to a zeroed global. The downstreamemitConstAggregatealready recurses over nested aggregates, so const/AOT (sx build) and JIT (sx run) both materialize the declared values. Regression:examples/0137-types-global-aggregate-literal-init.sx(global[N]Structliteral, global struct literal, struct-with-array, nested array-of- struct-with-array; values read back with no prior store, plus a store on top). FAILS on the pre-fix compiler (array-of-struct fields read 0), PASSES after.
Symptom
A module-global fixed array whose elements are struct literals is emitted as zero-initialized storage instead of preserving the literal fields.
Observed: reading pairs[0].b and pairs[1].a prints 0.
Expected: the global should contain the declared struct literal values
(2 and 3), or the compiler should reject the initializer loudly if this
constant shape is unsupported.
Reproduction
#import "modules/std.sx";
Pair :: struct {
a: i64;
b: i64;
}
pairs : [2]Pair = .[ .{ a = 1, b = 2 }, .{ a = 3, b = 4 } ];
main :: () -> i32 {
print("pairs[0]={},{}\n", pairs[0].a, pairs[0].b);
print("pairs[1]={},{}\n", pairs[1].a, pairs[1].b);
if pairs[0].a == 1 and pairs[0].b == 2 and pairs[1].a == 3 and pairs[1].b == 4 {
print("PASS\n");
return 0;
}
print("FAIL: global array struct literal initializer zeroed\n");
return 1;
}
On the current compiler this prints:
pairs[0]=0,0
pairs[1]=0,0
FAIL: global array struct literal initializer zeroed
sx ir <file> shows the global as:
@pairs = internal global [2 x { i64, i64 }] zeroinitializer
Investigation prompt
Fix issue 0080: a module-global array initialized with struct literal elements
silently becomes zeroinitializer.
Suspected area:
src/ir/lower.zig,Lowering.globalInitValue.src/ir/lower.zig,Lowering.constArrayLiteral.src/ir/lower.zig,Lowering.constExprValue.src/ir/lower.zig,Lowering.constStructLiteral.
Likely root cause: globalInitValue handles a top-level .array_literal by
calling constArrayLiteral, and constArrayLiteral serializes each element via
constExprValue. constExprValue handles primitive literals and nested arrays,
but not .struct_literal, so an array whose element is a struct literal returns
null. That null initializer payload is later emitted as zero-initialized
storage, recreating the silent zero pattern from issues 0071/0072 one level
inside an otherwise-supported array literal.
Likely fix:
- Thread the expected element
TypeIdintoconstArrayLiteral, or otherwise makeconstExprValuetype-aware for struct literals. - Serialize each struct element through
constStructLiteralwith the array's element type. - If any element shape is still unsupported, emit a diagnostic naming the global
instead of returning
nulland allowing zero-initialization.
Verification:
- Run the repro above and expect:
pairs[0]=1,2
pairs[1]=3,4
PASS
- Add a pinned regression in the
01xxtypes block. - Run:
zig build
zig build test
bash tests/run_examples.sh