diff --git a/examples/0612-comptime-inline-for-range-bounds.sx b/examples/0612-comptime-inline-for-range-bounds.sx new file mode 100644 index 0000000..8857e93 --- /dev/null +++ b/examples/0612-comptime-inline-for-range-bounds.sx @@ -0,0 +1,24 @@ +// An `inline for` / `for` range bound is a range ENDPOINT, not a count, so the +// count negative-rejection rule does NOT apply to it: negative endpoints are +// valid and an empty/inverted range simply runs zero iterations. +// +// Regression (F0.4 attempt 11, Agra ruling): the spec wrongly lumped inline-for +// bounds with counts (array dim / Vector lane / value-param), which reject +// negatives. Bounds are exempt — `inline for -2..1` iterates -2,-1,0 and an +// integral-float empty range `0..(-2.0)` runs zero iterations. Comptime and +// runtime loops must agree. +#import "modules/std.sx"; + +main :: () { + s := 0; + inline for -2..1: (i) { s += i; } + print("inline for -2..1 sum = {}\n", s); // -2 + -1 + 0 = -3 + + r := 0; + for -2..1: (i) { r += i; } + print("for -2..1 sum = {}\n", r); // -2 + -1 + 0 = -3 (runtime parity) + + e := 0; + inline for 0..(-2.0): (i) { e += i; } + print("inline for 0..(-2.0) sum = {}\n", e); // empty range -> 0 iterations +} diff --git a/examples/1138-diagnostics-inline-for-non-integral-bound.sx b/examples/1138-diagnostics-inline-for-non-integral-bound.sx new file mode 100644 index 0000000..71481a3 --- /dev/null +++ b/examples/1138-diagnostics-inline-for-non-integral-bound.sx @@ -0,0 +1,14 @@ +// A NON-integral float (`4.5`) as an `inline for` range bound is a hard error: +// the loop cursor must be a compile-time integer, so only an integral float +// (`4.0`, `-2.0`) folds. Clean diagnostic + non-zero exit. +// +// Regression (F0.4 attempt 11, Agra ruling): range bounds are exempt from the +// count negative-rejection (negatives are valid endpoints), but the +// must-be-integer requirement still applies — `4.5` has no integer value. +#import "modules/std.sx"; + +main :: () { + s := 0; + inline for 0..4.5: (i) { s += i; } + print("unreachable: {}\n", s); +} diff --git a/examples/expected/0612-comptime-inline-for-range-bounds.exit b/examples/expected/0612-comptime-inline-for-range-bounds.exit new file mode 100644 index 0000000..573541a --- /dev/null +++ b/examples/expected/0612-comptime-inline-for-range-bounds.exit @@ -0,0 +1 @@ +0 diff --git a/examples/expected/0612-comptime-inline-for-range-bounds.stderr b/examples/expected/0612-comptime-inline-for-range-bounds.stderr new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/examples/expected/0612-comptime-inline-for-range-bounds.stderr @@ -0,0 +1 @@ + diff --git a/examples/expected/0612-comptime-inline-for-range-bounds.stdout b/examples/expected/0612-comptime-inline-for-range-bounds.stdout new file mode 100644 index 0000000..d331b45 --- /dev/null +++ b/examples/expected/0612-comptime-inline-for-range-bounds.stdout @@ -0,0 +1,3 @@ +inline for -2..1 sum = -3 +for -2..1 sum = -3 +inline for 0..(-2.0) sum = 0 diff --git a/examples/expected/1138-diagnostics-inline-for-non-integral-bound.exit b/examples/expected/1138-diagnostics-inline-for-non-integral-bound.exit new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/examples/expected/1138-diagnostics-inline-for-non-integral-bound.exit @@ -0,0 +1 @@ +1 diff --git a/examples/expected/1138-diagnostics-inline-for-non-integral-bound.stderr b/examples/expected/1138-diagnostics-inline-for-non-integral-bound.stderr new file mode 100644 index 0000000..23039e6 --- /dev/null +++ b/examples/expected/1138-diagnostics-inline-for-non-integral-bound.stderr @@ -0,0 +1,5 @@ +error: inline for: range end is not a compile-time integer + --> examples/1138-diagnostics-inline-for-non-integral-bound.sx:12:19 + | +12 | inline for 0..4.5: (i) { s += i; } + | ^^^ diff --git a/examples/expected/1138-diagnostics-inline-for-non-integral-bound.stdout b/examples/expected/1138-diagnostics-inline-for-non-integral-bound.stdout new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/examples/expected/1138-diagnostics-inline-for-non-integral-bound.stdout @@ -0,0 +1 @@ + diff --git a/specs.md b/specs.md index 4958ae5..183295f 100644 --- a/specs.md +++ b/specs.md @@ -651,11 +651,20 @@ Arrays can also be constructed programmatically with the `Array` builtin: MyArr :: Array(5, s32); // equivalent to [5]s32 ``` -An array dimension — and likewise a `Vector` lane count, a generic value-param -count, and an `inline for` bound — accepts any compile-time numeric constant -whose value is a positive integral number. An integral float (`4.0`, or a -float-typed const `N : f64 : 4.0`) folds to its integer (`[4.0]s64` ≡ `[4]s64`); -a non-integral float (`4.5`) or a negative value is rejected. +A **count** — an array dimension, a `Vector` lane count, or a generic +value-param count — accepts any compile-time numeric constant whose value is a +positive integral number. An integral float (`4.0`, or a float-typed const +`N : f64 : 4.0`) folds to its integer (`[4.0]s64` ≡ `[4]s64`); a non-integral +float (`4.5`) or a negative value is rejected. + +A **range bound** — the start/end of an `inline for` or `for` range — is a +range *endpoint*, not a count, so the count rules above do not apply. A bound +accepts any compile-time **integer**, including a negative one; an integral +float (`-2.0`) folds to its integer. A non-integral float (`4.5`) is still +rejected, because the loop cursor must be a compile-time integer. Negative +endpoints are valid: `inline for -2..1` iterates `-2, -1, 0`. An empty or +inverted range (start ≥ end, e.g. `0..(-2.0)`) simply runs zero iterations +rather than being an error. ### Slice Types A slice `[]T` is a fat pointer `{ptr, i64}` referencing a contiguous sequence of `T` elements. Same runtime layout as `string`.