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...@@ -10343,6 +10343,9 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
10343 }10343 }
10344 if (err_set) try sema.maybeErrorUnwrapComptime(&child_block, special.body, operand);10344 if (err_set) try sema.maybeErrorUnwrapComptime(&child_block, special.body, operand);
10345 if (special.is_inline) child_block.inline_case_capture = operand;10345 if (special.is_inline) child_block.inline_case_capture = operand;
10346 if (empty_enum) {
10347 return Air.Inst.Ref.void_value;
10348 }
10346 return sema.resolveBlockBody(block, src, &child_block, special.body, inst, merges);10349 return sema.resolveBlockBody(block, src, &child_block, special.body, inst, merges);
10347 }10350 }
1034810351
...@@ -30479,23 +30482,23 @@ pub fn typeHasOnePossibleValue(...@@ -30479,23 +30482,23 @@ pub fn typeHasOnePossibleValue(
30479 if (enum_obj.tag_ty.hasRuntimeBits()) {30482 if (enum_obj.tag_ty.hasRuntimeBits()) {
30480 return null;30483 return null;
30481 }30484 }
30482 if (enum_obj.fields.count() == 1) {30485 switch (enum_obj.fields.count()) {
30483 if (enum_obj.values.count() == 0) {30486 0 => return Value.initTag(.unreachable_value),
30487 1 => if (enum_obj.values.count() == 0) {
30484 return Value.zero; // auto-numbered30488 return Value.zero; // auto-numbered
30485 } else {30489 } else {
30486 return enum_obj.values.keys()[0];30490 return enum_obj.values.keys()[0];
30487 }30491 },
30488 } else {30492 else => return null,
30489 return null;
30490 }30493 }
30491 },30494 },
30492 .enum_simple => {30495 .enum_simple => {
30493 const resolved_ty = try sema.resolveTypeFields(block, src, ty);30496 const resolved_ty = try sema.resolveTypeFields(block, src, ty);
30494 const enum_simple = resolved_ty.castTag(.enum_simple).?.data;30497 const enum_simple = resolved_ty.castTag(.enum_simple).?.data;
30495 if (enum_simple.fields.count() == 1) {30498 switch (enum_simple.fields.count()) {
30496 return Value.zero;30499 0 => return Value.initTag(.unreachable_value),
30497 } else {30500 1 => return Value.zero,
30498 return null;30501 else => return null,
30499 }30502 }
30500 },30503 },
30501 .enum_nonexhaustive => {30504 .enum_nonexhaustive => {
...@@ -30512,7 +30515,7 @@ pub fn typeHasOnePossibleValue(...@@ -30512,7 +30515,7 @@ pub fn typeHasOnePossibleValue(
30512 const tag_val = (try sema.typeHasOnePossibleValue(block, src, union_obj.tag_ty)) orelse30515 const tag_val = (try sema.typeHasOnePossibleValue(block, src, union_obj.tag_ty)) orelse
30513 return null;30516 return null;
30514 const fields = union_obj.fields.values();30517 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);
30516 const only_field = fields[0];30519 const only_field = fields[0];
30517 if (only_field.ty.eql(resolved_ty, sema.mod)) {30520 if (only_field.ty.eql(resolved_ty, sema.mod)) {
30518 const msg = try Module.ErrorMsg.create(30521 const msg = try Module.ErrorMsg.create(
src/type.zig+11-10
...@@ -5015,22 +5015,22 @@ pub const Type = extern union {...@@ -5015,22 +5015,22 @@ pub const Type = extern union {
5015 if (enum_full.tag_ty.hasRuntimeBits()) {5015 if (enum_full.tag_ty.hasRuntimeBits()) {
5016 return null;5016 return null;
5017 }5017 }
5018 if (enum_full.fields.count() == 1) {5018 switch (enum_full.fields.count()) {
5019 if (enum_full.values.count() == 0) {5019 0 => return Value.initTag(.unreachable_value),
5020 return Value.zero;5020 1 => if (enum_full.values.count() == 0) {
5021 return Value.zero; // auto-numbered
5021 } else {5022 } else {
5022 return enum_full.values.keys()[0];5023 return enum_full.values.keys()[0];
5023 }5024 },
5024 } else {5025 else => return null,
5025 return null;
5026 }5026 }
5027 },5027 },
5028 .enum_simple => {5028 .enum_simple => {
5029 const enum_simple = ty.castTag(.enum_simple).?.data;5029 const enum_simple = ty.castTag(.enum_simple).?.data;
5030 if (enum_simple.fields.count() == 1) {5030 switch (enum_simple.fields.count()) {
5031 return Value.zero;5031 0 => return Value.initTag(.unreachable_value),
5032 } else {5032 1 => return Value.zero,
5033 return null;5033 else => return null,
5034 }5034 }
5035 },5035 },
5036 .enum_nonexhaustive => {5036 .enum_nonexhaustive => {
...@@ -5044,6 +5044,7 @@ pub const Type = extern union {...@@ -5044,6 +5044,7 @@ pub const Type = extern union {
5044 .@"union", .union_safety_tagged, .union_tagged => {5044 .@"union", .union_safety_tagged, .union_tagged => {
5045 const union_obj = ty.cast(Payload.Union).?.data;5045 const union_obj = ty.cast(Payload.Union).?.data;
5046 const tag_val = union_obj.tag_ty.onePossibleValue() orelse return null;5046 const tag_val = union_obj.tag_ty.onePossibleValue() orelse return null;
5047 if (union_obj.fields.count() == 0) return Value.initTag(.unreachable_value);
5047 const only_field = union_obj.fields.values()[0];5048 const only_field = union_obj.fields.values()[0];
5048 const val_val = only_field.ty.onePossibleValue() orelse return null;5049 const val_val = only_field.ty.onePossibleValue() orelse return null;
5049 _ = tag_val;5050 _ = tag_val;
test/behavior/empty_union.zig+18
...@@ -48,3 +48,21 @@ test "empty extern union" {...@@ -48,3 +48,21 @@ test "empty extern union" {
48 try expect(@sizeOf(U) == 0);48 try expect(@sizeOf(U) == 0);
49 try expect(@alignOf(U) == 1);49 try expect(@alignOf(U) == 1);
50}50}
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}