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.
This commit is contained in:
Andrew Kelley
2021-10-19 20:14:10 -07:00
parent 4a76523b92
commit dfb3231959
8 changed files with 428 additions and 480 deletions

View File

@@ -71,3 +71,34 @@ test "0-sized extern union definition" {
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,
}
}

View File

@@ -3,37 +3,6 @@ const expect = std.testing.expect;
const expectEqual = std.testing.expectEqual;
const Tag = std.meta.Tag;
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,
}
}
const Letter = enum { A, B, C };
const Payload = union(Letter) {
A: i32,