Commit 57aa289fde

Andrew Kelley <andrew@ziglang.org>
2021-04-08 07:19:17
Sema: fix switch validation '_' prong on wrong type
1 parent e730172
Changed files (3)
src
test
stage2
src/Sema.zig
@@ -1972,7 +1972,7 @@ fn zirIntToEnum(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerErr
         return mod.fail(&block.base, dest_ty_src, "expected enum, found {}", .{dest_ty});
     }
 
-    if (!dest_ty.isExhaustiveEnum()) {
+    if (dest_ty.isNonexhaustiveEnum()) {
         if (operand.value()) |int_val| {
             return mod.constInst(arena, src, .{
                 .ty = dest_ty,
@@ -2762,7 +2762,7 @@ fn analyzeSwitch(
     const operand_src: LazySrcLoc = .{ .node_offset_switch_operand = src_node_offset };
 
     // Validate usage of '_' prongs.
-    if (special_prong == .under and !operand.ty.isExhaustiveEnum()) {
+    if (special_prong == .under and !operand.ty.isNonexhaustiveEnum()) {
         const msg = msg: {
             const msg = try mod.errMsg(
                 &block.base,
src/type.zig
@@ -2119,9 +2119,9 @@ pub const Type = extern union {
         }
     }
 
-    pub fn isExhaustiveEnum(ty: Type) bool {
+    pub fn isNonexhaustiveEnum(ty: Type) bool {
         return switch (ty.tag()) {
-            .enum_full, .enum_simple => true,
+            .enum_nonexhaustive => true,
             else => false,
         };
     }
test/stage2/cbe.zig
@@ -717,6 +717,52 @@ pub fn addCases(ctx: *TestContext) !void {
             ":4:5: note: unhandled enumeration value: 'b'",
             ":1:11: note: enum 'E' declared here",
         });
+
+        case.addError(
+            \\const E = enum { a, b, c };
+            \\export fn foo() void {
+            \\    var x: E = .a;
+            \\    switch (x) {
+            \\        .a => {},
+            \\        .b => {},
+            \\        .b => {},
+            \\        .c => {},
+            \\    }
+            \\}
+        , &.{
+            ":7:10: error: duplicate switch value",
+            ":6:10: note: previous value here",
+        });
+
+        case.addError(
+            \\const E = enum { a, b, c };
+            \\export fn foo() void {
+            \\    var x: E = .a;
+            \\    switch (x) {
+            \\        .a => {},
+            \\        .b => {},
+            \\        .c => {},
+            \\        else => {},
+            \\    }
+            \\}
+        , &.{
+            ":8:14: error: unreachable else prong; all cases already handled",
+        });
+
+        case.addError(
+            \\const E = enum { a, b, c };
+            \\export fn foo() void {
+            \\    var x: E = .a;
+            \\    switch (x) {
+            \\        .a => {},
+            \\        .b => {},
+            \\        _ => {},
+            \\    }
+            \\}
+        , &.{
+            ":4:5: error: '_' prong only allowed when switching on non-exhaustive enums",
+            ":7:11: note: '_' prong here",
+        });
     }
 
     ctx.c("empty start function", linux_x64,