fix(ir): reject typed module const whose initializer mismatches annotation [F0.7]
A typed module-level constant whose initializer did not match its annotation was silently accepted: `N : string : 4` compiled, then `print(N)` segfaulted (an integer emitted as a `string` const → a bogus pointer) and `[N]s64` folded `N` to 4 as an integer count. Issue 0088. Root cause: `registerTypedModuleConst` stored the annotation type but never validated the initializer literal against it, and `program_index.moduleConstInt` folded a const into a count by inspecting the initializer node alone, ignoring `ModuleConstInfo.ty`. Fix at the declaration (kills both symptoms): - lower.zig: `registerTypedModuleConst` now validates the initializer via `typedConstInitFits` (arms mirror `emitModuleConst`'s faithful-emit precondition: int→int/float, float→float, bool→bool, string→string, null→pointer/optional, `---`→any). A mismatch emits a `type mismatch` diagnostic at the initializer span and does not register the const (also evicting the pass-0 placeholder). Not routed through `coercionResolver().classify`: that runtime-coercion planner is unsound here (null's natural type is void → false-rejects `*T`; bool is 1 bit → false-accepts s64). - program_index.zig: `moduleConstInt` now takes the `TypeTable` and gates the fold on `isCountableConstType(ci.ty)` (integer of any width, or a float), so a non-numeric typed const can never fold into a count off its initializer node. Callers in lower.zig and type_bridge.zig updated. Regression: - examples/1143-diagnostics-typed-module-const-mismatch.sx (negative, exit 1) - examples/0162-types-typed-module-const-roundtrip.sx (positive) - program_index.test.zig: gate-on-declared-type unit test Docs: specs.md §3 Constant Binding + readme.md note the compatibility rule.
This commit is contained in:
35
examples/0162-types-typed-module-const-roundtrip.sx
Normal file
35
examples/0162-types-typed-module-const-roundtrip.sx
Normal file
@@ -0,0 +1,35 @@
|
||||
// Valid typed module-level constants compile, fold, and print correctly across
|
||||
// every initializer/annotation pairing the registrar accepts:
|
||||
// - integer → integer (`K : s64 : 4`) — usable as an array count too
|
||||
// - integer → float (`W : f32 : 800`)
|
||||
// - float → float (`PI : f32 : 3.14159`)
|
||||
// - string → string (`S : string : "hi"`)
|
||||
// - null → pointer (`P : *void : null`)
|
||||
//
|
||||
// Companion to the negative example 1143: the issue-0088 fix rejects a typed
|
||||
// const whose initializer mismatches its annotation, and these correctly-typed
|
||||
// consts must keep working (no over-rejection).
|
||||
#import "modules/std.sx";
|
||||
|
||||
K : s64 : 4;
|
||||
W : f32 : 800;
|
||||
PI : f32 : 3.14159;
|
||||
S : string : "hi";
|
||||
P : *void : null;
|
||||
|
||||
main :: () {
|
||||
// Integer const: prints AND drives an array dimension (len 4).
|
||||
a : [K]s64 = ---;
|
||||
a[0] = 10;
|
||||
a[3] = 40;
|
||||
print("K={} len={} a0={} a3={}\n", K, a.len, a[0], a[3]);
|
||||
|
||||
// Integer-into-float and float consts print as floats.
|
||||
print("W={} PI={}\n", W, PI);
|
||||
|
||||
// String const prints its text.
|
||||
print("S={}\n", S);
|
||||
|
||||
// Null pointer const is null.
|
||||
print("P_is_null={}\n", P == null);
|
||||
}
|
||||
20
examples/1143-diagnostics-typed-module-const-mismatch.sx
Normal file
20
examples/1143-diagnostics-typed-module-const-mismatch.sx
Normal file
@@ -0,0 +1,20 @@
|
||||
// A typed module-level constant whose initializer does not match its
|
||||
// annotation is a compile-time type error — not a silently-accepted const.
|
||||
// Each declaration below pairs a literal with an incompatible annotation, so
|
||||
// the compiler must emit a `type mismatch` diagnostic at the initializer and
|
||||
// abort (exit 1) rather than registering a usable const.
|
||||
//
|
||||
// Regression (issue 0088): `N : string : 4` was accepted; `print(N)` then
|
||||
// segfaulted (an integer emitted as a `string` const → a bogus pointer) and
|
||||
// `[N]s64` folded `N` to 4. The fix rejects the declaration at the root.
|
||||
|
||||
#import "modules/std.sx";
|
||||
|
||||
N : string : 4; // integer literal where a string is annotated
|
||||
F : s64 : "x"; // string literal where an integer is annotated
|
||||
B : s64 : true; // boolean literal where an integer is annotated
|
||||
G : s64 : 1.5; // float literal where an integer is annotated
|
||||
|
||||
main :: () {
|
||||
print("unreachable\n");
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
0
|
||||
@@ -0,0 +1 @@
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
K=4 len=4 a0=10 a3=40
|
||||
W=800.000000 PI=3.141590
|
||||
S=hi
|
||||
P_is_null=true
|
||||
@@ -0,0 +1 @@
|
||||
1
|
||||
@@ -0,0 +1,23 @@
|
||||
error: type mismatch: constant 'N' is declared 'string' but its initializer is an integer literal
|
||||
--> examples/1143-diagnostics-typed-module-const-mismatch.sx:13:14
|
||||
|
|
||||
13 | N : string : 4; // integer literal where a string is annotated
|
||||
| ^
|
||||
|
||||
error: type mismatch: constant 'F' is declared 's64' but its initializer is a string literal
|
||||
--> examples/1143-diagnostics-typed-module-const-mismatch.sx:14:14
|
||||
|
|
||||
14 | F : s64 : "x"; // string literal where an integer is annotated
|
||||
| ^^^
|
||||
|
||||
error: type mismatch: constant 'B' is declared 's64' but its initializer is a boolean literal
|
||||
--> examples/1143-diagnostics-typed-module-const-mismatch.sx:15:14
|
||||
|
|
||||
15 | B : s64 : true; // boolean literal where an integer is annotated
|
||||
| ^^^^
|
||||
|
||||
error: type mismatch: constant 'G' is declared 's64' but its initializer is a float literal
|
||||
--> examples/1143-diagnostics-typed-module-const-mismatch.sx:16:14
|
||||
|
|
||||
16 | G : s64 : 1.5; // float literal where an integer is annotated
|
||||
| ^^^
|
||||
@@ -0,0 +1 @@
|
||||
|
||||
Reference in New Issue
Block a user