From 50bcfb8c906be67a044ff4bef857a8d6d615de71 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Thu, 1 Apr 2021 11:58:55 -0700 Subject: stage2: implement struct init syntax with ptr result loc --- src/AstGen.zig | 77 ++++++++++++++++++++++++++++++++++++++++++++++------------ src/Module.zig | 10 ++++++++ src/Sema.zig | 16 ++++++++++++ src/zir.zig | 7 ++++++ 4 files changed, 95 insertions(+), 15 deletions(-) (limited to 'src') diff --git a/src/AstGen.zig b/src/AstGen.zig index 2c3c1871ac..119c47acab 100644 --- a/src/AstGen.zig +++ b/src/AstGen.zig @@ -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); } diff --git a/src/Module.zig b/src/Module.zig index 8037785232..ebb4b2dc1d 100644 --- a/src/Module.zig +++ b/src/Module.zig @@ -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, diff --git a/src/Sema.zig b/src/Sema.zig index 876016df8c..bb1daf1121 100644 --- a/src/Sema.zig +++ b/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(); diff --git a/src/zir.zig b/src/zir.zig index 8f9d43a8ae..02586ba1ff 100644 --- a/src/zir.zig +++ b/src/zir.zig @@ -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, -- cgit v1.2.3