fix(ir): integral-float counts + range-checked value-param binds (0083)
Item 2 (Agra ruling): a compile-time INTEGRAL float (`4.0`, `N : f64 : 4.0`, `N :: 4.0`) used as an array dimension / Vector lane / generic value-param count / `inline for` bound now folds to its integer at the shared leaf — `program_index.floatToIntExact`, used by both the `.float_literal` arm of `evalConstIntExpr` and `moduleConstInt`. All four consumers route through the one evaluator, so `[4.0]s64` lays out the same `[4]s64` uniformly; a non-integral (`4.5`) or negative value stays rejected by the downstream `foldDimU32` gate. Pass-0 now pre-registers float-valued module consts for forward-alias parity with int consts. Item 1: a generic value-param bind (`Box($K: u32)`) never range-checked the folded arg, so `Box(5_000_000_000)` compiled and ran. The bind now range-checks against the param's declared type — a `u32` count through the shared `foldDimU32` gate (making program_index's "single u32 gate for value-param counts" doc true), any other integer type through the new `program_index.intTypeRange` — and emits a clean "value N does not fit in u32 parameter K" otherwise. The declared type is threaded via a new `TemplateParam.value_type`. Regressions: examples 0145 (integral-float array dim), 1504 (Vector lane), 0611 (inline-for bound), 0209 (value-param integral-float), 1132 (non-integral float dim rejected), 1133 (negative float dim rejected), 1134 (oversized u32 value-param rejected) + program_index float-fold unit tests. Gate: zig build, zig build test, 406/0 run_examples.
This commit is contained in:
29
examples/0145-types-integral-float-array-dim.sx
Normal file
29
examples/0145-types-integral-float-array-dim.sx
Normal file
@@ -0,0 +1,29 @@
|
||||
// An array dimension accepts any compile-time numeric constant whose value is a
|
||||
// positive INTEGRAL number — an integral float (`4.0`) folds to its integer just
|
||||
// like `4`. A float-typed const (`N : f64 : 4.0`), an untyped-float const
|
||||
// (`M :: 4.0`), and a direct float literal (`[4.0]s64`) all lay out the same
|
||||
// `[4]s64` as the integer spelling, so element store/read is in bounds.
|
||||
//
|
||||
// Regression (issue 0083 / F0.4 attempt 8, Agra ruling): an integral float used
|
||||
// as a dimension was wrongly rejected "must be a compile-time integer constant".
|
||||
// The shared const-int evaluator now folds an integral float literal (and a
|
||||
// float-typed module const) via `program_index.floatToIntExact`; a non-integral
|
||||
// float (`4.5`) is still rejected (see 1132).
|
||||
#import "modules/std.sx";
|
||||
|
||||
N : f64 : 4.0; // float-typed const
|
||||
M :: 4.0; // untyped float const
|
||||
|
||||
main :: () {
|
||||
a : [N]s64 = ---; // dim from a float-typed const
|
||||
a[0] = 10; a[3] = 40;
|
||||
print("a len={} a0={} a3={}\n", a.len, a[0], a[3]);
|
||||
|
||||
b : [M]s64 = ---; // dim from an untyped float const
|
||||
b[1] = 21;
|
||||
print("b len={} b1={}\n", b.len, b[1]);
|
||||
|
||||
c : [4.0]s64 = ---; // direct integral-float-literal dim
|
||||
c[2] = 32;
|
||||
print("c len={} c2={}\n", c.len, c[2]);
|
||||
}
|
||||
19
examples/0209-generics-value-param-integral-float.sx
Normal file
19
examples/0209-generics-value-param-integral-float.sx
Normal file
@@ -0,0 +1,19 @@
|
||||
// A generic value parameter (`$K: u32`) binds a literal (`Vec(3, s64)`) and an
|
||||
// integral-float named const (`Vec(L, s64)` with `L : f64 : 4.0`) to the same
|
||||
// integer a plain `4` would — the value-param arg folds through the shared
|
||||
// const-int evaluator, so the integral-float rule (F0.4 attempt 8, Agra ruling)
|
||||
// reaches value params too. The folded value is the array length `[K]s64`.
|
||||
//
|
||||
// The bind is range-checked against the declared `u32` (an out-of-range arg is a
|
||||
// clean compile error — see 1134); a valid in-range value binds normally.
|
||||
#import "modules/std.sx";
|
||||
|
||||
Vec :: struct ($K: u32, $T: Type) { data: [K]T; }
|
||||
|
||||
L : f64 : 4.0;
|
||||
|
||||
main :: () {
|
||||
a : Vec(3, s64) = ---; // literal value param
|
||||
b : Vec(L, s64) = ---; // integral-float named-const value param → 4
|
||||
print("a.len={} b.len={}\n", a.data.len, b.data.len); // 3 and 4
|
||||
}
|
||||
14
examples/0611-comptime-integral-float-inline-for.sx
Normal file
14
examples/0611-comptime-integral-float-inline-for.sx
Normal file
@@ -0,0 +1,14 @@
|
||||
// An `inline for 0..M` bound accepts an integral float constant — `M :: 3.0`
|
||||
// unrolls the same three iterations as `M :: 3`. The inline-for bound folder
|
||||
// (`evalComptimeInt`) delegates to the shared const-int evaluator, so the
|
||||
// integral-float rule (issue 0083 / F0.4 attempt 8, Agra ruling) applies here
|
||||
// too.
|
||||
#import "modules/std.sx";
|
||||
|
||||
M :: 3.0;
|
||||
|
||||
main :: () {
|
||||
s := 0;
|
||||
inline for 0..M: (i) { s += i; }
|
||||
print("sum 0..M = {}\n", s); // 0 + 1 + 2 = 3
|
||||
}
|
||||
14
examples/1132-diagnostics-array-dim-non-integral-float.sx
Normal file
14
examples/1132-diagnostics-array-dim-non-integral-float.sx
Normal file
@@ -0,0 +1,14 @@
|
||||
// A NON-integral float constant (`4.5`) used as an array dimension is a hard
|
||||
// error — only an integral float (`4.0`) folds to a count. Clean diagnostic +
|
||||
// non-zero exit, NOT a fabricated length.
|
||||
//
|
||||
// Regression (F0.4 attempt 8, Agra ruling): the integral-float rule accepts
|
||||
// `4.0` as a dimension but must keep rejecting `4.5` (it is not an integer).
|
||||
#import "modules/std.sx";
|
||||
|
||||
N : f64 : 4.5;
|
||||
|
||||
main :: () {
|
||||
a : [N]s64 = ---;
|
||||
print("unreachable: {}\n", a.len);
|
||||
}
|
||||
12
examples/1133-diagnostics-array-dim-negative-float.sx
Normal file
12
examples/1133-diagnostics-array-dim-negative-float.sx
Normal file
@@ -0,0 +1,12 @@
|
||||
// A NEGATIVE integral float (`-2.0`) used as an array dimension is a hard error.
|
||||
// The integral-float rule folds and negates it to `-2`, then the shared u32 dim
|
||||
// gate rejects a below-minimum dimension — a clean diagnostic + non-zero exit.
|
||||
//
|
||||
// Regression (F0.4 attempt 8, Agra ruling): integral floats fold, but a negative
|
||||
// result is still rejected (a dimension must be non-negative).
|
||||
#import "modules/std.sx";
|
||||
|
||||
main :: () {
|
||||
a : [-2.0]s64 = ---;
|
||||
print("unreachable: {}\n", a.len);
|
||||
}
|
||||
17
examples/1134-diagnostics-value-param-u32-overflow.sx
Normal file
17
examples/1134-diagnostics-value-param-u32-overflow.sx
Normal file
@@ -0,0 +1,17 @@
|
||||
// A generic value-param arg that does not fit the param's declared integer type
|
||||
// (`Box(5_000_000_000)` for `$K: u32`) is a hard error — a clean diagnostic +
|
||||
// non-zero exit, NOT a silent truncating bind.
|
||||
//
|
||||
// Regression (F0.4 attempt 8, item 1): `resolveValueParamArg` bound the folded
|
||||
// i64 without range-checking the declared type, so an out-of-u32 arg compiled
|
||||
// and ran. The bind now routes a `u32` count through the shared
|
||||
// `program_index.foldDimU32` gate (the same one array dims / Vector lanes use),
|
||||
// so an oversized value is rejected before instantiation.
|
||||
#import "modules/std.sx";
|
||||
|
||||
Box :: struct ($K: u32) { value: s64; }
|
||||
|
||||
main :: () {
|
||||
b : Box(5000000000) = ---;
|
||||
print("unreachable\n");
|
||||
}
|
||||
12
examples/1504-vectors-integral-float-lane.sx
Normal file
12
examples/1504-vectors-integral-float-lane.sx
Normal file
@@ -0,0 +1,12 @@
|
||||
// A Vector lane count accepts an integral float constant — `L : f64 : 4.0` lays
|
||||
// out the same `Vector(4, f32)` as the literal `4`. The lane resolver shares the
|
||||
// const-int evaluator with the array-dim path, so the integral-float rule
|
||||
// (issue 0083 / F0.4 attempt 8, Agra ruling) applies uniformly.
|
||||
#import "modules/std.sx";
|
||||
|
||||
L : f64 : 4.0;
|
||||
|
||||
main :: () {
|
||||
v : Vector(L, f32) = .[1.0, 2.0, 3.0, 4.0];
|
||||
print("v0={} v2={} v3={}\n", v[0], v[2], v[3]);
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
0
|
||||
@@ -0,0 +1 @@
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
a len=4 a0=10 a3=40
|
||||
b len=4 b1=21
|
||||
c len=4 c2=32
|
||||
@@ -0,0 +1 @@
|
||||
0
|
||||
@@ -0,0 +1 @@
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
a.len=3 b.len=4
|
||||
@@ -0,0 +1 @@
|
||||
0
|
||||
@@ -0,0 +1 @@
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
sum 0..M = 3
|
||||
@@ -0,0 +1 @@
|
||||
1
|
||||
@@ -0,0 +1,5 @@
|
||||
error: array dimension must be a compile-time integer constant
|
||||
--> examples/1132-diagnostics-array-dim-non-integral-float.sx:12:10
|
||||
|
|
||||
12 | a : [N]s64 = ---;
|
||||
| ^
|
||||
@@ -0,0 +1 @@
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
1
|
||||
@@ -0,0 +1,5 @@
|
||||
error: array dimension must be non-negative, got -2
|
||||
--> examples/1133-diagnostics-array-dim-negative-float.sx:10:10
|
||||
|
|
||||
10 | a : [-2.0]s64 = ---;
|
||||
| ^^^^
|
||||
@@ -0,0 +1 @@
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
1
|
||||
@@ -0,0 +1,5 @@
|
||||
error: value 5000000000 does not fit in u32 parameter K
|
||||
--> examples/1134-diagnostics-value-param-u32-overflow.sx:15:13
|
||||
|
|
||||
15 | b : Box(5000000000) = ---;
|
||||
| ^^^^^^^^^^
|
||||
@@ -0,0 +1 @@
|
||||
|
||||
1
examples/expected/1504-vectors-integral-float-lane.exit
Normal file
1
examples/expected/1504-vectors-integral-float-lane.exit
Normal file
@@ -0,0 +1 @@
|
||||
0
|
||||
@@ -0,0 +1 @@
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
v0=1.000000 v2=3.000000 v3=4.000000
|
||||
Reference in New Issue
Block a user