feature. See also
. The project being documented here (as the example) is the Zig library itself.
AstGen.arrayInitExpr
fn arrayInitExpr(
gz: *GenZir,
scope: *Scope,
ri: ResultInfo,
node: Ast.Node.Index,
array_init: Ast.full.ArrayInit,
) InnerError!Zir.Inst.Ref
File
Code
fn arrayInitExpr(
gz: *GenZir,
scope: *Scope,
ri: ResultInfo,
node: Ast.Node.Index,
array_init: Ast.full.ArrayInit,
) InnerError!Zir.Inst.Ref {
const astgen = gz.astgen;
const tree = astgen.tree;
assert(array_init.ast.elements.len != 0);
const array_ty: Zir.Inst.Ref, const elem_ty: Zir.Inst.Ref = inst: {
const type_expr = array_init.ast.type_expr.unwrap() orelse break :inst .{ .none, .none };
infer: {
const array_type: Ast.full.ArrayType = tree.fullArrayType(type_expr) orelse break :infer;
if (tree.nodeTag(array_type.ast.elem_count) == .identifier and
mem.eql(u8, tree.tokenSlice(tree.nodeMainToken(array_type.ast.elem_count)), "_"))
{
const len_inst = try gz.addInt(array_init.ast.elements.len);
const elem_type = try typeExpr(gz, scope, array_type.ast.elem_type);
if (array_type.ast.sentinel == .none) {
const array_type_inst = try gz.addPlNode(.array_type, type_expr, Zir.Inst.Bin{
.lhs = len_inst,
.rhs = elem_type,
});
break :inst .{ array_type_inst, elem_type };
} else {
const sentinel_node = array_type.ast.sentinel.unwrap().?;
const sentinel = try comptimeExpr(gz, scope, .{ .rl = .{ .ty = elem_type } }, sentinel_node, .array_sentinel);
const array_type_inst = try gz.addPlNode(
.array_type_sentinel,
type_expr,
Zir.Inst.ArrayTypeSentinel{
.len = len_inst,
.elem_type = elem_type,
.sentinel = sentinel,
},
);
break :inst .{ array_type_inst, elem_type };
}
}
}
const array_type_inst = try typeExpr(gz, scope, type_expr);
_ = try gz.addPlNode(.validate_array_init_ty, node, Zir.Inst.ArrayInit{
.ty = array_type_inst,
.init_count = @intCast(array_init.ast.elements.len),
});
break :inst .{ array_type_inst, .none };
};
if (array_ty != .none) {
switch (ri.rl) {
.discard => {
if (elem_ty != .none) {
const elem_ri: ResultInfo = .{ .rl = .{ .ty = elem_ty } };
for (array_init.ast.elements) |elem_init| {
_ = try expr(gz, scope, elem_ri, elem_init);
}
} else {
for (array_init.ast.elements, 0..) |elem_init, i| {
const this_elem_ty = try gz.add(.{
.tag = .array_init_elem_type,
.data = .{ .bin = .{
.lhs = array_ty,
.rhs = @fromBackingInt(@intCast(i)),
} },
});
_ = try expr(gz, scope, .{ .rl = .{ .ty = this_elem_ty } }, elem_init);
}
}
return .void_value;
},
.ref, .ref_const => return arrayInitExprTyped(gz, scope, node, array_init.ast.elements, array_ty, elem_ty, true),
else => {
const array_inst = try arrayInitExprTyped(gz, scope, node, array_init.ast.elements, array_ty, elem_ty, false);
return rvalue(gz, ri, array_inst, node);
},
}
}
switch (ri.rl) {
.none => return arrayInitExprAnon(gz, scope, node, array_init.ast.elements),
.discard => {
for (array_init.ast.elements) |elem_init| {
_ = try expr(gz, scope, .{ .rl = .discard }, elem_init);
}
return Zir.Inst.Ref.void_value;
},
.ref, .ref_const => {
const result = try arrayInitExprAnon(gz, scope, node, array_init.ast.elements);
return gz.addUnTok(.ref, result, tree.firstToken(node));
},
.ref_coerced_ty => |ptr_ty_inst| {
const dest_arr_ty_inst = try gz.addPlNode(.validate_array_init_ref_ty, node, Zir.Inst.ArrayInitRefTy{
.ptr_ty = ptr_ty_inst,
.elem_count = @intCast(array_init.ast.elements.len),
});
return arrayInitExprTyped(gz, scope, node, array_init.ast.elements, dest_arr_ty_inst, .none, true);
},
.ty, .coerced_ty => |result_ty_inst| {
_ = try gz.addPlNode(.validate_array_init_result_ty, node, Zir.Inst.ArrayInit{
.ty = result_ty_inst,
.init_count = @intCast(array_init.ast.elements.len),
});
return arrayInitExprTyped(gz, scope, node, array_init.ast.elements, result_ty_inst, .none, false);
},
.ptr => |ptr| {
try arrayInitExprPtr(gz, scope, node, array_init.ast.elements, ptr.inst);
return .void_value;
},
.inferred_ptr => {
// standard anonymous initialization followed by an rvalue store.
// See corresponding logic in structInitExpr.
const result = try arrayInitExprAnon(gz, scope, node, array_init.ast.elements);
return rvalue(gz, ri, result, node);
},
.destructure => |destructure| {
if (array_init.ast.elements.len != destructure.components.len) {
return astgen.failNodeNotes(node, "expected {} elements for destructure, found {}", .{
destructure.components.len,
array_init.ast.elements.len,
}, &.{
try astgen.errNoteNode(destructure.src_node, "result destructured here", .{}),
});
}
for (array_init.ast.elements, destructure.components) |elem_init, ds_comp| {
const elem_ri: ResultInfo = .{ .rl = switch (ds_comp) {
.typed_ptr => |ptr_rl| .{ .ptr = ptr_rl },
.inferred_ptr => |ptr_inst| .{ .inferred_ptr = ptr_inst },
.discard => .discard,
} };
_ = try expr(gz, scope, elem_ri, elem_init);
}
return .void_value;
},
}
}