authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-04-07 22:19:17-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-04-07 22:19:17-07:00
log57aa289fdef543a507d8da039f5b7e7f2762c878
tree1e8f3c072f2c004554880cd23e53337bbc24a39b
parente730172e47749db8a9d3be5949231bde95343b39

Sema: fix switch validation '_' prong on wrong type


3 files changed, 50 insertions(+), 4 deletions(-)

src/Sema.zig+2-2
...@@ -1972,7 +1972,7 @@ fn zirIntToEnum(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerErr...@@ -1972,7 +1972,7 @@ fn zirIntToEnum(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerErr
1972 return mod.fail(&block.base, dest_ty_src, "expected enum, found {}", .{dest_ty});1972 return mod.fail(&block.base, dest_ty_src, "expected enum, found {}", .{dest_ty});
1973 }1973 }
19741974
1975 if (!dest_ty.isExhaustiveEnum()) {1975 if (dest_ty.isNonexhaustiveEnum()) {
1976 if (operand.value()) |int_val| {1976 if (operand.value()) |int_val| {
1977 return mod.constInst(arena, src, .{1977 return mod.constInst(arena, src, .{
1978 .ty = dest_ty,1978 .ty = dest_ty,
...@@ -2762,7 +2762,7 @@ fn analyzeSwitch(...@@ -2762,7 +2762,7 @@ fn analyzeSwitch(
2762 const operand_src: LazySrcLoc = .{ .node_offset_switch_operand = src_node_offset };2762 const operand_src: LazySrcLoc = .{ .node_offset_switch_operand = src_node_offset };
27632763
2764 // Validate usage of '_' prongs.2764 // Validate usage of '_' prongs.
2765 if (special_prong == .under and !operand.ty.isExhaustiveEnum()) {2765 if (special_prong == .under and !operand.ty.isNonexhaustiveEnum()) {
2766 const msg = msg: {2766 const msg = msg: {
2767 const msg = try mod.errMsg(2767 const msg = try mod.errMsg(
2768 &block.base,2768 &block.base,
src/type.zig+2-2
...@@ -2119,9 +2119,9 @@ pub const Type = extern union {...@@ -2119,9 +2119,9 @@ pub const Type = extern union {
2119 }2119 }
2120 }2120 }
21212121
2122 pub fn isExhaustiveEnum(ty: Type) bool {2122 pub fn isNonexhaustiveEnum(ty: Type) bool {
2123 return switch (ty.tag()) {2123 return switch (ty.tag()) {
2124 .enum_full, .enum_simple => true,2124 .enum_nonexhaustive => true,
2125 else => false,2125 else => false,
2126 };2126 };
2127 }2127 }
test/stage2/cbe.zig+46
...@@ -717,6 +717,52 @@ pub fn addCases(ctx: *TestContext) !void {...@@ -717,6 +717,52 @@ pub fn addCases(ctx: *TestContext) !void {
717 ":4:5: note: unhandled enumeration value: 'b'",717 ":4:5: note: unhandled enumeration value: 'b'",
718 ":1:11: note: enum 'E' declared here",718 ":1:11: note: enum 'E' declared here",
719 });719 });
720
721 case.addError(
722 \\const E = enum { a, b, c };
723 \\export fn foo() void {
724 \\ var x: E = .a;
725 \\ switch (x) {
726 \\ .a => {},
727 \\ .b => {},
728 \\ .b => {},
729 \\ .c => {},
730 \\ }
731 \\}
732 , &.{
733 ":7:10: error: duplicate switch value",
734 ":6:10: note: previous value here",
735 });
736
737 case.addError(
738 \\const E = enum { a, b, c };
739 \\export fn foo() void {
740 \\ var x: E = .a;
741 \\ switch (x) {
742 \\ .a => {},
743 \\ .b => {},
744 \\ .c => {},
745 \\ else => {},
746 \\ }
747 \\}
748 , &.{
749 ":8:14: error: unreachable else prong; all cases already handled",
750 });
751
752 case.addError(
753 \\const E = enum { a, b, c };
754 \\export fn foo() void {
755 \\ var x: E = .a;
756 \\ switch (x) {
757 \\ .a => {},
758 \\ .b => {},
759 \\ _ => {},
760 \\ }
761 \\}
762 , &.{
763 ":4:5: error: '_' prong only allowed when switching on non-exhaustive enums",
764 ":7:11: note: '_' prong here",
765 });
720 }766 }
721767
722 ctx.c("empty start function", linux_x64,768 ctx.c("empty start function", linux_x64,