aboutsummaryrefslogtreecommitdiff
path: root/src/Sema.zig
diff options
context:
space:
mode:
authorAndrew Kelley <andrew@ziglang.org>2021-04-02 21:06:09 -0700
committerAndrew Kelley <andrew@ziglang.org>2021-04-02 21:06:09 -0700
commitd47f0abd5b5ba95bacd2d573aeabcc53db8c8fc3 (patch)
tree18e901d51e99848a038e0e81eb412829b1069978 /src/Sema.zig
parent97d7fddfb78d17132749cae59fea36fe661bf642 (diff)
downloadzig-d47f0abd5b5ba95bacd2d573aeabcc53db8c8fc3.tar.gz
zig-d47f0abd5b5ba95bacd2d573aeabcc53db8c8fc3.zip
stage2: Sema: implement validate_struct_init_ptr
Diffstat (limited to 'src/Sema.zig')
-rw-r--r--src/Sema.zig106
1 files changed, 95 insertions, 11 deletions
diff --git a/src/Sema.zig b/src/Sema.zig
index 216544e1df..0b5a21ce42 100644
--- a/src/Sema.zig
+++ b/src/Sema.zig
@@ -838,12 +838,100 @@ fn zirValidateStructInitPtr(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Ind
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];
+ const gpa = sema.gpa;
+ const mod = sema.mod;
+ const validate_inst = sema.code.instructions.items(.data)[inst].pl_node;
+ const struct_init_src = validate_inst.src();
+ const validate_extra = sema.code.extraData(zir.Inst.Block, validate_inst.payload_index);
+ const instrs = sema.code.extra[validate_extra.end..][0..validate_extra.data.body_len];
+
+ const struct_obj: *Module.Struct = s: {
+ const field_ptr_data = sema.code.instructions.items(.data)[instrs[0]].pl_node;
+ const field_ptr_extra = sema.code.extraData(zir.Inst.Field, field_ptr_data.payload_index).data;
+ const object_ptr = try sema.resolveInst(field_ptr_extra.lhs);
+ break :s object_ptr.ty.elemType().castTag(.@"struct").?.data;
+ };
+
+ // Maps field index to field_ptr index of where it was already initialized.
+ const found_fields = try gpa.alloc(zir.Inst.Index, struct_obj.fields.entries.items.len);
+ defer gpa.free(found_fields);
+
+ mem.set(zir.Inst.Index, found_fields, 0);
+
+ for (instrs) |field_ptr| {
+ const field_ptr_data = sema.code.instructions.items(.data)[field_ptr].pl_node;
+ const field_src: LazySrcLoc = .{ .node_offset_back2tok = field_ptr_data.src_node };
+ const field_ptr_extra = sema.code.extraData(zir.Inst.Field, field_ptr_data.payload_index).data;
+ const field_name = sema.code.nullTerminatedString(field_ptr_extra.field_name_start);
+ const field_index = struct_obj.fields.getIndex(field_name) orelse
+ return sema.failWithBadFieldAccess(block, struct_obj, field_src, field_name);
+ if (found_fields[field_index] != 0) {
+ const other_field_ptr = found_fields[field_index];
+ const other_field_ptr_data = sema.code.instructions.items(.data)[other_field_ptr].pl_node;
+ const other_field_src: LazySrcLoc = .{ .node_offset_back2tok = other_field_ptr_data.src_node };
+ const msg = msg: {
+ const msg = try mod.errMsg(&block.base, field_src, "duplicate field", .{});
+ errdefer msg.destroy(gpa);
+ try mod.errNote(&block.base, other_field_src, msg, "other field here", .{});
+ break :msg msg;
+ };
+ return mod.failWithOwnedErrorMsg(&block.base, msg);
+ }
+ found_fields[field_index] = field_ptr;
+ }
+
+ var root_msg: ?*Module.ErrorMsg = null;
+
+ for (found_fields) |field_ptr, i| {
+ if (field_ptr != 0) continue;
+
+ const field_name = struct_obj.fields.entries.items[i].key;
+ const template = "mising struct field: {s}";
+ const args = .{field_name};
+ if (root_msg) |msg| {
+ try mod.errNote(&block.base, struct_init_src, msg, template, args);
+ } else {
+ root_msg = try mod.errMsg(&block.base, struct_init_src, template, args);
+ }
+ }
+ if (root_msg) |msg| {
+ const fqn = try struct_obj.getFullyQualifiedName(gpa);
+ defer gpa.free(fqn);
+ try mod.errNoteNonLazy(
+ struct_obj.srcLoc(),
+ msg,
+ "'{s}' declared here",
+ .{fqn},
+ );
+ return mod.failWithOwnedErrorMsg(&block.base, msg);
+ }
+}
+
+fn failWithBadFieldAccess(
+ sema: *Sema,
+ block: *Scope.Block,
+ struct_obj: *Module.Struct,
+ field_src: LazySrcLoc,
+ field_name: []const u8,
+) InnerError {
+ const mod = sema.mod;
+ const gpa = sema.gpa;
- log.warn("TODO implement zirValidateStructInitPtr (compile errors for missing/dupe fields)", .{});
+ const fqn = try struct_obj.getFullyQualifiedName(gpa);
+ defer gpa.free(fqn);
+
+ const msg = msg: {
+ const msg = try mod.errMsg(
+ &block.base,
+ field_src,
+ "no field named '{s}' in struct '{s}'",
+ .{ field_name, fqn },
+ );
+ errdefer msg.destroy(gpa);
+ try mod.errNoteNonLazy(struct_obj.srcLoc(), msg, "'{s}' declared here", .{fqn});
+ break :msg msg;
+ };
+ return mod.failWithOwnedErrorMsg(&block.base, msg);
}
fn zirStoreToBlockPtr(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!void {
@@ -4245,12 +4333,8 @@ fn analyzeStructFieldPtr(
const struct_obj = elem_ty.castTag(.@"struct").?.data;
- const field_index = struct_obj.fields.getIndex(field_name) orelse {
- // TODO note: struct S declared here
- return mod.fail(&block.base, field_name_src, "no field named '{s}' in struct '{}'", .{
- field_name, elem_ty,
- });
- };
+ const field_index = struct_obj.fields.getIndex(field_name) orelse
+ return sema.failWithBadFieldAccess(block, struct_obj, field_name_src, field_name);
const field = struct_obj.fields.entries.items[field_index].value;
const ptr_field_ty = try mod.simplePtrType(arena, field.ty, true, .One);
// TODO comptime field access