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