lang: multi-iterable for loops — drop ':', add '..=', open ranges, arrow bodies

The for header is now a comma-separated list of iterables with a
positional capture group and no ':' separator:

    for xs (x) { }                    // collection
    for 0..n (i) { }                  // range (end exclusive)
    for 1..=5 (a) { }                 // ..= inclusive end
    for xs, 0.. (x, i) { }            // index idiom (replaces (x, i))
    for xs, ys (x, y) { }             // parallel (zip) iteration
    for xs (x) => sum += x;           // arrow body (full statement)

First-iterable-wins: the first iterable's length drives the loop and
must be bounded; the other positions follow by their own cursors (a
non-first range's end is not consulted or evaluated; a shorter
non-first collection is read past its length on mismatch). The old
single-iterable index capture is replaced by the trailing open range.

Capture/call disambiguation is positional: the paren group immediately
before '{' or '=>' is the capture, every earlier top-level group is a
call. 'for zip(a, b) (x, y)' calls zip; 'for f(n) { }' reads (n) as
the capture and errors with a parenthesize/add-capture hint. The old
':' form errors with a migration hint.

Lowering is unified across forms: one cursor slot per position (ranges
start at their start, collections at 0), all advanced together, the
first position's bound terminating. inline for keeps the single
bounded comptime range.

Migrated the full corpus (examples, library modules, issue repros,
in-source test strings). New coverage: examples/0050 (the full feature
surface) and examples/1149-1155 (seven diagnostic faces). specs.md For
Loop section + grammar rewritten; readme teaser updated.
This commit is contained in:
agra
2026-06-10 20:30:55 +03:00
parent c640e88513
commit 116af2359e
75 changed files with 701 additions and 391 deletions

View File

