master
  1const builtin = @import("builtin");
  2const std = @import("std");
  3const expect = std.testing.expect;
  4
  5test "simple switch loop" {
  6    if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
  7    if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
  8    if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
  9    if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; // TODO
 10
 11    const S = struct {
 12        fn doTheTest() !void {
 13            var start: u32 = undefined;
 14            start = 32;
 15            const result: u32 = s: switch (start) {
 16                0 => 0,
 17                1 => 1,
 18                2 => 2,
 19                3 => 3,
 20                else => |x| continue :s x / 2,
 21            };
 22            try expect(result == 2);
 23        }
 24    };
 25    try S.doTheTest();
 26    try comptime S.doTheTest();
 27}
 28
 29test "switch loop with ranges" {
 30    if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
 31    if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
 32    if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
 33    if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; // TODO
 34
 35    const S = struct {
 36        fn doTheTest() !void {
 37            var start: u32 = undefined;
 38            start = 32;
 39            const result = s: switch (start) {
 40                0...3 => |x| x,
 41                else => |x| continue :s x / 2,
 42            };
 43            try expect(result == 2);
 44        }
 45    };
 46    try S.doTheTest();
 47    try comptime S.doTheTest();
 48}
 49
 50test "switch loop on enum" {
 51    if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
 52    if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
 53    if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
 54    if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; // TODO
 55
 56    const S = struct {
 57        const E = enum { a, b, c };
 58
 59        fn doTheTest() !void {
 60            var start: E = undefined;
 61            start = .a;
 62            const result: u32 = s: switch (start) {
 63                .a => continue :s .b,
 64                .b => continue :s .c,
 65                .c => 123,
 66            };
 67            try expect(result == 123);
 68        }
 69    };
 70    try S.doTheTest();
 71    try comptime S.doTheTest();
 72}
 73
 74test "switch loop with error set" {
 75    if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
 76    if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
 77    if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
 78    if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; // TODO
 79
 80    const S = struct {
 81        const E = error{ Foo, Bar, Baz };
 82
 83        fn doTheTest() !void {
 84            var start: E = undefined;
 85            start = error.Foo;
 86            const result: u32 = s: switch (start) {
 87                error.Foo => continue :s error.Bar,
 88                error.Bar => continue :s error.Baz,
 89                error.Baz => 123,
 90            };
 91            try expect(result == 123);
 92        }
 93    };
 94    try S.doTheTest();
 95    try comptime S.doTheTest();
 96}
 97
 98test "switch loop on tagged union" {
 99    if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
100    if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
101    if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
102    if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; // TODO
103    if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
104
105    const S = struct {
106        const U = union(enum) {
107            a: u32,
108            b: f32,
109            c: f32,
110        };
111
112        fn doTheTest() !void {
113            var start: U = undefined;
114            start = .{ .a = 80 };
115            const result = s: switch (start) {
116                .a => |x| switch (x) {
117                    0...49 => continue :s .{ .b = @floatFromInt(x) },
118                    50 => continue :s .{ .c = @floatFromInt(x) },
119                    else => continue :s .{ .a = x / 2 },
120                },
121                .b => |x| x,
122                .c => return error.TestFailed,
123            };
124            try expect(result == 40.0);
125        }
126    };
127    try S.doTheTest();
128    try comptime S.doTheTest();
129}
130
131test "switch loop dispatching instructions" {
132    if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
133    if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
134    if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
135    if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; // TODO
136
137    const S = struct {
138        const Inst = union(enum) {
139            set: u32,
140            add: u32,
141            sub: u32,
142            end,
143        };
144
145        fn doTheTest() !void {
146            var insts: [5]Inst = undefined;
147            @memcpy(&insts, &[5]Inst{
148                .{ .set = 123 },
149                .{ .add = 100 },
150                .{ .sub = 50 },
151                .{ .sub = 10 },
152                .end,
153            });
154            var i: u32 = 0;
155            var cur: u32 = undefined;
156            eval: switch (insts[0]) {
157                .set => |x| {
158                    cur = x;
159                    i += 1;
160                    continue :eval insts[i];
161                },
162                .add => |x| {
163                    cur += x;
164                    i += 1;
165                    continue :eval insts[i];
166                },
167                .sub => |x| {
168                    cur -= x;
169                    i += 1;
170                    continue :eval insts[i];
171                },
172                .end => {},
173            }
174            try expect(cur == 163);
175        }
176    };
177    try S.doTheTest();
178    try comptime S.doTheTest();
179}
180
181test "switch loop with pointer capture" {
182    if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
183    if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
184    if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
185    if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; // TODO
186
187    const S = struct {
188        const U = union(enum) {
189            a: u32,
190            b: u32,
191            c: u32,
192        };
193
194        fn doTheTest() !void {
195            var a: U = .{ .a = 100 };
196            var b: U = .{ .b = 200 };
197            var c: U = .{ .c = 300 };
198            inc: switch (a) {
199                .a => |*x| {
200                    x.* += 1;
201                    continue :inc b;
202                },
203                .b => |*x| {
204                    x.* += 10;
205                    continue :inc c;
206                },
207                .c => |*x| {
208                    x.* += 50;
209                },
210            }
211            try expect(a.a == 101);
212            try expect(b.b == 210);
213            try expect(c.c == 350);
214        }
215    };
216    try S.doTheTest();
217    try comptime S.doTheTest();
218}
219
220test "unanalyzed continue with operand" {
221    @setRuntimeSafety(false);
222    label: switch (false) {
223        false => if (false) continue :label true,
224        true => {},
225    }
226}
227
228test "switch loop on larger than pointer integer" {
229    if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
230    if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
231    if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
232
233    var entry: @Int(.unsigned, @bitSizeOf(usize) + 1) = undefined;
234    entry = 0;
235    loop: switch (entry) {
236        0 => {
237            entry += 1;
238            continue :loop 1;
239        },
240        1 => |x| {
241            entry += 1;
242            continue :loop x + 1;
243        },
244        2 => entry += 1,
245        else => unreachable,
246    }
247    try expect(entry == 3);
248}
249
250test "switch loop on non-exhaustive enum" {
251    if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
252    if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
253    if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
254    if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; // TODO
255
256    const S = struct {
257        const E = enum(u8) { a, b, c, _ };
258
259        fn doTheTest() !void {
260            var start: E = undefined;
261            start = .a;
262            const result: u32 = s: switch (start) {
263                .a => continue :s .c,
264                else => continue :s @enumFromInt(123),
265                .b, _ => |x| break :s @intFromEnum(x),
266            };
267            try expect(result == 123);
268        }
269    };
270    try S.doTheTest();
271    try comptime S.doTheTest();
272}