Commit e8143f6cbe

Andrew Kelley <andrew@ziglang.org>
2021-04-01 03:38:26
stage2: compile error for duplicate switch value on sparse
1 parent cec766f
Changed files (3)
src/Sema.zig
@@ -62,8 +62,6 @@ const LazySrcLoc = Module.LazySrcLoc;
 const RangeSet = @import("RangeSet.zig");
 const AstGen = @import("AstGen.zig");
 
-const ValueSrcMap = std.HashMap(Value, LazySrcLoc, Value.hash, Value.eql, std.hash_map.DefaultMaxLoadPercentage);
-
 pub fn root(sema: *Sema, root_block: *Scope.Block) !zir.Inst.Index {
     const inst_data = sema.code.instructions.items(.data)[0].pl_node;
     const extra = sema.code.extraData(zir.Inst.Block, inst_data.payload_index);
@@ -2557,7 +2555,7 @@ fn analyzeSwitch(
 
             var extra_index: usize = special.end;
             {
-                var scalar_i: usize = 0;
+                var scalar_i: u32 = 0;
                 while (scalar_i < scalar_cases_len) : (scalar_i += 1) {
                     const item_ref = @intToEnum(zir.Inst.Ref, sema.code.extra[extra_index]);
                     extra_index += 1;
@@ -2571,11 +2569,12 @@ fn analyzeSwitch(
                         &seen_values,
                         item_ref,
                         src_node_offset,
+                        .{ .scalar = scalar_i },
                     );
                 }
             }
             {
-                var multi_i: usize = 0;
+                var multi_i: u32 = 0;
                 while (multi_i < multi_cases_len) : (multi_i += 1) {
                     const items_len = sema.code.extra[extra_index];
                     extra_index += 1;
@@ -2586,12 +2585,13 @@ fn analyzeSwitch(
                     const items = sema.code.refSlice(extra_index, items_len);
                     extra_index += items_len + body_len;
 
-                    for (items) |item_ref| {
+                    for (items) |item_ref, item_i| {
                         try sema.validateSwitchItemSparse(
                             block,
                             &seen_values,
                             item_ref,
                             src_node_offset,
+                            .{ .multi = .{ .prong = multi_i, .item = @intCast(u32, item_i) } },
                         );
                     }
 
@@ -2981,14 +2981,19 @@ fn validateSwitchItemBool(
     }
 }
 
+const ValueSrcMap = std.HashMap(Value, AstGen.SwitchProngSrc, Value.hash, Value.eql, std.hash_map.DefaultMaxLoadPercentage);
+
 fn validateSwitchItemSparse(
     sema: *Sema,
     block: *Scope.Block,
     seen_values: *ValueSrcMap,
     item_ref: zir.Inst.Ref,
     src_node_offset: i32,
+    switch_prong_src: AstGen.SwitchProngSrc,
 ) InnerError!void {
-    @panic("TODO");
+    const item_val = try sema.resolveSwitchItemVal(block, item_ref, src_node_offset, switch_prong_src, .none);
+    const entry = (try seen_values.fetchPut(item_val, switch_prong_src)) orelse return;
+    return sema.validateSwitchDupe(block, entry.value, switch_prong_src, src_node_offset);
 }
 
 fn validateSwitchNoRange(
test/stage2/cbe.zig
@@ -359,6 +359,22 @@ pub fn addCases(ctx: *TestContext) !void {
         , &.{
             ":6:9: error: duplicate switch value",
         });
+
+        // Sparse (no range capable) switch expression has duplicate case value.
+        case.addError(
+            \\export fn main() c_int {
+            \\    const A: type = i32;
+            \\    const b: c_int = switch (A) {
+            \\        i32 => 1,
+            \\        bool => 2,
+            \\        f64, i32 => 3,
+            \\        else => 4,
+            \\    };
+            \\}
+        , &.{
+            ":6:14: error: duplicate switch value",
+            ":4:9: note: previous value here",
+        });
     }
     //{
     //    var case = ctx.exeFromCompiledC("optionals", .{});
BRANCH_TODO
@@ -36,16 +36,3 @@ Performance optimizations to look into:
  * look into not emitting redundant dbg stmts to TZIR
  * make decl references in ZIR be u32 indexes to the Decl dependencies array hash map
    instead of duplicating *Decl entries in zir.Code.
-
-
-            for (inst.positionals.items) |item| {
-                const resolved = try sema.resolveInst(item);
-                const casted = try sema.coerce(block, operand.ty, resolved);
-                const val = try sema.resolveConstValue(block, item_src, casted);
-
-                if (try seen_values.fetchPut(val, item.src)) |prev| {
-                    return sema.mod.fail(&block.base, item.src, "duplicate switch value", .{});
-                    // TODO notes "previous value here" prev.value
-                }
-            }
-