zig/test/behavior/union.zig
Andrew Kelley dfb3231959 stage2: implement switching on unions
* AstGen: Move `refToIndex` and `indexToRef` to Zir
 * ZIR: the switch_block_*_* instruction tags are collapsed into one
   switch_block tag which uses 4 bits for flags, and reduces the
   scalar_cases_len field from 32 to 28 bits.
   This freed up more ZIR tags, 2 of which are now used for
   `switch_cond` and `switch_cond_ref` for producing the switch
   condition value. For example, for union values it returns the
   corresponding enum value.
 * switching with multiple cases and ranges is not yet supported because
   I want to change the ZIR encoding to store index pointers into the
   extra array rather than storing prong indexes. This will avoid O(N^2)
   iteration over prongs.
 * AstGen now adds a `switch_cond` on the operand and then passes the
   result of that to the `switch_block` instruction.
 * Sema: partially implement `switch_capture_*` instructions.
 * Sema: `unionToTag` notices if the enum type has only one possible value.
2021-10-19 20:22:47 -07:00

105 lines
2.0 KiB
Zig

const std = @import("std");
const expect = std.testing.expect;
const expectEqual = std.testing.expectEqual;
const Tag = std.meta.Tag;
const Foo = union {
float: f64,
int: i32,
};
test "basic unions" {
var foo = Foo{ .int = 1 };
try expect(foo.int == 1);
foo = Foo{ .float = 12.34 };
try expect(foo.float == 12.34);
}
test "init union with runtime value" {
var foo: Foo = undefined;
setFloat(&foo, 12.34);
try expect(foo.float == 12.34);
setInt(&foo, 42);
try expect(foo.int == 42);
}
fn setFloat(foo: *Foo, x: f64) void {
foo.* = Foo{ .float = x };
}
fn setInt(foo: *Foo, x: i32) void {
foo.* = Foo{ .int = x };
}
test "comptime union field access" {
comptime {
var foo = Foo{ .int = 0 };
try expect(foo.int == 0);
foo = Foo{ .float = 42.42 };
try expect(foo.float == 42.42);
}
}
const FooExtern = extern union {
float: f64,
int: i32,
};
test "basic extern unions" {
var foo = FooExtern{ .int = 1 };
try expect(foo.int == 1);
foo.float = 12.34;
try expect(foo.float == 12.34);
}
const ExternPtrOrInt = extern union {
ptr: *u8,
int: u64,
};
test "extern union size" {
comptime try expect(@sizeOf(ExternPtrOrInt) == 8);
}
test "0-sized extern union definition" {
const U = extern union {
a: void,
const f = 1;
};
try expect(U.f == 1);
}
const Value = union(enum) {
Int: u64,
Array: [9]u8,
};
const Agg = struct {
val1: Value,
val2: Value,
};
const v1 = Value{ .Int = 1234 };
const v2 = Value{ .Array = [_]u8{3} ** 9 };
const err = @as(anyerror!Agg, Agg{
.val1 = v1,
.val2 = v2,
});
const array = [_]Value{ v1, v2, v1, v2 };
test "unions embedded in aggregate types" {
switch (array[1]) {
Value.Array => |arr| try expect(arr[4] == 3),
else => unreachable,
}
switch ((err catch unreachable).val1) {
Value.Int => |x| try expect(x == 1234),
else => unreachable,
}
}