From d47f0abd5b5ba95bacd2d573aeabcc53db8c8fc3 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Fri, 2 Apr 2021 21:06:09 -0700 Subject: stage2: Sema: implement validate_struct_init_ptr --- src/Sema.zig | 106 ++++++++++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 95 insertions(+), 11 deletions(-) (limited to 'src/Sema.zig') 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 -- cgit v1.2.3