AstGen: add error for discard of unbounded counter

This commit is contained in:
Andrew Kelley 2023-02-18 13:04:27 -07:00
parent 22965e6fcb
commit bcb72401d3
6 changed files with 150 additions and 1 deletions

View file

@ -6346,8 +6346,9 @@ fn forExpr(
const i = @intCast(u32, i_usize);
const capture_is_ref = token_tags[capture_token] == .asterisk;
const ident_tok = capture_token + @boolToInt(capture_is_ref);
const is_discard = mem.eql(u8, tree.tokenSlice(ident_tok), "_");
if (mem.eql(u8, tree.tokenSlice(ident_tok), "_") and capture_is_ref) {
if (is_discard and capture_is_ref) {
return astgen.failTok(capture_token, "pointer modifier invalid on discard", .{});
}
// Skip over the comma, and on to the next capture (or the ending pipe character).
@ -6367,6 +6368,10 @@ fn forExpr(
else
.none;
if (end_val == .none and is_discard) {
return astgen.failTok(ident_tok, "discard of unbounded counter", .{});
}
const start_is_zero = nodeIsTriviallyZero(tree, start_node);
const range_len = if (end_val == .none or start_is_zero)
end_val

View file

@ -276,3 +276,103 @@ test "two counters" {
try expect(sum == 10);
}
test "1-based counter and ptr to array" {
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
var ok: usize = 0;
for (1..6, "hello") |i, b| {
if (i == 1) {
try expect(b == 'h');
ok += 1;
}
if (i == 2) {
try expect(b == 'e');
ok += 1;
}
if (i == 3) {
try expect(b == 'l');
ok += 1;
}
if (i == 4) {
try expect(b == 'l');
ok += 1;
}
if (i == 5) {
try expect(b == 'o');
ok += 1;
}
}
try expect(ok == 5);
}
test "slice and two counters, one is offset and one is runtime" {
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
const slice: []const u8 = "blah";
var start: usize = 0;
for (slice, start..4, 1..5) |a, b, c| {
if (a == 'b') {
try expect(b == 0);
try expect(c == 1);
}
if (a == 'l') {
try expect(b == 1);
try expect(c == 2);
}
if (a == 'a') {
try expect(b == 2);
try expect(c == 3);
}
if (a == 'h') {
try expect(b == 3);
try expect(c == 4);
}
}
}
test "two slices, one captured by-ref" {
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
var buf: [10]u8 = undefined;
const slice1: []const u8 = "blah";
const slice2: []u8 = buf[0..4];
for (slice1, slice2) |a, *b| {
b.* = a;
}
try expect(slice2[0] == 'b');
try expect(slice2[1] == 'l');
try expect(slice2[2] == 'a');
try expect(slice2[3] == 'h');
}
test "raw pointer and slice" {
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
var buf: [10]u8 = undefined;
const slice: []const u8 = "blah";
const ptr: [*]u8 = buf[0..4];
for (ptr, slice) |*a, b| {
a.* = b;
}
try expect(buf[0] == 'b');
try expect(buf[1] == 'l');
try expect(buf[2] == 'a');
try expect(buf[3] == 'h');
}

View file

@ -0,0 +1,10 @@
export fn a() void {
for (0..10, 10..) |i, _| {
_ = i;
}
}
// error
// backend=stage2
// target=native
//
// :2:27: error: discard of unbounded counter

View file

@ -0,0 +1,11 @@
export fn b() void {
for () |i| {
_ = i;
}
}
// error
// backend=stage2
// target=native
//
// :2:10: error: expected expression, found ')'

View file

@ -0,0 +1,12 @@
export fn b() void {
for (0..10) |i, j| {
_ = i; _ = j;
}
}
// error
// backend=stage2
// target=native
//
// :2:21: error: extra capture in for loop
// :2:21: note: run 'zig fmt' to upgrade your code automatically

View file

@ -0,0 +1,11 @@
export fn a() void {
for (0..10, 10..20) |i| {
_ = i;
}
}
// error
// backend=stage2
// target=native
//
// :2:19: error: for input is not captured