Rewrote 20 issue writeups to the extern/runtime-class vocabulary (#foreign→extern, foreign_class_map→runtime_class_map, parseForeignClassDecl→parseRuntimeClassDecl, findForeignMethodInChain→findRuntimeMethodInChain, dedupeForeignSymbol→ dedupeExternSymbol, is_foreign_c_api→is_extern_c_api, stale filename refs to the renamed examples, foreign-class→runtime-class, bare foreign→extern). Renamed issues/0043-…-foreign-class-…→…-runtime-class-…. PHASE 9 COMPLETE — 9.4 GATE PASSES: zero 'foreign' across src/library/examples/ issues/docs/editors/specs/readme/CLAUDE, excluding only the SQLite API constant SQLITE_CONSTRAINT_FOREIGNKEY + vendored sqlite3.c/.h (upstream third-party). Suite green (644 corpus / 443 unit, 0 failed).
3.9 KiB
0071 — global initialized from module const silently zero-initializes
RESOLVED. Root cause:
Lowering.registerTopLevelGlobal's init_val switch serialized only literal / array-literal / struct-literal initializers; an identifier initializer (g : A = K;) fell through toelse => null, so the global was emitted with no payload and silently zero-initialized. Fix: extracted the initializer serialization intoLowering.globalInitValueand added an.identifierarm that materializes the global's static value fromProgramIndex.module_const_map(typed module consts are registered in the same pass-2 just before, viaregisterTypedModuleConst). An identifier that names no usable constant now emits a diagnostic instead of silently zeroing. Other initializer shapes (enum-literal shorthand, etc.) keep their established static-lowering behavior — this pass only closes the identifier/module-const hole. Regression:examples/0134-types-global-init-from-module-const.sx(g=42/ exit 42).
Symptom
A top-level global initialized from a module constant compiles but is zero-initialized instead of receiving the constant's value.
Observed:
g=0
Expected: g should be initialized to 42, or the compiler should reject the
initializer loudly if identifier/module-const global initializers are not
supported.
Reproduction
#import "modules/std.sx";
A :: B;
B :: i32;
K : A : 42;
g : A = K;
main :: () -> i32 {
print("g={}\n", g);
return g;
}
Run:
./zig-out/bin/sx run .sx-tmp/probe-0070-global-init-from-const.sx
The repro is standalone; the inline source above is sufficient to recreate the
scratch file under .sx-tmp/.
Investigation prompt
Fix issue 0071: a top-level global initialized from a module constant must not silently become zero.
Context:
- This surfaced during Codex re-review of
932cdfa, the issue-0070 fix. 932cdfacorrectly defers top-level global and typed-module-const annotation resolution until after the forward-alias fixpoint.- The remaining bug is in the global initializer path, not the annotation path:
K : A : 42; g : A = K;resolvesAcorrectly, registersKinProgramIndex.module_const_map, butgis emitted as zero.
Suspected area:
src/ir/lower.zig,Lowering.registerTopLevelGlobal.- Its
init_valswitch serializes literal / array / struct-literal initializers, but an identifier initializer falls through toelse => null, and the global is emitted with no initializer payload. That silently becomes zero-initialized. - Related facts:
ProgramIndex.module_const_mapalready records typed module constants viaregisterTypedModuleConst, now in pass 2 after alias convergence.
Likely fix:
- Add explicit handling for identifier initializers that name a module constant,
converting the recorded constant value into the global's
ConstantValuewith the global's declared type. - If some initializer shape cannot be represented as a global constant yet, emit
a diagnostic instead of returning
null/ zero-initializing. - Do not regress issue 0070:
A :: B; B :: i32; g : A = 7;andK : A : 35;must still resolve through the converged alias map. - Preserve literal, array literal, struct literal, and extern-global behavior.
Verification:
- Add a focused regression, likely in the
01xxtypes block:
#import "modules/std.sx";
A :: B;
B :: i32;
K : A : 42;
g : A = K;
main :: () -> i32 { print("g={}\n", g); return g; }
- Keep these green:
examples/0133-types-forward-alias-global.sxexamples/0132-types-forward-type-alias.sxexamples/0116-types-type-alias-size-align.sxexamples/0201-generics-generic-struct.sxexamples/1117-diagnostics-value-const-as-type-rejected.sx
- Run:
zig build
zig build test
bash tests/run_examples.sh
Expected result: the new regression prints g=42 and exits 42; unsupported
global initializer shapes no longer silently zero-initialize; the full suite
passes.