Commit c10fdde5a6
Changed files (4)
src
codegen
test
src/codegen/llvm.zig
@@ -809,7 +809,16 @@ pub const DeclGen = struct {
};
}
- fn llvmType(dg: *DeclGen, t: Type) Error!*const llvm.Type {
+ fn isUnnamedType(dg: *DeclGen, ty: Type, val: *const llvm.Value) bool {
+ // Once `llvmType` succeeds, successive calls to it with the same Zig type
+ // are guaranteed to succeed. So if a call to `llvmType` fails here it means
+ // it is the first time lowering the type, which means the value can't possible
+ // have that type.
+ const llvm_ty = dg.llvmType(ty) catch return true;
+ return val.typeOf() != llvm_ty;
+ }
+
+ fn llvmType(dg: *DeclGen, t: Type) Allocator.Error!*const llvm.Type {
const gpa = dg.gpa;
switch (t.zigTypeTag()) {
.Void, .NoReturn => return dg.context.voidType(),
@@ -1168,9 +1177,8 @@ pub const DeclGen = struct {
.BoundFn => @panic("TODO remove BoundFn from the language"),
- .Frame,
- .AnyFrame,
- => return dg.todo("implement llvmType for type '{}'", .{t}),
+ .Frame => @panic("TODO implement llvmType for Frame types"),
+ .AnyFrame => @panic("TODO implement llvmType for AnyFrame types"),
}
}
@@ -1299,7 +1307,8 @@ pub const DeclGen = struct {
llvm_u32.constInt(0, .False),
llvm_u32.constInt(field_ptr.field_index, .False),
};
- return parent_ptr.constInBoundsGEP(&indices, indices.len);
+ const uncasted = parent_ptr.constInBoundsGEP(&indices, indices.len);
+ return uncasted.constBitCast(try dg.llvmType(tv.ty));
},
.elem_ptr => {
const elem_ptr = tv.val.castTag(.elem_ptr).?.data;
@@ -1463,6 +1472,7 @@ pub const DeclGen = struct {
var llvm_fields = try std.ArrayListUnmanaged(*const llvm.Value).initCapacity(gpa, llvm_field_count);
defer llvm_fields.deinit(gpa);
+ var make_unnamed_struct = false;
const struct_obj = tv.ty.castTag(.@"struct").?.data;
if (struct_obj.layout == .Packed) {
const target = dg.module.getTarget();
@@ -1558,17 +1568,30 @@ pub const DeclGen = struct {
const field_ty = tv.ty.structFieldType(i);
if (!field_ty.hasRuntimeBits()) continue;
- llvm_fields.appendAssumeCapacity(try dg.genTypedValue(.{
+ const field_llvm_val = try dg.genTypedValue(.{
.ty = field_ty,
.val = field_val,
- }));
+ });
+
+ make_unnamed_struct = make_unnamed_struct or
+ dg.isUnnamedType(field_ty, field_llvm_val);
+
+ llvm_fields.appendAssumeCapacity(field_llvm_val);
}
}
- return llvm_struct_ty.constNamedStruct(
- llvm_fields.items.ptr,
- @intCast(c_uint, llvm_fields.items.len),
- );
+ if (make_unnamed_struct) {
+ return dg.context.constStruct(
+ llvm_fields.items.ptr,
+ @intCast(c_uint, llvm_fields.items.len),
+ .False,
+ );
+ } else {
+ return llvm_struct_ty.constNamedStruct(
+ llvm_fields.items.ptr,
+ @intCast(c_uint, llvm_fields.items.len),
+ );
+ }
},
.Union => {
const llvm_union_ty = try dg.llvmType(tv.ty);
test/behavior/union.zig
@@ -490,3 +490,483 @@ test "tagged union with all void fields but a meaningful tag" {
// TODO enable the test at comptime too
//comptime try S.doTheTest();
}
+
+test "union(enum(u32)) with specified and unspecified tag values" {
+ if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO
+
+ comptime try expect(Tag(Tag(MultipleChoice2)) == u32);
+ try testEnumWithSpecifiedAndUnspecifiedTagValues(MultipleChoice2{ .C = 123 });
+ comptime try testEnumWithSpecifiedAndUnspecifiedTagValues(MultipleChoice2{ .C = 123 });
+}
+
+const MultipleChoice2 = union(enum(u32)) {
+ Unspecified1: i32,
+ A: f32 = 20,
+ Unspecified2: void,
+ B: bool = 40,
+ Unspecified3: i32,
+ C: i8 = 60,
+ Unspecified4: void,
+ D: void = 1000,
+ Unspecified5: i32,
+};
+
+fn testEnumWithSpecifiedAndUnspecifiedTagValues(x: MultipleChoice2) !void {
+ try expect(@enumToInt(@as(Tag(MultipleChoice2), x)) == 60);
+ try expect(1123 == switch (x) {
+ MultipleChoice2.A => 1,
+ MultipleChoice2.B => 2,
+ MultipleChoice2.C => |v| @as(i32, 1000) + v,
+ MultipleChoice2.D => 4,
+ MultipleChoice2.Unspecified1 => 5,
+ MultipleChoice2.Unspecified2 => 6,
+ MultipleChoice2.Unspecified3 => 7,
+ MultipleChoice2.Unspecified4 => 8,
+ MultipleChoice2.Unspecified5 => 9,
+ });
+}
+
+test "switch on union with only 1 field" {
+ if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO
+
+ var r: PartialInst = undefined;
+ r = PartialInst.Compiled;
+ switch (r) {
+ PartialInst.Compiled => {
+ var z: PartialInstWithPayload = undefined;
+ z = PartialInstWithPayload{ .Compiled = 1234 };
+ switch (z) {
+ PartialInstWithPayload.Compiled => |x| {
+ try expect(x == 1234);
+ return;
+ },
+ }
+ },
+ }
+ unreachable;
+}
+
+const PartialInst = union(enum) {
+ Compiled,
+};
+
+const PartialInstWithPayload = union(enum) {
+ Compiled: i32,
+};
+
+test "union with only 1 field casted to its enum type which has enum value specified" {
+ if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO
+
+ const Literal = union(enum) {
+ Number: f64,
+ Bool: bool,
+ };
+
+ const ExprTag = enum(comptime_int) {
+ Literal = 33,
+ };
+
+ const Expr = union(ExprTag) {
+ Literal: Literal,
+ };
+
+ var e = Expr{ .Literal = Literal{ .Bool = true } };
+ comptime try expect(Tag(ExprTag) == comptime_int);
+ var t = @as(ExprTag, e);
+ try expect(t == Expr.Literal);
+ try expect(@enumToInt(t) == 33);
+ comptime try expect(@enumToInt(t) == 33);
+}
+
+test "@enumToInt works on unions" {
+ if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO
+
+ const Bar = union(enum) {
+ A: bool,
+ B: u8,
+ C,
+ };
+
+ const a = Bar{ .A = true };
+ var b = Bar{ .B = undefined };
+ var c = Bar.C;
+ try expect(@enumToInt(a) == 0);
+ try expect(@enumToInt(b) == 1);
+ try expect(@enumToInt(c) == 2);
+}
+
+test "comptime union field value equality" {
+ if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO
+
+ const a0 = Setter(Attribute{ .A = false });
+ const a1 = Setter(Attribute{ .A = true });
+ const a2 = Setter(Attribute{ .A = false });
+
+ const b0 = Setter(Attribute{ .B = 5 });
+ const b1 = Setter(Attribute{ .B = 9 });
+ const b2 = Setter(Attribute{ .B = 5 });
+
+ try expect(a0 == a0);
+ try expect(a1 == a1);
+ try expect(a0 == a2);
+
+ try expect(b0 == b0);
+ try expect(b1 == b1);
+ try expect(b0 == b2);
+
+ try expect(a0 != b0);
+ try expect(a0 != a1);
+ try expect(b0 != b1);
+}
+
+const Attribute = union(enum) {
+ A: bool,
+ B: u8,
+};
+
+fn setAttribute(attr: Attribute) void {
+ _ = attr;
+}
+
+fn Setter(attr: Attribute) type {
+ return struct {
+ fn set() void {
+ setAttribute(attr);
+ }
+ };
+}
+
+test "return union init with void payload" {
+ if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO
+
+ const S = struct {
+ fn entry() !void {
+ try expect(func().state == State.one);
+ }
+ const Outer = union(enum) {
+ state: State,
+ };
+ const State = union(enum) {
+ one: void,
+ two: u32,
+ };
+ fn func() Outer {
+ return Outer{ .state = State{ .one = {} } };
+ }
+ };
+ try S.entry();
+ comptime try S.entry();
+}
+
+test "@unionInit can modify a union type" {
+ if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO
+
+ const UnionInitEnum = union(enum) {
+ Boolean: bool,
+ Byte: u8,
+ };
+
+ var value: UnionInitEnum = undefined;
+
+ value = @unionInit(UnionInitEnum, "Boolean", true);
+ try expect(value.Boolean == true);
+ value.Boolean = false;
+ try expect(value.Boolean == false);
+
+ value = @unionInit(UnionInitEnum, "Byte", 2);
+ try expect(value.Byte == 2);
+ value.Byte = 3;
+ try expect(value.Byte == 3);
+}
+
+test "@unionInit can modify a pointer value" {
+ if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO
+
+ const UnionInitEnum = union(enum) {
+ Boolean: bool,
+ Byte: u8,
+ };
+
+ var value: UnionInitEnum = undefined;
+ var value_ptr = &value;
+
+ value_ptr.* = @unionInit(UnionInitEnum, "Boolean", true);
+ try expect(value.Boolean == true);
+
+ value_ptr.* = @unionInit(UnionInitEnum, "Byte", 2);
+ try expect(value.Byte == 2);
+}
+
+test "union no tag with struct member" {
+ if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO
+
+ const Struct = struct {};
+ const Union = union {
+ s: Struct,
+ pub fn foo(self: *@This()) void {
+ _ = self;
+ }
+ };
+ var u = Union{ .s = Struct{} };
+ u.foo();
+}
+
+test "union with comptime_int tag" {
+ if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO
+
+ const Union = union(enum(comptime_int)) {
+ X: u32,
+ Y: u16,
+ Z: u8,
+ };
+ comptime try expect(Tag(Tag(Union)) == comptime_int);
+}
+
+test "extern union doesn't trigger field check at comptime" {
+ if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO
+
+ const U = extern union {
+ x: u32,
+ y: u8,
+ };
+
+ const x = U{ .x = 0x55AAAA55 };
+ comptime try expect(x.y == 0x55);
+}
+
+test "anonymous union literal syntax" {
+ if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO
+
+ const S = struct {
+ const Number = union {
+ int: i32,
+ float: f64,
+ };
+
+ fn doTheTest() !void {
+ var i: Number = .{ .int = 42 };
+ var f = makeNumber();
+ try expect(i.int == 42);
+ try expect(f.float == 12.34);
+ }
+
+ fn makeNumber() Number {
+ return .{ .float = 12.34 };
+ }
+ };
+ try S.doTheTest();
+ comptime try S.doTheTest();
+}
+
+test "function call result coerces from tagged union to the tag" {
+ if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO
+
+ const S = struct {
+ const Arch = union(enum) {
+ One,
+ Two: usize,
+ };
+
+ const ArchTag = Tag(Arch);
+
+ fn doTheTest() !void {
+ var x: ArchTag = getArch1();
+ try expect(x == .One);
+
+ var y: ArchTag = getArch2();
+ try expect(y == .Two);
+ }
+
+ pub fn getArch1() Arch {
+ return .One;
+ }
+
+ pub fn getArch2() Arch {
+ return .{ .Two = 99 };
+ }
+ };
+ try S.doTheTest();
+ comptime try S.doTheTest();
+}
+
+test "cast from anonymous struct to union" {
+ if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO
+
+ const S = struct {
+ const U = union(enum) {
+ A: u32,
+ B: []const u8,
+ C: void,
+ };
+ fn doTheTest() !void {
+ var y: u32 = 42;
+ const t0 = .{ .A = 123 };
+ const t1 = .{ .B = "foo" };
+ const t2 = .{ .C = {} };
+ const t3 = .{ .A = y };
+ const x0: U = t0;
+ var x1: U = t1;
+ const x2: U = t2;
+ var x3: U = t3;
+ try expect(x0.A == 123);
+ try expect(std.mem.eql(u8, x1.B, "foo"));
+ try expect(x2 == .C);
+ try expect(x3.A == y);
+ }
+ };
+ try S.doTheTest();
+ comptime try S.doTheTest();
+}
+
+test "cast from pointer to anonymous struct to pointer to union" {
+ if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO
+
+ const S = struct {
+ const U = union(enum) {
+ A: u32,
+ B: []const u8,
+ C: void,
+ };
+ fn doTheTest() !void {
+ var y: u32 = 42;
+ const t0 = &.{ .A = 123 };
+ const t1 = &.{ .B = "foo" };
+ const t2 = &.{ .C = {} };
+ const t3 = &.{ .A = y };
+ const x0: *const U = t0;
+ var x1: *const U = t1;
+ const x2: *const U = t2;
+ var x3: *const U = t3;
+ try expect(x0.A == 123);
+ try expect(std.mem.eql(u8, x1.B, "foo"));
+ try expect(x2.* == .C);
+ try expect(x3.A == y);
+ }
+ };
+ try S.doTheTest();
+ comptime try S.doTheTest();
+}
+
+test "switching on non exhaustive union" {
+ if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO
+
+ const S = struct {
+ const E = enum(u8) {
+ a,
+ b,
+ _,
+ };
+ const U = union(E) {
+ a: i32,
+ b: u32,
+ };
+ fn doTheTest() !void {
+ var a = U{ .a = 2 };
+ switch (a) {
+ .a => |val| try expect(val == 2),
+ .b => unreachable,
+ }
+ }
+ };
+ try S.doTheTest();
+ comptime try S.doTheTest();
+}
+
+test "containers with single-field enums" {
+ if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO
+
+ const S = struct {
+ const A = union(enum) { f1 };
+ const B = union(enum) { f1: void };
+ const C = struct { a: A };
+ const D = struct { a: B };
+
+ fn doTheTest() !void {
+ var array1 = [1]A{A{ .f1 = {} }};
+ var array2 = [1]B{B{ .f1 = {} }};
+ try expect(array1[0] == .f1);
+ try expect(array2[0] == .f1);
+
+ var struct1 = C{ .a = A{ .f1 = {} } };
+ var struct2 = D{ .a = B{ .f1 = {} } };
+ try expect(struct1.a == .f1);
+ try expect(struct2.a == .f1);
+ }
+ };
+
+ try S.doTheTest();
+ comptime try S.doTheTest();
+}
+
+test "@unionInit on union w/ tag but no fields" {
+ if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO
+
+ const S = struct {
+ const Type = enum(u8) { no_op = 105 };
+
+ const Data = union(Type) {
+ no_op: void,
+
+ pub fn decode(buf: []const u8) Data {
+ _ = buf;
+ return @unionInit(Data, "no_op", {});
+ }
+ };
+
+ comptime {
+ std.debug.assert(@sizeOf(Data) != 0);
+ }
+
+ fn doTheTest() !void {
+ var data: Data = .{ .no_op = .{} };
+ _ = data;
+ var o = Data.decode(&[_]u8{});
+ try expectEqual(Type.no_op, o);
+ }
+ };
+
+ try S.doTheTest();
+ comptime try S.doTheTest();
+}
+
+test "union enum type gets a separate scope" {
+ if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO
+
+ const S = struct {
+ const U = union(enum) {
+ a: u8,
+ const foo = 1;
+ };
+
+ fn doTheTest() !void {
+ try expect(!@hasDecl(Tag(U), "foo"));
+ }
+ };
+
+ try S.doTheTest();
+}
+
+test "global variable struct contains union initialized to non-most-aligned field" {
+ if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
+ if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
+
+ const T = struct {
+ const U = union(enum) {
+ a: i32,
+ b: f64,
+ };
+
+ const S = struct {
+ u: U,
+ };
+
+ var s: S = .{
+ .u = .{
+ .a = 3,
+ },
+ };
+ };
+
+ T.s.u.a += 1;
+ try expect(T.s.u.a == 4);
+}
test/behavior/union_stage1.zig
@@ -1,421 +0,0 @@
-const std = @import("std");
-const expect = std.testing.expect;
-const expectEqual = std.testing.expectEqual;
-const Tag = std.meta.Tag;
-
-const MultipleChoice2 = union(enum(u32)) {
- Unspecified1: i32,
- A: f32 = 20,
- Unspecified2: void,
- B: bool = 40,
- Unspecified3: i32,
- C: i8 = 60,
- Unspecified4: void,
- D: void = 1000,
- Unspecified5: i32,
-};
-
-test "union(enum(u32)) with specified and unspecified tag values" {
- comptime try expect(Tag(Tag(MultipleChoice2)) == u32);
- try testEnumWithSpecifiedAndUnspecifiedTagValues(MultipleChoice2{ .C = 123 });
- comptime try testEnumWithSpecifiedAndUnspecifiedTagValues(MultipleChoice2{ .C = 123 });
-}
-
-fn testEnumWithSpecifiedAndUnspecifiedTagValues(x: MultipleChoice2) !void {
- try expect(@enumToInt(@as(Tag(MultipleChoice2), x)) == 60);
- try expect(1123 == switch (x) {
- MultipleChoice2.A => 1,
- MultipleChoice2.B => 2,
- MultipleChoice2.C => |v| @as(i32, 1000) + v,
- MultipleChoice2.D => 4,
- MultipleChoice2.Unspecified1 => 5,
- MultipleChoice2.Unspecified2 => 6,
- MultipleChoice2.Unspecified3 => 7,
- MultipleChoice2.Unspecified4 => 8,
- MultipleChoice2.Unspecified5 => 9,
- });
-}
-
-test "switch on union with only 1 field" {
- var r: PartialInst = undefined;
- r = PartialInst.Compiled;
- switch (r) {
- PartialInst.Compiled => {
- var z: PartialInstWithPayload = undefined;
- z = PartialInstWithPayload{ .Compiled = 1234 };
- switch (z) {
- PartialInstWithPayload.Compiled => |x| {
- try expect(x == 1234);
- return;
- },
- }
- },
- }
- unreachable;
-}
-
-const PartialInst = union(enum) {
- Compiled,
-};
-
-const PartialInstWithPayload = union(enum) {
- Compiled: i32,
-};
-
-test "union with only 1 field casted to its enum type which has enum value specified" {
- const Literal = union(enum) {
- Number: f64,
- Bool: bool,
- };
-
- const ExprTag = enum(comptime_int) {
- Literal = 33,
- };
-
- const Expr = union(ExprTag) {
- Literal: Literal,
- };
-
- var e = Expr{ .Literal = Literal{ .Bool = true } };
- comptime try expect(Tag(ExprTag) == comptime_int);
- var t = @as(ExprTag, e);
- try expect(t == Expr.Literal);
- try expect(@enumToInt(t) == 33);
- comptime try expect(@enumToInt(t) == 33);
-}
-
-test "@enumToInt works on unions" {
- const Bar = union(enum) {
- A: bool,
- B: u8,
- C,
- };
-
- const a = Bar{ .A = true };
- var b = Bar{ .B = undefined };
- var c = Bar.C;
- try expect(@enumToInt(a) == 0);
- try expect(@enumToInt(b) == 1);
- try expect(@enumToInt(c) == 2);
-}
-
-const Attribute = union(enum) {
- A: bool,
- B: u8,
-};
-
-fn setAttribute(attr: Attribute) void {
- _ = attr;
-}
-
-fn Setter(attr: Attribute) type {
- return struct {
- fn set() void {
- setAttribute(attr);
- }
- };
-}
-
-test "comptime union field value equality" {
- const a0 = Setter(Attribute{ .A = false });
- const a1 = Setter(Attribute{ .A = true });
- const a2 = Setter(Attribute{ .A = false });
-
- const b0 = Setter(Attribute{ .B = 5 });
- const b1 = Setter(Attribute{ .B = 9 });
- const b2 = Setter(Attribute{ .B = 5 });
-
- try expect(a0 == a0);
- try expect(a1 == a1);
- try expect(a0 == a2);
-
- try expect(b0 == b0);
- try expect(b1 == b1);
- try expect(b0 == b2);
-
- try expect(a0 != b0);
- try expect(a0 != a1);
- try expect(b0 != b1);
-}
-
-test "return union init with void payload" {
- const S = struct {
- fn entry() !void {
- try expect(func().state == State.one);
- }
- const Outer = union(enum) {
- state: State,
- };
- const State = union(enum) {
- one: void,
- two: u32,
- };
- fn func() Outer {
- return Outer{ .state = State{ .one = {} } };
- }
- };
- try S.entry();
- comptime try S.entry();
-}
-
-test "@unionInit can modify a union type" {
- const UnionInitEnum = union(enum) {
- Boolean: bool,
- Byte: u8,
- };
-
- var value: UnionInitEnum = undefined;
-
- value = @unionInit(UnionInitEnum, "Boolean", true);
- try expect(value.Boolean == true);
- value.Boolean = false;
- try expect(value.Boolean == false);
-
- value = @unionInit(UnionInitEnum, "Byte", 2);
- try expect(value.Byte == 2);
- value.Byte = 3;
- try expect(value.Byte == 3);
-}
-
-test "@unionInit can modify a pointer value" {
- const UnionInitEnum = union(enum) {
- Boolean: bool,
- Byte: u8,
- };
-
- var value: UnionInitEnum = undefined;
- var value_ptr = &value;
-
- value_ptr.* = @unionInit(UnionInitEnum, "Boolean", true);
- try expect(value.Boolean == true);
-
- value_ptr.* = @unionInit(UnionInitEnum, "Byte", 2);
- try expect(value.Byte == 2);
-}
-
-test "union no tag with struct member" {
- const Struct = struct {};
- const Union = union {
- s: Struct,
- pub fn foo(self: *@This()) void {
- _ = self;
- }
- };
- var u = Union{ .s = Struct{} };
- u.foo();
-}
-
-test "union with comptime_int tag" {
- const Union = union(enum(comptime_int)) {
- X: u32,
- Y: u16,
- Z: u8,
- };
- comptime try expect(Tag(Tag(Union)) == comptime_int);
-}
-
-test "extern union doesn't trigger field check at comptime" {
- const U = extern union {
- x: u32,
- y: u8,
- };
-
- const x = U{ .x = 0x55AAAA55 };
- comptime try expect(x.y == 0x55);
-}
-
-test "anonymous union literal syntax" {
- const S = struct {
- const Number = union {
- int: i32,
- float: f64,
- };
-
- fn doTheTest() !void {
- var i: Number = .{ .int = 42 };
- var f = makeNumber();
- try expect(i.int == 42);
- try expect(f.float == 12.34);
- }
-
- fn makeNumber() Number {
- return .{ .float = 12.34 };
- }
- };
- try S.doTheTest();
- comptime try S.doTheTest();
-}
-
-test "function call result coerces from tagged union to the tag" {
- const S = struct {
- const Arch = union(enum) {
- One,
- Two: usize,
- };
-
- const ArchTag = Tag(Arch);
-
- fn doTheTest() !void {
- var x: ArchTag = getArch1();
- try expect(x == .One);
-
- var y: ArchTag = getArch2();
- try expect(y == .Two);
- }
-
- pub fn getArch1() Arch {
- return .One;
- }
-
- pub fn getArch2() Arch {
- return .{ .Two = 99 };
- }
- };
- try S.doTheTest();
- comptime try S.doTheTest();
-}
-
-test "cast from anonymous struct to union" {
- const S = struct {
- const U = union(enum) {
- A: u32,
- B: []const u8,
- C: void,
- };
- fn doTheTest() !void {
- var y: u32 = 42;
- const t0 = .{ .A = 123 };
- const t1 = .{ .B = "foo" };
- const t2 = .{ .C = {} };
- const t3 = .{ .A = y };
- const x0: U = t0;
- var x1: U = t1;
- const x2: U = t2;
- var x3: U = t3;
- try expect(x0.A == 123);
- try expect(std.mem.eql(u8, x1.B, "foo"));
- try expect(x2 == .C);
- try expect(x3.A == y);
- }
- };
- try S.doTheTest();
- comptime try S.doTheTest();
-}
-
-test "cast from pointer to anonymous struct to pointer to union" {
- const S = struct {
- const U = union(enum) {
- A: u32,
- B: []const u8,
- C: void,
- };
- fn doTheTest() !void {
- var y: u32 = 42;
- const t0 = &.{ .A = 123 };
- const t1 = &.{ .B = "foo" };
- const t2 = &.{ .C = {} };
- const t3 = &.{ .A = y };
- const x0: *const U = t0;
- var x1: *const U = t1;
- const x2: *const U = t2;
- var x3: *const U = t3;
- try expect(x0.A == 123);
- try expect(std.mem.eql(u8, x1.B, "foo"));
- try expect(x2.* == .C);
- try expect(x3.A == y);
- }
- };
- try S.doTheTest();
- comptime try S.doTheTest();
-}
-
-test "switching on non exhaustive union" {
- const S = struct {
- const E = enum(u8) {
- a,
- b,
- _,
- };
- const U = union(E) {
- a: i32,
- b: u32,
- };
- fn doTheTest() !void {
- var a = U{ .a = 2 };
- switch (a) {
- .a => |val| try expect(val == 2),
- .b => unreachable,
- }
- }
- };
- try S.doTheTest();
- comptime try S.doTheTest();
-}
-
-test "containers with single-field enums" {
- const S = struct {
- const A = union(enum) { f1 };
- const B = union(enum) { f1: void };
- const C = struct { a: A };
- const D = struct { a: B };
-
- fn doTheTest() !void {
- var array1 = [1]A{A{ .f1 = {} }};
- var array2 = [1]B{B{ .f1 = {} }};
- try expect(array1[0] == .f1);
- try expect(array2[0] == .f1);
-
- var struct1 = C{ .a = A{ .f1 = {} } };
- var struct2 = D{ .a = B{ .f1 = {} } };
- try expect(struct1.a == .f1);
- try expect(struct2.a == .f1);
- }
- };
-
- try S.doTheTest();
- comptime try S.doTheTest();
-}
-
-test "@unionInit on union w/ tag but no fields" {
- const S = struct {
- const Type = enum(u8) { no_op = 105 };
-
- const Data = union(Type) {
- no_op: void,
-
- pub fn decode(buf: []const u8) Data {
- _ = buf;
- return @unionInit(Data, "no_op", {});
- }
- };
-
- comptime {
- std.debug.assert(@sizeOf(Data) != 0);
- }
-
- fn doTheTest() !void {
- var data: Data = .{ .no_op = .{} };
- _ = data;
- var o = Data.decode(&[_]u8{});
- try expectEqual(Type.no_op, o);
- }
- };
-
- try S.doTheTest();
- comptime try S.doTheTest();
-}
-
-test "union enum type gets a separate scope" {
- const S = struct {
- const U = union(enum) {
- a: u8,
- const foo = 1;
- };
-
- fn doTheTest() !void {
- try expect(!@hasDecl(Tag(U), "foo"));
- }
- };
-
- try S.doTheTest();
-}
test/behavior.zig
@@ -166,7 +166,6 @@ test {
_ = @import("behavior/tuple.zig");
_ = @import("behavior/type_stage1.zig");
_ = @import("behavior/typename.zig");
- _ = @import("behavior/union_stage1.zig");
_ = @import("behavior/union_with_members.zig");
_ = @import("behavior/var_args.zig");
_ = @import("behavior/vector.zig");