master
   1const builtin = @import("builtin");
   2const std = @import("std");
   3const endian = builtin.cpu.arch.endian();
   4const expect = std.testing.expect;
   5const assert = std.debug.assert;
   6const expectEqual = std.testing.expectEqual;
   7const Tag = std.meta.Tag;
   8
   9const FooWithFloats = union {
  10    float: f64,
  11    int: i32,
  12};
  13
  14test "basic unions with floats" {
  15    if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
  16    if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
  17    if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
  18    if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
  19
  20    var foo = FooWithFloats{ .int = 1 };
  21    try expect(foo.int == 1);
  22    foo = FooWithFloats{ .float = 12.34 };
  23    try expect(foo.float == 12.34);
  24}
  25
  26fn setFloat(foo: *FooWithFloats, x: f64) void {
  27    foo.* = FooWithFloats{ .float = x };
  28}
  29
  30test "init union with runtime value - floats" {
  31    if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
  32    if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
  33    if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
  34
  35    var foo: FooWithFloats = undefined;
  36
  37    setFloat(&foo, 12.34);
  38    try expect(foo.float == 12.34);
  39}
  40
  41test "basic unions" {
  42    if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
  43    if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
  44    if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
  45
  46    var foo = Foo{ .int = 1 };
  47    try expect(foo.int == 1);
  48    foo = Foo{ .str = .{ .slice = "Hello!" } };
  49    try expect(std.mem.eql(u8, foo.str.slice, "Hello!"));
  50}
  51
  52const Foo = union {
  53    int: i32,
  54    str: struct {
  55        slice: []const u8,
  56    },
  57};
  58
  59test "init union with runtime value" {
  60    if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
  61    if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
  62    if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
  63    if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
  64
  65    var foo: Foo = undefined;
  66
  67    setInt(&foo, 42);
  68    try expect(foo.int == 42);
  69
  70    setStr(&foo, "Hello!");
  71    try expect(std.mem.eql(u8, foo.str.slice, "Hello!"));
  72}
  73
  74fn setInt(foo: *Foo, x: i32) void {
  75    foo.* = Foo{ .int = x };
  76}
  77
  78fn setStr(foo: *Foo, slice: []const u8) void {
  79    foo.* = Foo{ .str = .{ .slice = slice } };
  80}
  81
  82test "comptime union field access" {
  83    comptime {
  84        var foo = FooWithFloats{ .int = 0 };
  85        try expect(foo.int == 0);
  86
  87        foo = FooWithFloats{ .float = 12.34 };
  88        try expect(foo.float == 12.34);
  89    }
  90}
  91
  92const FooExtern = extern union {
  93    int: i32,
  94    str: extern struct {
  95        slice: [*:0]const u8,
  96    },
  97};
  98
  99test "basic extern unions" {
 100    if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
 101    if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
 102
 103    var foo = FooExtern{ .int = 1 };
 104    try expect(foo.int == 1);
 105    foo.str.slice = "Well";
 106    try expect(foo.str.slice[0] == 'W');
 107    try expect(foo.str.slice[1] == 'e');
 108    try expect(foo.str.slice[2] == 'l');
 109    try expect(foo.str.slice[3] == 'l');
 110    try expect(foo.str.slice[4] == 0);
 111}
 112
 113const ExternPtrOrInt = extern union {
 114    ptr: *u8,
 115    int: u64,
 116};
 117test "extern union size" {
 118    comptime assert(@sizeOf(ExternPtrOrInt) == 8);
 119}
 120
 121test "0-sized extern union definition" {
 122    const U = extern union {
 123        a: void,
 124        const f = 1;
 125    };
 126
 127    try expect(U.f == 1);
 128}
 129
 130const Value = union(enum) {
 131    Int: u64,
 132    Array: [9]u8,
 133};
 134
 135const Agg = struct {
 136    val1: Value,
 137    val2: Value,
 138};
 139
 140const v1 = Value{ .Int = 1234 };
 141const v2 = Value{ .Array = [_]u8{3} ** 9 };
 142
 143const err = @as(anyerror!Agg, Agg{
 144    .val1 = v1,
 145    .val2 = v2,
 146});
 147
 148const array = [_]Value{ v1, v2, v1, v2 };
 149
 150test "unions embedded in aggregate types" {
 151    switch (array[1]) {
 152        Value.Array => |arr| try expect(arr[4] == 3),
 153        else => unreachable,
 154    }
 155    switch ((err catch unreachable).val1) {
 156        Value.Int => |x| try expect(x == 1234),
 157        else => unreachable,
 158    }
 159}
 160
 161test "constant tagged union with payload" {
 162    if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
 163    if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
 164
 165    var empty = TaggedUnionWithPayload{ .Empty = {} };
 166    var full = TaggedUnionWithPayload{ .Full = 13 };
 167    _ = .{ &empty, &full };
 168    shouldBeEmpty(empty);
 169    shouldBeNotEmpty(full);
 170}
 171
 172fn shouldBeEmpty(x: TaggedUnionWithPayload) void {
 173    switch (x) {
 174        TaggedUnionWithPayload.Empty => {},
 175        else => unreachable,
 176    }
 177}
 178
 179fn shouldBeNotEmpty(x: TaggedUnionWithPayload) void {
 180    switch (x) {
 181        TaggedUnionWithPayload.Empty => unreachable,
 182        else => {},
 183    }
 184}
 185
 186const TaggedUnionWithPayload = union(enum) {
 187    Empty: void,
 188    Full: i32,
 189};
 190
 191test "union alignment" {
 192    comptime {
 193        try expect(@alignOf(AlignTestTaggedUnion) >= @alignOf([9]u8));
 194        try expect(@alignOf(AlignTestTaggedUnion) >= @alignOf(u64));
 195    }
 196}
 197
 198const AlignTestTaggedUnion = union(enum) {
 199    A: [9]u8,
 200    B: u64,
 201};
 202
 203const Letter = enum { A, B, C };
 204const Payload = union(Letter) {
 205    A: i32,
 206    B: f64,
 207    C: bool,
 208};
 209
 210test "union with specified enum tag" {
 211    if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
 212    if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
 213    if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
 214    if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
 215
 216    try doTest();
 217    try comptime doTest();
 218}
 219
 220test "packed union generates correctly aligned type" {
 221    // This test will be removed after the following accepted proposal is implemented:
 222    // https://github.com/ziglang/zig/issues/24657
 223    if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
 224    if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
 225    if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
 226    if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
 227    if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
 228
 229    const U = packed union {
 230        f1: *const fn () error{TestUnexpectedResult}!void,
 231        f2: usize,
 232    };
 233    var foo = [_]U{
 234        U{ .f1 = doTest },
 235        U{ .f2 = 0 },
 236    };
 237    try foo[0].f1();
 238}
 239
 240fn doTest() error{TestUnexpectedResult}!void {
 241    try expect((try bar(Payload{ .A = 1234 })) == -10);
 242}
 243
 244fn bar(value: Payload) error{TestUnexpectedResult}!i32 {
 245    try expect(@as(Letter, value) == Letter.A);
 246    return switch (value) {
 247        Payload.A => |x| return x - 1244,
 248        Payload.B => |x| if (x == 12.34) @as(i32, 20) else 21,
 249        Payload.C => |x| if (x) @as(i32, 30) else 31,
 250    };
 251}
 252
 253fn testComparison() !void {
 254    var x = Payload{ .A = 42 };
 255    _ = &x;
 256    try expect(x == .A);
 257    try expect(x != .B);
 258    try expect(x != .C);
 259    try expect((x == .B) == false);
 260    try expect((x == .C) == false);
 261    try expect((x != .A) == false);
 262}
 263
 264test "comparison between union and enum literal" {
 265    if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
 266    if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
 267    if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
 268
 269    try testComparison();
 270    try comptime testComparison();
 271}
 272
 273const TheTag = enum { A, B, C };
 274const TheUnion = union(TheTag) {
 275    A: i32,
 276    B: i32,
 277    C: i32,
 278};
 279test "cast union to tag type of union" {
 280    if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
 281    if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
 282
 283    try testCastUnionToTag();
 284    try comptime testCastUnionToTag();
 285}
 286
 287fn testCastUnionToTag() !void {
 288    var u = TheUnion{ .B = 1234 };
 289    _ = &u;
 290    try expect(@as(TheTag, u) == TheTag.B);
 291}
 292
 293test "union field access gives the enum values" {
 294    try expect(TheUnion.A == TheTag.A);
 295    try expect(TheUnion.B == TheTag.B);
 296    try expect(TheUnion.C == TheTag.C);
 297}
 298
 299test "cast tag type of union to union" {
 300    if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
 301    if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
 302
 303    var x: Value2 = Letter2.B;
 304    _ = &x;
 305    try expect(@as(Letter2, x) == Letter2.B);
 306}
 307const Letter2 = enum { A, B, C };
 308const Value2 = union(Letter2) {
 309    A: i32,
 310    B,
 311    C,
 312};
 313
 314test "implicit cast union to its tag type" {
 315    if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
 316    if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
 317
 318    var x: Value2 = Letter2.B;
 319    _ = &x;
 320    try expect(x == Letter2.B);
 321    try giveMeLetterB(x);
 322}
 323fn giveMeLetterB(x: Letter2) !void {
 324    try expect(x == Value2.B);
 325}
 326
 327// TODO it looks like this test intended to test packed unions, but this is not a packed
 328// union. go through git history and find out what happened.
 329pub const PackThis = union(enum) {
 330    Invalid: bool,
 331    StringLiteral: u2,
 332};
 333
 334test "constant packed union" {
 335    if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
 336    if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
 337    if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
 338
 339    try testConstPackedUnion(&[_]PackThis{PackThis{ .StringLiteral = 1 }});
 340}
 341
 342fn testConstPackedUnion(expected_tokens: []const PackThis) !void {
 343    try expect(expected_tokens[0].StringLiteral == 1);
 344}
 345
 346const MultipleChoice = union(enum(u32)) {
 347    A = 20,
 348    B = 40,
 349    C = 60,
 350    D = 1000,
 351};
 352test "simple union(enum(u32))" {
 353    if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
 354    if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
 355
 356    var x = MultipleChoice.C;
 357    _ = &x;
 358    try expect(x == MultipleChoice.C);
 359    try expect(@intFromEnum(@as(Tag(MultipleChoice), x)) == 60);
 360}
 361
 362const PackedPtrOrInt = packed union {
 363    ptr: *u8,
 364    int: usize,
 365};
 366test "packed union size" {
 367    comptime assert(@sizeOf(PackedPtrOrInt) == @sizeOf(usize));
 368}
 369
 370const ZeroBits = union {
 371    OnlyField: void,
 372};
 373test "union with only 1 field which is void should be zero bits" {
 374    comptime assert(@sizeOf(ZeroBits) == 0);
 375}
 376
 377test "assigning to union with zero size field" {
 378    const U = union {
 379        a: u32,
 380        b: void,
 381        c: f32,
 382    };
 383
 384    const u: U = .{ .b = {} };
 385    _ = u;
 386
 387    const UE = union(enum) {
 388        a: f32,
 389        b: u32,
 390        c: u0,
 391    };
 392
 393    const ue: UE = .{ .c = 0 };
 394    _ = ue;
 395}
 396
 397test "tagged union initialization with runtime void" {
 398    if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
 399    if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
 400
 401    try expect(testTaggedUnionInit({}));
 402}
 403
 404const TaggedUnionWithAVoid = union(enum) {
 405    A,
 406    B: i32,
 407};
 408
 409fn testTaggedUnionInit(x: anytype) bool {
 410    const y = TaggedUnionWithAVoid{ .A = x };
 411    return @as(Tag(TaggedUnionWithAVoid), y) == TaggedUnionWithAVoid.A;
 412}
 413
 414pub const UnionEnumNoPayloads = union(enum) { A, B };
 415
 416test "tagged union with no payloads" {
 417    if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
 418    if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
 419
 420    const a = UnionEnumNoPayloads{ .B = {} };
 421    switch (a) {
 422        Tag(UnionEnumNoPayloads).A => @panic("wrong"),
 423        Tag(UnionEnumNoPayloads).B => {},
 424    }
 425}
 426
 427test "union with only 1 field casted to its enum type" {
 428    if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
 429
 430    const Literal = union(enum) {
 431        Number: f64,
 432        Bool: bool,
 433    };
 434
 435    const Expr = union(enum) {
 436        Literal: Literal,
 437    };
 438
 439    var e = Expr{ .Literal = Literal{ .Bool = true } };
 440    _ = &e;
 441    const ExprTag = Tag(Expr);
 442    comptime assert(Tag(ExprTag) == u0);
 443    var t = @as(ExprTag, e);
 444    _ = &t;
 445    try expect(t == Expr.Literal);
 446}
 447
 448test "union with one member defaults to u0 tag type" {
 449    const U0 = union(enum) {
 450        X: u32,
 451    };
 452    comptime assert(Tag(Tag(U0)) == u0);
 453}
 454
 455const Foo1 = union(enum) {
 456    f: struct {
 457        x: usize,
 458    },
 459};
 460var glbl: Foo1 = undefined;
 461
 462test "global union with single field is correctly initialized" {
 463    if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
 464    if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
 465
 466    glbl = Foo1{
 467        .f = @typeInfo(Foo1).@"union".fields[0].type{ .x = 123 },
 468    };
 469    try expect(glbl.f.x == 123);
 470}
 471
 472pub const FooUnion = union(enum) {
 473    U0: usize,
 474    U1: u8,
 475};
 476
 477var glbl_array: [2]FooUnion = undefined;
 478
 479test "initialize global array of union" {
 480    if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
 481    if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
 482    if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
 483
 484    glbl_array[1] = FooUnion{ .U1 = 2 };
 485    glbl_array[0] = FooUnion{ .U0 = 1 };
 486    try expect(glbl_array[0].U0 == 1);
 487    try expect(glbl_array[1].U1 == 2);
 488}
 489
 490test "update the tag value for zero-sized unions" {
 491    if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
 492    if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
 493
 494    const S = union(enum) {
 495        U0: void,
 496        U1: void,
 497    };
 498    var x = S{ .U0 = {} };
 499    try expect(x == .U0);
 500    x = S{ .U1 = {} };
 501    try expect(x == .U1);
 502}
 503
 504test "union initializer generates padding only if needed" {
 505    if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
 506    if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
 507
 508    const U = union(enum) {
 509        A: u24,
 510    };
 511
 512    var v = U{ .A = 532 };
 513    _ = &v;
 514    try expect(v.A == 532);
 515}
 516
 517test "runtime tag name with single field" {
 518    if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
 519    if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
 520
 521    const U = union(enum) {
 522        A: i32,
 523    };
 524
 525    var v = U{ .A = 42 };
 526    _ = &v;
 527    try expect(std.mem.eql(u8, @tagName(v), "A"));
 528}
 529
 530test "method call on an empty union" {
 531    if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
 532    if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
 533
 534    const S = struct {
 535        const MyUnion = union(MyUnionTag) {
 536            pub const MyUnionTag = enum { X1, X2 };
 537            X1: [0]u8,
 538            X2: [0]u8,
 539
 540            pub fn useIt(self: *@This()) bool {
 541                _ = self;
 542                return true;
 543            }
 544        };
 545
 546        fn doTheTest() !void {
 547            var u = MyUnion{ .X1 = [0]u8{} };
 548            try expect(u.useIt());
 549        }
 550    };
 551    try S.doTheTest();
 552    try comptime S.doTheTest();
 553}
 554
 555const Point = struct {
 556    x: u64,
 557    y: u64,
 558};
 559const TaggedFoo = union(enum) {
 560    One: i32,
 561    Two: Point,
 562    Three: void,
 563};
 564const FooNoVoid = union(enum) {
 565    One: i32,
 566    Two: Point,
 567};
 568const Baz = enum { A, B, C, D };
 569
 570test "tagged union type" {
 571    if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
 572
 573    const foo1 = TaggedFoo{ .One = 13 };
 574    const foo2 = TaggedFoo{
 575        .Two = Point{
 576            .x = 1234,
 577            .y = 5678,
 578        },
 579    };
 580    try expect(foo1.One == 13);
 581    try expect(foo2.Two.x == 1234 and foo2.Two.y == 5678);
 582    const baz = Baz.B;
 583
 584    try expect(baz == Baz.B);
 585    try expect(@typeInfo(TaggedFoo).@"union".fields.len == 3);
 586    try expect(@typeInfo(Baz).@"enum".fields.len == 4);
 587    try expect(@sizeOf(TaggedFoo) == @sizeOf(FooNoVoid));
 588    try expect(@sizeOf(Baz) == 1);
 589}
 590
 591test "tagged union as return value" {
 592    if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
 593    if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
 594    if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
 595    if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
 596    if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
 597
 598    switch (returnAnInt(13)) {
 599        TaggedFoo.One => |value| try expect(value == 13),
 600        else => unreachable,
 601    }
 602}
 603
 604fn returnAnInt(x: i32) TaggedFoo {
 605    return TaggedFoo{ .One = x };
 606}
 607
 608test "tagged union with all void fields but a meaningful tag" {
 609    if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
 610    if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
 611
 612    const S = struct {
 613        const B = union(enum) {
 614            c: C,
 615            None,
 616        };
 617
 618        const A = struct {
 619            b: B,
 620        };
 621
 622        const C = struct {};
 623
 624        fn doTheTest() !void {
 625            var a: A = A{ .b = B{ .c = C{} } };
 626            try expect(@as(Tag(B), a.b) == Tag(B).c);
 627            a = A{ .b = B.None };
 628            try expect(@as(Tag(B), a.b) == Tag(B).None);
 629        }
 630    };
 631    try S.doTheTest();
 632    try comptime S.doTheTest();
 633}
 634
 635test "union(enum(u32)) with specified and unspecified tag values" {
 636    if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
 637    if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
 638    if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
 639    if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
 640
 641    comptime assert(Tag(Tag(MultipleChoice2)) == u32);
 642    try testEnumWithSpecifiedAndUnspecifiedTagValues(MultipleChoice2{ .C = 123 });
 643    try comptime testEnumWithSpecifiedAndUnspecifiedTagValues(MultipleChoice2{ .C = 123 });
 644}
 645
 646const MultipleChoice2 = union(enum(u32)) {
 647    Unspecified1: i32,
 648    A: f32 = 20,
 649    Unspecified2: void,
 650    B: bool = 40,
 651    Unspecified3: i32,
 652    C: i8 = 60,
 653    Unspecified4: void,
 654    D: void = 1000,
 655    Unspecified5: i32,
 656};
 657
 658fn testEnumWithSpecifiedAndUnspecifiedTagValues(x: MultipleChoice2) !void {
 659    try expect(@intFromEnum(@as(Tag(MultipleChoice2), x)) == 60);
 660    try expect(1123 == switch (x) {
 661        MultipleChoice2.A => 1,
 662        MultipleChoice2.B => 2,
 663        MultipleChoice2.C => |v| @as(i32, 1000) + v,
 664        MultipleChoice2.D => 4,
 665        MultipleChoice2.Unspecified1 => 5,
 666        MultipleChoice2.Unspecified2 => 6,
 667        MultipleChoice2.Unspecified3 => 7,
 668        MultipleChoice2.Unspecified4 => 8,
 669        MultipleChoice2.Unspecified5 => 9,
 670    });
 671}
 672
 673test "switch on union with only 1 field" {
 674    if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
 675    if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
 676
 677    var r: PartialInst = undefined;
 678    r = PartialInst.Compiled;
 679    switch (r) {
 680        PartialInst.Compiled => {
 681            var z: PartialInstWithPayload = undefined;
 682            z = PartialInstWithPayload{ .Compiled = 1234 };
 683            switch (z) {
 684                PartialInstWithPayload.Compiled => |x| {
 685                    try expect(x == 1234);
 686                    return;
 687                },
 688            }
 689        },
 690    }
 691    unreachable;
 692}
 693
 694const PartialInst = union(enum) {
 695    Compiled,
 696};
 697
 698const PartialInstWithPayload = union(enum) {
 699    Compiled: i32,
 700};
 701
 702test "union with only 1 field casted to its enum type which has enum value specified" {
 703    if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
 704
 705    const Literal = union(enum) {
 706        Number: f64,
 707        Bool: bool,
 708    };
 709
 710    const ExprTag = enum(comptime_int) {
 711        Literal = 33,
 712    };
 713
 714    const Expr = union(ExprTag) {
 715        Literal: Literal,
 716    };
 717
 718    var e = Expr{ .Literal = Literal{ .Bool = true } };
 719    _ = &e;
 720    comptime assert(Tag(ExprTag) == comptime_int);
 721    const t = comptime @as(ExprTag, e);
 722    try expect(t == Expr.Literal);
 723    try expect(@intFromEnum(t) == 33);
 724    comptime assert(@intFromEnum(t) == 33);
 725}
 726
 727test "@intFromEnum works on unions" {
 728    if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
 729    if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
 730
 731    const Bar = union(enum) {
 732        A: bool,
 733        B: u8,
 734        C,
 735    };
 736
 737    const a = Bar{ .A = true };
 738    var b = Bar{ .B = undefined };
 739    var c = Bar.C;
 740    _ = .{ &b, &c };
 741    try expect(@intFromEnum(a) == 0);
 742    try expect(@intFromEnum(b) == 1);
 743    try expect(@intFromEnum(c) == 2);
 744}
 745
 746test "comptime union field value equality" {
 747    const a0 = Setter(Attribute{ .A = false });
 748    const a1 = Setter(Attribute{ .A = true });
 749    const a2 = Setter(Attribute{ .A = false });
 750
 751    const b0 = Setter(Attribute{ .B = 5 });
 752    const b1 = Setter(Attribute{ .B = 9 });
 753    const b2 = Setter(Attribute{ .B = 5 });
 754
 755    try expect(a0 == a0);
 756    try expect(a1 == a1);
 757    try expect(a0 == a2);
 758
 759    try expect(b0 == b0);
 760    try expect(b1 == b1);
 761    try expect(b0 == b2);
 762
 763    try expect(a0 != b0);
 764    try expect(a0 != a1);
 765    try expect(b0 != b1);
 766}
 767
 768const Attribute = union(enum) {
 769    A: bool,
 770    B: u8,
 771};
 772
 773fn setAttribute(attr: Attribute) void {
 774    _ = attr;
 775}
 776
 777fn Setter(comptime attr: Attribute) type {
 778    return struct {
 779        fn set() void {
 780            setAttribute(attr);
 781        }
 782    };
 783}
 784
 785test "return union init with void payload" {
 786    if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
 787    if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
 788    if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
 789
 790    const S = struct {
 791        fn entry() !void {
 792            try expect(func().state == State.one);
 793        }
 794        const Outer = union(enum) {
 795            state: State,
 796        };
 797        const State = union(enum) {
 798            one: void,
 799            two: u32,
 800        };
 801        fn func() Outer {
 802            return Outer{ .state = State{ .one = {} } };
 803        }
 804    };
 805    try S.entry();
 806    try comptime S.entry();
 807}
 808
 809test "@unionInit stored to a const" {
 810    if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
 811    if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
 812    if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
 813
 814    const S = struct {
 815        const U = union(enum) {
 816            boolean: bool,
 817            byte: u8,
 818        };
 819        fn doTheTest() !void {
 820            {
 821                var t = true;
 822                _ = &t;
 823                const u = @unionInit(U, "boolean", t);
 824                try expect(u.boolean);
 825            }
 826            {
 827                var byte: u8 = 69;
 828                _ = &byte;
 829                const u = @unionInit(U, "byte", byte);
 830                try expect(u.byte == 69);
 831            }
 832        }
 833    };
 834
 835    try comptime S.doTheTest();
 836    try S.doTheTest();
 837}
 838
 839test "@unionInit can modify a union type" {
 840    if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
 841    if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
 842
 843    const UnionInitEnum = union(enum) {
 844        Boolean: bool,
 845        Byte: u8,
 846    };
 847
 848    var value: UnionInitEnum = undefined;
 849
 850    value = @unionInit(UnionInitEnum, "Boolean", true);
 851    try expect(value.Boolean == true);
 852    value.Boolean = false;
 853    try expect(value.Boolean == false);
 854
 855    value = @unionInit(UnionInitEnum, "Byte", 2);
 856    try expect(value.Byte == 2);
 857    value.Byte = 3;
 858    try expect(value.Byte == 3);
 859}
 860
 861test "@unionInit can modify a pointer value" {
 862    if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
 863    if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
 864
 865    const UnionInitEnum = union(enum) {
 866        Boolean: bool,
 867        Byte: u8,
 868    };
 869
 870    var value: UnionInitEnum = undefined;
 871    const value_ptr = &value;
 872
 873    value_ptr.* = @unionInit(UnionInitEnum, "Boolean", true);
 874    try expect(value.Boolean == true);
 875
 876    value_ptr.* = @unionInit(UnionInitEnum, "Byte", 2);
 877    try expect(value.Byte == 2);
 878}
 879
 880test "union no tag with struct member" {
 881    if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
 882    if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
 883    if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
 884
 885    const Struct = struct {};
 886    const Union = union {
 887        s: Struct,
 888        pub fn foo(self: *@This()) void {
 889            _ = self;
 890        }
 891    };
 892    var u = Union{ .s = Struct{} };
 893    u.foo();
 894}
 895
 896test "union with comptime_int tag" {
 897    const Union = union(enum(comptime_int)) {
 898        X: u32,
 899        Y: u16,
 900        Z: u8,
 901    };
 902    comptime assert(Tag(Tag(Union)) == comptime_int);
 903}
 904
 905test "extern union doesn't trigger field check at comptime" {
 906    const U = extern union {
 907        x: u32,
 908        y: u8,
 909    };
 910
 911    const x = U{ .x = 0x55AAAA55 };
 912    comptime assert(x.y == 0x55);
 913}
 914
 915test "anonymous union literal syntax" {
 916    if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
 917    if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
 918    if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
 919    if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
 920
 921    const S = struct {
 922        const Number = union {
 923            int: i32,
 924            float: f64,
 925        };
 926
 927        fn doTheTest() !void {
 928            var i: Number = .{ .int = 42 };
 929            _ = &i;
 930            const f = makeNumber();
 931            try expect(i.int == 42);
 932            try expect(f.float == 12.34);
 933        }
 934
 935        fn makeNumber() Number {
 936            return .{ .float = 12.34 };
 937        }
 938    };
 939    try S.doTheTest();
 940    try comptime S.doTheTest();
 941}
 942
 943test "function call result coerces from tagged union to the tag" {
 944    if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
 945    if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
 946    if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
 947
 948    const S = struct {
 949        const Arch = union(enum) {
 950            One,
 951            Two: usize,
 952        };
 953
 954        const ArchTag = Tag(Arch);
 955
 956        fn doTheTest() !void {
 957            var x: ArchTag = getArch1();
 958            _ = &x;
 959            try expect(x == .One);
 960
 961            var y: ArchTag = getArch2();
 962            _ = &y;
 963            try expect(y == .Two);
 964        }
 965
 966        pub fn getArch1() Arch {
 967            return .One;
 968        }
 969
 970        pub fn getArch2() Arch {
 971            return .{ .Two = 99 };
 972        }
 973    };
 974    try S.doTheTest();
 975    try comptime S.doTheTest();
 976}
 977
 978test "switching on non exhaustive union" {
 979    if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
 980    if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
 981
 982    const S = struct {
 983        const E = enum(u8) {
 984            a,
 985            b,
 986            _,
 987        };
 988        const U = union(E) {
 989            a: i32,
 990            b: u32,
 991        };
 992        fn doTheTest() !void {
 993            var a = U{ .a = 2 };
 994            _ = &a;
 995            switch (a) {
 996                .a => |val| try expect(val == 2),
 997                .b => return error.Fail,
 998            }
 999        }
1000    };
1001    try S.doTheTest();
1002    try comptime S.doTheTest();
1003}
1004
1005test "containers with single-field enums" {
1006    if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1007    if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1008
1009    const S = struct {
1010        const A = union(enum) { f1 };
1011        const B = union(enum) { f1: void };
1012        const C = struct { a: A };
1013        const D = struct { a: B };
1014
1015        fn doTheTest() !void {
1016            var array1 = [1]A{A{ .f1 = {} }};
1017            var array2 = [1]B{B{ .f1 = {} }};
1018            _ = .{ &array1, &array2 };
1019            try expect(array1[0] == .f1);
1020            try expect(array2[0] == .f1);
1021
1022            var struct1 = C{ .a = A{ .f1 = {} } };
1023            var struct2 = D{ .a = B{ .f1 = {} } };
1024            _ = .{ &struct1, &struct2 };
1025            try expect(struct1.a == .f1);
1026            try expect(struct2.a == .f1);
1027        }
1028    };
1029
1030    try S.doTheTest();
1031    try comptime S.doTheTest();
1032}
1033
1034test "@unionInit on union with tag but no fields" {
1035    if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1036    if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1037
1038    const S = struct {
1039        const Type = enum(u8) { no_op = 105 };
1040
1041        const Data = union(Type) {
1042            no_op: void,
1043
1044            pub fn decode(buf: []const u8) Data {
1045                _ = buf;
1046                return @unionInit(Data, "no_op", {});
1047            }
1048        };
1049
1050        comptime {
1051            assert(@sizeOf(Data) == 1);
1052        }
1053
1054        fn doTheTest() !void {
1055            var data: Data = .{ .no_op = {} };
1056            _ = &data;
1057            var o = Data.decode(&[_]u8{});
1058            _ = &o;
1059            try expectEqual(Type.no_op, o);
1060        }
1061    };
1062
1063    try S.doTheTest();
1064    try comptime S.doTheTest();
1065}
1066
1067test "union enum type gets a separate scope" {
1068    const S = struct {
1069        const U = union(enum) {
1070            a: u8,
1071            const foo = 1;
1072        };
1073
1074        fn doTheTest() !void {
1075            try expect(!@hasDecl(Tag(U), "foo"));
1076        }
1077    };
1078
1079    try S.doTheTest();
1080}
1081
1082test "global variable struct contains union initialized to non-most-aligned field" {
1083    if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1084    if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1085    if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
1086
1087    const T = struct {
1088        const U = union(enum) {
1089            a: i32,
1090            b: f64,
1091        };
1092
1093        const S = struct {
1094            u: U,
1095        };
1096
1097        var s: S = .{
1098            .u = .{
1099                .a = 3,
1100            },
1101        };
1102    };
1103
1104    T.s.u.a += 1;
1105    try expect(T.s.u.a == 4);
1106}
1107
1108test "union with no result loc initiated with a runtime value" {
1109    if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1110    if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1111    if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
1112
1113    const U = union {
1114        a: u32,
1115        b: u32,
1116        fn foo(u: @This()) void {
1117            _ = u;
1118        }
1119    };
1120    var a: u32 = 1;
1121    _ = &a;
1122    U.foo(U{ .a = a });
1123}
1124
1125test "union with a large struct field" {
1126    if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1127    if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1128    if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
1129
1130    const S = struct {
1131        a: [8]usize,
1132    };
1133
1134    const U = union {
1135        s: S,
1136        b: u32,
1137        fn foo(_: @This()) void {}
1138    };
1139    var s: S = undefined;
1140    _ = &s;
1141    U.foo(U{ .s = s });
1142}
1143
1144test "comptime equality of extern unions with same tag" {
1145    const S = struct {
1146        const U = extern union {
1147            a: i32,
1148            b: f32,
1149        };
1150        fn foo(comptime x: U) i32 {
1151            return x.a;
1152        }
1153    };
1154    const a = S.U{ .a = 1234 };
1155    const b = S.U{ .a = 1234 };
1156    try expect(S.foo(a) == S.foo(b));
1157}
1158
1159test "union tag is set when initiated as a temporary value at runtime" {
1160    if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1161    if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1162    if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
1163
1164    const U = union(enum) {
1165        a,
1166        b: u32,
1167        c,
1168
1169        fn doTheTest(u: @This()) !void {
1170            try expect(u == .b);
1171        }
1172    };
1173    var b: u32 = 1;
1174    _ = &b;
1175    try (U{ .b = b }).doTheTest();
1176}
1177
1178test "extern union most-aligned field is smaller" {
1179    if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1180    if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1181    if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1182    if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
1183
1184    const U = extern union {
1185        in6: extern struct {
1186            family: u16,
1187            port: u16,
1188            flowinfo: u32,
1189            addr: [20]u8,
1190        },
1191        un: [110]u8,
1192    };
1193    var a: ?U = .{ .un = [_]u8{0} ** 110 };
1194    _ = &a;
1195    try expect(a != null);
1196}
1197
1198test "return an extern union from C calling convention" {
1199    if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1200    if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1201    if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
1202
1203    const namespace = struct {
1204        const S = extern struct {
1205            x: c_int,
1206        };
1207        const U = extern union {
1208            l: c_long,
1209            d: f64,
1210            s: S,
1211        };
1212
1213        fn bar(arg_u: U) callconv(.c) U {
1214            var u = arg_u;
1215            _ = &u;
1216            return u;
1217        }
1218    };
1219
1220    var u: namespace.U = namespace.U{
1221        .l = @as(c_long, 42),
1222    };
1223    u = namespace.bar(namespace.U{
1224        .d = 4.0,
1225    });
1226    try expect(u.d == 4.0);
1227}
1228
1229test "noreturn field in union" {
1230    if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1231    if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1232
1233    const U = union(enum) {
1234        a: u32,
1235        b: noreturn,
1236        c: noreturn,
1237    };
1238    var a = U{ .a = 1 };
1239    var count: u32 = 0;
1240    if (a == .b) @compileError("bad");
1241    switch (a) {
1242        .a => count += 1,
1243        .b => |val| {
1244            _ = val;
1245            @compileError("bad");
1246        },
1247        .c => @compileError("bad"),
1248    }
1249    switch (a) {
1250        .a => count += 1,
1251        .b, .c => @compileError("bad"),
1252    }
1253    switch (a) {
1254        .a, .b, .c => {
1255            count += 1;
1256            try expect(a == .a);
1257        },
1258    }
1259    switch (a) {
1260        .a => count += 1,
1261        else => @compileError("bad"),
1262    }
1263    switch (a) {
1264        else => {
1265            count += 1;
1266            try expect(a == .a);
1267        },
1268    }
1269    switch (a) {
1270        .a => count += 1,
1271        .b, .c => |*val| {
1272            _ = val;
1273            @compileError("bad");
1274        },
1275    }
1276    try expect(count == 6);
1277}
1278
1279test "@unionInit uses tag value instead of field index" {
1280    if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1281    if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1282    if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
1283
1284    const E = enum(u8) {
1285        b = 255,
1286        a = 3,
1287    };
1288    const U = union(E) {
1289        b: isize,
1290        a: usize,
1291    };
1292    var i: isize = -1;
1293    _ = &i;
1294    var u = @unionInit(U, "b", i);
1295    {
1296        var a = u.b;
1297        _ = &a;
1298        try expect(a == i);
1299    }
1300    {
1301        var a = &u.b;
1302        _ = &a;
1303        try expect(a.* == i);
1304    }
1305    try expect(@intFromEnum(u) == 255);
1306}
1307
1308test "union field ptr - zero sized payload" {
1309    if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1310    if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1311    if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
1312
1313    const U = union {
1314        foo: void,
1315        bar: void,
1316        fn qux(_: *void) void {}
1317    };
1318    var u: U = .{ .foo = {} };
1319    U.qux(&u.foo);
1320}
1321
1322test "union field ptr - zero sized field" {
1323    if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1324    if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1325    if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
1326
1327    const U = union {
1328        foo: void,
1329        bar: u32,
1330        fn qux(_: *void) void {}
1331    };
1332    var u: U = .{ .foo = {} };
1333    U.qux(&u.foo);
1334}
1335
1336test "packed union in packed struct" {
1337    if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1338    if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1339    if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1340
1341    const S = packed struct {
1342        nested: packed union {
1343            val: u32,
1344            foo: u32,
1345        },
1346        bar: u16,
1347
1348        fn unpack(self: @This()) usize {
1349            return self.nested.foo;
1350        }
1351    };
1352    const a: S = .{ .nested = .{ .foo = 123 }, .bar = 5 };
1353    try expect(a.unpack() == 123);
1354}
1355
1356test "Namespace-like union" {
1357    const DepType = enum {
1358        git,
1359        http,
1360        const DepType = @This();
1361        const Version = union(DepType) {
1362            git: Git,
1363            http: void,
1364            const Git = enum {
1365                branch,
1366                tag,
1367                commit,
1368                fn frozen(self: Git) bool {
1369                    return self == .tag;
1370                }
1371            };
1372        };
1373    };
1374    var a: DepType.Version.Git = .tag;
1375    try expect(a.frozen());
1376}
1377
1378test "union int tag type is properly managed" {
1379    const Bar = union(enum(u2)) {
1380        x: bool,
1381        y: u8,
1382        z: u8,
1383    };
1384    try expect(@sizeOf(Bar) + 1 == 3);
1385}
1386
1387test "no dependency loop when function pointer in union returns the union" {
1388    if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1389    if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
1390    if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
1391
1392    const U = union(enum) {
1393        const U = @This();
1394        a: u8,
1395        b: *const fn (x: U) void,
1396        c: *const fn (x: U) U,
1397        d: *const fn (x: u8) U,
1398        e: *const fn (x: *U) void,
1399        f: *const fn (x: *U) U,
1400        fn foo(x: u8) U {
1401            return .{ .a = x };
1402        }
1403    };
1404    var b: U = .{ .d = U.foo };
1405    try expect(b.d(2).a == 2);
1406}
1407
1408test "union reassignment can use previous value" {
1409    if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1410    if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
1411
1412    const U = union {
1413        a: u32,
1414        b: u32,
1415    };
1416    var a = U{ .a = 32 };
1417    a = U{ .b = a.a };
1418    try expect(a.b == 32);
1419}
1420
1421test "reinterpreting enum value inside packed union" {
1422    if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1423
1424    const U = packed union {
1425        tag: enum(u8) { a, b },
1426        val: u8,
1427
1428        fn doTest() !void {
1429            var u: @This() = .{ .tag = .a };
1430            u.val += 1;
1431            try expect(u.tag == .b);
1432        }
1433    };
1434    try U.doTest();
1435    try comptime U.doTest();
1436}
1437
1438test "access the tag of a global tagged union" {
1439    const U = union(enum) {
1440        a,
1441        b: u8,
1442        var u: @This() = .a;
1443    };
1444    try expect(U.u == .a);
1445}
1446
1447test "coerce enum literal to union in result loc" {
1448    const U = union(enum) {
1449        a,
1450        b: u8,
1451
1452        fn doTest(c: bool) !void {
1453            const u = if (c) .a else @This(){ .b = 0 };
1454            try expect(u == .a);
1455        }
1456    };
1457    try U.doTest(true);
1458    try comptime U.doTest(true);
1459}
1460
1461test "defined-layout union field pointer has correct alignment" {
1462    if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
1463    if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1464    if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1465    if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
1466
1467    const S = struct {
1468        fn doTheTest(comptime U: type) !void {
1469            var a: U = .{ .x = 123 };
1470            var b: U align(1) = .{ .x = 456 };
1471            var c: U align(64) = .{ .x = 789 };
1472
1473            const ap = &a.x;
1474            const bp = &b.x;
1475            const cp = &c.x;
1476
1477            comptime assert(@TypeOf(ap) == *u32);
1478            comptime assert(@TypeOf(bp) == *align(1) u32);
1479            comptime assert(@TypeOf(cp) == *align(64) u32);
1480
1481            try expectEqual(@as(u32, 123), ap.*);
1482            try expectEqual(@as(u32, 456), bp.*);
1483            try expectEqual(@as(u32, 789), cp.*);
1484        }
1485    };
1486
1487    const U1 = extern union { x: u32 };
1488    const U2 = packed union { x: u32 };
1489
1490    try S.doTheTest(U1);
1491    try S.doTheTest(U2);
1492    try comptime S.doTheTest(U1);
1493    try comptime S.doTheTest(U2);
1494}
1495
1496test "undefined-layout union field pointer has correct alignment" {
1497    if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
1498    if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1499    if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1500    if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
1501
1502    const S = struct {
1503        fn doTheTest(comptime U: type) !void {
1504            var a: U = .{ .x = 123 };
1505            var b: U align(1) = .{ .x = 456 };
1506            var c: U align(64) = .{ .x = 789 };
1507
1508            const ap = &a.x;
1509            const bp = &b.x;
1510            const cp = &c.x;
1511
1512            comptime assert(@TypeOf(ap) == *u32);
1513            comptime assert(@TypeOf(bp) == *align(1) u32);
1514            comptime assert(@TypeOf(cp) == *u32); // undefined layout so does not inherit larger aligns
1515
1516            try expectEqual(@as(u32, 123), ap.*);
1517            try expectEqual(@as(u32, 456), bp.*);
1518            try expectEqual(@as(u32, 789), cp.*);
1519        }
1520    };
1521
1522    const U1 = union { x: u32 };
1523    const U2 = union(enum) { x: u32 };
1524
1525    try S.doTheTest(U1);
1526    try S.doTheTest(U2);
1527    try comptime S.doTheTest(U1);
1528    try comptime S.doTheTest(U2);
1529}
1530
1531test "packed union field pointer has correct alignment" {
1532    if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1533    if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1534    if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1535    if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; // TODO
1536
1537    const U = packed union { x: u20 };
1538    const S = packed struct(u24) { a: u2, u: U, b: u2 };
1539
1540    var a: S = undefined;
1541    var b: S align(1) = undefined;
1542    var c: S align(64) = undefined;
1543
1544    const ap = &a.u.x;
1545    const bp = &b.u.x;
1546    const cp = &c.u.x;
1547
1548    const host_size = switch (builtin.zig_backend) {
1549        else => comptime std.math.divCeil(comptime_int, @bitSizeOf(S), 8) catch unreachable,
1550        .stage2_x86_64, .stage2_c => @sizeOf(S),
1551    };
1552    comptime assert(@TypeOf(ap) == *align(4:2:host_size) u20);
1553    comptime assert(@TypeOf(bp) == *align(1:2:host_size) u20);
1554    comptime assert(@TypeOf(cp) == *align(64:2:host_size) u20);
1555
1556    a.u = .{ .x = 123 };
1557    b.u = .{ .x = 456 };
1558    c.u = .{ .x = 789 };
1559
1560    try expectEqual(@as(u20, 123), ap.*);
1561    try expectEqual(@as(u20, 456), bp.*);
1562    try expectEqual(@as(u20, 789), cp.*);
1563}
1564
1565test "union with 128 bit integer" {
1566    if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1567    if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
1568
1569    const ValueTag = enum { int, other };
1570
1571    const Value3 = union(ValueTag) {
1572        int: i128,
1573        other: bool,
1574    };
1575    var values: [2]Value3 = undefined;
1576    values[0] = .{ .int = 3 };
1577    values[1] = .{ .int = 4 };
1578
1579    var ok: usize = 0;
1580
1581    for (values) |val| {
1582        switch (val) {
1583            .int => ok += 1,
1584            else => return error.TestFailed,
1585        }
1586    }
1587}
1588
1589test "memset extern union" {
1590    if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
1591
1592    const U = extern union {
1593        foo: u8,
1594        bar: u32,
1595    };
1596
1597    const S = struct {
1598        fn doTheTest() !void {
1599            var u: U = undefined;
1600            @memset(std.mem.asBytes(&u), 0);
1601            try expectEqual(@as(u8, 0), u.foo);
1602            try expectEqual(@as(u32, 0), u.bar);
1603        }
1604    };
1605
1606    try comptime S.doTheTest();
1607    try S.doTheTest();
1608}
1609
1610test "memset packed union" {
1611    if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
1612
1613    const U = packed union {
1614        a: u32,
1615        b: u32,
1616    };
1617
1618    const S = struct {
1619        fn doTheTest() !void {
1620            var u: U = undefined;
1621            @memset(@as([]u8, @ptrCast(&u)), 42);
1622            try expectEqual(@as(u32, 0x2a2a2a2a), u.a);
1623            try expectEqual(@as(u32, 0x2a2a2a2a), u.b);
1624        }
1625    };
1626
1627    try comptime S.doTheTest();
1628
1629    if (builtin.cpu.arch.isWasm()) return error.SkipZigTest; // TODO
1630    try S.doTheTest();
1631}
1632
1633fn littleToNativeEndian(comptime T: type, v: T) T {
1634    return if (endian == .little) v else @byteSwap(v);
1635}
1636
1637test "reinterpret extern union" {
1638    if (true) {
1639        // https://github.com/ziglang/zig/issues/19389
1640        return error.SkipZigTest;
1641    }
1642
1643    const U = extern union {
1644        foo: u8,
1645        baz: u32 align(8),
1646        bar: u32,
1647    };
1648
1649    const S = struct {
1650        fn doTheTest() !void {
1651            {
1652                // Undefined initialization
1653                const u = blk: {
1654                    var u: U = undefined;
1655                    @memset(std.mem.asBytes(&u), 0);
1656                    u.bar = 0xbbbbbbbb;
1657                    u.foo = 0x2a;
1658                    break :blk u;
1659                };
1660
1661                try expectEqual(@as(u8, 0x2a), u.foo);
1662                try expectEqual(littleToNativeEndian(u32, 0xbbbbbb2a), u.bar);
1663                try expectEqual(littleToNativeEndian(u32, 0xbbbbbb2a), u.baz);
1664            }
1665
1666            {
1667                // Union initialization
1668                var u: U = .{
1669                    .foo = 0x2a,
1670                };
1671
1672                {
1673                    const expected, const mask = switch (endian) {
1674                        .little => .{ 0x2a, 0xff },
1675                        .big => .{ 0x2a000000, 0xff000000 },
1676                    };
1677
1678                    try expectEqual(@as(u8, 0x2a), u.foo);
1679                    try expectEqual(@as(u32, expected), u.bar & mask);
1680                    try expectEqual(@as(u32, expected), u.baz & mask);
1681                }
1682
1683                // Writing to a larger field
1684                u.baz = 0xbbbbbbbb;
1685                try expectEqual(@as(u8, 0xbb), u.foo);
1686                try expectEqual(@as(u32, 0xbbbbbbbb), u.bar);
1687                try expectEqual(@as(u32, 0xbbbbbbbb), u.baz);
1688
1689                // Writing to the same field
1690                u.baz = 0xcccccccc;
1691                try expectEqual(@as(u8, 0xcc), u.foo);
1692                try expectEqual(@as(u32, 0xcccccccc), u.bar);
1693                try expectEqual(@as(u32, 0xcccccccc), u.baz);
1694
1695                // Writing to a smaller field
1696                u.foo = 0xdd;
1697                try expectEqual(@as(u8, 0xdd), u.foo);
1698                try expectEqual(littleToNativeEndian(u32, 0xccccccdd), u.bar);
1699                try expectEqual(littleToNativeEndian(u32, 0xccccccdd), u.baz);
1700            }
1701        }
1702    };
1703
1704    try comptime S.doTheTest();
1705
1706    if (builtin.zig_backend == .stage2_llvm) return error.SkipZigTest; // TODO
1707    try S.doTheTest();
1708}
1709
1710test "reinterpret packed union" {
1711    if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1712    if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
1713
1714    const U = packed union {
1715        foo: packed struct(u64) {
1716            a: u8,
1717            b: u56,
1718        },
1719        bar: packed struct(u64) {
1720            a: u29,
1721            b: u35,
1722        },
1723        baz: u64,
1724        qux: packed struct(u64) {
1725            a: u12,
1726            b: u52,
1727        },
1728    };
1729
1730    const S = struct {
1731        fn doTheTest() !void {
1732            {
1733                const u = blk: {
1734                    var u: U = undefined;
1735                    @memset(std.mem.asBytes(&u), 0);
1736                    u.baz = 0xbbbbbbbb;
1737                    u.qux.a = 0xe2a;
1738                    break :blk u;
1739                };
1740
1741                try expectEqual(@as(u8, 0x2a), u.foo.a);
1742                try expectEqual(@as(u12, 0xe2a), u.qux.a);
1743
1744                // https://github.com/ziglang/zig/issues/17360
1745                if (@inComptime()) {
1746                    try expectEqual(@as(u29, 0x1bbbbe2a), u.bar.a);
1747                    try expectEqual(@as(u64, 0xbbbbbe2a), u.baz);
1748                }
1749            }
1750
1751            {
1752                // Union initialization
1753                var u: U = .{ .baz = 0 }; // ensure all bits are defined
1754                u.qux.a = 0xe2a;
1755                try expectEqual(@as(u8, 0x2a), u.foo.a);
1756                try expectEqual(@as(u12, 0xe2a), u.qux.a);
1757                try expectEqual(@as(u29, 0xe2a), u.bar.a & 0xfff);
1758                try expectEqual(@as(u64, 0xe2a), u.baz & 0xfff);
1759
1760                // Writing to a larger field
1761                u.baz = 0xbbbbbbbb;
1762                try expectEqual(@as(u8, 0xbb), u.foo.a);
1763                try expectEqual(@as(u12, 0xbbb), u.qux.a);
1764                try expectEqual(@as(u29, 0x1bbbbbbb), u.bar.a);
1765                try expectEqual(@as(u64, 0xbbbbbbbb), u.baz);
1766
1767                // Writing to the same field
1768                u.baz = 0xcccccccc;
1769                try expectEqual(@as(u8, 0xcc), u.foo.a);
1770                try expectEqual(@as(u12, 0xccc), u.qux.a);
1771                try expectEqual(@as(u29, 0x0ccccccc), u.bar.a);
1772                try expectEqual(@as(u64, 0xcccccccc), u.baz);
1773
1774                // Writing to a smaller field
1775                u.foo.a = 0xdd;
1776                try expectEqual(@as(u8, 0xdd), u.foo.a);
1777                try expectEqual(@as(u12, 0xcdd), u.qux.a);
1778                try expectEqual(@as(u29, 0x0cccccdd), u.bar.a);
1779                try expectEqual(@as(u64, 0xccccccdd), u.baz);
1780            }
1781        }
1782    };
1783
1784    try comptime S.doTheTest();
1785
1786    if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
1787    if (builtin.cpu.arch.isWasm()) return error.SkipZigTest; // TODO
1788    if (builtin.cpu.arch.endian() == .big) return error.SkipZigTest; // https://github.com/ziglang/zig/issues/21050
1789    try S.doTheTest();
1790}
1791
1792test "reinterpret packed union inside packed struct" {
1793    if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1794    if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
1795    if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; // TODO
1796
1797    const U = packed union {
1798        a: u7,
1799        b: packed struct(u7) {
1800            a: u1,
1801            b: u6,
1802        },
1803    };
1804
1805    const V = packed struct {
1806        lo: U,
1807        hi: U,
1808    };
1809
1810    const S = struct {
1811        fn doTheTest() !void {
1812            var v: V = undefined;
1813            @memset(@as([]u8, @ptrCast(&v)), 0x55);
1814            try expect(@as(u7, 0x55) == v.lo.a);
1815            try expect(@as(u1, 1) == v.lo.b.a);
1816            try expect(@as(u7, 0x2a) == v.hi.a);
1817            try expect(@as(u1, 0) == v.hi.b.a);
1818
1819            v.lo.b.a = 0;
1820            try expect(@as(u7, 0x54) == v.lo.a);
1821            try expect(@as(u1, 0) == v.lo.b.a);
1822            v.hi.b.a = 1;
1823            try expect(@as(u7, 0x2b) == v.hi.a);
1824            try expect(@as(u1, 1) == v.hi.b.a);
1825        }
1826    };
1827
1828    try comptime S.doTheTest();
1829
1830    if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
1831    try S.doTheTest();
1832}
1833
1834test "inner struct initializer uses union layout" {
1835    const namespace = struct {
1836        const U = union {
1837            a: struct {
1838                x: u32 = @alignOf(U) + 1,
1839            },
1840            b: struct {
1841                y: u16 = @sizeOf(U) + 2,
1842            },
1843        };
1844    };
1845
1846    {
1847        const u: namespace.U = .{ .a = .{} };
1848        try expectEqual(4, @alignOf(namespace.U));
1849        try expectEqual(@as(usize, 5), u.a.x);
1850    }
1851
1852    {
1853        const u: namespace.U = .{ .b = .{} };
1854        try expectEqual(@as(usize, @sizeOf(namespace.U) + 2), u.b.y);
1855    }
1856}
1857
1858test "inner struct initializer uses packed union layout" {
1859    const namespace = struct {
1860        const U = packed union {
1861            a: packed struct {
1862                x: u32 = @alignOf(U) + 1,
1863            },
1864            b: packed struct(u32) {
1865                y: u16 = @sizeOf(U) + 2,
1866                padding: u16 = 0,
1867            },
1868        };
1869    };
1870
1871    {
1872        const u: namespace.U = .{ .a = .{} };
1873        try expectEqual(4, @alignOf(namespace.U));
1874        try expectEqual(@as(usize, 5), u.a.x);
1875    }
1876
1877    {
1878        const u: namespace.U = .{ .b = .{} };
1879        try expectEqual(@as(usize, @sizeOf(namespace.U) + 2), u.b.y);
1880    }
1881}
1882
1883test "extern union initialized via reintepreted struct field initializer" {
1884    if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
1885
1886    const bytes = [_]u8{ 0xaa, 0xbb, 0xcc, 0xdd };
1887
1888    const U = extern union {
1889        a: u32,
1890        b: u8,
1891    };
1892
1893    const S = extern struct {
1894        u: U = @as(*align(1) const U, @ptrCast(&bytes)).*,
1895    };
1896
1897    const s: S = .{};
1898    try expect(s.u.a == littleToNativeEndian(u32, 0xddccbbaa));
1899    try expect(s.u.b == 0xaa);
1900}
1901
1902test "packed union initialized via reintepreted struct field initializer" {
1903    if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1904
1905    const bytes = [_]u8{ 0xaa, 0xbb, 0xcc, 0xdd };
1906
1907    const U = packed union {
1908        a: u32,
1909        b: packed struct(u32) {
1910            a: u8,
1911            b: u24,
1912        },
1913    };
1914
1915    const S = packed struct {
1916        u: U = @as(*align(1) const U, @ptrCast(&bytes)).*,
1917    };
1918
1919    var s: S = .{};
1920    _ = &s;
1921    try expect(s.u.a == littleToNativeEndian(u32, 0xddccbbaa));
1922    try expect(s.u.b.a == if (endian == .little) 0xaa else 0xdd);
1923}
1924
1925test "store of comptime reinterpreted memory to extern union" {
1926    if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
1927
1928    const bytes = [_]u8{ 0xaa, 0xbb, 0xcc, 0xdd };
1929
1930    const U = extern union {
1931        a: u32,
1932        b: u8,
1933    };
1934
1935    const reinterpreted = comptime b: {
1936        var u: U = undefined;
1937        u = @as(*align(1) const U, @ptrCast(&bytes)).*;
1938        break :b u;
1939    };
1940
1941    var u: U = reinterpreted;
1942    _ = &u;
1943    try expect(u.a == littleToNativeEndian(u32, 0xddccbbaa));
1944    try expect(u.b == 0xaa);
1945}
1946
1947test "store of comptime reinterpreted memory to packed union" {
1948    if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1949
1950    const bytes = [_]u8{ 0xaa, 0xbb, 0xcc, 0xdd };
1951
1952    const U = packed union {
1953        a: u32,
1954        b: packed struct(u32) {
1955            a: u8,
1956            b: u24,
1957        },
1958    };
1959
1960    const reinterpreted = comptime b: {
1961        var u: U = undefined;
1962        u = @as(*align(1) const U, @ptrCast(&bytes)).*;
1963        break :b u;
1964    };
1965
1966    var u: U = reinterpreted;
1967    _ = &u;
1968    try expect(u.a == littleToNativeEndian(u32, 0xddccbbaa));
1969    try expect(u.b.a == if (endian == .little) 0xaa else 0xdd);
1970}
1971
1972test "union field is a pointer to an aligned version of itself" {
1973    if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
1974    if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
1975
1976    const E = union {
1977        next: *align(1) @This(),
1978    };
1979    var e: E = undefined;
1980    e = .{ .next = &e };
1981
1982    try expect(&e == e.next);
1983}
1984
1985test "pass register-sized field as non-register-sized union" {
1986    if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1987    if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
1988    if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
1989
1990    const S = struct {
1991        fn taggedUnion(u: union(enum) { x: usize, y: [2]usize }) !void {
1992            try expectEqual(@as(usize, 42), u.x);
1993        }
1994
1995        fn untaggedUnion(u: union { x: usize, y: [2]usize }) !void {
1996            try expectEqual(@as(usize, 42), u.x);
1997        }
1998
1999        fn externUnion(u: extern union { x: usize, y: [2]usize }) !void {
2000            try expectEqual(@as(usize, 42), u.x);
2001        }
2002    };
2003
2004    var x: usize = 42;
2005    _ = &x;
2006    try S.taggedUnion(.{ .x = x });
2007    try S.untaggedUnion(.{ .x = x });
2008    try S.externUnion(.{ .x = x });
2009}
2010
2011test "circular dependency through pointer field of a union" {
2012    if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
2013
2014    const S = struct {
2015        const UnionInner = extern struct {
2016            outer: UnionOuter = std.mem.zeroes(UnionOuter),
2017        };
2018
2019        const UnionMiddle = extern union {
2020            outer: ?*UnionOuter,
2021            inner: ?*UnionInner,
2022        };
2023
2024        const UnionOuter = extern struct {
2025            u: UnionMiddle = std.mem.zeroes(UnionMiddle),
2026        };
2027    };
2028    var outer: S.UnionOuter = .{};
2029    _ = &outer;
2030    try expect(outer.u.outer == null);
2031    try expect(outer.u.inner == null);
2032}
2033
2034test "pass nested union with rls" {
2035    if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
2036    if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
2037
2038    const Union = union(enum) {
2039        a: u32,
2040        b: union(enum) {
2041            c: u7,
2042            d: u3,
2043        },
2044
2045        fn getC(u: @This()) u7 {
2046            return u.b.c;
2047        }
2048    };
2049
2050    var c: u7 = 32;
2051    _ = &c;
2052    try expectEqual(@as(u7, 32), Union.getC(.{ .b = .{ .c = c } }));
2053}
2054
2055test "runtime union init, most-aligned field != largest" {
2056    if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
2057    if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
2058    if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
2059    if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
2060
2061    const U = union(enum) {
2062        x: u128,
2063        y: [17]u8,
2064
2065        fn foo(val: @This()) !void {
2066            try expect(val.x == 1);
2067        }
2068    };
2069    var x: u8 = 1;
2070    _ = &x;
2071    try U.foo(.{ .x = x });
2072
2073    const val: U = @unionInit(U, "x", x);
2074    try expect(val.x == 1);
2075
2076    const val2: U = .{ .x = x };
2077    try expect(val2.x == 1);
2078}
2079
2080test "copied union field doesn't alias source" {
2081    if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
2082    if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
2083    if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
2084
2085    const U = union(enum) {
2086        array: [10]u32,
2087        other: u32,
2088    };
2089
2090    var x = U{ .array = undefined };
2091
2092    x.array[1] = 0;
2093    const a = x.array;
2094    x.array[1] = 15;
2095
2096    try expect(a[1] == 0);
2097}
2098
2099test "create union(enum) from other union(enum)" {
2100    if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
2101    if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
2102    if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
2103    if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
2104
2105    const string = "hello world";
2106    const TempRef = struct {
2107        index: usize,
2108        is_weak: bool,
2109    };
2110    const BuiltinEnum = struct {
2111        name: []const u8,
2112    };
2113    const ParamType = union(enum) {
2114        boolean,
2115        buffer,
2116        one_of: BuiltinEnum,
2117    };
2118    const EnumLiteral = struct {
2119        label: []const u8,
2120    };
2121
2122    const ExpressionResult = union(enum) {
2123        temp_buffer: TempRef,
2124        literal_boolean: bool,
2125        literal_enum_value: []const u8,
2126
2127        fn commitCalleeParam(result: @This(), callee_param_type: ParamType) @This() {
2128            switch (callee_param_type) {
2129                .boolean => return result,
2130                .buffer => return .{
2131                    .temp_buffer = .{ .index = 0, .is_weak = false },
2132                },
2133                .one_of => return result,
2134            }
2135        }
2136    };
2137    const Expression = union(enum) {
2138        literal_boolean: bool,
2139        literal_enum_value: EnumLiteral,
2140
2141        fn genExpression(expr: @This()) !ExpressionResult {
2142            switch (expr) {
2143                .literal_boolean => |value| return .{
2144                    .literal_boolean = value,
2145                },
2146                .literal_enum_value => |v| {
2147                    try std.testing.expectEqualStrings(string, v.label);
2148                    const result: ExpressionResult = .{
2149                        .literal_enum_value = v.label,
2150                    };
2151                    switch (result) {
2152                        .literal_enum_value => |w| {
2153                            try std.testing.expectEqualStrings(string, w);
2154                        },
2155                        else => {},
2156                    }
2157                    return result;
2158                },
2159            }
2160        }
2161    };
2162    const CallArg = struct {
2163        value: Expression,
2164    };
2165
2166    var param: ParamType = .{
2167        .one_of = .{ .name = "name" },
2168    };
2169    _ = &param;
2170    var arg: CallArg = .{
2171        .value = .{
2172            .literal_enum_value = .{
2173                .label = string,
2174            },
2175        },
2176    };
2177    _ = &arg;
2178
2179    const result = try arg.value.genExpression();
2180    switch (result) {
2181        .literal_enum_value => |w| {
2182            try std.testing.expectEqualStrings(string, w);
2183        },
2184        else => {},
2185    }
2186
2187    const derp = result.commitCalleeParam(param);
2188    switch (derp) {
2189        .literal_enum_value => |w| {
2190            try std.testing.expectEqualStrings(string, w);
2191        },
2192        else => {},
2193    }
2194}
2195
2196test "matching captures causes union equivalence" {
2197    const S = struct {
2198        fn SignedUnsigned(comptime I: type) type {
2199            const bits = @typeInfo(I).int.bits;
2200            return union {
2201                u: @Int(.unsigned, bits),
2202                i: @Int(.signed, bits),
2203            };
2204        }
2205    };
2206
2207    comptime assert(S.SignedUnsigned(u8) == S.SignedUnsigned(i8));
2208    comptime assert(S.SignedUnsigned(u16) == S.SignedUnsigned(i16));
2209    comptime assert(S.SignedUnsigned(u8) != S.SignedUnsigned(u16));
2210
2211    const a: S.SignedUnsigned(u8) = .{ .u = 10 };
2212    const b: S.SignedUnsigned(i8) = .{ .u = 10 };
2213    comptime assert(@TypeOf(a) == @TypeOf(b));
2214    try expect(a.u == b.u);
2215}
2216
2217test "signed enum tag with negative value" {
2218    if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
2219    if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
2220    if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
2221
2222    const Enum = enum(i8) {
2223        a = -1,
2224    };
2225
2226    const Union = union(Enum) {
2227        a: i32,
2228    };
2229
2230    var i: i32 = 0;
2231    i = i;
2232    const e = Union{ .a = i };
2233
2234    try expect(e.a == i);
2235}
2236
2237test "union @FieldType" {
2238    const U = union {
2239        a: u32,
2240        b: f64,
2241        c: *@This(),
2242    };
2243
2244    comptime assert(@FieldType(U, "a") == u32);
2245    comptime assert(@FieldType(U, "b") == f64);
2246    comptime assert(@FieldType(U, "c") == *U);
2247}
2248
2249test "tagged union @FieldType" {
2250    const U = union(enum) {
2251        a: u32,
2252        b: f64,
2253        c: *@This(),
2254    };
2255
2256    comptime assert(@FieldType(U, "a") == u32);
2257    comptime assert(@FieldType(U, "b") == f64);
2258    comptime assert(@FieldType(U, "c") == *U);
2259}
2260
2261test "extern union @FieldType" {
2262    const U = extern union {
2263        a: u32,
2264        b: f64,
2265        c: *@This(),
2266    };
2267
2268    comptime assert(@FieldType(U, "a") == u32);
2269    comptime assert(@FieldType(U, "b") == f64);
2270    comptime assert(@FieldType(U, "c") == *U);
2271}
2272
2273test "assign global tagged union" {
2274    if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
2275
2276    const U = union(enum) {
2277        a: u16,
2278        b: u32,
2279
2280        var global: @This() = undefined;
2281    };
2282
2283    U.global = .{ .a = 123 };
2284    try expect(U.global == .a);
2285    try expect(U.global != .b);
2286    try expect(U.global.a == 123);
2287
2288    U.global = .{ .b = 123456 };
2289    try expect(U.global != .a);
2290    try expect(U.global == .b);
2291    try expect(U.global.b == 123456);
2292}
2293
2294test "set mutable union by switching on same union" {
2295    const U = union(enum) {
2296        foo,
2297        bar: usize,
2298    };
2299
2300    var val: U = .foo;
2301    val = switch (val) {
2302        .foo => .{ .bar = 2 },
2303        .bar => .foo,
2304    };
2305
2306    try expect(val == .bar);
2307    try expect(val.bar == 2);
2308}
2309
2310test "initialize empty field of union inside comptime-known struct constant" {
2311    const Inner = union { none: void, some: u8 };
2312    const Wrapper = struct { inner: Inner };
2313
2314    const val: Wrapper = .{ .inner = .{ .none = {} } };
2315    comptime assert(val.inner.none == {});
2316}
2317
2318test "union with function body field" {
2319    const U = union {
2320        f: fn () void,
2321        fn foo() void {}
2322        fn bar() void {}
2323    };
2324    const x: U = .{ .f = U.foo };
2325    try std.testing.expect(x.f == U.foo);
2326    x.f();
2327
2328    comptime var y: U = .{ .f = U.bar };
2329    try std.testing.expect(y.f == U.bar);
2330    y.f();
2331    y.f = U.foo;
2332    try std.testing.expect(y.f == U.foo);
2333    y.f();
2334}