authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-03-31 18:38:26-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-03-31 18:39:34-07:00
loge8143f6cbe3d1bdaeda5cd5af13447f6639b80ad
tree954e032848a0abb638e1e0af45dc4ec3114e8f3e
parentcec766f73c298d287c20d1bd830c159958fe177d

stage2: compile error for duplicate switch value on sparse


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

BRANCH_TODO-13
...@@ -36,16 +36,3 @@ Performance optimizations to look into:...@@ -36,16 +36,3 @@ Performance optimizations to look into:
36 * look into not emitting redundant dbg stmts to TZIR36 * look into not emitting redundant dbg stmts to TZIR
37 * make decl references in ZIR be u32 indexes to the Decl dependencies array hash map37 * make decl references in ZIR be u32 indexes to the Decl dependencies array hash map
38 instead of duplicating *Decl entries in zir.Code.38 instead of duplicating *Decl entries in zir.Code.
39
40
41 for (inst.positionals.items) |item| {
42 const resolved = try sema.resolveInst(item);
43 const casted = try sema.coerce(block, operand.ty, resolved);
44 const val = try sema.resolveConstValue(block, item_src, casted);
45
46 if (try seen_values.fetchPut(val, item.src)) |prev| {
47 return sema.mod.fail(&block.base, item.src, "duplicate switch value", .{});
48 // TODO notes "previous value here" prev.value
49 }
50 }
51
src/Sema.zig+11-6
...@@ -62,8 +62,6 @@ const LazySrcLoc = Module.LazySrcLoc;...@@ -62,8 +62,6 @@ const LazySrcLoc = Module.LazySrcLoc;
62const RangeSet = @import("RangeSet.zig");62const RangeSet = @import("RangeSet.zig");
63const AstGen = @import("AstGen.zig");63const AstGen = @import("AstGen.zig");
6464
65const ValueSrcMap = std.HashMap(Value, LazySrcLoc, Value.hash, Value.eql, std.hash_map.DefaultMaxLoadPercentage);
66
67pub fn root(sema: *Sema, root_block: *Scope.Block) !zir.Inst.Index {65pub fn root(sema: *Sema, root_block: *Scope.Block) !zir.Inst.Index {
68 const inst_data = sema.code.instructions.items(.data)[0].pl_node;66 const inst_data = sema.code.instructions.items(.data)[0].pl_node;
69 const extra = sema.code.extraData(zir.Inst.Block, inst_data.payload_index);67 const extra = sema.code.extraData(zir.Inst.Block, inst_data.payload_index);
...@@ -2557,7 +2555,7 @@ fn analyzeSwitch(...@@ -2557,7 +2555,7 @@ fn analyzeSwitch(
25572555
2558 var extra_index: usize = special.end;2556 var extra_index: usize = special.end;
2559 {2557 {
2560 var scalar_i: usize = 0;2558 var scalar_i: u32 = 0;
2561 while (scalar_i < scalar_cases_len) : (scalar_i += 1) {2559 while (scalar_i < scalar_cases_len) : (scalar_i += 1) {
2562 const item_ref = @intToEnum(zir.Inst.Ref, sema.code.extra[extra_index]);2560 const item_ref = @intToEnum(zir.Inst.Ref, sema.code.extra[extra_index]);
2563 extra_index += 1;2561 extra_index += 1;
...@@ -2571,11 +2569,12 @@ fn analyzeSwitch(...@@ -2571,11 +2569,12 @@ fn analyzeSwitch(
2571 &seen_values,2569 &seen_values,
2572 item_ref,2570 item_ref,
2573 src_node_offset,2571 src_node_offset,
2572 .{ .scalar = scalar_i },
2574 );2573 );
2575 }2574 }
2576 }2575 }
2577 {2576 {
2578 var multi_i: usize = 0;2577 var multi_i: u32 = 0;
2579 while (multi_i < multi_cases_len) : (multi_i += 1) {2578 while (multi_i < multi_cases_len) : (multi_i += 1) {
2580 const items_len = sema.code.extra[extra_index];2579 const items_len = sema.code.extra[extra_index];
2581 extra_index += 1;2580 extra_index += 1;
...@@ -2586,12 +2585,13 @@ fn analyzeSwitch(...@@ -2586,12 +2585,13 @@ fn analyzeSwitch(
2586 const items = sema.code.refSlice(extra_index, items_len);2585 const items = sema.code.refSlice(extra_index, items_len);
2587 extra_index += items_len + body_len;2586 extra_index += items_len + body_len;
25882587
2589 for (items) |item_ref| {2588 for (items) |item_ref, item_i| {
2590 try sema.validateSwitchItemSparse(2589 try sema.validateSwitchItemSparse(
2591 block,2590 block,
2592 &seen_values,2591 &seen_values,
2593 item_ref,2592 item_ref,
2594 src_node_offset,2593 src_node_offset,
2594 .{ .multi = .{ .prong = multi_i, .item = @intCast(u32, item_i) } },
2595 );2595 );
2596 }2596 }
25972597
...@@ -2981,14 +2981,19 @@ fn validateSwitchItemBool(...@@ -2981,14 +2981,19 @@ fn validateSwitchItemBool(
2981 }2981 }
2982}2982}
29832983
2984const ValueSrcMap = std.HashMap(Value, AstGen.SwitchProngSrc, Value.hash, Value.eql, std.hash_map.DefaultMaxLoadPercentage);
2985
2984fn validateSwitchItemSparse(2986fn validateSwitchItemSparse(
2985 sema: *Sema,2987 sema: *Sema,
2986 block: *Scope.Block,2988 block: *Scope.Block,
2987 seen_values: *ValueSrcMap,2989 seen_values: *ValueSrcMap,
2988 item_ref: zir.Inst.Ref,2990 item_ref: zir.Inst.Ref,
2989 src_node_offset: i32,2991 src_node_offset: i32,
2992 switch_prong_src: AstGen.SwitchProngSrc,
2990) InnerError!void {2993) InnerError!void {
2991 @panic("TODO");2994 const item_val = try sema.resolveSwitchItemVal(block, item_ref, src_node_offset, switch_prong_src, .none);
2995 const entry = (try seen_values.fetchPut(item_val, switch_prong_src)) orelse return;
2996 return sema.validateSwitchDupe(block, entry.value, switch_prong_src, src_node_offset);
2992}2997}
29932998
2994fn validateSwitchNoRange(2999fn validateSwitchNoRange(
test/stage2/cbe.zig+16
...@@ -359,6 +359,22 @@ pub fn addCases(ctx: *TestContext) !void {...@@ -359,6 +359,22 @@ pub fn addCases(ctx: *TestContext) !void {
359 , &.{359 , &.{
360 ":6:9: error: duplicate switch value",360 ":6:9: error: duplicate switch value",
361 });361 });
362
363 // Sparse (no range capable) switch expression has duplicate case value.
364 case.addError(
365 \\export fn main() c_int {
366 \\ const A: type = i32;
367 \\ const b: c_int = switch (A) {
368 \\ i32 => 1,
369 \\ bool => 2,
370 \\ f64, i32 => 3,
371 \\ else => 4,
372 \\ };
373 \\}
374 , &.{
375 ":6:14: error: duplicate switch value",
376 ":4:9: note: previous value here",
377 });
362 }378 }
363 //{379 //{
364 // var case = ctx.exeFromCompiledC("optionals", .{});380 // var case = ctx.exeFromCompiledC("optionals", .{});