| ... | @@ -21727,7 +21727,7 @@ fn resolveTypeFieldsUnion( | ... | @@ -21727,7 +21727,7 @@ fn resolveTypeFieldsUnion( |
| 21727 | } | 21727 | } |
| 21728 | | 21728 | |
| 21729 | union_obj.status = .field_types_wip; | 21729 | union_obj.status = .field_types_wip; |
| 21730 | try semaUnionFields(sema.mod, union_obj); | 21730 | try semaUnionFields(block, sema.mod, union_obj); |
| 21731 | union_obj.status = .have_field_types; | 21731 | union_obj.status = .have_field_types; |
| 21732 | } | 21732 | } |
| 21733 | | 21733 | |
| ... | @@ -21967,7 +21967,7 @@ fn semaStructFields( | ... | @@ -21967,7 +21967,7 @@ fn semaStructFields( |
| 21967 | } | 21967 | } |
| 21968 | } | 21968 | } |
| 21969 | | 21969 | |
| 21970 | fn semaUnionFields(mod: *Module, union_obj: *Module.Union) CompileError!void { | 21970 | fn semaUnionFields(block: *Block, mod: *Module, union_obj: *Module.Union) CompileError!void { |
| 21971 | const tracy = trace(@src()); | 21971 | const tracy = trace(@src()); |
| 21972 | defer tracy.end(); | 21972 | defer tracy.end(); |
| 21973 | | 21973 | |
| ... | @@ -22067,6 +22067,7 @@ fn semaUnionFields(mod: *Module, union_obj: *Module.Union) CompileError!void { | ... | @@ -22067,6 +22067,7 @@ fn semaUnionFields(mod: *Module, union_obj: *Module.Union) CompileError!void { |
| 22067 | var int_tag_ty: Type = undefined; | 22067 | var int_tag_ty: Type = undefined; |
| 22068 | var enum_field_names: ?*Module.EnumNumbered.NameMap = null; | 22068 | var enum_field_names: ?*Module.EnumNumbered.NameMap = null; |
| 22069 | var enum_value_map: ?*Module.EnumNumbered.ValueMap = null; | 22069 | var enum_value_map: ?*Module.EnumNumbered.ValueMap = null; |
| | 22070 | var tag_ty_field_names: ?Module.EnumFull.NameMap = null; |
| 22070 | if (tag_type_ref != .none) { | 22071 | if (tag_type_ref != .none) { |
| 22071 | const provided_ty = try sema.resolveType(&block_scope, src, tag_type_ref); | 22072 | const provided_ty = try sema.resolveType(&block_scope, src, tag_type_ref); |
| 22072 | if (small.auto_enum_tag) { | 22073 | if (small.auto_enum_tag) { |
| ... | @@ -22079,6 +22080,10 @@ fn semaUnionFields(mod: *Module, union_obj: *Module.Union) CompileError!void { | ... | @@ -22079,6 +22080,10 @@ fn semaUnionFields(mod: *Module, union_obj: *Module.Union) CompileError!void { |
| 22079 | } else { | 22080 | } else { |
| 22080 | // The provided type is the enum tag type. | 22081 | // The provided type is the enum tag type. |
| 22081 | union_obj.tag_ty = try provided_ty.copy(decl_arena_allocator); | 22082 | 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); |
| 22082 | } | 22087 | } |
| 22083 | } else { | 22088 | } else { |
| 22084 | // If auto_enum_tag is false, this is an untagged union. However, for semantic analysis | 22089 | // 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 { | ... | @@ -22172,6 +22177,20 @@ fn semaUnionFields(mod: *Module, union_obj: *Module.Union) CompileError!void { |
| 22172 | set.putAssumeCapacity(field_name, {}); | 22177 | set.putAssumeCapacity(field_name, {}); |
| 22173 | } | 22178 | } |
| 22174 | | 22179 | |
| | 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 | |
| 22175 | const field_ty: Type = if (!has_type) | 22194 | const field_ty: Type = if (!has_type) |
| 22176 | Type.void | 22195 | Type.void |
| 22177 | else if (field_type_ref == .none) | 22196 | else if (field_type_ref == .none) |
| ... | @@ -22202,6 +22221,27 @@ fn semaUnionFields(mod: *Module, union_obj: *Module.Union) CompileError!void { | ... | @@ -22202,6 +22221,27 @@ fn semaUnionFields(mod: *Module, union_obj: *Module.Union) CompileError!void { |
| 22202 | gop.value_ptr.abi_align = 0; | 22221 | gop.value_ptr.abi_align = 0; |
| 22203 | } | 22222 | } |
| 22204 | } | 22223 | } |
| | 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 | } |
| 22205 | } | 22245 | } |
| 22206 | | 22246 | |
| 22207 | fn generateUnionTagTypeNumbered( | 22247 | fn generateUnionTagTypeNumbered( |