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