authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2023-02-18 13:04:27-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2023-02-18 19:17:21-07:00
logbcb72401d3cf01c190a346af9c9d8eec4a334b45
treed6af8c82405705c49fd01a8a190df9db5d600248
parent22965e6fcbafbcba207a6da8eb493af2cf7ef924

AstGen: add error for discard of unbounded counter


6 files changed, 150 insertions(+), 1 deletions(-)

src/AstGen.zig+6-1
......@@ -6346,8 +6346,9 @@ fn forExpr(
63466346 const i = @intCast(u32, i_usize);
63476347 const capture_is_ref = token_tags[capture_token] == .asterisk;
63486348 const ident_tok = capture_token + @boolToInt(capture_is_ref);
6349 const is_discard = mem.eql(u8, tree.tokenSlice(ident_tok), "_");
63496350
6350 if (mem.eql(u8, tree.tokenSlice(ident_tok), "_") and capture_is_ref) {
6351 if (is_discard and capture_is_ref) {
63516352 return astgen.failTok(capture_token, "pointer modifier invalid on discard", .{});
63526353 }
63536354 // Skip over the comma, and on to the next capture (or the ending pipe character).
......@@ -6367,6 +6368,10 @@ fn forExpr(
63676368 else
63686369 .none;
63696370
6371 if (end_val == .none and is_discard) {
6372 return astgen.failTok(ident_tok, "discard of unbounded counter", .{});
6373 }
6374
63706375 const start_is_zero = nodeIsTriviallyZero(tree, start_node);
63716376 const range_len = if (end_val == .none or start_is_zero)
63726377 end_val
test/behavior/for.zig+100
......@@ -276,3 +276,103 @@ test "two counters" {
276276
277277 try expect(sum == 10);
278278}
279
280test "1-based counter and ptr to array" {
281 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
282 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
283 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
284
285 var ok: usize = 0;
286
287 for (1..6, "hello") |i, b| {
288 if (i == 1) {
289 try expect(b == 'h');
290 ok += 1;
291 }
292 if (i == 2) {
293 try expect(b == 'e');
294 ok += 1;
295 }
296 if (i == 3) {
297 try expect(b == 'l');
298 ok += 1;
299 }
300 if (i == 4) {
301 try expect(b == 'l');
302 ok += 1;
303 }
304 if (i == 5) {
305 try expect(b == 'o');
306 ok += 1;
307 }
308 }
309
310 try expect(ok == 5);
311}
312
313test "slice and two counters, one is offset and one is runtime" {
314 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
315 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
316 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
317
318 const slice: []const u8 = "blah";
319 var start: usize = 0;
320
321 for (slice, start..4, 1..5) |a, b, c| {
322 if (a == 'b') {
323 try expect(b == 0);
324 try expect(c == 1);
325 }
326 if (a == 'l') {
327 try expect(b == 1);
328 try expect(c == 2);
329 }
330 if (a == 'a') {
331 try expect(b == 2);
332 try expect(c == 3);
333 }
334 if (a == 'h') {
335 try expect(b == 3);
336 try expect(c == 4);
337 }
338 }
339}
340
341test "two slices, one captured by-ref" {
342 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
343 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
344 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
345
346 var buf: [10]u8 = undefined;
347 const slice1: []const u8 = "blah";
348 const slice2: []u8 = buf[0..4];
349
350 for (slice1, slice2) |a, *b| {
351 b.* = a;
352 }
353
354 try expect(slice2[0] == 'b');
355 try expect(slice2[1] == 'l');
356 try expect(slice2[2] == 'a');
357 try expect(slice2[3] == 'h');
358}
359
360test "raw pointer and slice" {
361 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
362 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
363 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
364 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
365
366 var buf: [10]u8 = undefined;
367 const slice: []const u8 = "blah";
368 const ptr: [*]u8 = buf[0..4];
369
370 for (ptr, slice) |*a, b| {
371 a.* = b;
372 }
373
374 try expect(buf[0] == 'b');
375 try expect(buf[1] == 'l');
376 try expect(buf[2] == 'a');
377 try expect(buf[3] == 'h');
378}
test/cases/compile_errors/for_discard_unbounded.zig created+10
......@@ -0,0 +1,10 @@
1export fn a() void {
2 for (0..10, 10..) |i, _| {
3 _ = i;
4 }
5}
6// error
7// backend=stage2
8// target=native
9//
10// :2:27: error: discard of unbounded counter
test/cases/compile_errors/for_empty.zig created+11
......@@ -0,0 +1,11 @@
1export fn b() void {
2 for () |i| {
3 _ = i;
4 }
5}
6
7// error
8// backend=stage2
9// target=native
10//
11// :2:10: error: expected expression, found ')'
test/cases/compile_errors/for_extra_capture.zig created+12
......@@ -0,0 +1,12 @@
1export fn b() void {
2 for (0..10) |i, j| {
3 _ = i; _ = j;
4 }
5}
6
7// error
8// backend=stage2
9// target=native
10//
11// :2:21: error: extra capture in for loop
12// :2:21: note: run 'zig fmt' to upgrade your code automatically
test/cases/compile_errors/for_extra_condition.zig created+11
......@@ -0,0 +1,11 @@
1export fn a() void {
2 for (0..10, 10..20) |i| {
3 _ = i;
4 }
5}
6
7// error
8// backend=stage2
9// target=native
10//
11// :2:19: error: for input is not captured