master
1const builtin = @import("builtin");
2const std = @import("std");
3const assert = std.debug.assert;
4const expect = std.testing.expect;
5const expectError = std.testing.expectError;
6const expectEqual = std.testing.expectEqual;
7const minInt = std.math.minInt;
8const maxInt = std.math.maxInt;
9
10test "switch with numbers" {
11 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
12 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
13
14 try testSwitchWithNumbers(13);
15}
16
17fn testSwitchWithNumbers(x: u32) !void {
18 const result = switch (x) {
19 1, 2, 3, 4...8 => false,
20 13 => true,
21 else => false,
22 };
23 try expect(result);
24}
25
26test "switch with all ranges" {
27 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
28 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; // TODO
29
30 try expect(testSwitchWithAllRanges(50, 3) == 1);
31 try expect(testSwitchWithAllRanges(101, 0) == 2);
32 try expect(testSwitchWithAllRanges(300, 5) == 3);
33 try expect(testSwitchWithAllRanges(301, 6) == 6);
34}
35
36fn testSwitchWithAllRanges(x: u32, y: u32) u32 {
37 return switch (x) {
38 0...100 => 1,
39 101...200 => 2,
40 201...300 => 3,
41 else => y,
42 };
43}
44
45test "switch arbitrary int size" {
46 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
47 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
48 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
49 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; // TODO
50 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; // TODO
51
52 if (builtin.zig_backend == .stage2_c and builtin.os.tag == .windows) return error.SkipZigTest; // TODO
53
54 try expect(testSwitchArbInt(u64, 0) == 0);
55 try expect(testSwitchArbInt(u64, 12) == 1);
56 try expect(testSwitchArbInt(u64, maxInt(u64)) == 2);
57 try expect(testSwitchArbInt(u64, 5555) == 3);
58
59 try expect(testSwitchArbInt(i64, minInt(i64)) == 0);
60 try expect(testSwitchArbInt(i64, 12) == 1);
61 try expect(testSwitchArbInt(i64, maxInt(i64)) == 2);
62 try expect(testSwitchArbInt(i64, -1000) == 3);
63
64 try expect(testSwitchArbInt(u128, 0) == 0);
65 try expect(testSwitchArbInt(u128, 12) == 1);
66 try expect(testSwitchArbInt(u128, maxInt(u128)) == 2);
67 try expect(testSwitchArbInt(u128, 5555) == 3);
68
69 try expect(testSwitchArbInt(i128, minInt(i128)) == 0);
70 try expect(testSwitchArbInt(i128, 12) == 1);
71 try expect(testSwitchArbInt(i128, maxInt(i128)) == 2);
72 try expect(testSwitchArbInt(i128, -1000) == 3);
73}
74
75fn testSwitchArbInt(comptime T: type, x: T) u32 {
76 return switch (x) {
77 minInt(T) => 0,
78 10...15 => 1,
79 maxInt(T) => 2,
80 else => 3,
81 };
82}
83
84test "implicit comptime switch" {
85 const x = 3 + 4;
86 const result = switch (x) {
87 3 => 10,
88 4 => 11,
89 5, 6 => 12,
90 7, 8 => 13,
91 else => 14,
92 };
93
94 comptime {
95 try expect(result + 1 == 14);
96 }
97}
98
99test "switch on enum" {
100 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
101
102 const fruit = Fruit.Orange;
103 try expect(nonConstSwitchOnEnum(fruit));
104}
105const Fruit = enum {
106 Apple,
107 Orange,
108 Banana,
109};
110fn nonConstSwitchOnEnum(fruit: Fruit) bool {
111 return switch (fruit) {
112 Fruit.Apple => false,
113 Fruit.Orange => true,
114 Fruit.Banana => false,
115 };
116}
117
118test "switch statement" {
119 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
120
121 try nonConstSwitch(SwitchStatementFoo.C);
122}
123fn nonConstSwitch(foo: SwitchStatementFoo) !void {
124 const val = switch (foo) {
125 SwitchStatementFoo.A => @as(i32, 1),
126 SwitchStatementFoo.B => 2,
127 SwitchStatementFoo.C => 3,
128 SwitchStatementFoo.D => 4,
129 };
130 try expect(val == 3);
131}
132const SwitchStatementFoo = enum { A, B, C, D };
133
134test "switch with multiple expressions" {
135 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
136
137 const x = switch (returnsFive()) {
138 1, 2, 3 => 1,
139 4, 5, 6 => 2,
140 else => @as(i32, 3),
141 };
142 try expect(x == 2);
143}
144fn returnsFive() i32 {
145 return 5;
146}
147
148test "switch on type" {
149 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
150
151 try expect(trueIfBoolFalseOtherwise(bool));
152 try expect(!trueIfBoolFalseOtherwise(i32));
153}
154
155fn trueIfBoolFalseOtherwise(comptime T: type) bool {
156 return switch (T) {
157 bool => true,
158 else => false,
159 };
160}
161
162test "switching on booleans" {
163 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
164
165 try testSwitchOnBools();
166 try comptime testSwitchOnBools();
167}
168
169fn testSwitchOnBools() !void {
170 try expect(testSwitchOnBoolsTrueAndFalse(true) == false);
171 try expect(testSwitchOnBoolsTrueAndFalse(false) == true);
172
173 try expect(testSwitchOnBoolsTrueWithElse(true) == false);
174 try expect(testSwitchOnBoolsTrueWithElse(false) == true);
175
176 try expect(testSwitchOnBoolsFalseWithElse(true) == false);
177 try expect(testSwitchOnBoolsFalseWithElse(false) == true);
178}
179
180fn testSwitchOnBoolsTrueAndFalse(x: bool) bool {
181 return switch (x) {
182 true => false,
183 false => true,
184 };
185}
186
187fn testSwitchOnBoolsTrueWithElse(x: bool) bool {
188 return switch (x) {
189 true => false,
190 else => true,
191 };
192}
193
194fn testSwitchOnBoolsFalseWithElse(x: bool) bool {
195 return switch (x) {
196 false => true,
197 else => false,
198 };
199}
200
201test "u0" {
202 var val: u0 = 0;
203 _ = &val;
204 switch (val) {
205 0 => try expect(val == 0),
206 }
207}
208
209test "undefined.u0" {
210 var val: u0 = undefined;
211 _ = &val;
212 switch (val) {
213 0 => try expect(val == 0),
214 }
215}
216
217test "switch with disjoint range" {
218 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
219 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; // TODO
220
221 var q: u8 = 0;
222 _ = &q;
223 switch (q) {
224 0...125 => {},
225 127...255 => {},
226 126...126 => {},
227 }
228}
229
230test "switch variable for range and multiple prongs" {
231 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; // TODO
232
233 const S = struct {
234 fn doTheTest() !void {
235 try doTheSwitch(16);
236 try doTheSwitch(42);
237 }
238 fn doTheSwitch(q: u8) !void {
239 switch (q) {
240 0...40 => |x| try expect(x == 16),
241 41, 42, 43 => |x| try expect(x == 42),
242 else => try expect(false),
243 }
244 }
245 };
246 try S.doTheTest();
247 try comptime S.doTheTest();
248}
249
250var state: u32 = 0;
251fn poll() void {
252 switch (state) {
253 0 => {
254 state = 1;
255 },
256 else => {
257 state += 1;
258 },
259 }
260}
261
262test "switch on global mutable var isn't constant-folded" {
263 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
264
265 while (state < 2) {
266 poll();
267 }
268}
269
270const SwitchProngWithVarEnum = union(enum) {
271 One: i32,
272 Two: f32,
273 Meh: void,
274};
275
276test "switch prong with variable" {
277 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
278 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
279 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
280 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
281
282 try switchProngWithVarFn(SwitchProngWithVarEnum{ .One = 13 });
283 try switchProngWithVarFn(SwitchProngWithVarEnum{ .Two = 13.0 });
284 try switchProngWithVarFn(SwitchProngWithVarEnum{ .Meh = {} });
285}
286fn switchProngWithVarFn(a: SwitchProngWithVarEnum) !void {
287 switch (a) {
288 SwitchProngWithVarEnum.One => |x| {
289 try expect(x == 13);
290 },
291 SwitchProngWithVarEnum.Two => |x| {
292 try expect(x == 13.0);
293 },
294 SwitchProngWithVarEnum.Meh => |x| {
295 const v: void = x;
296 _ = v;
297 },
298 }
299}
300
301test "switch on enum using pointer capture" {
302 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
303 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
304
305 try testSwitchEnumPtrCapture();
306 try comptime testSwitchEnumPtrCapture();
307}
308
309fn testSwitchEnumPtrCapture() !void {
310 var value = SwitchProngWithVarEnum{ .One = 1234 };
311 switch (value) {
312 SwitchProngWithVarEnum.One => |*x| x.* += 1,
313 else => unreachable,
314 }
315 switch (value) {
316 SwitchProngWithVarEnum.One => |x| try expect(x == 1235),
317 else => unreachable,
318 }
319}
320
321test "switch handles all cases of number" {
322 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
323 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
324
325 try testSwitchHandleAllCases();
326 try comptime testSwitchHandleAllCases();
327}
328
329fn testSwitchHandleAllCases() !void {
330 try expect(testSwitchHandleAllCasesExhaustive(0) == 3);
331 try expect(testSwitchHandleAllCasesExhaustive(1) == 2);
332 try expect(testSwitchHandleAllCasesExhaustive(2) == 1);
333 try expect(testSwitchHandleAllCasesExhaustive(3) == 0);
334
335 try expect(testSwitchHandleAllCasesRange(100) == 0);
336 try expect(testSwitchHandleAllCasesRange(200) == 1);
337 try expect(testSwitchHandleAllCasesRange(201) == 2);
338 try expect(testSwitchHandleAllCasesRange(202) == 4);
339 try expect(testSwitchHandleAllCasesRange(230) == 3);
340}
341
342fn testSwitchHandleAllCasesExhaustive(x: u2) u2 {
343 return switch (x) {
344 0 => @as(u2, 3),
345 1 => 2,
346 2 => 1,
347 3 => 0,
348 };
349}
350
351fn testSwitchHandleAllCasesRange(x: u8) u8 {
352 return switch (x) {
353 0...100 => @as(u8, 0),
354 101...200 => 1,
355 201, 203 => 2,
356 202 => 4,
357 204...255 => 3,
358 };
359}
360
361test "switch on union with some prongs capturing" {
362 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
363 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
364
365 const X = union(enum) {
366 a,
367 b: i32,
368 };
369
370 var x: X = X{ .b = 10 };
371 _ = &x;
372 const y: i32 = switch (x) {
373 .a => unreachable,
374 .b => |b| b + 1,
375 };
376 try expect(y == 11);
377}
378
379const Number = union(enum) {
380 One: u64,
381 Two: u8,
382 Three: f32,
383};
384
385const number = Number{ .Three = 1.23 };
386
387fn returnsFalse() bool {
388 switch (number) {
389 Number.One => |x| return x > 1234,
390 Number.Two => |x| return x == 'a',
391 Number.Three => |x| return x > 12.34,
392 }
393}
394test "switch on const enum with var" {
395 try expect(!returnsFalse());
396}
397
398test "anon enum literal used in switch on union enum" {
399 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
400
401 const Foo = union(enum) {
402 a: i32,
403 };
404
405 var foo = Foo{ .a = 1234 };
406 _ = &foo;
407 switch (foo) {
408 .a => |x| {
409 try expect(x == 1234);
410 },
411 }
412}
413
414test "switch all prongs unreachable" {
415 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
416
417 try testAllProngsUnreachable();
418 try comptime testAllProngsUnreachable();
419}
420
421fn testAllProngsUnreachable() !void {
422 try expect(switchWithUnreachable(1) == 2);
423 try expect(switchWithUnreachable(2) == 10);
424}
425
426fn switchWithUnreachable(x: i32) i32 {
427 while (true) {
428 switch (x) {
429 1 => return 2,
430 2 => break,
431 else => continue,
432 }
433 }
434 return 10;
435}
436
437test "capture value of switch with all unreachable prongs" {
438 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
439
440 const x = return_a_number() catch |err| switch (err) {
441 else => unreachable,
442 };
443 try expect(x == 1);
444}
445
446fn return_a_number() anyerror!i32 {
447 return 1;
448}
449
450test "switch on integer with else capturing expr" {
451 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
452
453 const S = struct {
454 fn doTheTest() !void {
455 var x: i32 = 5;
456 _ = &x;
457 switch (x + 10) {
458 14 => return error.TestFailed,
459 16 => return error.TestFailed,
460 else => |e| try expect(e == 15),
461 }
462 }
463 };
464 try S.doTheTest();
465 try comptime S.doTheTest();
466}
467
468test "else prong of switch on error set excludes other cases" {
469 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
470 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
471 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
472 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
473
474 const S = struct {
475 fn doTheTest() !void {
476 try expectError(error.C, bar());
477 }
478 const E = error{
479 A,
480 B,
481 } || E2;
482
483 const E2 = error{
484 C,
485 D,
486 };
487
488 fn foo() E!void {
489 return error.C;
490 }
491
492 fn bar() E2!void {
493 foo() catch |err| switch (err) {
494 error.A, error.B => {},
495 else => |e| return e,
496 };
497 }
498 };
499 try S.doTheTest();
500 try comptime S.doTheTest();
501}
502
503test "switch prongs with error set cases make a new error set type for capture value" {
504 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
505 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
506 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
507 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
508
509 const S = struct {
510 fn doTheTest() !void {
511 try expectError(error.B, bar());
512 }
513 const E = E1 || E2;
514
515 const E1 = error{
516 A,
517 B,
518 };
519
520 const E2 = error{
521 C,
522 D,
523 };
524
525 fn foo() E!void {
526 return error.B;
527 }
528
529 fn bar() E1!void {
530 foo() catch |err| switch (err) {
531 error.A, error.B => |e| return e,
532 else => {},
533 };
534 }
535 };
536 try S.doTheTest();
537 try comptime S.doTheTest();
538}
539
540test "return result loc and then switch with range implicit casted to error union" {
541 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
542 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; // TODO
543
544 const S = struct {
545 fn doTheTest() !void {
546 try expect((func(0xb) catch unreachable) == 0xb);
547 }
548 fn func(d: u8) anyerror!u8 {
549 return switch (d) {
550 0xa...0xf => d,
551 else => unreachable,
552 };
553 }
554 };
555 try S.doTheTest();
556 try comptime S.doTheTest();
557}
558
559test "switch with null and T peer types and inferred result location type" {
560 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
561 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
562
563 const S = struct {
564 fn doTheTest(c: u8) !void {
565 if (switch (c) {
566 0 => true,
567 else => null,
568 }) |v| {
569 _ = v;
570 return error.TestFailed;
571 }
572 }
573 };
574 try S.doTheTest(1);
575 try comptime S.doTheTest(1);
576}
577
578test "switch prongs with cases with identical payload types" {
579 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
580 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
581
582 const Union = union(enum) {
583 A: usize,
584 B: isize,
585 C: usize,
586 };
587 const S = struct {
588 fn doTheTest() !void {
589 try doTheSwitch1(Union{ .A = 8 });
590 try doTheSwitch2(Union{ .B = -8 });
591 }
592 fn doTheSwitch1(u: Union) !void {
593 switch (u) {
594 .A, .C => |e| {
595 comptime assert(@TypeOf(e) == usize);
596 try expect(e == 8);
597 },
598 .B => |e| {
599 _ = e;
600 return error.TestFailed;
601 },
602 }
603 }
604 fn doTheSwitch2(u: Union) !void {
605 switch (u) {
606 .A, .C => |e| {
607 _ = e;
608 return error.TestFailed;
609 },
610 .B => |e| {
611 comptime assert(@TypeOf(e) == isize);
612 try expect(e == -8);
613 },
614 }
615 }
616 };
617 try S.doTheTest();
618 try comptime S.doTheTest();
619}
620
621test "switch prong pointer capture alignment" {
622 const U = union(enum) {
623 a: u8 align(8),
624 b: u8 align(4),
625 c: u8,
626 };
627
628 const S = struct {
629 fn doTheTest() !void {
630 const u = U{ .a = 1 };
631 switch (u) {
632 .a => |*a| comptime assert(@TypeOf(a) == *align(8) const u8),
633 .b, .c => |*p| {
634 _ = p;
635 return error.TestFailed;
636 },
637 }
638
639 switch (u) {
640 .a, .b => |*p| comptime assert(@TypeOf(p) == *align(4) const u8),
641 .c => |*p| {
642 _ = p;
643 return error.TestFailed;
644 },
645 }
646
647 switch (u) {
648 .a, .c => |*p| comptime assert(@TypeOf(p) == *const u8),
649 .b => |*p| {
650 _ = p;
651 return error.TestFailed;
652 },
653 }
654 }
655
656 fn doTheTest2() !void {
657 const un1 = U{ .b = 1 };
658 switch (un1) {
659 .b => |*b| comptime assert(@TypeOf(b) == *align(4) const u8),
660 .a, .c => |*p| {
661 _ = p;
662 return error.TestFailed;
663 },
664 }
665
666 const un2 = U{ .c = 1 };
667 switch (un2) {
668 .c => |*c| comptime assert(@TypeOf(c) == *const u8),
669 .a, .b => |*p| {
670 _ = p;
671 return error.TestFailed;
672 },
673 }
674 }
675 };
676
677 try S.doTheTest();
678 try comptime S.doTheTest();
679
680 try S.doTheTest2();
681 try comptime S.doTheTest2();
682}
683
684test "switch on pointer type" {
685 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
686 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
687 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
688
689 const S = struct {
690 const X = struct {
691 field: u32,
692 };
693
694 const P1 = @as(*X, @ptrFromInt(0x400));
695 const P2 = @as(*X, @ptrFromInt(0x800));
696 const P3 = @as(*X, @ptrFromInt(0xC00));
697
698 fn doTheTest(arg: *X) i32 {
699 switch (arg) {
700 P1 => return 1,
701 P2 => return 2,
702 else => return 3,
703 }
704 }
705 };
706
707 try expect(1 == S.doTheTest(S.P1));
708 try expect(2 == S.doTheTest(S.P2));
709 try expect(3 == S.doTheTest(S.P3));
710 comptime assert(1 == S.doTheTest(S.P1));
711 comptime assert(2 == S.doTheTest(S.P2));
712 comptime assert(3 == S.doTheTest(S.P3));
713}
714
715test "switch on error set with single else" {
716 const S = struct {
717 fn doTheTest() !void {
718 var some: error{Foo} = error.Foo;
719 _ = &some;
720 try expect(switch (some) {
721 else => blk: {
722 break :blk true;
723 },
724 });
725 }
726 };
727
728 try S.doTheTest();
729 try comptime S.doTheTest();
730}
731
732test "switch capture copies its payload" {
733 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
734 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
735 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
736
737 const S = struct {
738 fn doTheTest() !void {
739 var tmp: union(enum) {
740 A: u8,
741 B: u32,
742 } = .{ .A = 42 };
743 switch (tmp) {
744 .A => |value| {
745 // Modify the original union
746 tmp = .{ .B = 0x10101010 };
747 try expectEqual(@as(u8, 42), value);
748 },
749 else => unreachable,
750 }
751 }
752 };
753 try S.doTheTest();
754 try comptime S.doTheTest();
755}
756
757test "capture of integer forwards the switch condition directly" {
758 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
759 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; // TODO
760
761 const S = struct {
762 fn foo(x: u8) !void {
763 switch (x) {
764 40...45 => |capture| {
765 try expect(capture == 42);
766 },
767 else => |capture| {
768 try expect(capture == 100);
769 },
770 }
771 }
772 };
773 try S.foo(42);
774 try S.foo(100);
775 try comptime S.foo(42);
776 try comptime S.foo(100);
777}
778
779test "enum value without tag name used as switch item" {
780 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
781
782 const E = enum(u32) {
783 a = 1,
784 b = 2,
785 _,
786 };
787 var e: E = @enumFromInt(0);
788 _ = &e;
789 switch (e) {
790 @as(E, @enumFromInt(0)) => {},
791 .a => return error.TestFailed,
792 .b => return error.TestFailed,
793 _ => return error.TestFailed,
794 }
795}
796
797test "switch item sizeof" {
798 const S = struct {
799 fn doTheTest() !void {
800 var a: usize = 0;
801 _ = &a;
802 switch (a) {
803 @sizeOf(struct {}) => {},
804 else => return error.TestFailed,
805 }
806 }
807 };
808 try S.doTheTest();
809 try comptime S.doTheTest();
810}
811
812test "comptime inline switch" {
813 const U = union(enum) { a: type, b: type };
814 const value = comptime blk: {
815 var u: U = .{ .a = u32 };
816 _ = &u;
817 break :blk switch (u) {
818 inline .a, .b => |v| v,
819 };
820 };
821
822 try expectEqual(u32, value);
823}
824
825test "switch capture peer type resolution" {
826 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
827
828 const U = union(enum) {
829 a: u32,
830 b: u64,
831 fn innerVal(u: @This()) u64 {
832 switch (u) {
833 .a, .b => |x| return x,
834 }
835 }
836 };
837
838 try expectEqual(@as(u64, 100), U.innerVal(.{ .a = 100 }));
839 try expectEqual(@as(u64, 200), U.innerVal(.{ .b = 200 }));
840}
841
842test "switch capture peer type resolution for in-memory coercible payloads" {
843 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
844
845 const T1 = c_int;
846 const t1_info = @typeInfo(T1).int;
847 const T2 = @Int(t1_info.signedness, t1_info.bits);
848
849 comptime assert(T1 != T2);
850
851 const U = union(enum) {
852 a: T1,
853 b: T2,
854 fn innerVal(u: @This()) c_int {
855 switch (u) {
856 .a, .b => |x| return x,
857 }
858 }
859 };
860
861 try expectEqual(@as(c_int, 100), U.innerVal(.{ .a = 100 }));
862 try expectEqual(@as(c_int, 200), U.innerVal(.{ .b = 200 }));
863}
864
865test "switch pointer capture peer type resolution" {
866 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
867
868 const T1 = c_int;
869 const t1_info = @typeInfo(T1).int;
870 const T2 = @Int(t1_info.signedness, t1_info.bits);
871
872 comptime assert(T1 != T2);
873
874 const U = union(enum) {
875 a: T1,
876 b: T2,
877 fn innerVal(u: *@This()) *c_int {
878 switch (u.*) {
879 .a, .b => |*ptr| return ptr,
880 }
881 }
882 };
883
884 var ua: U = .{ .a = 100 };
885 var ub: U = .{ .b = 200 };
886
887 ua.innerVal().* = 111;
888 ub.innerVal().* = 222;
889
890 try expectEqual(U{ .a = 111 }, ua);
891 try expectEqual(U{ .b = 222 }, ub);
892}
893
894test "inline switch range that includes the maximum value of the switched type" {
895 const inputs: [3]u8 = .{ 0, 254, 255 };
896 for (inputs) |input| {
897 switch (input) {
898 inline 254...255 => |val| try expectEqual(input, val),
899 else => |val| try expectEqual(input, val),
900 }
901 }
902}
903
904test "nested break ignores switch conditions and breaks instead" {
905 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
906 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
907 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
908
909 const S = struct {
910 fn register_to_address(ident: []const u8) !u8 {
911 const reg: u8 = if (std.mem.eql(u8, ident, "zero")) 0x00 else blk: {
912 break :blk switch (ident[0]) {
913 0x61 => (try std.fmt.parseInt(u8, ident[1..], 0)) + 1,
914 0x66 => (try std.fmt.parseInt(u8, ident[1..], 0)) + 1,
915 else => {
916 break :blk 0xFF;
917 },
918 };
919 };
920 return reg;
921 }
922 };
923 // Originally reported at https://github.com/ziglang/zig/issues/10196
924 try expect(0x01 == try S.register_to_address("a0"));
925}
926
927test "peer type resolution on switch captures ignores unused payload bits" {
928 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
929 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
930
931 const Foo = union(enum) {
932 a: u32,
933 b: u64,
934 };
935
936 var val: Foo = undefined;
937 @memset(std.mem.asBytes(&val), 0xFF);
938
939 // This is runtime-known so the following store isn't comptime-known.
940 var rt: u32 = 123;
941 _ = &rt;
942 val = .{ .a = rt }; // will not necessarily zero remaning payload memory
943
944 // Fields intentionally backwards here
945 const x = switch (val) {
946 .b, .a => |x| x,
947 };
948
949 try expect(x == 123);
950}
951
952test "switch prong captures range" {
953 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
954 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; // TODO
955
956 const S = struct {
957 fn a(b: []u3, c: u3) void {
958 switch (c) {
959 0...1 => b[c] = c,
960 2...3 => b[c] = c,
961 4...7 => |d| b[d] = c,
962 }
963 }
964 };
965
966 var arr: [8]u3 = undefined;
967 S.a(&arr, 5);
968 try expect(arr[5] == 5);
969}
970
971test "prong with inline call to unreachable" {
972 const U = union(enum) {
973 void: void,
974 bool: bool,
975
976 inline fn unreach() noreturn {
977 unreachable;
978 }
979 };
980 var u: U = undefined;
981 u = .{ .bool = true };
982 switch (u) {
983 .void => U.unreach(),
984 .bool => |ok| try expect(ok),
985 }
986}
987
988test "block error return trace index is reset between prongs" {
989 const S = struct {
990 fn returnError() error{TestFailed} {
991 return error.TestFailed;
992 }
993 };
994
995 var x: u1 = 0;
996 _ = &x;
997
998 const result = switch (x) {
999 0 => {
1000 const result: anyerror!i32 = blk: {
1001 break :blk 1;
1002 };
1003 _ = &result;
1004 },
1005 1 => blk: {
1006 const err = switch (x) {
1007 0 => {},
1008 1 => S.returnError(),
1009 };
1010 break :blk err;
1011 },
1012 };
1013 try result;
1014}
1015
1016test "labeled switch with break" {
1017 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; // TODO
1018
1019 var six: u32 = undefined;
1020 six = 6;
1021
1022 const val = s: switch (six) {
1023 0...4 => break :s false,
1024 5 => break :s false,
1025 6...7 => break :s true,
1026 else => break :s false,
1027 };
1028
1029 try expect(val);
1030
1031 // Make sure the switch is implicitly comptime!
1032 const comptime_val = s: switch (@as(u32, 6)) {
1033 0...4 => break :s false,
1034 5 => break :s false,
1035 6...7 => break :s true,
1036 else => break :s false,
1037 };
1038
1039 comptime assert(comptime_val);
1040}
1041
1042test "unlabeled break ignores switch" {
1043 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1044 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1045 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1046 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; // TODO
1047
1048 const result = while (true) {
1049 _ = s: switch (@as(u32, 1)) {
1050 1 => continue :s 123,
1051 else => |x| break x,
1052 };
1053 comptime unreachable; // control flow never breaks from the switch
1054 };
1055 try expect(result == 123);
1056}
1057
1058test "switch on a signed value smaller than the smallest prong value" {
1059 var v: i32 = undefined;
1060 v = -1;
1061 switch (v) {
1062 inline 0...10 => return error.TestFailed,
1063 else => {},
1064 }
1065}
1066
1067test "switch on 8-bit mod result" {
1068 var x: u8 = undefined;
1069 x = 16;
1070 switch (x % 4) {
1071 0 => {},
1072 1, 2, 3 => return error.TestFailed,
1073 else => unreachable,
1074 }
1075}
1076
1077test "switch on non-exhaustive enum" {
1078 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; // TODO
1079
1080 const E = enum(u4) {
1081 a,
1082 b,
1083 c,
1084 _,
1085
1086 fn doTheTest(e: @This()) !void {
1087 switch (e) {
1088 .a, .b => {},
1089 else => return error.TestFailed,
1090 }
1091 switch (e) {
1092 .a, .b => {},
1093 .c => return error.TestFailed,
1094 _ => return error.TestFailed,
1095 }
1096 switch (e) {
1097 .a, .b => {},
1098 .c, _ => return error.TestFailed,
1099 }
1100 switch (e) {
1101 .a => {},
1102 .b, .c, _ => return error.TestFailed,
1103 }
1104 switch (e) {
1105 .b => return error.TestFailed,
1106 else => {},
1107 _ => return error.TestFailed,
1108 }
1109 switch (e) {
1110 else => {},
1111 _ => return error.TestFailed,
1112 }
1113 switch (e) {
1114 inline else => {},
1115 _ => return error.TestFailed,
1116 }
1117 }
1118 };
1119
1120 try E.doTheTest(.a);
1121 try comptime E.doTheTest(.a);
1122}