master
  1const std = @import("std");
  2const builtin = @import("builtin");
  3const expect = std.testing.expect;
  4const assert = std.debug.assert;
  5
  6test "while loop" {
  7    if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
  8
  9    var i: i32 = 0;
 10    while (i < 4) {
 11        i += 1;
 12    }
 13    try expect(i == 4);
 14    try expect(whileLoop1() == 1);
 15}
 16fn whileLoop1() i32 {
 17    return whileLoop2();
 18}
 19fn whileLoop2() i32 {
 20    while (true) {
 21        return 1;
 22    }
 23}
 24
 25test "static eval while" {
 26    if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
 27
 28    try expect(static_eval_while_number == 1);
 29}
 30const static_eval_while_number = staticWhileLoop1();
 31fn staticWhileLoop1() i32 {
 32    return staticWhileLoop2();
 33}
 34fn staticWhileLoop2() i32 {
 35    while (true) {
 36        return 1;
 37    }
 38}
 39
 40test "while with continue expression" {
 41    if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
 42
 43    var sum: i32 = 0;
 44    {
 45        var i: i32 = 0;
 46        while (i < 10) : (i += 1) {
 47            if (i == 5) continue;
 48            sum += i;
 49        }
 50    }
 51    try expect(sum == 40);
 52}
 53
 54test "while with else" {
 55    var sum: i32 = 0;
 56    var i: i32 = 0;
 57    var got_else: i32 = 0;
 58    while (i < 10) : (i += 1) {
 59        sum += 1;
 60    } else {
 61        got_else += 1;
 62    }
 63    try expect(sum == 10);
 64    try expect(got_else == 1);
 65}
 66
 67var numbers_left: i32 = undefined;
 68fn getNumberOrErr() anyerror!i32 {
 69    return if (numbers_left == 0) error.OutOfNumbers else x: {
 70        numbers_left -= 1;
 71        break :x numbers_left;
 72    };
 73}
 74fn getNumberOrNull() ?i32 {
 75    return if (numbers_left == 0) null else x: {
 76        numbers_left -= 1;
 77        break :x numbers_left;
 78    };
 79}
 80
 81test "continue outer while loop" {
 82    testContinueOuter();
 83    comptime testContinueOuter();
 84}
 85
 86fn testContinueOuter() void {
 87    var i: usize = 0;
 88    outer: while (i < 10) : (i += 1) {
 89        while (true) {
 90            continue :outer;
 91        }
 92    }
 93}
 94
 95test "break from outer while loop" {
 96    testBreakOuter();
 97    comptime testBreakOuter();
 98}
 99
