aboutsummaryrefslogtreecommitdiff
path: root/test
diff options
context:
space:
mode:
authorAndrew Kelley <andrew@ziglang.org>2021-12-28 23:10:48 -0700
committerAndrew Kelley <andrew@ziglang.org>2021-12-28 23:22:09 -0700
commitefb7148a4574c608b21359fcbf2edf06afdb5e0c (patch)
tree23e47a49f95e60ea315603407bd5793310978c62 /test
parent91619cdf57f54accbdbb3ff616856eaf79b537a3 (diff)
downloadzig-efb7148a4574c608b21359fcbf2edf06afdb5e0c.tar.gz
zig-efb7148a4574c608b21359fcbf2edf06afdb5e0c.zip
Sema: more union fixes
* `Module.Union.getLayout`: fixes to support components of the union being 0 bits. * Implement `@typeInfo` for unions. * Add missing calls to `resolveTypeFields`. * Fix explicitly-provided union tag types passing a `Zir.Inst.Ref` where an `Air.Inst.Ref` was expected. We don't have any type safety for this; these typess are aliases. * Fix explicitly-provided `union(enum)` tag Values allocated to the wrong arena.
Diffstat (limited to 'test')
-rw-r--r--test/behavior/switch.zig13
-rw-r--r--test/behavior/switch_stage1.zig13
-rw-r--r--test/behavior/union.zig205
-rw-r--r--test/behavior/union_stage1.zig211
4 files changed, 218 insertions, 224 deletions
diff --git a/test/behavior/switch.zig b/test/behavior/switch.zig
index 16bb890c9e..caec804ec2 100644
--- a/test/behavior/switch.zig
+++ b/test/behavior/switch.zig
@@ -313,3 +313,16 @@ fn returnsFalse() bool {
test "switch on const enum with var" {
try expect(!returnsFalse());
}
+
+test "anon enum literal used in switch on union enum" {
+ const Foo = union(enum) {
+ a: i32,
+ };
+
+ var foo = Foo{ .a = 1234 };
+ switch (foo) {
+ .a => |x| {
+ try expect(x == 1234);
+ },
+ }
+}
diff --git a/test/behavior/switch_stage1.zig b/test/behavior/switch_stage1.zig
index 1b85d767d5..267ac321b3 100644
--- a/test/behavior/switch_stage1.zig
+++ b/test/behavior/switch_stage1.zig
@@ -35,19 +35,6 @@ test "capture value of switch with all unreachable prongs" {
try expect(x == 1);
}
-test "anon enum literal used in switch on union enum" {
- const Foo = union(enum) {
- a: i32,
- };
-
- var foo = Foo{ .a = 1234 };
- switch (foo) {
- .a => |x| {
- try expect(x == 1234);
- },
- }
-}
-
test "else prong of switch on error set excludes other cases" {
const S = struct {
fn doTheTest() !void {
diff --git a/test/behavior/union.zig b/test/behavior/union.zig
index 05bd8070a2..325586d35c 100644
--- a/test/behavior/union.zig
+++ b/test/behavior/union.zig
@@ -221,6 +221,12 @@ fn testCastUnionToTag() !void {
try expect(@as(TheTag, u) == TheTag.B);
}
+test "union field access gives the enum values" {
+ try expect(TheUnion.A == TheTag.A);
+ try expect(TheUnion.B == TheTag.B);
+ try expect(TheUnion.C == TheTag.C);
+}
+
test "cast tag type of union to union" {
var x: Value2 = Letter2.B;
try expect(@as(Letter2, x) == Letter2.B);
@@ -255,3 +261,202 @@ test "constant packed union" {
fn testConstPackedUnion(expected_tokens: []const PackThis) !void {
try expect(expected_tokens[0].StringLiteral == 1);
}
+
+const MultipleChoice = union(enum(u32)) {
+ A = 20,
+ B = 40,
+ C = 60,
+ D = 1000,
+};
+test "simple union(enum(u32))" {
+ var x = MultipleChoice.C;
+ try expect(x == MultipleChoice.C);
+ try expect(@enumToInt(@as(Tag(MultipleChoice), x)) == 60);
+}
+
+const PackedPtrOrInt = packed union {
+ ptr: *u8,
+ int: u64,
+};
+test "packed union size" {
+ comptime try expect(@sizeOf(PackedPtrOrInt) == 8);
+}
+
+const ZeroBits = union {
+ OnlyField: void,
+};
+test "union with only 1 field which is void should be zero bits" {
+ comptime try expect(@sizeOf(ZeroBits) == 0);
+}
+
+test "tagged union initialization with runtime void" {
+ try expect(testTaggedUnionInit({}));
+}
+
+const TaggedUnionWithAVoid = union(enum) {
+ A,
+ B: i32,
+};
+
+fn testTaggedUnionInit(x: anytype) bool {
+ const y = TaggedUnionWithAVoid{ .A = x };
+ return @as(Tag(TaggedUnionWithAVoid), y) == TaggedUnionWithAVoid.A;
+}
+
+pub const UnionEnumNoPayloads = union(enum) { A, B };
+
+test "tagged union with no payloads" {
+ const a = UnionEnumNoPayloads{ .B = {} };
+ switch (a) {
+ Tag(UnionEnumNoPayloads).A => @panic("wrong"),
+ Tag(UnionEnumNoPayloads).B => {},
+ }
+}
+
+test "union with only 1 field casted to its enum type" {
+ const Literal = union(enum) {
+ Number: f64,
+ Bool: bool,
+ };
+
+ const Expr = union(enum) {
+ Literal: Literal,
+ };
+
+ var e = Expr{ .Literal = Literal{ .Bool = true } };
+ const ExprTag = Tag(Expr);
+ comptime try expect(Tag(ExprTag) == u0);
+ var t = @as(ExprTag, e);
+ try expect(t == Expr.Literal);
+}
+
+test "union with one member defaults to u0 tag type" {
+ const U0 = union(enum) {
+ X: u32,
+ };
+ comptime try expect(Tag(Tag(U0)) == u0);
+}
+
+const Foo1 = union(enum) {
+ f: struct {
+ x: usize,
+ },
+};
+var glbl: Foo1 = undefined;
+
+test "global union with single field is correctly initialized" {
+ glbl = Foo1{
+ .f = @typeInfo(Foo1).Union.fields[0].field_type{ .x = 123 },
+ };
+ try expect(glbl.f.x == 123);
+}
+
+pub const FooUnion = union(enum) {
+ U0: usize,
+ U1: u8,
+};
+
+var glbl_array: [2]FooUnion = undefined;
+
+test "initialize global array of union" {
+ glbl_array[1] = FooUnion{ .U1 = 2 };
+ glbl_array[0] = FooUnion{ .U0 = 1 };
+ try expect(glbl_array[0].U0 == 1);
+ try expect(glbl_array[1].U1 == 2);
+}
+
+test "update the tag value for zero-sized unions" {
+ const S = union(enum) {
+ U0: void,
+ U1: void,
+ };
+ var x = S{ .U0 = {} };
+ try expect(x == .U0);
+ x = S{ .U1 = {} };
+ try expect(x == .U1);
+}
+
+test "union initializer generates padding only if needed" {
+ const U = union(enum) {
+ A: u24,
+ };
+
+ var v = U{ .A = 532 };
+ try expect(v.A == 532);
+}
+
+test "runtime tag name with single field" {
+ const U = union(enum) {
+ A: i32,
+ };
+
+ var v = U{ .A = 42 };
+ try expect(std.mem.eql(u8, @tagName(v), "A"));
+}
+
+test "method call on an empty union" {
+ const S = struct {
+ const MyUnion = union(MyUnionTag) {
+ pub const MyUnionTag = enum { X1, X2 };
+ X1: [0]u8,
+ X2: [0]u8,
+
+ pub fn useIt(self: *@This()) bool {
+ _ = self;
+ return true;
+ }
+ };
+
+ fn doTheTest() !void {
+ var u = MyUnion{ .X1 = [0]u8{} };
+ try expect(u.useIt());
+ }
+ };
+ try S.doTheTest();
+ comptime try S.doTheTest();
+}
+
+const Point = struct {
+ x: u64,
+ y: u64,
+};
+const TaggedFoo = union(enum) {
+ One: i32,
+ Two: Point,
+ Three: void,
+};
+const FooNoVoid = union(enum) {
+ One: i32,
+ Two: Point,
+};
+const Baz = enum { A, B, C, D };
+
+test "tagged union type" {
+ const foo1 = TaggedFoo{ .One = 13 };
+ const foo2 = TaggedFoo{
+ .Two = Point{
+ .x = 1234,
+ .y = 5678,
+ },
+ };
+ try expect(foo1.One == 13);
+ try expect(foo2.Two.x == 1234 and foo2.Two.y == 5678);
+ const baz = Baz.B;
+
+ try expect(baz == Baz.B);
+ try expect(@typeInfo(TaggedFoo).Union.fields.len == 3);
+ try expect(@typeInfo(Baz).Enum.fields.len == 4);
+ try expect(@sizeOf(TaggedFoo) == @sizeOf(FooNoVoid));
+ try expect(@sizeOf(Baz) == 1);
+}
+
+test "tagged union as return value" {
+ switch (returnAnInt(13)) {
+ TaggedFoo.One => |value| try expect(value == 13),
+ else => unreachable,
+ }
+}
+
+fn returnAnInt(x: i32) TaggedFoo {
+ return TaggedFoo{ .One = x };
+}
diff --git a/test/behavior/union_stage1.zig b/test/behavior/union_stage1.zig
index f5de087ce8..2eefa46705 100644
--- a/test/behavior/union_stage1.zig
+++ b/test/behavior/union_stage1.zig
@@ -3,18 +3,6 @@ const expect = std.testing.expect;
const expectEqual = std.testing.expectEqual;
const Tag = std.meta.Tag;
-const MultipleChoice = union(enum(u32)) {
- A = 20,
- B = 40,
- C = 60,
- D = 1000,
-};
-test "simple union(enum(u32))" {
- var x = MultipleChoice.C;
- try expect(x == MultipleChoice.C);
- try expect(@enumToInt(@as(Tag(MultipleChoice), x)) == 60);
-}
-
const MultipleChoice2 = union(enum(u32)) {
Unspecified1: i32,
A: f32 = 20,
@@ -48,33 +36,6 @@ fn testEnumWithSpecifiedAndUnspecifiedTagValues(x: MultipleChoice2) !void {
});
}
-const PackedPtrOrInt = packed union {
- ptr: *u8,
- int: u64,
-};
-test "packed union size" {
- comptime try expect(@sizeOf(PackedPtrOrInt) == 8);
-}
-
-const ZeroBits = union {
- OnlyField: void,
-};
-test "union with only 1 field which is void should be zero bits" {
- comptime try expect(@sizeOf(ZeroBits) == 0);
-}
-
-const TheTag = enum { A, B, C };
-const TheUnion = union(TheTag) {
- A: i32,
- B: i32,
- C: i32,
-};
-test "union field access gives the enum values" {
- try expect(TheUnion.A == TheTag.A);
- try expect(TheUnion.B == TheTag.B);
- try expect(TheUnion.C == TheTag.C);
-}
-
test "switch on union with only 1 field" {
var r: PartialInst = undefined;
r = PartialInst.Compiled;
@@ -101,47 +62,6 @@ const PartialInstWithPayload = union(enum) {
Compiled: i32,
};
-test "tagged union initialization with runtime void" {
- try expect(testTaggedUnionInit({}));
-}
-
-const TaggedUnionWithAVoid = union(enum) {
- A,
- B: i32,
-};
-
-fn testTaggedUnionInit(x: anytype) bool {
- const y = TaggedUnionWithAVoid{ .A = x };
- return @as(Tag(TaggedUnionWithAVoid), y) == TaggedUnionWithAVoid.A;
-}
-
-pub const UnionEnumNoPayloads = union(enum) { A, B };
-
-test "tagged union with no payloads" {
- const a = UnionEnumNoPayloads{ .B = {} };
- switch (a) {
- Tag(UnionEnumNoPayloads).A => @panic("wrong"),
- Tag(UnionEnumNoPayloads).B => {},
- }
-}
-
-test "union with only 1 field casted to its enum type" {
- const Literal = union(enum) {
- Number: f64,
- Bool: bool,
- };
-
- const Expr = union(enum) {
- Literal: Literal,
- };
-
- var e = Expr{ .Literal = Literal{ .Bool = true } };
- const ExprTag = Tag(Expr);
- comptime try expect(Tag(ExprTag) == u0);
- var t = @as(ExprTag, e);
- try expect(t == Expr.Literal);
-}
-
test "union with only 1 field casted to its enum type which has enum value specified" {
const Literal = union(enum) {
Number: f64,
@@ -285,13 +205,6 @@ test "union no tag with struct member" {
u.foo();
}
-test "union with one member defaults to u0 tag type" {
- const U0 = union(enum) {
- X: u32,
- };
- comptime try expect(Tag(Tag(U0)) == u0);
-}
-
test "union with comptime_int tag" {
const Union = union(enum(comptime_int)) {
X: u32,
@@ -311,34 +224,6 @@ test "extern union doesn't trigger field check at comptime" {
comptime try expect(x.y == 0x55);
}
-const Foo1 = union(enum) {
- f: struct {
- x: usize,
- },
-};
-var glbl: Foo1 = undefined;
-
-test "global union with single field is correctly initialized" {
- glbl = Foo1{
- .f = @typeInfo(Foo1).Union.fields[0].field_type{ .x = 123 },
- };
- try expect(glbl.f.x == 123);
-}
-
-pub const FooUnion = union(enum) {
- U0: usize,
- U1: u8,
-};
-
-var glbl_array: [2]FooUnion = undefined;
-
-test "initialize global array of union" {
- glbl_array[1] = FooUnion{ .U1 = 2 };
- glbl_array[0] = FooUnion{ .U0 = 1 };
- try expect(glbl_array[0].U0 == 1);
- try expect(glbl_array[1].U1 == 2);
-}
-
test "anonymous union literal syntax" {
const S = struct {
const Number = union {
@@ -361,17 +246,6 @@ test "anonymous union literal syntax" {
comptime try S.doTheTest();
}
-test "update the tag value for zero-sized unions" {
- const S = union(enum) {
- U0: void,
- U1: void,
- };
- var x = S{ .U0 = {} };
- try expect(x == .U0);
- x = S{ .U1 = {} };
- try expect(x == .U1);
-}
-
test "function call result coerces from tagged union to the tag" {
const S = struct {
const Arch = union(enum) {
@@ -401,24 +275,6 @@ test "function call result coerces from tagged union to the tag" {
comptime try S.doTheTest();
}
-test "union initializer generates padding only if needed" {
- const U = union(enum) {
- A: u24,
- };
-
- var v = U{ .A = 532 };
- try expect(v.A == 532);
-}
-
-test "runtime tag name with single field" {
- const U = union(enum) {
- A: i32,
- };
-
- var v = U{ .A = 42 };
- try expect(std.mem.eql(u8, @tagName(v), "A"));
-}
-
test "cast from anonymous struct to union" {
const S = struct {
const U = union(enum) {
@@ -473,28 +329,6 @@ test "cast from pointer to anonymous struct to pointer to union" {
comptime try S.doTheTest();
}
-test "method call on an empty union" {
- const S = struct {
- const MyUnion = union(MyUnionTag) {
- pub const MyUnionTag = enum { X1, X2 };
- X1: [0]u8,
- X2: [0]u8,
-
- pub fn useIt(self: *@This()) bool {
- _ = self;
- return true;
- }
- };
-
- fn doTheTest() !void {
- var u = MyUnion{ .X1 = [0]u8{} };
- try expect(u.useIt());
- }
- };
- try S.doTheTest();
- comptime try S.doTheTest();
-}
-
test "switching on non exhaustive union" {
const S = struct {
const E = enum(u8) {
@@ -590,48 +424,3 @@ test "anytype union field: issue #9233" {
const Quux = union(enum) { bar: anytype };
_ = Quux;
}
-
-const Point = struct {
- x: u64,
- y: u64,
-};
-const TaggedFoo = union(enum) {
- One: i32,
- Two: Point,
- Three: void,
-};
-const FooNoVoid = union(enum) {
- One: i32,
- Two: Point,
-};
-const Baz = enum { A, B, C, D };
-
-test "tagged union type" {
- const foo1 = TaggedFoo{ .One = 13 };
- const foo2 = TaggedFoo{
- .Two = Point{
- .x = 1234,
- .y = 5678,
- },
- };
- try expect(foo1.One == 13);
- try expect(foo2.Two.x == 1234 and foo2.Two.y == 5678);
- const baz = Baz.B;
-
- try expect(baz == Baz.B);
- try expect(@typeInfo(TaggedFoo).Union.fields.len == 3);
- try expect(@typeInfo(Baz).Enum.fields.len == 4);
- try expect(@sizeOf(TaggedFoo) == @sizeOf(FooNoVoid));
- try expect(@sizeOf(Baz) == 1);
-}
-
-test "tagged union as return value" {
- switch (returnAnInt(13)) {
- TaggedFoo.One => |value| try expect(value == 13),
- else => unreachable,
- }
-}
-
-fn returnAnInt(x: i32) TaggedFoo {
- return TaggedFoo{ .One = x };
-}