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.3 KiB
0082 - global enum-literal initializer silently zero-initializes
RESOLVED. Root cause:
Lowering.globalInitValue(src/ir/lower.zig) carried an.enum_literal => nullcarve-out: any enum-literal global initializer returned a null payload, which the LLVM/interp emitters turn into a zero-initialized global — sochosen : Color = .greenread back as the first tag (.red).constExprValuehad no enum-literal arm either, so an enum tag inside a global array ([2]Color = .[.green, .blue]) or struct field made the whole aggregate look non-constant and the global was rejected outright. Fix: a newLowering.constEnumLiteralserializes an enum literal to aConstantValue.intholding the variant's tag value, resolved against the destination enum type and respecting explicit variant values (enum { a; b :: 5; }); the global's type drives the backing width at emit time. Wired into bothglobalInitValue(scalar global) andconstExprValue(array element / struct field / nested aggregate). A non-enum destination or an unknown variant is diagnosed loudly — never silently zero-initialized. The compiler-injectedOS/ARCHglobals now serialize to their real.unknowntag (6 / 4) instead of relying on the null→zero fallback; runtime reads are unchanged because they resolve throughcomptime_constants. As part of the same exhaustiveness pass, the silentfunc_ref => … orelse LLVMConstNullfallbacks in the LLVM constant emitters (src/ir/emit_llvm.zig) were removed: aggregate func_ref leaves carry arequire_resolvedflag (transient null in Pass 0, loud diagnostic if still unresolved in the Pass-1.5 re-emit), a top-level func_ref global is resolved ininitVtableGlobals, and the comptime (#run) path bails loudly instead of emitting a null function pointer. Regression:examples/0139-types-global-enum-literal-init.sx(scalar enum global, global array of enum, enum struct field, explicit-valueenum u16for element-stride, struct-array with enum field) — FAILS on the pre-fix compiler (wrong tag / rejected as non-constant), PASSES after. Negative:examples/1127-diagnostics-global-enum-literal-bad-variant.sx(unknown variant rejected loudly, exit 1).
Symptom
A module-global enum initialized with a non-zero enum literal silently reads back
as the zero tag. Observed: chosen : Color = .green; prints .red and the
program exits 1. Expected: it should print .green and exit 0, or the compiler
should reject unsupported enum-literal global initializers loudly instead of
zero-initializing.
Reproduction
#import "modules/std.sx";
Color :: enum u8 { red; green; blue; }
chosen : Color = .green;
main :: () -> i32 {
print("chosen={}\n", chosen);
if chosen == .green {
print("PASS\n");
return 0;
}
print("FAIL\n");
return 1;
}
Observed:
chosen=.red
FAIL
Expected:
chosen=.green
PASS
Investigation prompt
Fix issue 0082: module-global enum literal initializers silently become the zero tag.
Suspected area:
src/ir/lower.zig,Lowering.globalInitValue: the.enum_literal => nullcarve-out preserves the stdlib's historical zero-init path for compiler- injectedOS : OperatingSystem = .unknown, but it also silently drops any user-written non-zero enum literal such as.green.src/ir/lower.zig,Lowering.constExprValue: aggregate enum-literal fields are currently not serialized either, so audit both top-level and aggregate enum literals.
Likely fix:
- Resolve the destination enum type from
var_ty/expected_tyand serialize the enum tag as aConstantValue.intwith the variant index/value. - If a particular enum literal shape cannot be serialized yet (payload variants,
unsupported explicit tag values, etc.), emit a diagnostic instead of returning
null. - Preserve the compiler-injected
OperatingSystem/Architecturebehavior by making those globals real constants, not by relying on null initializer fallback.
Verification:
- Run the repro above and expect
chosen=.green/PASS/ exit 0. - Add a pinned regression in the
01xxtypes block for a non-zero enum global and, if supported by the fix, an enum field inside a global aggregate. - Run:
zig build
zig build test
bash tests/run_examples.sh