authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-07-19 18:39:48-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-07-19 18:39:48-07:00
log0efc6a35bead74b5faffbc87b446b5087f1bb99b
tree6b8eaabe33a371d366c0be57b76c57e458d963e4
parent1d5f865cfafdaa96cac35ada9bb9e8b1a4e2bc36

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.

2 files changed, 27 insertions(+), 19 deletions(-)

src/Sema.zig+9-19
...@@ -8378,9 +8378,12 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError...@@ -8378,9 +8378,12 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
8378 .Enum => {8378 .Enum => {
8379 var seen_fields = try gpa.alloc(?Module.SwitchProngSrc, operand_ty.enumFieldCount());8379 var seen_fields = try gpa.alloc(?Module.SwitchProngSrc, operand_ty.enumFieldCount());
8380 defer gpa.free(seen_fields);8380 defer gpa.free(seen_fields);
8381
8382 mem.set(?Module.SwitchProngSrc, seen_fields, null);8381 mem.set(?Module.SwitchProngSrc, seen_fields, null);
83838382
8383 // This is used for non-exhaustive enum values that do not correspond to any tags.
8384 var range_set = RangeSet.init(gpa, sema.mod);
8385 defer range_set.deinit();
8386
8384 var extra_index: usize = special.end;8387 var extra_index: usize = special.end;
8385 {8388 {
8386 var scalar_i: u32 = 0;8389 var scalar_i: u32 = 0;
...@@ -8394,6 +8397,7 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError...@@ -8394,6 +8397,7 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
8394 try sema.validateSwitchItemEnum(8397 try sema.validateSwitchItemEnum(
8395 block,8398 block,
8396 seen_fields,8399 seen_fields,
8400 &range_set,
8397 item_ref,8401 item_ref,
8398 src_node_offset,8402 src_node_offset,
8399 .{ .scalar = scalar_i },8403 .{ .scalar = scalar_i },
...@@ -8416,6 +8420,7 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError...@@ -8416,6 +8420,7 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
8416 try sema.validateSwitchItemEnum(8420 try sema.validateSwitchItemEnum(
8417 block,8421 block,
8418 seen_fields,8422 seen_fields,
8423 &range_set,
8419 item_ref,8424 item_ref,
8420 src_node_offset,8425 src_node_offset,
8421 .{ .multi = .{ .prong = multi_i, .item = @intCast(u32, item_i) } },8426 .{ .multi = .{ .prong = multi_i, .item = @intCast(u32, item_i) } },
...@@ -9317,30 +9322,15 @@ fn validateSwitchItemEnum(...@@ -9317,30 +9322,15 @@ fn validateSwitchItemEnum(
9317 sema: *Sema,9322 sema: *Sema,
9318 block: *Block,9323 block: *Block,
9319 seen_fields: []?Module.SwitchProngSrc,9324 seen_fields: []?Module.SwitchProngSrc,
9325 range_set: *RangeSet,
9320 item_ref: Zir.Inst.Ref,9326 item_ref: Zir.Inst.Ref,
9321 src_node_offset: i32,9327 src_node_offset: i32,
9322 switch_prong_src: Module.SwitchProngSrc,9328 switch_prong_src: Module.SwitchProngSrc,
9323) CompileError!void {9329) CompileError!void {
9324 const item_tv = try sema.resolveSwitchItemVal(block, item_ref, src_node_offset, switch_prong_src, .none);9330 const item_tv = try sema.resolveSwitchItemVal(block, item_ref, src_node_offset, switch_prong_src, .none);
9325 const field_index = item_tv.ty.enumTagFieldIndex(item_tv.val, sema.mod) orelse {9331 const field_index = item_tv.ty.enumTagFieldIndex(item_tv.val, sema.mod) orelse {
9326 const msg = msg: {9332 const maybe_prev_src = try range_set.add(item_tv.val, item_tv.val, item_tv.ty, switch_prong_src);
9327 const src = switch_prong_src.resolve(sema.gpa, sema.mod.declPtr(block.src_decl), src_node_offset, .none);9333 return sema.validateSwitchDupe(block, maybe_prev_src, switch_prong_src, src_node_offset);
9328 const msg = try sema.errMsg(
9329 block,
9330 src,
9331 "enum '{}' has no tag with value '{}'",
9332 .{ item_tv.ty.fmt(sema.mod), item_tv.val.fmtValue(item_tv.ty, sema.mod) },
9333 );
9334 errdefer msg.destroy(sema.gpa);
9335 try sema.mod.errNoteNonLazy(
9336 item_tv.ty.declSrcLoc(sema.mod),
9337 msg,
9338 "enum declared here",
9339 .{},
9340 );
9341 break :msg msg;
9342 };
9343 return sema.failWithOwnedErrorMsg(block, msg);
9344 };9334 };
9345 const maybe_prev_src = seen_fields[field_index];9335 const maybe_prev_src = seen_fields[field_index];
9346 seen_fields[field_index] = switch_prong_src;9336 seen_fields[field_index] = switch_prong_src;
test/behavior/switch.zig+18
...@@ -672,3 +672,21 @@ test "capture of integer forwards the switch condition directly" {...@@ -672,3 +672,21 @@ test "capture of integer forwards the switch condition directly" {
672 comptime try S.foo(42);672 comptime try S.foo(42);
673 comptime try S.foo(100);673 comptime try S.foo(100);
674}674}
675
676test "enum value without tag name used as switch item" {
677 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
678 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
679
680 const E = enum(u32) {
681 a = 1,
682 b = 2,
683 _,
684 };
685 var e: E = @intToEnum(E, 0);
686 switch (e) {
687 @intToEnum(E, 0) => {},
688 .a => return error.TestFailed,
689 .b => return error.TestFailed,
690 _ => return error.TestFailed,
691 }
692}