aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/Sema.zig23
-rw-r--r--src/type.zig21
-rw-r--r--test/behavior/empty_union.zig18
3 files changed, 42 insertions, 20 deletions
diff --git a/src/Sema.zig b/src/Sema.zig
index 849b0053ac..d7fce06e7f 100644
--- a/src/Sema.zig
+++ b/src/Sema.zig
@@ -10343,6 +10343,9 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
}
if (err_set) try sema.maybeErrorUnwrapComptime(&child_block, special.body, operand);
if (special.is_inline) child_block.inline_case_capture = operand;
+ if (empty_enum) {
+ return Air.Inst.Ref.void_value;
+ }
return sema.resolveBlockBody(block, src, &child_block, special.body, inst, merges);
}
@@ -30479,23 +30482,23 @@ pub fn typeHasOnePossibleValue(
if (enum_obj.tag_ty.hasRuntimeBits()) {
return null;
}
- if (enum_obj.fields.count() == 1) {
- if (enum_obj.values.count() == 0) {
+ switch (enum_obj.fields.count()) {
+ 0 => return Value.initTag(.unreachable_value),
+ 1 => if (enum_obj.values.count() == 0) {
return Value.zero; // auto-numbered
} else {
return enum_obj.values.keys()[0];
- }
- } else {
- return null;
+ },
+ else => return null,
}
},
.enum_simple => {
const resolved_ty = try sema.resolveTypeFields(block, src, ty);
const enum_simple = resolved_ty.castTag(.enum_simple).?.data;
- if (enum_simple.fields.count() == 1) {
- return Value.zero;
- } else {
- return null;
+ switch (enum_simple.fields.count()) {
+ 0 => return Value.initTag(.unreachable_value),
+ 1 => return Value.zero,
+ else => return null,
}
},
.enum_nonexhaustive => {
@@ -30512,7 +30515,7 @@ pub fn typeHasOnePossibleValue(
const tag_val = (try sema.typeHasOnePossibleValue(block, src, union_obj.tag_ty)) orelse
return null;
const fields = union_obj.fields.values();
- if (fields.len == 0) return Value.initTag(.empty_struct_value);
+ if (fields.len == 0) return Value.initTag(.unreachable_value);
const only_field = fields[0];
if (only_field.ty.eql(resolved_ty, sema.mod)) {
const msg = try Module.ErrorMsg.create(
diff --git a/src/type.zig b/src/type.zig
index a12733cbcb..605e4396c0 100644
--- a/src/type.zig
+++ b/src/type.zig
@@ -5015,22 +5015,22 @@ pub const Type = extern union {
if (enum_full.tag_ty.hasRuntimeBits()) {
return null;
}
- if (enum_full.fields.count() == 1) {
- if (enum_full.values.count() == 0) {
- return Value.zero;
+ switch (enum_full.fields.count()) {
+ 0 => return Value.initTag(.unreachable_value),
+ 1 => if (enum_full.values.count() == 0) {
+ return Value.zero; // auto-numbered
} else {
return enum_full.values.keys()[0];
- }
- } else {
- return null;
+ },
+ else => return null,
}
},
.enum_simple => {
const enum_simple = ty.castTag(.enum_simple).?.data;
- if (enum_simple.fields.count() == 1) {
- return Value.zero;
- } else {
- return null;
+ switch (enum_simple.fields.count()) {
+ 0 => return Value.initTag(.unreachable_value),
+ 1 => return Value.zero,
+ else => return null,
}
},
.enum_nonexhaustive => {
@@ -5044,6 +5044,7 @@ pub const Type = extern union {
.@"union", .union_safety_tagged, .union_tagged => {
const union_obj = ty.cast(Payload.Union).?.data;
const tag_val = union_obj.tag_ty.onePossibleValue() orelse return null;
+ if (union_obj.fields.count() == 0) return Value.initTag(.unreachable_value);
const only_field = union_obj.fields.values()[0];
const val_val = only_field.ty.onePossibleValue() orelse return null;
_ = tag_val;
diff --git a/test/behavior/empty_union.zig b/test/behavior/empty_union.zig
index 55dac727e8..c91fa16d0c 100644
--- a/test/behavior/empty_union.zig
+++ b/test/behavior/empty_union.zig
@@ -48,3 +48,21 @@ test "empty extern union" {
try expect(@sizeOf(U) == 0);
try expect(@alignOf(U) == 1);
}
+
+test "empty union passed as argument" {
+ const U = union(enum) {
+ fn f(u: @This()) void {
+ switch (u) {}
+ }
+ };
+ U.f(@as(U, undefined));
+}
+
+test "empty enum passed as argument" {
+ const E = enum {
+ fn f(e: @This()) void {
+ switch (e) {}
+ }
+ };
+ E.f(@as(E, undefined));
+}