fn parseUnion(self: *@This(), T: type, node: Zoir.Node.Index) !T {
const @"union" = @typeInfo(T).@"union";
if (@"union".field_names.len == 0) comptime unreachable;
// Gather info on the fields
const field_indices = b: {
comptime var kvs_list: [@"union".field_names.len]struct { []const u8, usize } = undefined;
inline for (@"union".field_names, 0..) |field_name, i| {
kvs_list[i] = .{ field_name, i };
}
break :b std.StaticStringMap(usize).initComptime(kvs_list);
};
// Parse the union
switch (node.get(self.zoir)) {
.enum_literal => |field_name| {
// The union must be tagged for an enum literal to coerce to it
if (@"union".tag_type == null) {
return error.WrongType;
}
// Get the index of the named field. We don't use `parseEnum` here as
// the order of the enum and the order of the union might not match!
const field_index = b: {
const field_name_str = field_name.get(self.zoir);
break :b field_indices.get(field_name_str) orelse
return self.failUnexpected(T, "field", node, null, field_name_str);
};
// Initialize the union from the given field.
switch (field_index) {
inline 0...@"union".field_names.len - 1 => |i| {
// Fail if the field is not void
if (@"union".field_types[i] != void)
return self.failNode(node, "expected union");
// Instantiate the union
return @unionInit(T, @"union".field_names[i], {});
},
else => unreachable, // Can't be out of bounds
}
},
.struct_literal => |struct_fields| {
if (struct_fields.names.len != 1) {
return error.WrongType;
}
// Fill in the field we found
const field_name = struct_fields.names[0];
const field_name_str = field_name.get(self.zoir);
const field_val = struct_fields.vals.at(0);
const field_index = field_indices.get(field_name_str) orelse
return self.failUnexpected(T, "field", node, 0, field_name_str);
switch (field_index) {
inline 0...@"union".field_names.len - 1 => |i| {
if (@"union".field_types[i] == void) {
return self.failNode(field_val, "expected type 'void'");
} else {
const value = try self.parseExpr(@"union".field_types[i], field_val);
return @unionInit(T, @"union".field_names[i], value);
}
},
else => unreachable, // Can't be out of bounds
}
},
else => return error.WrongType,
}
}