authorgravatar for git@vexu.euVeikka Tuominen <git@vexu.eu> 2022-11-04 18:38:42+02:00
committergravatar for git@vexu.euVeikka Tuominen <git@vexu.eu> 2022-11-04 23:13:50+02:00
log51b1083d66b29d110c8cf60b59052170dd34a95f
tree4d2d18a6358c4a3ce3a2957d101dbc793b3d37d3
parent42db468dcb3de15426f9f8ec8da78e36155e3510

stage2: fix onePossibleValue of empty unions and enums

Closes #13402

3 files changed, 42 insertions(+), 20 deletions(-)

src/Sema.zig+13-10
......@@ -10343,6 +10343,9 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
1034310343 }
1034410344 if (err_set) try sema.maybeErrorUnwrapComptime(&child_block, special.body, operand);
1034510345 if (special.is_inline) child_block.inline_case_capture = operand;
10346 if (empty_enum) {
10347 return Air.Inst.Ref.void_value;
10348 }
1034610349 return sema.resolveBlockBody(block, src, &child_block, special.body, inst, merges);
1034710350 }
1034810351
......@@ -30479,23 +30482,23 @@ pub fn typeHasOnePossibleValue(
3047930482 if (enum_obj.tag_ty.hasRuntimeBits()) {
3048030483 return null;
3048130484 }
30482 if (enum_obj.fields.count() == 1) {
30483 if (enum_obj.values.count() == 0) {
30485 switch (enum_obj.fields.count()) {
30486 0 => return Value.initTag(.unreachable_value),
30487 1 => if (enum_obj.values.count() == 0) {
3048430488 return Value.zero; // auto-numbered
3048530489 } else {
3048630490 return enum_obj.values.keys()[0];
30487 }
30488 } else {
30489 return null;
30491 },
30492 else => return null,
3049030493 }
3049130494 },
3049230495 .enum_simple => {
3049330496 const resolved_ty = try sema.resolveTypeFields(block, src, ty);
3049430497 const enum_simple = resolved_ty.castTag(.enum_simple).?.data;
30495 if (enum_simple.fields.count() == 1) {
30496 return Value.zero;
30497 } else {
30498 return null;
30498 switch (enum_simple.fields.count()) {
30499 0 => return Value.initTag(.unreachable_value),
30500 1 => return Value.zero,
30501 else => return null,
3049930502 }
3050030503 },
3050130504 .enum_nonexhaustive => {
......@@ -30512,7 +30515,7 @@ pub fn typeHasOnePossibleValue(
3051230515 const tag_val = (try sema.typeHasOnePossibleValue(block, src, union_obj.tag_ty)) orelse
3051330516 return null;
3051430517 const fields = union_obj.fields.values();
30515 if (fields.len == 0) return Value.initTag(.empty_struct_value);
30518 if (fields.len == 0) return Value.initTag(.unreachable_value);
3051630519 const only_field = fields[0];
3051730520 if (only_field.ty.eql(resolved_ty, sema.mod)) {
3051830521 const msg = try Module.ErrorMsg.create(
src/type.zig+11-10
......@@ -5015,22 +5015,22 @@ pub const Type = extern union {
50155015 if (enum_full.tag_ty.hasRuntimeBits()) {
50165016 return null;
50175017 }
5018 if (enum_full.fields.count() == 1) {
5019 if (enum_full.values.count() == 0) {
5020 return Value.zero;
5018 switch (enum_full.fields.count()) {
5019 0 => return Value.initTag(.unreachable_value),
5020 1 => if (enum_full.values.count() == 0) {
5021 return Value.zero; // auto-numbered
50215022 } else {
50225023 return enum_full.values.keys()[0];
5023 }
5024 } else {
5025 return null;
5024 },
5025 else => return null,
50265026 }
50275027 },
50285028 .enum_simple => {
50295029 const enum_simple = ty.castTag(.enum_simple).?.data;
5030 if (enum_simple.fields.count() == 1) {
5031 return Value.zero;
5032 } else {
5033 return null;
5030 switch (enum_simple.fields.count()) {
5031 0 => return Value.initTag(.unreachable_value),
5032 1 => return Value.zero,
5033 else => return null,
50345034 }
50355035 },
50365036 .enum_nonexhaustive => {
......@@ -5044,6 +5044,7 @@ pub const Type = extern union {
50445044 .@"union", .union_safety_tagged, .union_tagged => {
50455045 const union_obj = ty.cast(Payload.Union).?.data;
50465046 const tag_val = union_obj.tag_ty.onePossibleValue() orelse return null;
5047 if (union_obj.fields.count() == 0) return Value.initTag(.unreachable_value);
50475048 const only_field = union_obj.fields.values()[0];
50485049 const val_val = only_field.ty.onePossibleValue() orelse return null;
50495050 _ = tag_val;
test/behavior/empty_union.zig+18
......@@ -48,3 +48,21 @@ test "empty extern union" {
4848 try expect(@sizeOf(U) == 0);
4949 try expect(@alignOf(U) == 1);
5050}
51
52test "empty union passed as argument" {
53 const U = union(enum) {
54 fn f(u: @This()) void {
55 switch (u) {}
56 }
57 };
58 U.f(@as(U, undefined));
59}
60
61test "empty enum passed as argument" {
62 const E = enum {
63 fn f(e: @This()) void {
64 switch (e) {}
65 }
66 };
67 E.f(@as(E, undefined));
68}