100fn testBreakOuter() void {
101    outer: while (true) {
102        while (true) {
103            break :outer;
104        }
105    }
106}
107
108test "while copies its payload" {
109    if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
110    if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
111
112    const S = struct {
113        fn doTheTest() !void {
114            var tmp: ?i32 = 10;
115            while (tmp) |value| {
116                // Modify the original variable
117                tmp = null;
118                try expect(value == 10);
119            }
120        }
121    };
122    try S.doTheTest();
123    try comptime S.doTheTest();
124}
125
126test "continue and break" {
127    try runContinueAndBreakTest();
128    try expect(continue_and_break_counter == 8);
129}
130var continue_and_break_counter: i32 = 0;
131fn runContinueAndBreakTest() !void {
132    var i: i32 = 0;
133    while (true) {
134        continue_and_break_counter += 2;
135        i += 1;
136        if (i < 4) {
137            continue;
138        }
139        break;
140    }
141    try expect(i == 4);
142}
143
144test "while with optional as condition" {
145    if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
146    if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
147    if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
148
149    numbers_left = 10;
150    var sum: i32 = 0;
151    while (getNumberOrNull()) |value| {
152        sum += value;
153    }
154    try expect(sum == 45);
155}
156
157test "while with optional as condition with else" {
158    if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
159    if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
160    if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
161    if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
162
163    numbers_left = 10;
164    var sum: i32 = 0;
165    var got_else: i32 = 0;
166    while (getNumberOrNull()) |value| {
167        sum += value;
168        try expect(got_else == 0);
169    } else {
170        got_else += 1;
171    }
172    try expect(sum == 45);
173    try expect(got_else == 1);
174}
175
176test "while with error union condition" {
177    if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
178    if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
179    if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
180
181    numbers_left = 10;
182    var sum: i32 = 0;
183    var got_else: i32 = 0;
184    while (getNumberOrErr()) |value| {
185        sum += value;
186    } else |err| {
187        try expect(err == error.OutOfNumbers);
188        got_else += 1;
189    }
190    try expect(sum == 45);
191    try expect(got_else == 1);
192}
193
194test "while on bool with else result follow else prong" {
195    const result = while (returnFalse()) {
196        break @as(i32, 10);
197    } else @as(i32, 2);
198    try expect(result == 2);
199}
200
201test "while on bool with else result follow break prong" {
202    const result = while (returnTrue()) {
203        break @as(i32, 10);
204    } else @as(i32, 2);
205    try expect(result == 10);
206}
207
208test "while on optional with else result follow else prong" {
209    if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
210    if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
211
212    const result = while (returnNull()) |value| {
213        break value;
214    } else @as(i32, 2);
215    try expect(result == 2);
216}
217
218test "while on optional with else result follow break prong" {
219    if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
220    if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
221
222    const result = while (returnOptional(10)) |value| {
223        break value;
224    } else @as(i32, 2);
225    try expect(result == 10);
226}
227
228fn returnNull() ?i32 {
229    return null;
230}
231fn returnOptional(x: i32) ?i32 {
232    return x;
233}
234fn returnError() anyerror!i32 {
235    return error.YouWantedAnError;
236}
237fn returnSuccess(x: i32) anyerror!i32 {
238    return x;
239}
240fn returnFalse() bool {
241    return false;
242}
243fn returnTrue() bool {
244    return true;
245}
246
247test "return with implicit cast from while loop" {
248    returnWithImplicitCastFromWhileLoopTest() catch unreachable;
249}
250fn returnWithImplicitCastFromWhileLoopTest() anyerror!void {
251    while (true) {
252        return;
253    }
254}
255
256test "while on error union with else result follow else prong" {
257    if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
258
259    const result = while (returnError()) |value| {
260        break value;
261    } else |_| @as(i32, 2);
262    try expect(result == 2);
263}
264
265test "while on error union with else result follow break prong" {
266    if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
267
268    const result = while (returnSuccess(10)) |value| {
269        break value;
270    } else |_| @as(i32, 2);
271    try expect(result == 10);
272}
273
274test "while bool 2 break statements and an else" {
275    const S = struct {
276        fn entry(t: bool, f: bool) !void {
277            var ok = false;
278            ok = while (t) {
279                if (f) break false;
280                if (t) break true;
281            } else false;
282            try expect(ok);
283        }
284    };
285    try S.entry(true, false);
286    try comptime S.entry(true, false);
287}
288
289test "while optional 2 break statements and an else" {
290    if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
291    if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
292
293    const S = struct {
294        fn entry(opt_t: ?bool, f: bool) !void {
295            var ok = false;
296            ok = while (opt_t) |t| {
297                if (f) break false;
298                if (t) break true;
299            } else false;
300            try expect(ok);
301        }
302    };
303    try S.entry(true, false);
304    try comptime S.entry(true, false);
305}
306
307test "while error 2 break statements and an else" {
308    if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
309    if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
310
311    const S = struct {
312        fn entry(opt_t: anyerror!bool, f: bool) !void {
313            var ok = false;
314            ok = while (opt_t) |t| {
315                if (f) break false;
316                if (t) break true;
317            } else |_| false;
318            try expect(ok);
319        }
320    };
321    try S.entry(true, false);
322    try comptime S.entry(true, false);
323}
324
325test "continue inline while loop" {
326    comptime var i = 0;
327    inline while (i < 10) : (i += 1) {
328        if (i < 5) continue;
329        break;
330    }
331    comptime assert(i == 5);
332}
333
334test "else continue outer while" {
335    var i: usize = 0;
336    while (true) {
337        i += 1;
338        while (i > 5) {
339            return;
340        } else continue;
341    }
342}
343
344test "try terminating an infinite loop" {
345    if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
346    if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
347
348    // Test coverage for https://github.com/ziglang/zig/issues/13546
349    const Foo = struct {
350        trash: i32,
351
352        fn bar() anyerror!@This() {
353            return .{ .trash = 1234 };
354        }
355    };
356    var t = true;
357    errdefer t = false;
358    try expect(while (true) {
359        if (t) break t;
360        _ = try Foo.bar();
361    } else unreachable);
362}
363
364test "while loop with comptime true condition needs no else block to return value with break" {
365    const x = while (true) {
366        break @as(u32, 69);
367    };
368    try expect(x == 69);
369}
370
371test "int returned from switch in while" {
372    if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
373
374    var x: u32 = 3;
375    const val: usize = while (true) switch (x) {
376        1 => break 2,
377        else => x -= 1,
378    };
379    try std.testing.expect(val == 2);
380}
381
382test "breaking from a loop in an if statement" {
383    if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
384    if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
385
386    const S = struct {
387        fn retOpt() ?u32 {
388            return null;
389        }
390    };
391
392    var cond = true;
393    _ = &cond;
394    const opt = while (cond) {
395        if (S.retOpt()) |opt| {
396            break opt;
397        }
398        break 1;
399    } else 2;
400    _ = opt;
401}