1const builtin = @import("builtin");
2const std = @import("std");
3const expect = std.testing.expect;
4const expectEqual = std.testing.expectEqual;
5const mem = std.mem;
6
7test "continue in for loop" {
8 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
9
10 const array = [_]i32{ 1, 2, 3, 4, 5 };
11 var sum: i32 = 0;
12 for (array) |x| {
13 sum += x;
14 if (x < 3) {
15 continue;
16 }
17 break;
18 }
19 if (sum != 6) unreachable;
20}
21
22test "break from outer for loop" {
23 try testBreakOuter();
24 try comptime testBreakOuter();
25}
26
27fn testBreakOuter() !void {
28 const array = "aoeu";
29 var count: usize = 0;
30 outer: for (array) |_| {
31 for (array) |_| {
32 count += 1;
33 break :outer;
34 }
35 }
36 try expect(count == 1);
37}
38
39test "continue outer for loop" {
40 try testContinueOuter();
41 try comptime testContinueOuter();
42}
43
44fn testContinueOuter() !void {
45 const array = "aoeu";
46 var counter: usize = 0;
47 outer: for (array) |_| {
48 for (array) |_| {
49 counter += 1;
50 continue :outer;
51 }
52 }
53 try expect(counter == array.len);
54}
55
56test "ignore lval with underscore (for loop)" {
57 for ([_]void{}, 0..) |_, i| {
58 _ = i;
59 for ([_]void{}, 0..) |_, j| {
60 _ = j;
61 break;
62 }
63 break;
64 }
65}
66
67test "basic for loop" {
68 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
69 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
70 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
71
72 const expected_result: [24]u8 = .{
73 9, 8, 7, 6, 0, 1, 2, 3,
74 9, 8, 7, 6, 0, 1, 2, 3,
75 9, 8, 7, 6, 0, 1, 2, 3,
76 };
77
78 var buffer: [expected_result.len]u8 = undefined;
79 var buf_index: usize = 0;
80
81 const array = [_]u8{ 9, 8, 7, 6 };
82 for (array) |item| {
83 buffer[buf_index] = item;
84 buf_index += 1;
85 }
86 for (array, 0..) |item, index| {
87 _ = item;
88 buffer[buf_index] = @as(u8, @intCast(index));
89 buf_index += 1;
90 }
91 const array_ptr = &array;
92 for (array_ptr) |item| {
93 buffer[buf_index] = item;
94 buf_index += 1;
95 }
96 for (array_ptr, 0..) |item, index| {
97 _ = item;
98 buffer[buf_index] = @as(u8, @intCast(index));
99 buf_index += 1;
100 }
101 const unknown_size: []const u8 = &array;
102 for (unknown_size) |item| {
103 buffer[buf_index] = item;
104 buf_index += 1;
105 }
106 for (unknown_size, 0..) |_, index| {
107 buffer[buf_index] = @as(u8, @intCast(index));
108 buf_index += 1;
109 }
110
111 try expect(mem.eql(u8, buffer[0..buf_index], &expected_result));
112}
113
114test "for with null and T peer types and inferred result location type" {
115 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
116 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
117 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
118
119 const S = struct {
120 fn doTheTest(slice: []const u8) !void {
121 if (for (slice) |item| {
122 if (item == 10) {
123 break item;
124 }
125 } else null) |v| {
126 _ = v;
127 @panic("fail");
128 }
129 }
130 };
131 try S.doTheTest(&[_]u8{ 1, 2 });
132 try comptime S.doTheTest(&[_]u8{ 1, 2 });
133}
134
135test "2 break statements and an else" {
136 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
137
138 const S = struct {
139 fn entry(t: bool, f: bool) !void {
140 var buf: [10]u8 = undefined;
141 var ok = false;
142 ok = for (&buf) |*item| {
143 _ = item;
144 if (f) break false;
145 if (t) break true;
146 } else false;
147 try expect(ok);
148 }
149 };
150 try S.entry(true, false);
151 try comptime S.entry(true, false);
152}
153
154test "for loop with pointer elem var" {
155 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
156 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
157 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
158
159 const source = "abcdefg";
160 var target: [source.len]u8 = undefined;
161 @memcpy(target[0..], source);
162 mangleString(target[0..]);
163 try expect(mem.eql(u8, &target, "bcdefgh"));
164
165 for (source, 0..) |*c, i| {
166 _ = i;
167 try expect(@TypeOf(c) == *const u8);
168 }
169 for (&target, 0..) |*c, i| {
170 _ = i;
171 try expect(@TypeOf(c) == *u8);
172 }
173}
174
175fn mangleString(s: []u8) void {
176 for (s) |*c| {
177 c.* += 1;
178 }
179}
180
181test "for copies its payload" {
182 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
183
184 const S = struct {
185 fn doTheTest() !void {
186 var x = [_]usize{ 1, 2, 3 };
187 for (x, 0..) |value, i| {
188 // Modify the original array
189 x[i] += 99;
190 try expect(value == i + 1);
191 }
192 }
193 };
194 try S.doTheTest();
195 try comptime S.doTheTest();
196}
197
198test "for on slice with allowzero ptr" {
199 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
200 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
201 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
202
203 const S = struct {
204 fn doTheTest(slice: []const u8) !void {
205 const ptr = @as([*]allowzero const u8, @ptrCast(slice.ptr))[0..slice.len];
206 for (ptr, 0..) |x, i| try expect(x == i + 1);
207 for (ptr, 0..) |*x, i| try expect(x.* == i + 1);
208 }
209 };
210 try S.doTheTest(&[_]u8{ 1, 2, 3, 4 });
211 try comptime S.doTheTest(&[_]u8{ 1, 2, 3, 4 });
212}
213
214test "else continue outer for" {
215 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
216 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
217
218 var i: usize = 6;
219 var buf: [5]u8 = undefined;
220 while (true) {
221 i -= 1;
222 for (buf[i..5]) |_| {
223 return;
224 } else continue;
225 }
226}
227
228test "for loop with else branch" {
229 {
230 var x = [_]u32{ 1, 2 };
231 _ = &x;
232 const q = for (x) |y| {
233 if ((y & 1) != 0) continue;
234 break y * 2;
235 } else @as(u32, 1);
236 try expect(q == 4);
237 }
238 {
239 var x = [_]u32{ 1, 2 };
240 _ = &x;
241 const q = for (x) |y| {
242 if ((y & 1) != 0) continue;
243 break y * 2;
244 } else @panic("");
245 try expect(q == 4);
246 }
247}
248
249test "count over fixed range" {
250 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
251 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
252
253 var sum: usize = 0;
254 for (0..6) |i| {
255 sum += i;
256 }
257
258 try expect(sum == 15);
259}
260
261test "two counters" {
262 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
263 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
264
265 var sum: usize = 0;
266 for (0..10, 10..20) |i, j| {
267 sum += 1;
268 try expect(i + 10 == j);
269 }
270
271 try expect(sum == 10);
272}
273
274test "1-based counter and ptr to array" {
275 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
276 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
277
278 var ok: usize = 0;
279
280 for (1..6, "hello") |i, b| {
281 if (i == 1) {
282 try expect(b == 'h');
283 ok += 1;
284 }
285 if (i == 2) {
286 try expect(b == 'e');
287 ok += 1;
288 }
289 if (i == 3) {
290 try expect(b == 'l');
291 ok += 1;
292 }
293 if (i == 4) {
294 try expect(b == 'l');
295 ok += 1;
296 }
297 if (i == 5) {
298 try expect(b == 'o');
299 ok += 1;
300 }
301 }
302
303 try expect(ok == 5);
304}
305
306test "slice and two counters, one is offset and one is runtime" {
307 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
308 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
309 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
310
311 const slice: []const u8 = "blah";
312 var start: usize = 0;
313 _ = &start;
314
315 for (slice, start..4, 1..5) |a, b, c| {
316 if (a == 'b') {
317 try expect(b == 0);
318 try expect(c == 1);
319 }
320 if (a == 'l') {
321 try expect(b == 1);
322 try expect(c == 2);
323 }
324 if (a == 'a') {
325 try expect(b == 2);
326 try expect(c == 3);
327 }
328 if (a == 'h') {
329 try expect(b == 3);
330 try expect(c == 4);
331 }
332 }
333}
334
335test "two slices, one captured by-ref" {
336 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
337 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
338 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
339
340 var buf: [10]u8 = undefined;
341 const slice1: []const u8 = "blah";
342 const slice2: []u8 = buf[0..4];
343
344 for (slice1, slice2) |a, *b| {
345 b.* = a;
346 }
347
348 try expect(slice2[0] == 'b');
349 try expect(slice2[1] == 'l');
350 try expect(slice2[2] == 'a');
351 try expect(slice2[3] == 'h');
352}
353
354test "raw pointer and slice" {
355 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
356 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
357 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
358
359 var buf: [10]u8 = undefined;
360 const slice: []const u8 = "blah";
361 const ptr: [*]u8 = buf[0..4];
362
363 for (ptr, slice) |*a, b| {
364 a.* = b;
365 }
366
367 try expect(buf[0] == 'b');
368 try expect(buf[1] == 'l');
369 try expect(buf[2] == 'a');
370 try expect(buf[3] == 'h');
371}
372
373test "raw pointer and counter" {
374 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
375 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
376 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
377
378 var buf: [10]u8 = undefined;
379 const ptr: [*]u8 = &buf;
380
381 for (ptr, 0..4) |*a, b| {
382 a.* = @as(u8, @intCast('A' + b));
383 }
384
385 try expect(buf[0] == 'A');
386 try expect(buf[1] == 'B');
387 try expect(buf[2] == 'C');
388 try expect(buf[3] == 'D');
389}
390
391test "inline for with slice as the comptime-known" {
392 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
393 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
394 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
395
396 const comptime_slice = "hello";
397 var runtime_i: usize = 3;
398 _ = &runtime_i;
399
400 const S = struct {
401 var ok: usize = 0;
402 fn check(comptime a: u8, b: usize) !void {
403 if (a == 'l') {
404 try expect(b == 3);
405 ok += 1;
406 } else if (a == 'o') {
407 try expect(b == 4);
408 ok += 1;
409 } else {
410 @compileError("fail");
411 }
412 }
413 };
414
415 inline for (comptime_slice[3..5], runtime_i..5) |a, b| {
416 try S.check(a, b);
417 }
418
419 try expect(S.ok == 2);
420}
421
422test "inline for with counter as the comptime-known" {
423 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
424 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
425 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
426
427 var runtime_slice = "hello";
428 var runtime_i: usize = 3;
429 _ = &runtime_i;
430
431 const S = struct {
432 var ok: usize = 0;
433 fn check(a: u8, comptime b: usize) !void {
434 if (b == 3) {
435 try expect(a == 'l');
436 ok += 1;
437 } else if (b == 4) {
438 try expect(a == 'o');
439 ok += 1;
440 } else {
441 @compileError("fail");
442 }
443 }
444 };
445
446 inline for (runtime_slice[runtime_i..5], 3..5) |a, b| {
447 try S.check(a, b);
448 }
449
450 try expect(S.ok == 2);
451}
452
453test "inline for on tuple pointer" {
454 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
455 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
456 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
457
458 const S = struct { u32, u32, u32 };
459 var s: S = .{ 100, 200, 300 };
460
461 inline for (&s, 0..) |*x, i| {
462 x.* = i;
463 }
464
465 try expectEqual(S{ 0, 1, 2 }, s);
466}
467
468test "ref counter that starts at zero" {
469 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
470 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
471
472 for ([_]usize{ 0, 1, 2 }, 0..) |i, j| {
473 try expectEqual(i, j);
474 try expectEqual((&i).*, (&j).*);
475 }
476 inline for (.{ 0, 1, 2 }, 0..) |i, j| {
477 try expectEqual(i, j);
478 try expectEqual((&i).*, (&j).*);
479 }
480}
481
482test "inferred alloc ptr of for loop" {
483 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
484 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
485
486 {
487 var cond = false;
488 _ = &cond;
489 const opt = for (0..1) |_| {
490 if (cond) break cond;
491 } else null;
492 try expectEqual(@as(?bool, null), opt);
493 }
494 {
495 var cond = true;
496 _ = &cond;
497 const opt = for (0..1) |_| {
498 if (cond) break cond;
499 } else null;
500 try expectEqual(@as(?bool, true), opt);
501 }
502}
503
504test "for loop results in a bool" {
505 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
506
507 try std.testing.expect(for ([1]u8{0}) |x| {
508 if (x == 0) break true;
509 } else false);
510}
511
512test "return from inline for" {
513 const S = struct {
514 fn do() bool {
515 inline for (.{"a"}) |_| {
516 if (true) return false;
517 }
518 return true;
519 }
520 };
521 try std.testing.expect(!S.do());
522}
523
524test "for loop 0 length range" {
525 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
526
527 const map: []const u8 = &.{};
528 for (map, 0..map.len) |i, j| {
529 _ = i;
530 _ = j;
531 comptime unreachable;
532 }
533}
534
535test "labeled break from else" {
536 const S = struct {
537 fn doTheTest(x: u32) !void {
538 var y: u32 = 0;
539 const ok = label: while (y < x) : (y += 1) {
540 if (y == 10) break :label false;
541 } else {
542 break :label true;
543 };
544 try expect(ok);
545 }
546 };
547
548 try S.doTheTest(5);
549 try comptime S.doTheTest(5);
550}
551
552test "value break from inline for" {
553 const S = struct {
554 fn doTheTest() !void {
555 const x = inline for (0..2) |_| {
556 if (true) {
557 var idx: u32 = 0;
558 idx += 1;
559 break idx;
560 }
561 };
562 try expect(x == 1);
563 }
564 };
565 try S.doTheTest();
566 try comptime S.doTheTest();
567}