mirror of
https://github.com/ziglang/zig.git
synced 2024-11-22 12:20:16 +00:00
Parses unions to explicit return types
Coercing enum literals to unions isn't yet implemented, and some of the union tests are still skipped due to a bug with explicit tags I still need to fix
This commit is contained in:
parent
30d6f24581
commit
ea92351baa
78
src/zon.zig
78
src/zon.zig
@ -259,7 +259,7 @@ fn parseExpr(self: LowerZon, node: Ast.Node.Index, res_ty: Type) CompileError!In
|
||||
.enum_literal => return self.parseEnumLiteral(node, res_ty),
|
||||
.array => return self.parseArray(node, res_ty),
|
||||
.@"struct" => return self.parseStructOrTuple(node, res_ty),
|
||||
.@"union" => {},
|
||||
.@"union" => return self.parseUnion(node, res_ty),
|
||||
.pointer => return self.parsePointer(node, res_ty),
|
||||
|
||||
.type,
|
||||
@ -1011,6 +1011,82 @@ fn parseStringLiteral(self: LowerZon, node: Ast.Node.Index, res_ty: Type) !Inter
|
||||
} });
|
||||
}
|
||||
|
||||
fn parseUnion(self: LowerZon, node: Ast.Node.Index, res_ty: Type) !InternPool.Index {
|
||||
const tags = self.file.tree.nodes.items(.tag);
|
||||
const ip = &self.sema.pt.zcu.intern_pool;
|
||||
|
||||
try res_ty.resolveFully(self.sema.pt);
|
||||
const union_info = self.sema.pt.zcu.typeToUnion(res_ty).?;
|
||||
const enum_tag_info = union_info.loadTagType(ip);
|
||||
|
||||
if (tags[node] == .enum_literal) @panic("unimplemented");
|
||||
|
||||
var buf: [2]Ast.Node.Index = undefined;
|
||||
const field_nodes = try self.fields(res_ty, &buf, node);
|
||||
if (field_nodes.len > 1) {
|
||||
return self.fail(.{ .node_abs = node }, "expected {}", .{res_ty.fmt(self.sema.pt)});
|
||||
}
|
||||
const field_node = field_nodes[0];
|
||||
var field_name = try self.ident(self.file.tree.firstToken(field_node) - 2);
|
||||
defer field_name.deinit(self.sema.gpa);
|
||||
const field_name_string = try ip.getOrPutString(
|
||||
self.sema.pt.zcu.gpa,
|
||||
self.sema.pt.tid,
|
||||
field_name.bytes,
|
||||
.no_embedded_nulls,
|
||||
);
|
||||
|
||||
const name_index = enum_tag_info.nameIndex(ip, field_name_string) orelse {
|
||||
return self.fail(.{ .node_abs = node }, "expected {}", .{res_ty.fmt(self.sema.pt)});
|
||||
};
|
||||
const tag = if (enum_tag_info.values.len == 0) b: {
|
||||
// Fields are auto numbered
|
||||
break :b try self.sema.pt.intern(.{ .enum_tag = .{
|
||||
.ty = union_info.enum_tag_ty,
|
||||
.int = try self.sema.pt.intern(.{ .int = .{
|
||||
.ty = enum_tag_info.tag_ty,
|
||||
.storage = .{ .u64 = name_index },
|
||||
} }),
|
||||
} });
|
||||
} else b: {
|
||||
// Fields are explicitly numbered
|
||||
break :b enum_tag_info.values.get(ip)[name_index];
|
||||
};
|
||||
const field_type = Type.fromInterned(union_info.field_types.get(ip)[name_index]);
|
||||
const val = try self.parseExpr(field_node, field_type);
|
||||
return ip.getUnion(self.sema.pt.zcu.gpa, self.sema.pt.tid, .{
|
||||
.ty = res_ty.toIntern(),
|
||||
.tag = tag,
|
||||
.val = val,
|
||||
});
|
||||
}
|
||||
|
||||
fn fields(
|
||||
self: LowerZon,
|
||||
container: Type,
|
||||
buf: *[2]NodeIndex,
|
||||
node: NodeIndex,
|
||||
) ![]const NodeIndex {
|
||||
if (self.file.tree.fullStructInit(buf, node)) |init| {
|
||||
if (init.ast.type_expr != 0) {
|
||||
return self.fail(.{ .node_abs = node }, "ZON cannot contain type expressions", .{});
|
||||
}
|
||||
return init.ast.fields;
|
||||
}
|
||||
|
||||
if (self.file.tree.fullArrayInit(buf, node)) |init| {
|
||||
if (init.ast.type_expr != 0) {
|
||||
return self.fail(.{ .node_abs = node }, "ZON cannot contain type expressions", .{});
|
||||
}
|
||||
if (init.ast.elements.len != 0) {
|
||||
return self.fail(.{ .node_abs = node }, "expected {}", .{container.fmt(self.sema.pt)});
|
||||
}
|
||||
return init.ast.elements;
|
||||
}
|
||||
|
||||
return self.fail(.{ .node_abs = node }, "expected {}", .{container.fmt(self.sema.pt)});
|
||||
}
|
||||
|
||||
fn elements(
|
||||
self: LowerZon,
|
||||
container: Type,
|
||||
|
@ -25,17 +25,54 @@ test "optional" {
|
||||
}
|
||||
|
||||
test "union" {
|
||||
// No tag
|
||||
{
|
||||
const Union = union {
|
||||
x: f32,
|
||||
y: bool,
|
||||
};
|
||||
|
||||
const union1: Union = @import("zon/union1.zon");
|
||||
const union2: Union = @import("zon/union2.zon");
|
||||
|
||||
try expectEqual(union1.x, 1.5);
|
||||
try expectEqual(union2.y, true);
|
||||
}
|
||||
|
||||
// Inferred tag
|
||||
{
|
||||
const Union = union(enum) {
|
||||
x: f32,
|
||||
y: bool,
|
||||
};
|
||||
|
||||
const union1: Union = @import("zon/union1.zon");
|
||||
const union2: Union = @import("zon/union2.zon");
|
||||
|
||||
try expectEqual(union1.x, 1.5);
|
||||
try expectEqual(union2.y, true);
|
||||
}
|
||||
|
||||
// Skip because explicit tags aren't yet working as expected
|
||||
return error.SkipZigTest;
|
||||
// const Union = union {
|
||||
// x: f32,
|
||||
// y: bool,
|
||||
// };
|
||||
|
||||
// const union1: Union = @import("zon/union1.zon");
|
||||
// const union2: Union = @import("zon/union2.zon");
|
||||
// Explicit tag
|
||||
// {
|
||||
// const Tag = enum(i128) {
|
||||
// x = -1,
|
||||
// y = 2,
|
||||
// };
|
||||
// const Union = union(Tag) {
|
||||
// x: f32,
|
||||
// y: bool,
|
||||
// };
|
||||
|
||||
// try expectEqual(union1.x, 1.5);
|
||||
// try expectEqual(union2.y, true);
|
||||
// const union1: Union = @import("zon/union1.zon");
|
||||
// const union2: Union = @import("zon/union2.zon");
|
||||
|
||||
// try expectEqual(union1.x, 1.5);
|
||||
// try expectEqual(union2.y, true);
|
||||
// }
|
||||
}
|
||||
|
||||
test "struct" {
|
||||
|
Loading…
Reference in New Issue
Block a user