tupleDecl
Function parameters
Parameters
- gz:*GenZir
- scope:*Scope
- node:Ast.Node.Index
- container_decl:Ast.full.ContainerDecl
- layout:std.builtin.Type.ContainerLayout
- backing_int_node:Ast.Node.OptionalIndex
Functions in this namespace
Functions
Source
Implementation
fn tupleDecl(
gz: *GenZir,
scope: *Scope,
node: Ast.Node.Index,
container_decl: Ast.full.ContainerDecl,
layout: std.builtin.Type.ContainerLayout,
backing_int_node: Ast.Node.OptionalIndex,
) InnerError!Zir.Inst.Ref {
const astgen = gz.astgen;
const gpa = astgen.gpa;
const tree = astgen.tree;
switch (layout) {
.auto => {},
.@"extern", .@"packed" => return astgen.failNode(node, "{s} tuples are not supported", .{@tagName(layout)}),
}
if (backing_int_node.unwrap()) |arg| {
return astgen.failNode(arg, "tuple does not support backing integer type", .{});
}
// We will use the scratch buffer, starting here, for the field data:
// 1. fields: { // for every `fields_len` (stored in `extended.small`)
// type: Inst.Ref,
// init: Inst.Ref, // `.none` for non-`comptime` fields
// }
const fields_start = astgen.scratch.items.len;
defer astgen.scratch.items.len = fields_start;
try astgen.scratch.ensureUnusedCapacity(gpa, container_decl.ast.members.len * 2);
for (container_decl.ast.members) |member_node| {
const field = tree.fullContainerField(member_node) orelse {
const tuple_member = for (container_decl.ast.members) |maybe_tuple| switch (tree.nodeTag(maybe_tuple)) {
.container_field_init,
.container_field_align,
.container_field,
=> break maybe_tuple,
else => {},
} else unreachable;
return astgen.failNodeNotes(
member_node,
"tuple declarations cannot contain declarations",
.{},
&.{try astgen.errNoteNode(tuple_member, "tuple field here", .{})},
);
};
if (!field.ast.tuple_like) {
return astgen.failTok(field.ast.main_token, "tuple field has a name", .{});
}
if (field.ast.align_expr != .none) {
return astgen.failTok(field.ast.main_token, "tuple field has alignment", .{});
}
if (field.ast.value_expr != .none and field.comptime_token == null) {
return astgen.failTok(field.ast.main_token, "non-comptime tuple field has default initialization value", .{});
}
if (field.ast.value_expr == .none and field.comptime_token != null) {
return astgen.failTok(field.comptime_token.?, "comptime field without default initialization value", .{});
}
const field_type_ref = try typeExpr(gz, scope, field.ast.type_expr.unwrap().?);
astgen.scratch.appendAssumeCapacity(@intFromEnum(field_type_ref));
if (field.ast.value_expr.unwrap()) |value_expr| {
const field_init_ref = try comptimeExpr(gz, scope, .{ .rl = .{ .coerced_ty = field_type_ref } }, value_expr, .tuple_field_default_value);
astgen.scratch.appendAssumeCapacity(@intFromEnum(field_init_ref));
} else {
astgen.scratch.appendAssumeCapacity(@intFromEnum(Zir.Inst.Ref.none));
}
}
const fields_len = std.math.cast(u16, container_decl.ast.members.len) orelse {
return astgen.failNode(node, "this compiler implementation only supports 65535 tuple fields", .{});
};
const extra_trail = astgen.scratch.items[fields_start..];
assert(extra_trail.len == fields_len * 2);
try astgen.extra.ensureUnusedCapacity(gpa, @typeInfo(Zir.Inst.TupleDecl).@"struct".fields.len + extra_trail.len);
const payload_index = astgen.addExtraAssumeCapacity(Zir.Inst.TupleDecl{
.src_node = gz.nodeIndexToRelative(node),
});
astgen.extra.appendSliceAssumeCapacity(extra_trail);
return gz.add(.{
.tag = .extended,
.data = .{ .extended = .{
.opcode = .tuple_decl,
.small = fields_len,
.operand = payload_index,
} },
});
}