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}