stage2: implement struct init syntax with ptr result loc
This commit is contained in:
@@ -769,15 +769,20 @@ pub fn expr(gz: *GenZir, scope: *Scope, rl: ResultLoc, node: ast.Node.Index) Inn
|
||||
.array_init_comma,
|
||||
=> return mod.failNode(scope, node, "TODO implement astgen.expr for array literals", .{}),
|
||||
|
||||
.struct_init_one,
|
||||
.struct_init_one_comma,
|
||||
.struct_init_dot_two,
|
||||
.struct_init_dot_two_comma,
|
||||
.struct_init_one, .struct_init_one_comma => {
|
||||
var fields: [1]ast.Node.Index = undefined;
|
||||
return structInitExpr(gz, scope, rl, node, tree.structInitOne(&fields, node));
|
||||
},
|
||||
.struct_init_dot_two, .struct_init_dot_two_comma => {
|
||||
var fields: [2]ast.Node.Index = undefined;
|
||||
return structInitExpr(gz, scope, rl, node, tree.structInitDotTwo(&fields, node));
|
||||
},
|
||||
.struct_init_dot,
|
||||
.struct_init_dot_comma,
|
||||
=> return structInitExpr(gz, scope, rl, node, tree.structInitDot(node)),
|
||||
.struct_init,
|
||||
.struct_init_comma,
|
||||
=> return mod.failNode(scope, node, "TODO implement astgen.expr for struct literals", .{}),
|
||||
=> return structInitExpr(gz, scope, rl, node, tree.structInit(node)),
|
||||
|
||||
.@"anytype" => return mod.failNode(scope, node, "TODO implement astgen.expr for .anytype", .{}),
|
||||
.fn_proto_simple,
|
||||
@@ -788,6 +793,53 @@ pub fn expr(gz: *GenZir, scope: *Scope, rl: ResultLoc, node: ast.Node.Index) Inn
|
||||
}
|
||||
}
|
||||
|
||||
pub fn structInitExpr(
|
||||
gz: *GenZir,
|
||||
scope: *Scope,
|
||||
rl: ResultLoc,
|
||||
node: ast.Node.Index,
|
||||
struct_init: ast.full.StructInit,
|
||||
) InnerError!zir.Inst.Ref {
|
||||
const tree = gz.tree();
|
||||
const astgen = gz.astgen;
|
||||
const mod = astgen.mod;
|
||||
const gpa = mod.gpa;
|
||||
switch (rl) {
|
||||
.discard => return mod.failNode(scope, node, "TODO implement structInitExpr discard", .{}),
|
||||
.none => return mod.failNode(scope, node, "TODO implement structInitExpr none", .{}),
|
||||
.ref => unreachable, // struct literal not valid as l-value
|
||||
.ty => |ty_inst| {
|
||||
return mod.failNode(scope, node, "TODO implement structInitExpr ty", .{});
|
||||
},
|
||||
.ptr => |ptr_inst| {
|
||||
const field_ptr_list = try gpa.alloc(zir.Inst.Index, struct_init.ast.fields.len);
|
||||
defer gpa.free(field_ptr_list);
|
||||
|
||||
for (struct_init.ast.fields) |field_init, i| {
|
||||
const name_token = tree.firstToken(field_init) - 2;
|
||||
const str_index = try gz.identAsString(name_token);
|
||||
const field_ptr = try gz.addPlNode(.field_ptr, field_init, zir.Inst.Field{
|
||||
.lhs = ptr_inst,
|
||||
.field_name_start = str_index,
|
||||
});
|
||||
field_ptr_list[i] = astgen.refToIndex(field_ptr).?;
|
||||
_ = try expr(gz, scope, .{ .ptr = field_ptr }, field_init);
|
||||
}
|
||||
const validate_inst = try gz.addPlNode(.validate_struct_init_ptr, node, zir.Inst.Block{
|
||||
.body_len = @intCast(u32, field_ptr_list.len),
|
||||
});
|
||||
try astgen.extra.appendSlice(gpa, field_ptr_list);
|
||||
return validate_inst;
|
||||
},
|
||||
.inferred_ptr => |ptr_inst| {
|
||||
return mod.failNode(scope, node, "TODO implement structInitExpr inferred_ptr", .{});
|
||||
},
|
||||
.block_ptr => |block_gz| {
|
||||
return mod.failNode(scope, node, "TODO implement structInitExpr block", .{});
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
pub fn comptimeExpr(
|
||||
gz: *GenZir,
|
||||
scope: *Scope,
|
||||
@@ -1285,6 +1337,7 @@ fn blockExprStmts(
|
||||
.resolve_inferred_alloc,
|
||||
.repeat,
|
||||
.repeat_inline,
|
||||
.validate_struct_init_ptr,
|
||||
=> break :b true,
|
||||
}
|
||||
} else switch (maybe_unused_result) {
|
||||
@@ -1959,7 +2012,8 @@ pub fn fieldAccess(
|
||||
rl: ResultLoc,
|
||||
node: ast.Node.Index,
|
||||
) InnerError!zir.Inst.Ref {
|
||||
const mod = gz.astgen.mod;
|
||||
const astgen = gz.astgen;
|
||||
const mod = astgen.mod;
|
||||
const tree = gz.tree();
|
||||
const main_tokens = tree.nodes.items(.main_token);
|
||||
const node_datas = tree.nodes.items(.data);
|
||||
@@ -1967,10 +2021,7 @@ pub fn fieldAccess(
|
||||
const object_node = node_datas[node].lhs;
|
||||
const dot_token = main_tokens[node];
|
||||
const field_ident = dot_token + 1;
|
||||
const string_bytes = &gz.astgen.string_bytes;
|
||||
const str_index = @intCast(u32, string_bytes.items.len);
|
||||
try mod.appendIdentStr(scope, field_ident, string_bytes);
|
||||
try string_bytes.append(mod.gpa, 0);
|
||||
const str_index = try gz.identAsString(field_ident);
|
||||
switch (rl) {
|
||||
.ref => return gz.addPlNode(.field_ptr, node, zir.Inst.Field{
|
||||
.lhs = try expr(gz, scope, .ref, object_node),
|
||||
@@ -2031,11 +2082,7 @@ fn simpleStrTok(
|
||||
node: ast.Node.Index,
|
||||
op_inst_tag: zir.Inst.Tag,
|
||||
) InnerError!zir.Inst.Ref {
|
||||
const mod = gz.astgen.mod;
|
||||
const string_bytes = &gz.astgen.string_bytes;
|
||||
const str_index = @intCast(u32, string_bytes.items.len);
|
||||
try mod.appendIdentStr(scope, ident_token, string_bytes);
|
||||
try string_bytes.append(mod.gpa, 0);
|
||||
const str_index = try gz.identAsString(ident_token);
|
||||
const result = try gz.addStrTok(op_inst_tag, str_index, ident_token);
|
||||
return rvalue(gz, scope, rl, result, node);
|
||||
}
|
||||
|
||||
@@ -1046,6 +1046,16 @@ pub const Scope = struct {
|
||||
gz.astgen.extra.appendSliceAssumeCapacity(gz.instructions.items);
|
||||
}
|
||||
|
||||
pub fn identAsString(gz: *GenZir, ident_token: ast.TokenIndex) !u32 {
|
||||
const astgen = gz.astgen;
|
||||
const gpa = astgen.mod.gpa;
|
||||
const string_bytes = &astgen.string_bytes;
|
||||
const str_index = @intCast(u32, string_bytes.items.len);
|
||||
try astgen.mod.appendIdentStr(&gz.base, ident_token, string_bytes);
|
||||
try string_bytes.append(gpa, 0);
|
||||
return str_index;
|
||||
}
|
||||
|
||||
pub fn addFnTypeCc(gz: *GenZir, tag: zir.Inst.Tag, args: struct {
|
||||
src_node: ast.Node.Index,
|
||||
param_types: []const zir.Inst.Ref,
|
||||
|
||||
16
src/Sema.zig
16
src/Sema.zig
@@ -326,6 +326,10 @@ pub fn analyzeBody(
|
||||
try sema.zirResolveInferredAlloc(block, inst);
|
||||
continue;
|
||||
},
|
||||
.validate_struct_init_ptr => {
|
||||
try sema.zirValidateStructInitPtr(block, inst);
|
||||
continue;
|
||||
},
|
||||
|
||||
// Special case instructions to handle comptime control flow.
|
||||
.repeat_inline => {
|
||||
@@ -694,6 +698,18 @@ fn zirResolveInferredAlloc(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Inde
|
||||
ptr.tag = .alloc;
|
||||
}
|
||||
|
||||
fn zirValidateStructInitPtr(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!void {
|
||||
const tracy = trace(@src());
|
||||
defer tracy.end();
|
||||
|
||||
const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
|
||||
const src = inst_data.src();
|
||||
const extra = sema.code.extraData(zir.Inst.Block, inst_data.payload_index);
|
||||
const instrs = sema.code.extra[extra.end..][0..extra.data.body_len];
|
||||
|
||||
return sema.mod.fail(&block.base, src, "TODO implement zirValidateStructInitPtr", .{});
|
||||
}
|
||||
|
||||
fn zirStoreToBlockPtr(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!void {
|
||||
const tracy = trace(@src());
|
||||
defer tracy.end();
|
||||
|
||||
@@ -637,6 +637,11 @@ pub const Inst = struct {
|
||||
/// Result is a pointer to the value.
|
||||
/// Uses the `switch_capture` field.
|
||||
switch_capture_else_ref,
|
||||
/// Given a set of `field_ptr` instructions, assumes they are all part of a struct
|
||||
/// initialization expression, and emits compile errors for duplicate fields
|
||||
/// as well as missing fields, if applicable.
|
||||
/// Uses the `pl_node` field. Payload is `Block`.
|
||||
validate_struct_init_ptr,
|
||||
|
||||
/// Returns whether the instruction is one of the control flow "noreturn" types.
|
||||
/// Function calls do not count.
|
||||
@@ -784,6 +789,7 @@ pub const Inst = struct {
|
||||
.switch_block_ref_else_multi,
|
||||
.switch_block_ref_under,
|
||||
.switch_block_ref_under_multi,
|
||||
.validate_struct_init_ptr,
|
||||
=> false,
|
||||
|
||||
.@"break",
|
||||
@@ -1568,6 +1574,7 @@ const Writer = struct {
|
||||
.block,
|
||||
.block_inline,
|
||||
.loop,
|
||||
.validate_struct_init_ptr,
|
||||
=> try self.writePlNodeBlock(stream, inst),
|
||||
|
||||
.condbr,
|
||||
|
||||
Reference in New Issue
Block a user