From 4e8fb9e6a5f9a65bbf6469e386e83ba469e7543b Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Wed, 7 Apr 2021 11:26:07 -0700 Subject: Sema: DRY up enum field analysis and add "declared here" notes --- src/Module.zig | 21 +++++++++++ src/Sema.zig | 114 ++++++++++++++++++++++++--------------------------------- src/type.zig | 36 ++++++++++++++++++ 3 files changed, 105 insertions(+), 66 deletions(-) (limited to 'src') diff --git a/src/Module.zig b/src/Module.zig index 8c58b63995..9d26738e14 100644 --- a/src/Module.zig +++ b/src/Module.zig @@ -366,6 +366,13 @@ pub const ErrorSet = struct { /// The string bytes are stored in the owner Decl arena. /// They are in the same order they appear in the AST. names_ptr: [*]const []const u8, + + pub fn srcLoc(self: ErrorSet) SrcLoc { + return .{ + .container = .{ .decl = self.owner_decl }, + .lazy = .{ .node_offset = self.node_offset }, + }; + } }; /// Represents the data that a struct declaration provides. @@ -408,6 +415,13 @@ pub const EnumSimple = struct { fields: std.StringArrayHashMapUnmanaged(void), /// Offset from `owner_decl`, points to the enum decl AST node. node_offset: i32, + + pub fn srcLoc(self: EnumSimple) SrcLoc { + return .{ + .container = .{ .decl = self.owner_decl }, + .lazy = .{ .node_offset = self.node_offset }, + }; + } }; /// Represents the data that an enum declaration provides, when there is @@ -429,6 +443,13 @@ pub const EnumFull = struct { node_offset: i32, pub const ValueMap = std.ArrayHashMapUnmanaged(Value, void, Value.hash_u32, Value.eql, false); + + pub fn srcLoc(self: EnumFull) SrcLoc { + return .{ + .container = .{ .decl = self.owner_decl }, + .lazy = .{ .node_offset = self.node_offset }, + }; + } }; /// Some Fn struct memory is owned by the Decl's TypedValue.Managed arena allocator. diff --git a/src/Sema.zig b/src/Sema.zig index 0cd9837c3a..41544cdfe5 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -897,7 +897,7 @@ fn zirValidateStructInitPtr(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Ind try mod.errNoteNonLazy( struct_obj.srcLoc(), msg, - "'{s}' declared here", + "struct '{s}' declared here", .{fqn}, ); return mod.failWithOwnedErrorMsg(&block.base, msg); @@ -925,7 +925,7 @@ fn failWithBadFieldAccess( .{ field_name, fqn }, ); errdefer msg.destroy(gpa); - try mod.errNoteNonLazy(struct_obj.srcLoc(), msg, "'{s}' declared here", .{fqn}); + try mod.errNoteNonLazy(struct_obj.srcLoc(), msg, "struct declared here", .{}); break :msg msg; }; return mod.failWithOwnedErrorMsg(&block.base, msg); @@ -4479,21 +4479,24 @@ fn namedFieldPtr( return sema.analyzeDeclRef(block, src, decl); } } - const maybe_field_index: ?usize = switch (child_type.tag()) { - .enum_full, .enum_nonexhaustive => blk: { - const enum_full = child_type.castTag(.enum_full).?.data; - break :blk enum_full.fields.getIndex(field_name); - }, - .enum_simple => blk: { - const enum_simple = child_type.castTag(.enum_simple).?.data; - break :blk enum_simple.fields.getIndex(field_name); - }, - else => unreachable, - }; - const field_index = maybe_field_index orelse { - return mod.fail(&block.base, src, "enum '{}' has no member named '{s}'", .{ - child_type, field_name, - }); + const field_index = child_type.enumFieldIndex(field_name) orelse { + const msg = msg: { + const msg = try mod.errMsg( + &block.base, + src, + "enum '{}' has no member named '{s}'", + .{ child_type, field_name }, + ); + errdefer msg.destroy(sema.gpa); + try mod.errNoteNonLazy( + child_type.declSrcLoc(), + msg, + "enum declared here", + .{}, + ); + break :msg msg; + }; + return mod.failWithOwnedErrorMsg(&block.base, msg); }; const field_index_u32 = @intCast(u32, field_index); const enum_val = try Value.Tag.enum_field_index.create(arena, field_index_u32); @@ -4593,10 +4596,13 @@ fn coerce( return sema.bitcast(block, dest_type, inst); } + const mod = sema.mod; + const arena = sema.arena; + // undefined to anything if (inst.value()) |val| { if (val.isUndef() or inst.ty.zigTypeTag() == .Undefined) { - return sema.mod.constInst(sema.arena, inst_src, .{ .ty = dest_type, .val = val }); + return mod.constInst(arena, inst_src, .{ .ty = dest_type, .val = val }); } } assert(inst.ty.zigTypeTag() != .Undefined); @@ -4610,13 +4616,13 @@ fn coerce( if (try sema.coerceNum(block, dest_type, inst)) |some| return some; - const target = sema.mod.getTarget(); + const target = mod.getTarget(); switch (dest_type.zigTypeTag()) { .Optional => { // null to ?T if (inst.ty.zigTypeTag() == .Null) { - return sema.mod.constInst(sema.arena, inst_src, .{ .ty = dest_type, .val = Value.initTag(.null_value) }); + return mod.constInst(arena, inst_src, .{ .ty = dest_type, .val = Value.initTag(.null_value) }); } // T to ?T @@ -4703,63 +4709,39 @@ fn coerce( } }, .Enum => { + // enum literal to enum if (inst.ty.zigTypeTag() == .EnumLiteral) { - const val = (try sema.resolveDefinedValue(block, inst_src, inst)).?; + const val = try sema.resolveConstValue(block, inst_src, inst); const bytes = val.castTag(.enum_literal).?.data; - switch (dest_type.tag()) { - .enum_full => { - const enumeration = dest_type.castTag(.enum_full).?.data; - const enum_fields = enumeration.fields; - const i = enum_fields.getIndex(bytes) orelse return sema.mod.fail( + const field_index = dest_type.enumFieldIndex(bytes) orelse { + const msg = msg: { + const msg = try mod.errMsg( &block.base, inst_src, - "enum '{s}' has no field named '{s}'", - .{ enumeration.owner_decl.name, bytes }, + "enum '{}' has no field named '{s}'", + .{ dest_type, bytes }, ); - const val_pl = try Value.Tag.enum_field_index.create(sema.arena, @intCast(u32, i)); - return sema.mod.constInst(sema.arena, inst_src, .{ - .ty = dest_type, - .val = val_pl, - }); - }, - .enum_simple => { - const enumeration = dest_type.castTag(.enum_simple).?.data; - const enum_fields = enumeration.fields; - const i = enum_fields.getIndex(bytes) orelse return sema.mod.fail( - &block.base, - inst_src, - "enum '{s}' has no field named '{s}'", - .{ enumeration.owner_decl.name, bytes }, - ); - const val_pl = try Value.Tag.enum_field_index.create(sema.arena, @intCast(u32, i)); - return sema.mod.constInst(sema.arena, inst_src, .{ - .ty = dest_type, - .val = val_pl, - }); - }, - .enum_nonexhaustive => { - const enumeration = dest_type.castTag(.enum_nonexhaustive).?.data; - const enum_fields = enumeration.fields; - const i = enum_fields.getIndex(bytes) orelse return sema.mod.fail( - &block.base, - inst_src, - "enum '{s}' has no field named '{s}'", - .{ enumeration.owner_decl.name, bytes }, + errdefer msg.destroy(sema.gpa); + try mod.errNoteNonLazy( + dest_type.declSrcLoc(), + msg, + "enum declared here", + .{}, ); - const val_pl = try Value.Tag.enum_field_index.create(sema.arena, @intCast(u32, i)); - return sema.mod.constInst(sema.arena, inst_src, .{ - .ty = dest_type, - .val = val_pl, - }); - }, - else => unreachable, - } + break :msg msg; + }; + return mod.failWithOwnedErrorMsg(&block.base, msg); + }; + return mod.constInst(arena, inst_src, .{ + .ty = dest_type, + .val = try Value.Tag.enum_field_index.create(arena, @intCast(u32, field_index)), + }); } }, else => {}, } - return sema.mod.fail(&block.base, inst_src, "expected {}, found {}", .{ dest_type, inst.ty }); + return mod.fail(&block.base, inst_src, "expected {}, found {}", .{ dest_type, inst.ty }); } const InMemoryCoercionResult = enum { diff --git a/src/type.zig b/src/type.zig index 6173c0b800..06e84c245b 100644 --- a/src/type.zig +++ b/src/type.zig @@ -2090,6 +2090,42 @@ pub const Type = extern union { }; } + pub fn enumFieldIndex(ty: Type, field_name: []const u8) ?usize { + switch (ty.tag()) { + .enum_full, .enum_nonexhaustive => { + const enum_full = ty.cast(Payload.EnumFull).?.data; + return enum_full.fields.getIndex(field_name); + }, + .enum_simple => { + const enum_simple = ty.castTag(.enum_simple).?.data; + return enum_simple.fields.getIndex(field_name); + }, + else => unreachable, + } + } + + pub fn declSrcLoc(ty: Type) Module.SrcLoc { + switch (ty.tag()) { + .enum_full, .enum_nonexhaustive => { + const enum_full = ty.cast(Payload.EnumFull).?.data; + return enum_full.srcLoc(); + }, + .enum_simple => { + const enum_simple = ty.castTag(.enum_simple).?.data; + return enum_simple.srcLoc(); + }, + .@"struct" => { + const struct_obj = ty.castTag(.@"struct").?.data; + return struct_obj.srcLoc(); + }, + .error_set => { + const error_set = ty.castTag(.error_set).?.data; + return error_set.srcLoc(); + }, + else => unreachable, + } + } + /// Asserts the type is an enum. pub fn enumHasInt(ty: Type, int: Value, target: Target) bool { const S = struct { -- cgit v1.2.3