| ... | ... | @@ -8979,6 +8979,8 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError |
| 8979 | 8979 | var seen_union_fields: []?Module.SwitchProngSrc = &.{}; |
| 8980 | 8980 | defer gpa.free(seen_union_fields); |
| 8981 | 8981 | |
| 8982 | var empty_enum = false; |
| 8983 | |
| 8982 | 8984 | const operand_ty = sema.typeOf(operand); |
| 8983 | 8985 | |
| 8984 | 8986 | var else_error_ty: ?Type = null; |
| ... | ... | @@ -9012,6 +9014,7 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError |
| 9012 | 9014 | .Union => unreachable, // handled in zirSwitchCond |
| 9013 | 9015 | .Enum => { |
| 9014 | 9016 | var seen_fields = try gpa.alloc(?Module.SwitchProngSrc, operand_ty.enumFieldCount()); |
| 9017 | empty_enum = seen_fields.len == 0 and !operand_ty.isNonexhaustiveEnum(); |
| 9015 | 9018 | defer if (!union_originally) gpa.free(seen_fields); |
| 9016 | 9019 | if (union_originally) seen_union_fields = seen_fields; |
| 9017 | 9020 | mem.set(?Module.SwitchProngSrc, seen_fields, null); |
| ... | ... | @@ -9607,6 +9610,9 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError |
| 9607 | 9610 | } |
| 9608 | 9611 | |
| 9609 | 9612 | if (scalar_cases_len + multi_cases_len == 0) { |
| 9613 | if (empty_enum) { |
| 9614 | return Air.Inst.Ref.void_value; |
| 9615 | } |
| 9610 | 9616 | if (special_prong == .none) { |
| 9611 | 9617 | return sema.fail(block, src, "switch must handle all possibilities", .{}); |
| 9612 | 9618 | } |
| ... | ... | @@ -16690,43 +16696,39 @@ fn zirReify(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData, in |
| 16690 | 16696 | |
| 16691 | 16697 | // Fields |
| 16692 | 16698 | const fields_len = try sema.usizeCast(block, src, fields_val.sliceLen(mod)); |
| 16693 | | if (fields_len > 0) { |
| 16694 | | try enum_obj.fields.ensureTotalCapacity(new_decl_arena_allocator, fields_len); |
| 16695 | | try enum_obj.values.ensureTotalCapacityContext(new_decl_arena_allocator, fields_len, .{ |
| 16696 | | .ty = enum_obj.tag_ty, |
| 16697 | | .mod = mod, |
| 16698 | | }); |
| 16699 | | |
| 16700 | | var i: usize = 0; |
| 16701 | | while (i < fields_len) : (i += 1) { |
| 16702 | | const elem_val = try fields_val.elemValue(sema.mod, sema.arena, i); |
| 16703 | | const field_struct_val = elem_val.castTag(.aggregate).?.data; |
| 16704 | | // TODO use reflection instead of magic numbers here |
| 16705 | | // name: []const u8 |
| 16706 | | const name_val = field_struct_val[0]; |
| 16707 | | // value: comptime_int |
| 16708 | | const value_val = field_struct_val[1]; |
| 16709 | | |
| 16710 | | const field_name = try name_val.toAllocatedBytes( |
| 16711 | | Type.initTag(.const_slice_u8), |
| 16712 | | new_decl_arena_allocator, |
| 16713 | | sema.mod, |
| 16714 | | ); |
| 16699 | try enum_obj.fields.ensureTotalCapacity(new_decl_arena_allocator, fields_len); |
| 16700 | try enum_obj.values.ensureTotalCapacityContext(new_decl_arena_allocator, fields_len, .{ |
| 16701 | .ty = enum_obj.tag_ty, |
| 16702 | .mod = mod, |
| 16703 | }); |
| 16715 | 16704 | |
| 16716 | | const gop = enum_obj.fields.getOrPutAssumeCapacity(field_name); |
| 16717 | | if (gop.found_existing) { |
| 16718 | | // TODO: better source location |
| 16719 | | return sema.fail(block, src, "duplicate enum tag {s}", .{field_name}); |
| 16720 | | } |
| 16705 | var i: usize = 0; |
| 16706 | while (i < fields_len) : (i += 1) { |
| 16707 | const elem_val = try fields_val.elemValue(sema.mod, sema.arena, i); |
| 16708 | const field_struct_val = elem_val.castTag(.aggregate).?.data; |
| 16709 | // TODO use reflection instead of magic numbers here |
| 16710 | // name: []const u8 |
| 16711 | const name_val = field_struct_val[0]; |
| 16712 | // value: comptime_int |
| 16713 | const value_val = field_struct_val[1]; |
| 16714 | |
| 16715 | const field_name = try name_val.toAllocatedBytes( |
| 16716 | Type.initTag(.const_slice_u8), |
| 16717 | new_decl_arena_allocator, |
| 16718 | sema.mod, |
| 16719 | ); |
| 16721 | 16720 | |
| 16722 | | const copied_tag_val = try value_val.copy(new_decl_arena_allocator); |
| 16723 | | enum_obj.values.putAssumeCapacityNoClobberContext(copied_tag_val, {}, .{ |
| 16724 | | .ty = enum_obj.tag_ty, |
| 16725 | | .mod = mod, |
| 16726 | | }); |
| 16721 | const gop = enum_obj.fields.getOrPutAssumeCapacity(field_name); |
| 16722 | if (gop.found_existing) { |
| 16723 | // TODO: better source location |
| 16724 | return sema.fail(block, src, "duplicate enum tag {s}", .{field_name}); |
| 16727 | 16725 | } |
| 16728 | | } else { |
| 16729 | | return sema.fail(block, src, "enums must have at least one field", .{}); |
| 16726 | |
| 16727 | const copied_tag_val = try value_val.copy(new_decl_arena_allocator); |
| 16728 | enum_obj.values.putAssumeCapacityNoClobberContext(copied_tag_val, {}, .{ |
| 16729 | .ty = enum_obj.tag_ty, |
| 16730 | .mod = mod, |
| 16731 | }); |
| 16730 | 16732 | } |
| 16731 | 16733 | |
| 16732 | 16734 | try new_decl.finalizeNewArena(&new_decl_arena); |
| ... | ... | @@ -16851,58 +16853,54 @@ fn zirReify(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData, in |
| 16851 | 16853 | } |
| 16852 | 16854 | |
| 16853 | 16855 | // Fields |
| 16854 | | if (fields_len > 0) { |
| 16855 | | try union_obj.fields.ensureTotalCapacity(new_decl_arena_allocator, fields_len); |
| 16856 | try union_obj.fields.ensureTotalCapacity(new_decl_arena_allocator, fields_len); |
| 16856 | 16857 | |
| 16857 | | var i: usize = 0; |
| 16858 | | while (i < fields_len) : (i += 1) { |
| 16859 | | const elem_val = try fields_val.elemValue(sema.mod, sema.arena, i); |
| 16860 | | const field_struct_val = elem_val.castTag(.aggregate).?.data; |
| 16861 | | // TODO use reflection instead of magic numbers here |
| 16862 | | // name: []const u8 |
| 16863 | | const name_val = field_struct_val[0]; |
| 16864 | | // field_type: type, |
| 16865 | | const field_type_val = field_struct_val[1]; |
| 16866 | | // alignment: comptime_int, |
| 16867 | | const alignment_val = field_struct_val[2]; |
| 16868 | | |
| 16869 | | const field_name = try name_val.toAllocatedBytes( |
| 16870 | | Type.initTag(.const_slice_u8), |
| 16871 | | new_decl_arena_allocator, |
| 16872 | | sema.mod, |
| 16873 | | ); |
| 16858 | var i: usize = 0; |
| 16859 | while (i < fields_len) : (i += 1) { |
| 16860 | const elem_val = try fields_val.elemValue(sema.mod, sema.arena, i); |
| 16861 | const field_struct_val = elem_val.castTag(.aggregate).?.data; |
| 16862 | // TODO use reflection instead of magic numbers here |
| 16863 | // name: []const u8 |
| 16864 | const name_val = field_struct_val[0]; |
| 16865 | // field_type: type, |
| 16866 | const field_type_val = field_struct_val[1]; |
| 16867 | // alignment: comptime_int, |
| 16868 | const alignment_val = field_struct_val[2]; |
| 16874 | 16869 | |
| 16875 | | if (enum_field_names) |set| { |
| 16876 | | set.putAssumeCapacity(field_name, {}); |
| 16877 | | } |
| 16870 | const field_name = try name_val.toAllocatedBytes( |
| 16871 | Type.initTag(.const_slice_u8), |
| 16872 | new_decl_arena_allocator, |
| 16873 | sema.mod, |
| 16874 | ); |
| 16878 | 16875 | |
| 16879 | | if (tag_ty_field_names) |*names| { |
| 16880 | | const enum_has_field = names.orderedRemove(field_name); |
| 16881 | | if (!enum_has_field) { |
| 16882 | | const msg = msg: { |
| 16883 | | const msg = try sema.errMsg(block, src, "no field named '{s}' in enum '{}'", .{ field_name, union_obj.tag_ty.fmt(sema.mod) }); |
| 16884 | | errdefer msg.destroy(sema.gpa); |
| 16885 | | try sema.addDeclaredHereNote(msg, union_obj.tag_ty); |
| 16886 | | break :msg msg; |
| 16887 | | }; |
| 16888 | | return sema.failWithOwnedErrorMsg(msg); |
| 16889 | | } |
| 16890 | | } |
| 16876 | if (enum_field_names) |set| { |
| 16877 | set.putAssumeCapacity(field_name, {}); |
| 16878 | } |
| 16891 | 16879 | |
| 16892 | | const gop = union_obj.fields.getOrPutAssumeCapacity(field_name); |
| 16893 | | if (gop.found_existing) { |
| 16894 | | // TODO: better source location |
| 16895 | | return sema.fail(block, src, "duplicate union field {s}", .{field_name}); |
| 16880 | if (tag_ty_field_names) |*names| { |
| 16881 | const enum_has_field = names.orderedRemove(field_name); |
| 16882 | if (!enum_has_field) { |
| 16883 | const msg = msg: { |
| 16884 | const msg = try sema.errMsg(block, src, "no field named '{s}' in enum '{}'", .{ field_name, union_obj.tag_ty.fmt(sema.mod) }); |
| 16885 | errdefer msg.destroy(sema.gpa); |
| 16886 | try sema.addDeclaredHereNote(msg, union_obj.tag_ty); |
| 16887 | break :msg msg; |
| 16888 | }; |
| 16889 | return sema.failWithOwnedErrorMsg(msg); |
| 16896 | 16890 | } |
| 16891 | } |
| 16897 | 16892 | |
| 16898 | | var buffer: Value.ToTypeBuffer = undefined; |
| 16899 | | gop.value_ptr.* = .{ |
| 16900 | | .ty = try field_type_val.toType(&buffer).copy(new_decl_arena_allocator), |
| 16901 | | .abi_align = @intCast(u32, alignment_val.toUnsignedInt(target)), |
| 16902 | | }; |
| 16893 | const gop = union_obj.fields.getOrPutAssumeCapacity(field_name); |
| 16894 | if (gop.found_existing) { |
| 16895 | // TODO: better source location |
| 16896 | return sema.fail(block, src, "duplicate union field {s}", .{field_name}); |
| 16903 | 16897 | } |
| 16904 | | } else { |
| 16905 | | return sema.fail(block, src, "unions must have at least one field", .{}); |
| 16898 | |
| 16899 | var buffer: Value.ToTypeBuffer = undefined; |
| 16900 | gop.value_ptr.* = .{ |
| 16901 | .ty = try field_type_val.toType(&buffer).copy(new_decl_arena_allocator), |
| 16902 | .abi_align = @intCast(u32, alignment_val.toUnsignedInt(target)), |
| 16903 | }; |
| 16906 | 16904 | } |
| 16907 | 16905 | |
| 16908 | 16906 | if (tag_ty_field_names) |names| { |
| ... | ... | @@ -28146,10 +28144,6 @@ fn semaUnionFields(mod: *Module, union_obj: *Module.Union) CompileError!void { |
| 28146 | 28144 | extra_index = decls_it.extra_index; |
| 28147 | 28145 | |
| 28148 | 28146 | const body = zir.extra[extra_index..][0..body_len]; |
| 28149 | | if (fields_len == 0) { |
| 28150 | | assert(body.len == 0); |
| 28151 | | return; |
| 28152 | | } |
| 28153 | 28147 | extra_index += body.len; |
| 28154 | 28148 | |
| 28155 | 28149 | const decl = mod.declPtr(decl_index); |
| ... | ... | @@ -28237,6 +28231,10 @@ fn semaUnionFields(mod: *Module, union_obj: *Module.Union) CompileError!void { |
| 28237 | 28231 | enum_field_names = &union_obj.tag_ty.castTag(.enum_simple).?.data.fields; |
| 28238 | 28232 | } |
| 28239 | 28233 | |
| 28234 | if (fields_len == 0) { |
| 28235 | return; |
| 28236 | } |
| 28237 | |
| 28240 | 28238 | const bits_per_field = 4; |
| 28241 | 28239 | const fields_per_u32 = 32 / bits_per_field; |
| 28242 | 28240 | const bit_bags_count = std.math.divCeil(usize, fields_len, fields_per_u32) catch unreachable; |
| ... | ... | @@ -28772,7 +28770,9 @@ pub fn typeHasOnePossibleValue( |
| 28772 | 28770 | const union_obj = resolved_ty.cast(Type.Payload.Union).?.data; |
| 28773 | 28771 | const tag_val = (try sema.typeHasOnePossibleValue(block, src, union_obj.tag_ty)) orelse |
| 28774 | 28772 | return null; |
| 28775 | | const only_field = union_obj.fields.values()[0]; |
| 28773 | const fields = union_obj.fields.values(); |
| 28774 | if (fields.len == 0) return Value.initTag(.empty_struct_value); |
| 28775 | const only_field = fields[0]; |
| 28776 | 28776 | if (only_field.ty.eql(resolved_ty, sema.mod)) { |
| 28777 | 28777 | const msg = try Module.ErrorMsg.create( |
| 28778 | 28778 | sema.gpa, |