@@ -1,5 +1,5 @@
// Range-based for loops: `for start..end: (i) { }` (cursor optional, `end`
// exclusive) is a runtime counting loop; `inline for start..end: (i) { }`
// Range-based for loops: `for start..end (i) { }` (cursor optional, `end`
// exclusive) is a runtime counting loop; `inline for start..end (i) { }`
// is comptime-unrolled — the cursor is a compile-time constant each
// iteration, so `xs[i]` over a heterogeneous pack substitutes the concrete
// per-position element (this is what drives pack iteration).
@@ -16,14 +16,14 @@ impl Show for B { show :: (self: *B) -> string => "B"; }
// Comptime-unrolled iteration over a pack; cursor `i` indexes the pack.
each :: (..xs: Show) -> void {
inline for 0..xs.len: (i) {
inline for 0..xs.len (i) {
print("[{}]={}\n", i, xs[i].show());
}
}
main :: () -> s32 {
// Runtime range, cursor used.
for 0..3: (i) { print("i={}\n", i); }
for 0..3 (i) { print("i={}\n", i); }
// Runtime range, no cursor — body runs `end - start` times.
n := 0;
@@ -31,7 +31,7 @@ main :: () -> s32 {
print("n={}\n", n);
// Non-zero start.
for 2..5: (j) { print("j={}\n", j); }
for 2..5 (j) { print("j={}\n", j); }
// Inline unroll over a heterogeneous pack.
each(A.{ x = 1 }, B.{ s = "hi" }, A.{ x = 3 });

View File

@@ -1,4 +1,4 @@
// `for xs: (*x)` binds each element by pointer — no per-element copy.
// `for xs (*x)` binds each element by pointer — no per-element copy.
// Mutations write back, and a pointer subject matches through the deref.
#import "modules/std.sx";
@@ -10,12 +10,12 @@ Shape :: enum {
main :: () -> s32 {
// By-ref mutation writes back into the array (impossible with a value copy).
xs : [3]s64 = .[1, 2, 3];
for xs: (*x) { x.* = x + 100; }
for xs (*x) { x.* = x + 100; }
print("{} {} {}\n", xs[0], xs[1], xs[2]);
// Pointer subject matches through the deref; payload reads through the ref.
shapes : [2]Shape = .[.circle(2.0), .none];
for shapes: (*s) {
for shapes (*s) {
if s == {
case .circle: (r) { print("circle {}\n", r); }
case .none: { print("none\n"); }

View File

@@ -10,7 +10,7 @@ Box :: struct {
sum_ptr :: (xs: *List(s64)) -> s64 {
total : s64 = 0;
for xs: (n) { total = total + n; } // iterate through a *List
for xs (n) { total = total + n; } // iterate through a *List
total
}
@@ -21,12 +21,12 @@ main :: () -> s32 {
xs.append(30);
s : s64 = 0;
for xs: (n) { s = s + n; } // value capture
for xs (n) { s = s + n; } // value capture
print("sum {}\n", s); // 60
for xs: (*n) { n.* = n + 100; } // by-ref: writes back
for xs (*n) { n.* = n + 100; } // by-ref: writes back
s = 0;
for xs: (n) { s = s + n; }
for xs (n) { s = s + n; }
print("sum2 {}\n", s); // 360
print("via ptr {}\n", sum_ptr(@xs)); // 360
@@ -34,7 +34,7 @@ main :: () -> s32 {
bs := List(Box).{};
bs.append(.{ v = 7 });
bt : s64 = 0;
for bs: (*b) { bt = bt + b.boxed(); } // *Box receiver, value-self method
for bs (*b) { bt = bt + b.boxed(); } // *Box receiver, value-self method
print("boxes {}\n", bt); // 7
0
}

View File

@@ -118,7 +118,7 @@ main :: () {
// For loop basic
farr : [4]s32 = .[10, 20, 30, 40];
out("for:");
for farr: (it) {
for farr (it) {
out(" ");
out(int_to_string(it));
}
@@ -126,14 +126,14 @@ main :: () {
// For with print
out("for-print:");
for farr: (it) {
for farr (it) {
print(" {}", it);
}
out("\n");
// For with index
out("for-idx:");
for farr: (_, ix) {
for farr, 0.. (_, ix) {
out(" ");
out(int_to_string(ix));
}
@@ -141,14 +141,14 @@ main :: () {
// For with print two args
out("for-2arg:");
for farr: (it, ix) {
for farr, 0.. (it, ix) {
print(" {}@{}", it, ix);
}
out("\n");
// For with break
out("for-break:");
for farr: (it) {
for farr (it) {
if it == 30 { break; }
print(" {}", it);
}
@@ -156,7 +156,7 @@ main :: () {
// For with continue
out("for-continue:");
for farr: (it) {
for farr (it) {
if it == 20 { continue; }
print(" {}", it);
}
@@ -165,14 +165,14 @@ main :: () {
// For on slice
fsl : []s32 = .[10, 20, 30];
out("for-slice:");
for fsl: (it) {
for fsl (it) {
print(" {}", it);
}
out("\n");
// For on slice with index
out("for-slice-idx:");
for fsl: (it, ix) {
for fsl, 0.. (it, ix) {
print(" {}:{}", ix, it);
}
out("\n");
@@ -181,8 +181,8 @@ main :: () {
nf_a : [2]s32 = .[0, 1];
nf_b : [2]s32 = .[0, 1];
out("for-nested:");
for nf_a: (oa) {
for nf_b: (ob) {
for nf_a (oa) {
for nf_b (ob) {
print(" ({},{})", oa, ob);
}
}
@@ -191,7 +191,7 @@ main :: () {
// For with break preserving index
fbi : [5]s32 = .[10, 20, 30, 40, 50];
fbi_idx := 0;
for fbi: (it, ix) {
for fbi, 0.. (it, ix) {
if it == 30 { fbi_idx = ix; break; }
}
print("for-break-idx: {}\n", fbi_idx);

View File

@@ -16,7 +16,7 @@ pair_add :: (a: $T, b: $U) -> s64 {
typed_sum :: (..args: []s32) -> s32 {
result := 0;
for args: (it) { result = result + it; }
for args (it) { result = result + it; }
result
}

View File

@@ -10,7 +10,7 @@
main :: () -> s32 {
sum := 0;
for 0..1000000: (i) {
for 0..1000000 (i) {
buf : [128]s64 = ---;
buf[0] = i;
sum += buf[0];
@@ -18,8 +18,8 @@ main :: () -> s32 {
print("sum={}\n", sum);
n := 0;
for 0..3000000: (i) {
for 0..1: (j) { n += 1; }
for 0..3000000 (i) {
for 0..1 (j) { n += 1; }
}
print("n={}\n", n);
0

View File

@@ -13,12 +13,12 @@ main :: () -> s32 {
i := 0;
while i < 4096 { arr[i] = i; i += 1; }
sum := 0;
for arr: (x) { sum += x; }
for arr (x) { sum += x; }
print("sum={}\n", sum);
// By-value capture is a copy: mutating it leaves the array untouched.
small : [3]s64 = .[10, 20, 30];
for small: (x) { x += 100; }
for small (x) { x += 100; }
print("copy-guard: {} {} {}\n", small[0], small[1], small[2]);
0
}

View File

@@ -7,14 +7,14 @@
#import "modules/std.sx";
main :: () -> s32 {
for 0..3: (i) {
for 0..3 (i) {
defer print("cleanup {}\n", i);
if i == 1 { break; }
print("body {}\n", i);
}
print("after break loop\n");
for 0..3: (i) {
for 0..3 (i) {
defer print("c2 {}\n", i);
if i == 1 { continue; }
print("b2 {}\n", i);
@@ -33,7 +33,7 @@ main :: () -> s32 {
// A break inside a nested block drains the nested block's defers AND the
// loop body's, in LIFO order.
for 0..2: (j) {
for 0..2 (j) {
defer print("outer {}\n", j);
{
defer print("inner {}\n", j);

View File

@@ -0,0 +1,54 @@
#import "modules/std.sx";
pair_sum :: (xs: []s64, ys: []s64) -> s64 {
total := 0;
for xs, ys (x, y) { total += x * y; }
total
}
make :: () -> [3]s64 {
r : [3]s64 = .[7, 8, 9];
r
}
main :: () -> s32 {
// Agra's example: a 1..5 inclusive, b open-ended following along.
for 1..=5, 0.. (a, b) { print("{}:{} ", a, b); }
print("\n");
// Index idiom replacing the old (x, i) form.
xs : [3]s64 = .[10, 20, 30];
for xs, 0.. (x, i) { print("[{}]={} ", i, x); }
print("\n");
// Parallel slices.
a4 : [4]s64 = .[1, 2, 3, 4];
b4 : [4]s64 = .[10, 20, 30, 40];
print("dot={}\n", pair_sum(a4, b4));
// Arrow bodies.
s := 0;
for 0..4 (i) => s += i;
print("arrow-range s={}\n", s);
t := 0;
for xs (x) => t += x;
print("arrow-coll t={}\n", t);
// Call iterable + capture (first group = args, last group = capture).
for make() (v) { print("v{} ", v); }
print("\n");
// No-capture call iterable via leading-group escape.
n := 0;
for (make()) { n += 1; }
print("escape n={}\n", n);
// Three-way zip: two collections + cursor.
for a4, b4, 100.. (p, q, k) { print("{}/{}/{} ", p, q, k); }
print("\n");
// By-ref capture in a multi-iterable header.
for a4, 0.. (*p, i) { p.* += i; }
print("after ref: {} {} {} {}\n", a4[0], a4[1], a4[2], a4[3]);
0
}

View File

@@ -16,7 +16,7 @@ main :: () {
spts : [2]Point = .[Point.{1, 2}, Point.{3, 4}];
spt2 := spts[1];
print("arr-struct-x: {}\n", spt2.x);
for spts: (it) {
for spts (it) {
print("for-struct: {}\n", it);
}
}

View File

@@ -63,6 +63,6 @@ main :: () {
mk : Make(N, s64) = ---; mk[2] = 33; print("vp.typefn.expr: len={} v={}\n", mk.len, mk[2]);
// inline-for bound — expr const (3) and integral float (4)
s := 0; inline for 0..N: (i) { s += i; } print("for.expr: {}\n", s); // 0+1+2 = 3
t := 0; inline for 0..F: (i) { t += i; } print("for.float: {}\n", t); // 0+1+2+3 = 6
s := 0; inline for 0..N (i) { s += i; } print("for.expr: {}\n", s); // 0+1+2 = 3
t := 0; inline for 0..F (i) { t += i; } print("for.float: {}\n", t); // 0+1+2+3 = 6
}

View File

@@ -35,7 +35,7 @@ main :: () -> s32 {
// for capture + index names
xs := [3]s64.{ 10, 20, 30 };
for xs: (`bool, `u16) {
for xs, 0.. (`bool, `u16) {
print("for = {} @ {}\n", `bool, `u16);
}

View File

@@ -61,7 +61,7 @@ pair_add :: (a: $T, b: $U) -> s64 {
typed_sum :: (..args: []s32) -> s32 {
result := 0;
for args: (it) { result = result + it; }
for args (it) { result = result + it; }
result
}

View File

@@ -2,14 +2,14 @@
sum :: (..args: []s32) -> s32 {
result := 0;
for args: (it) {
for args (it) {
result = result + it;
}
result
}
print_all :: (..args: []s32) {
for args: (it) {
for args (it) {
out(int_to_string(it));
out(" ");
}
@@ -26,7 +26,7 @@ main :: () -> s32 {
out(int_to_string(sum(..arr)));
out("\n");
for arr: (it) {
for arr (it) {
out(int_to_string(it));
out(" ");
}

View File

@@ -7,7 +7,7 @@ Point :: struct {
// Print all arguments — accepts any type, dispatches via type-switch
print_any :: (..args: []Any) {
for args: (it) {
for args (it) {
type := type_of(it);
if type == {
case int: out(int_to_string(cast(s32) it));

View File

@@ -6,7 +6,7 @@
// constant (a literal, or an `inline for` cursor). A runtime index (here a
// `while`-loop counter) must produce a clear diagnostic, not the confusing
// "unresolved 'args'" the slice-index fall-through used to give. To walk a
// pack, use `inline for 0..args.len: (i) { ... }`, which unrolls so each
// pack, use `inline for 0..args.len (i) { ... }`, which unrolls so each
// `args[i]` is a comptime index.
#import "modules/std.sx";

View File

@@ -14,7 +14,7 @@ sink :: (v: s64) -> void { _ = v; }
storage :: (..xs: Show) -> void { y := xs; _ = y; } // A: store
call :: (..xs: Show) -> void { sink(xs); } // B: pass to a call
ret :: (..xs: Show) -> s64 { return xs; } // C: return
iter :: (..xs: Show) -> void { for xs : (x) { _ = x; } } // D: runtime iterate
iter :: (..xs: Show) -> void { for xs (x) { _ = x; } } // D: runtime iterate
main :: () -> s32 {
storage(A.{});

View File

@@ -14,10 +14,10 @@ M :: 3;
main :: () {
s := 0;
inline for 0..M: (i) { s += i; }
inline for 0..M (i) { s += i; }
print("sum 0..M = {}\n", s); // 0 + 1 + 2 = 3
t := 0;
inline for 0..(M + 1): (i) { t += i; }
inline for 0..(M + 1) (i) { t += i; }
print("sum 0..(M+1) = {}\n", t); // 0 + 1 + 2 + 3 = 6
}

View File

@@ -9,6 +9,6 @@ M :: 3.0;
main :: () {
s := 0;
inline for 0..M: (i) { s += i; }
inline for 0..M (i) { s += i; }
print("sum 0..M = {}\n", s); // 0 + 1 + 2 = 3
}

View File

@@ -11,14 +11,14 @@
main :: () {
s := 0;
inline for -2..1: (i) { s += i; }
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; }
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; }
inline for 0..(-2.0) (i) { e += i; }
print("inline for 0..(-2.0) sum = {}\n", e); // empty range -> 0 iterations
}

View File

@@ -4,7 +4,7 @@
combine :: (x: s64, y: s64) -> s64 { return x + y; }
pick :: (..xs: []s64) -> s64 {
result := 0;
for xs: (it) { result = result + it; }
for xs (it) { result = result + it; }
result
}
from_a_combine :: () -> s64 { return combine(10, 20); }

View File

@@ -4,7 +4,7 @@
// pack, pick subtracts its two fixed args.
combine :: (..xs: []s64) -> s64 {
result := 0;
for xs: (it) { result = result + it; }
for xs (it) { result = result + it; }
result
}
pick :: (a: s64, b: s64) -> s64 { return b - a; }

View File

@@ -17,7 +17,7 @@ g :: () -> !E { return; }
f :: () -> !E {
defer { return; } // ERROR: return in defer body
onfail { try g(); } // ERROR: try in onfail body
defer { for 0..1: (i) { break; } } // ERROR: break in defer body (transitive through loop)
defer { for 0..1 (i) { break; } } // ERROR: break in defer body (transitive through loop)
onfail e { if e == error.Bad { continue; } } // ERROR: continue in onfail body
try g();
return;

View File

@@ -1,4 +1,4 @@
// A by-reference loop capture (`for xs: (*m)`) binds `m` to a `*T`.
// A by-reference loop capture (`for xs (*m)`) binds `m` to a `*T`.
// Passing it where a `T` value is expected used to slip through to the
// LLVM verifier ("Call parameter type does not match function signature").
// The compiler now reports it at the call site with a fix-it: write `m.*`.
@@ -11,7 +11,7 @@ take :: (m: Move) -> s64 { return m.flag; }
main :: () -> s32 {
moves : [2]Move = .[ Move.{ flag = 1 }, Move.{ flag = 2 } ];
for moves: (*m) {
for moves (*m) {
take(m);
}
return 0;

View File

@@ -1,5 +1,5 @@
// Passing a `*T` where a `T` value is expected is caught at the call site —
// not only for `for xs: (*m)` loop captures (see 215) but for any pointer,
// not only for `for xs (*m)` loop captures (see 215) but for any pointer,
// here a `*Move` parameter forwarded into a by-value parameter. Without the
// check this slipped through to the LLVM verifier as "Call parameter type
// does not match function signature".

View File

@@ -19,8 +19,8 @@ main :: () -> s32 {
if u8 := maybe() { } // if optional binding
while s16 := maybe() { break; } // while optional binding
xs := [3]s64.{ 10, 20, 30 };
for xs: (bool) { } // for capture name
for xs: (v, s32) { } // for index name
for xs (bool) { } // for capture name
for xs, 0.. (v, s32) { } // for index name
opt: ?s64 = 5;
r := if opt == { // match-arm capture
case .some: (string) { 0 }

View File

@@ -9,6 +9,6 @@
main :: () {
s := 0;
inline for 0..4.5: (i) { s += i; }
inline for 0..4.5 (i) { s += i; }
print("unreachable: {}\n", s);
}

View File

@@ -0,0 +1,9 @@
// The pre-multi-iterable `for xs: (x)` syntax (colon before the capture) is
// rejected with a migration hint.
#import "modules/std.sx";
main :: () {
xs : [2]s64 = .[1, 2];
for xs: (x) { }
}

View File

@@ -0,0 +1,9 @@
// A for capture group is positional: one capture per iterable (or none).
#import "modules/std.sx";
main :: () {
xs : [2]s64 = .[1, 2];
ys : [2]s64 = .[3, 4];
for xs, ys (x) { }
}

View File

@@ -0,0 +1,8 @@
// The FIRST iterable drives the loop, so it must be bounded; an open range
// `a..` may only follow it.
#import "modules/std.sx";
main :: () {
for 0.. (i) { }
}

View File

@@ -0,0 +1,7 @@
// `..=` is the inclusive bounded form — it requires an end expression.
#import "modules/std.sx";
main :: () {
for 0..= (i) { }
}

View File

@@ -0,0 +1,8 @@
// Range elements are synthesized values with no storage — `*` capture is
// rejected.
#import "modules/std.sx";
main :: () {
for 0..3 (*i) { }
}

View File

@@ -0,0 +1,11 @@
// In a for header the trailing paren group is the CAPTURE; a call iterable
// therefore needs one too. `()` cannot be a capture — parse error with the
// hint (`for f(n) (x) { }` / `for (f(n)) { }` / bind it first).
#import "modules/std.sx";
g :: () -> s64 { 1 }
main :: () {
for g() { }
}

View File

@@ -0,0 +1,12 @@
// The collision case of the positional capture rule: `for f(n) { }` reads
// `(n)` as the capture, making the iterable `f` itself — not iterable, with
// the parenthesize/add-capture hint.
#import "modules/std.sx";
f :: (n: s64) -> s64 { n }
main :: () {
n := 1;
for f(n) { }
}

View File

@@ -0,0 +1 @@
0

View File

@@ -0,0 +1 @@

View File

@@ -0,0 +1,9 @@
1:0 2:1 3:2 4:3 5:4
[0]=10 [1]=20 [2]=30
dot=300
arrow-range s=6
arrow-coll t=60
v7 v8 v9
escape n=3
1/10/100 2/20/101 3/30/102 4/40/103
after ref: 1 3 5 7

View File

@@ -1,5 +1,5 @@
error: pack 'xs' has no runtime value — a pack is comptime-only and can't be used as a value here
--> /Users/agra/projects/sx/examples/0536-packs-pack-as-value.sx:14:40
--> examples/0536-packs-pack-as-value.sx:14:40
|
14 | storage :: (..xs: Show) -> void { y := xs; _ = y; } // A: store
| ^^
@@ -10,7 +10,7 @@ help: to store it, materialize a tuple: `(..xs)`
| ^^
error: pack 'xs' has no runtime value — a pack is comptime-only and can't be used as a value here
--> /Users/agra/projects/sx/examples/0536-packs-pack-as-value.sx:15:40
--> examples/0536-packs-pack-as-value.sx:15:40
|
15 | call :: (..xs: Show) -> void { sink(xs); } // B: pass to a call
| ^^
@@ -21,7 +21,7 @@ help: materialize a tuple `(..xs)` to store it, or `xx xs` to convert it to an e
| ^^
error: pack 'xs' has no runtime value — a pack is comptime-only and can't be used as a value here
--> /Users/agra/projects/sx/examples/0536-packs-pack-as-value.sx:16:42
--> examples/0536-packs-pack-as-value.sx:16:42
|
16 | ret :: (..xs: Show) -> s64 { return xs; } // C: return
| ^^
@@ -32,12 +32,12 @@ help: to return it, return a tuple `(..xs)` and make the return type that tuple
| ^^
error: pack 'xs' has no runtime value — a pack is comptime-only and can't be used as a value here
--> /Users/agra/projects/sx/examples/0536-packs-pack-as-value.sx:17:39
--> examples/0536-packs-pack-as-value.sx:17:39
|
17 | iter :: (..xs: Show) -> void { for xs : (x) { _ = x; } } // D: runtime iterate
17 | iter :: (..xs: Show) -> void { for xs (x) { _ = x; } } // D: runtime iterate
| ^^
help: to iterate at comptime use `inline for 0..xs.len (i)`; for a runtime loop declare it as `..xs: []P` (a protocol slice) instead of a pack
|
17 | iter :: (..xs: Show) -> void { for xs : (x) { _ = x; } } // D: runtime iterate
17 | iter :: (..xs: Show) -> void { for xs (x) { _ = x; } } // D: runtime iterate
| ^^

View File

@@ -17,16 +17,16 @@ error: 's16' is a reserved type name and cannot be used as an identifier
| ^^^
error: 'bool' is a reserved type name and cannot be used as an identifier
--> examples/1121-diagnostics-reserved-name-control-flow.sx:22:14
--> examples/1121-diagnostics-reserved-name-control-flow.sx:22:13
|
22 | for xs: (bool) { } // for capture name
| ^^^^
22 | for xs (bool) { } // for capture name
| ^^^^
error: 's32' is a reserved type name and cannot be used as an identifier
--> examples/1121-diagnostics-reserved-name-control-flow.sx:23:17
--> examples/1121-diagnostics-reserved-name-control-flow.sx:23:21
|
23 | for xs: (v, s32) { } // for index name
| ^^^
23 | for xs, 0.. (v, s32) { } // for index name
| ^^^
error: 'string' is a reserved type name and cannot be used as an identifier
--> examples/1121-diagnostics-reserved-name-control-flow.sx:26:22

View File

@@ -1,5 +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; }
12 | inline for 0..4.5 (i) { s += i; }
| ^^^

View File

@@ -0,0 +1 @@
1

View File

@@ -0,0 +1,5 @@
error: for-loop syntax: the ':' before the capture was removed — write `for xs (x) { }` (index via `for xs, 0.. (x, i)`)
--> examples/1149-diagnostics-for-colon-removed.sx:8:11
|
8 | for xs: (x) { }
| ^

View File

@@ -0,0 +1 @@

View File

@@ -0,0 +1 @@
1

View File

@@ -0,0 +1,5 @@
error: for capture count must match the iterable count — one capture per iterable
--> examples/1150-diagnostics-for-capture-arity.sx:8:20
|
8 | for xs, ys (x) { }
| ^

View File

@@ -0,0 +1 @@

View File

@@ -0,0 +1 @@
1

View File

@@ -0,0 +1,5 @@
error: the first iterable must have a bounded length (it drives the loop) — an open range 'a..' may only follow it
--> examples/1151-diagnostics-for-open-first.sx:7:17
|
7 | for 0.. (i) { }
| ^

View File

@@ -0,0 +1 @@

View File

@@ -0,0 +1 @@
1

View File

@@ -0,0 +1,5 @@
error: '..=' requires an end expression — the open form is 'a..'
--> examples/1152-diagnostics-for-inclusive-open.sx:6:14
|
6 | for 0..= (i) { }
| ^

View File

@@ -0,0 +1 @@

View File

@@ -0,0 +1 @@
1

View File

@@ -0,0 +1,5 @@
error: a range element cannot be captured by reference
--> examples/1153-diagnostics-for-range-by-ref.sx:7:19
|
7 | for 0..3 (*i) { }
| ^

View File

@@ -0,0 +1 @@

View File

@@ -0,0 +1 @@
1

View File

@@ -0,0 +1,5 @@
error: expected capture variable name (a call iterable also needs a capture: `for f(n) (x) { }`)
--> examples/1154-diagnostics-for-call-needs-capture.sx:10:11
|
10 | for g() { }
| ^

View File

@@ -0,0 +1 @@
1

View File

@@ -0,0 +1,5 @@
error: cannot iterate this expression — if the parens were call arguments, a call iterable also needs a capture (`for f(n) (x) { }`) or parentheses (`for (f(n)) { }`)
--> examples/1155-diagnostics-for-not-iterable.sx:11:9
|
11 | for f(n) { }
| ^

View File

@@ -0,0 +1 @@