@@ -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,
0 commit comments