Sema: fix enum value without tag name used as switch item

Previously stage2 would report a false positive compile error saying there
was no tag for this value.
This commit is contained in:
Andrew Kelley 2022-07-19 18:39:48 -07:00
parent 1d5f865cfa
commit 0efc6a35be
2 changed files with 27 additions and 19 deletions

View File

@ -8378,9 +8378,12 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
.Enum => { .Enum => {
var seen_fields = try gpa.alloc(?Module.SwitchProngSrc, operand_ty.enumFieldCount()); var seen_fields = try gpa.alloc(?Module.SwitchProngSrc, operand_ty.enumFieldCount());
defer gpa.free(seen_fields); defer gpa.free(seen_fields);
mem.set(?Module.SwitchProngSrc, seen_fields, null); mem.set(?Module.SwitchProngSrc, seen_fields, null);
// This is used for non-exhaustive enum values that do not correspond to any tags.
var range_set = RangeSet.init(gpa, sema.mod);
defer range_set.deinit();
var extra_index: usize = special.end; var extra_index: usize = special.end;
{ {
var scalar_i: u32 = 0; var scalar_i: u32 = 0;
@ -8394,6 +8397,7 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
try sema.validateSwitchItemEnum( try sema.validateSwitchItemEnum(
block, block,
seen_fields, seen_fields,
&range_set,
item_ref, item_ref,
src_node_offset, src_node_offset,
.{ .scalar = scalar_i }, .{ .scalar = scalar_i },
@ -8416,6 +8420,7 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
try sema.validateSwitchItemEnum( try sema.validateSwitchItemEnum(
block, block,
seen_fields, seen_fields,
&range_set,
item_ref, item_ref,
src_node_offset, src_node_offset,
.{ .multi = .{ .prong = multi_i, .item = @intCast(u32, item_i) } }, .{ .multi = .{ .prong = multi_i, .item = @intCast(u32, item_i) } },
@ -9317,30 +9322,15 @@ fn validateSwitchItemEnum(
sema: *Sema, sema: *Sema,
block: *Block, block: *Block,
seen_fields: []?Module.SwitchProngSrc, seen_fields: []?Module.SwitchProngSrc,
range_set: *RangeSet,
item_ref: Zir.Inst.Ref, item_ref: Zir.Inst.Ref,
src_node_offset: i32, src_node_offset: i32,
switch_prong_src: Module.SwitchProngSrc, switch_prong_src: Module.SwitchProngSrc,
) CompileError!void { ) CompileError!void {
const item_tv = try sema.resolveSwitchItemVal(block, item_ref, src_node_offset, switch_prong_src, .none); const item_tv = try sema.resolveSwitchItemVal(block, item_ref, src_node_offset, switch_prong_src, .none);
const field_index = item_tv.ty.enumTagFieldIndex(item_tv.val, sema.mod) orelse { const field_index = item_tv.ty.enumTagFieldIndex(item_tv.val, sema.mod) orelse {
const msg = msg: { const maybe_prev_src = try range_set.add(item_tv.val, item_tv.val, item_tv.ty, switch_prong_src);
const src = switch_prong_src.resolve(sema.gpa, sema.mod.declPtr(block.src_decl), src_node_offset, .none); return sema.validateSwitchDupe(block, maybe_prev_src, switch_prong_src, src_node_offset);
const msg = try sema.errMsg(
block,
src,
"enum '{}' has no tag with value '{}'",
.{ item_tv.ty.fmt(sema.mod), item_tv.val.fmtValue(item_tv.ty, sema.mod) },
);
errdefer msg.destroy(sema.gpa);
try sema.mod.errNoteNonLazy(
item_tv.ty.declSrcLoc(sema.mod),
msg,
"enum declared here",
.{},
);
break :msg msg;
};
return sema.failWithOwnedErrorMsg(block, msg);
}; };
const maybe_prev_src = seen_fields[field_index]; const maybe_prev_src = seen_fields[field_index];
seen_fields[field_index] = switch_prong_src; seen_fields[field_index] = switch_prong_src;

View File

@ -672,3 +672,21 @@ test "capture of integer forwards the switch condition directly" {
comptime try S.foo(42); comptime try S.foo(42);
comptime try S.foo(100); comptime try S.foo(100);
} }
test "enum value without tag name used as switch item" {
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
const E = enum(u32) {
a = 1,
b = 2,
_,
};
var e: E = @intToEnum(E, 0);
switch (e) {
@intToEnum(E, 0) => {},
.a => return error.TestFailed,
.b => return error.TestFailed,
_ => return error.TestFailed,
}
}