authorgravatar for john.schmidt.h@gmail.comJohn Schmidt <john.schmidt.h@gmail.com> 2022-03-19 19:32:31+01:00
committergravatar for john.schmidt.h@gmail.comJohn Schmidt <john.schmidt.h@gmail.com> 2022-04-03 13:49:34+02:00
logb922caf1691111e5c23f01afbe1f1c9b5104807b
treeb4fa0d8fcab350779c546041f6b694e4ac47ef54
parentf7f4702795d76c606d119941e2cf5d5c3e2045b6

sema: add compile error for missing/extra enum fields in union decl


2 files changed, 86 insertions(+), 2 deletions(-)

src/Sema.zig+42-2
......@@ -21727,7 +21727,7 @@ fn resolveTypeFieldsUnion(
2172721727 }
2172821728
2172921729 union_obj.status = .field_types_wip;
21730 try semaUnionFields(sema.mod, union_obj);
21730 try semaUnionFields(block, sema.mod, union_obj);
2173121731 union_obj.status = .have_field_types;
2173221732}
2173321733
......@@ -21967,7 +21967,7 @@ fn semaStructFields(
2196721967 }
2196821968}
2196921969
21970fn semaUnionFields(mod: *Module, union_obj: *Module.Union) CompileError!void {
21970fn semaUnionFields(block: *Block, mod: *Module, union_obj: *Module.Union) CompileError!void {
2197121971 const tracy = trace(@src());
2197221972 defer tracy.end();
2197321973
......@@ -22067,6 +22067,7 @@ fn semaUnionFields(mod: *Module, union_obj: *Module.Union) CompileError!void {
2206722067 var int_tag_ty: Type = undefined;
2206822068 var enum_field_names: ?*Module.EnumNumbered.NameMap = null;
2206922069 var enum_value_map: ?*Module.EnumNumbered.ValueMap = null;
22070 var tag_ty_field_names: ?Module.EnumFull.NameMap = null;
2207022071 if (tag_type_ref != .none) {
2207122072 const provided_ty = try sema.resolveType(&block_scope, src, tag_type_ref);
2207222073 if (small.auto_enum_tag) {
......@@ -22079,6 +22080,10 @@ fn semaUnionFields(mod: *Module, union_obj: *Module.Union) CompileError!void {
2207922080 } else {
2208022081 // The provided type is the enum tag type.
2208122082 union_obj.tag_ty = try provided_ty.copy(decl_arena_allocator);
22083 // The fields of the union must match the enum exactly.
22084 // Store a copy of the enum field names so we can check for
22085 // missing or extraneous fields later.
22086 tag_ty_field_names = try union_obj.tag_ty.enumFields().clone(decl_arena_allocator);
2208222087 }
2208322088 } else {
2208422089 // If auto_enum_tag is false, this is an untagged union. However, for semantic analysis
......@@ -22172,6 +22177,20 @@ fn semaUnionFields(mod: *Module, union_obj: *Module.Union) CompileError!void {
2217222177 set.putAssumeCapacity(field_name, {});
2217322178 }
2217422179
22180 if (tag_ty_field_names) |*names| {
22181 const enum_has_field = names.contains(field_name);
22182 if (!enum_has_field) {
22183 const msg = msg: {
22184 const msg = try sema.errMsg(block, src, "enum '{}' has no field named '{s}'", .{ union_obj.tag_ty.fmt(target), field_name });
22185 errdefer msg.destroy(sema.gpa);
22186 try sema.addDeclaredHereNote(msg, union_obj.tag_ty);
22187 break :msg msg;
22188 };
22189 return sema.failWithOwnedErrorMsg(block, msg);
22190 }
22191 _ = names.orderedRemove(field_name);
22192 }
22193
2217522194 const field_ty: Type = if (!has_type)
2217622195 Type.void
2217722196 else if (field_type_ref == .none)
......@@ -22202,6 +22221,27 @@ fn semaUnionFields(mod: *Module, union_obj: *Module.Union) CompileError!void {
2220222221 gop.value_ptr.abi_align = 0;
2220322222 }
2220422223 }
22224
22225 if (tag_ty_field_names) |names| {
22226 if (names.count() > 0) {
22227 const msg = msg: {
22228 const msg = try sema.errMsg(block, src, "enum field(s) missing in union", .{});
22229 errdefer msg.destroy(sema.gpa);
22230
22231 const enum_ty = union_obj.tag_ty;
22232 const tree = try sema.getAstTree(block);
22233 const enum_decl = enum_ty.getOwnerDecl();
22234 for (names.keys()) |field_name| {
22235 const field_index = enum_ty.enumFieldIndex(field_name).?;
22236 const field_src = enumFieldSrcLoc(enum_decl, tree.*, enum_ty.getNodeOffset(), field_index);
22237 try sema.mod.errNoteNonLazy(field_src.toSrcLoc(enum_decl), msg, "field '{s}' missing, declared here", .{field_name});
22238 }
22239 try sema.addDeclaredHereNote(msg, union_obj.tag_ty);
22240 break :msg msg;
22241 };
22242 return sema.failWithOwnedErrorMsg(block, msg);
22243 }
22244 }
2220522245}
2220622246
2220722247fn generateUnionTagTypeNumbered(
src/type.zig+44
......@@ -5305,6 +5305,50 @@ pub const Type = extern union {
53055305 }
53065306 }
53075307
5308 pub fn getNodeOffset(ty: Type) i32 {
5309 switch (ty.tag()) {
5310 .enum_full, .enum_nonexhaustive => {
5311 const enum_full = ty.cast(Payload.EnumFull).?.data;
5312 return enum_full.node_offset;
5313 },
5314 .enum_numbered => return ty.castTag(.enum_numbered).?.data.node_offset,
5315 .enum_simple => {
5316 const enum_simple = ty.castTag(.enum_simple).?.data;
5317 return enum_simple.node_offset;
5318 },
5319 .@"struct" => {
5320 const struct_obj = ty.castTag(.@"struct").?.data;
5321 return struct_obj.node_offset;
5322 },
5323 .error_set => {
5324 const error_set = ty.castTag(.error_set).?.data;
5325 return error_set.node_offset;
5326 },
5327 .@"union", .union_tagged => {
5328 const union_obj = ty.cast(Payload.Union).?.data;
5329 return union_obj.node_offset;
5330 },
5331 .@"opaque" => {
5332 const opaque_obj = ty.cast(Payload.Opaque).?.data;
5333 return opaque_obj.node_offset;
5334 },
5335 .atomic_order,
5336 .atomic_rmw_op,
5337 .calling_convention,
5338 .address_space,
5339 .float_mode,
5340 .reduce_op,
5341 .call_options,
5342 .prefetch_options,
5343 .export_options,
5344 .extern_options,
5345 .type_info,
5346 => unreachable, // These need to be resolved earlier.
5347
5348 else => unreachable,
5349 }
5350 }
5351
53085352 /// Asserts the type is an enum.
53095353 pub fn enumHasInt(ty: Type, int: Value, target: Target) bool {
53105354 const S = struct {