authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-03-31 18:30:23-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-03-31 18:30:23-07:00
logcec766f73c298d287c20d1bd830c159958fe177d
tree6e7c247f87a472aff9f7c42b70da8aba5e40916b
parentfedc9ebd26175bf8309d665f3e1ee6769e8af86d

stage2: compile error for duplicate switch value on boolean


4 files changed, 61 insertions(+), 61 deletions(-)

BRANCH_TODO-12
......@@ -1,7 +1,6 @@
11this is my WIP branch scratch pad, to be deleted before merging into master
22
33Merge TODO list:
4 * uncomment the commented out stage2 tests
54 * remove the LazySrcLoc.todo tag
65 * update astgen.zig
76 * finish updating Sema.zig
......@@ -38,17 +37,6 @@ Performance optimizations to look into:
3837 * make decl references in ZIR be u32 indexes to the Decl dependencies array hash map
3938 instead of duplicating *Decl entries in zir.Code.
4039
41 const item = try sema.resolveInst(item_ref);
42 if ((try sema.resolveConstValue(block, item.src, item)).toBool()) {
43 true_count += 1;
44 } else {
45 false_count += 1;
46 }
47 if (true_count + false_count > 2) {
48 return sema.mod.fail(&block.base, item.src, "duplicate switch value", .{});
49 }
50
51
5240
5341 for (inst.positionals.items) |item| {
5442 const resolved = try sema.resolveInst(item);
src/AstGen.zig+3-1
......@@ -2551,13 +2551,15 @@ pub const SwitchProngSrc = union(enum) {
25512551 item: u32,
25522552 };
25532553
2554 pub const RangeExpand = enum { none, first, last };
2555
25542556 /// This function is intended to be called only when it is certain that we need
25552557 /// the LazySrcLoc in order to emit a compile error.
25562558 pub fn resolve(
25572559 prong_src: SwitchProngSrc,
25582560 decl: *Decl,
25592561 switch_node_offset: i32,
2560 range_expand: enum { none, first, last },
2562 range_expand: RangeExpand,
25612563 ) LazySrcLoc {
25622564 @setCold(true);
25632565 const switch_node = decl.relativeToNodeIndex(switch_node_offset);
src/Sema.zig+43-47
......@@ -2474,7 +2474,7 @@ fn analyzeSwitch(
24742474
24752475 var extra_index: usize = special.end;
24762476 {
2477 var scalar_i: usize = 0;
2477 var scalar_i: u32 = 0;
24782478 while (scalar_i < scalar_cases_len) : (scalar_i += 1) {
24792479 const item_ref = @intToEnum(zir.Inst.Ref, sema.code.extra[extra_index]);
24802480 extra_index += 1;
......@@ -2489,11 +2489,12 @@ fn analyzeSwitch(
24892489 &false_count,
24902490 item_ref,
24912491 src_node_offset,
2492 .{ .scalar = scalar_i },
24922493 );
24932494 }
24942495 }
24952496 {
2496 var multi_i: usize = 0;
2497 var multi_i: u32 = 0;
24972498 while (multi_i < multi_cases_len) : (multi_i += 1) {
24982499 const items_len = sema.code.extra[extra_index];
24992500 extra_index += 1;
......@@ -2504,13 +2505,14 @@ fn analyzeSwitch(
25042505 const items = sema.code.refSlice(extra_index, items_len);
25052506 extra_index += items_len + body_len;
25062507
2507 for (items) |item_ref| {
2508 for (items) |item_ref, item_i| {
25082509 try sema.validateSwitchItemBool(
25092510 block,
25102511 &true_count,
25112512 &false_count,
25122513 item_ref,
25132514 src_node_offset,
2515 .{ .multi = .{ .prong = multi_i, .item = @intCast(u32, item_i) } },
25142516 );
25152517 }
25162518
......@@ -2877,6 +2879,29 @@ fn analyzeSwitch(
28772879 return sema.analyzeBlockBody(block, &child_block, merges);
28782880}
28792881
2882fn resolveSwitchItemVal(
2883 sema: *Sema,
2884 block: *Scope.Block,
2885 item_ref: zir.Inst.Ref,
2886 switch_node_offset: i32,
2887 switch_prong_src: AstGen.SwitchProngSrc,
2888 range_expand: AstGen.SwitchProngSrc.RangeExpand,
2889) InnerError!Value {
2890 const item = try sema.resolveInst(item_ref);
2891 // We have to avoid the other helper functions here because we cannot construct a LazySrcLoc
2892 // because we only have the switch AST node. Only if we know for sure we need to report
2893 // a compile error do we resolve the full source locations.
2894 if (item.value()) |val| {
2895 if (val.isUndef()) {
2896 const src = switch_prong_src.resolve(block.src_decl, switch_node_offset, range_expand);
2897 return sema.failWithUseOfUndef(block, src);
2898 }
2899 return val;
2900 }
2901 const src = switch_prong_src.resolve(block.src_decl, switch_node_offset, range_expand);
2902 return sema.failWithNeededComptime(block, src);
2903}
2904
28802905fn validateSwitchRange(
28812906 sema: *Sema,
28822907 block: *Scope.Block,
......@@ -2886,33 +2911,8 @@ fn validateSwitchRange(
28862911 src_node_offset: i32,
28872912 switch_prong_src: AstGen.SwitchProngSrc,
28882913) InnerError!void {
2889 const first = try sema.resolveInst(first_ref);
2890 const last = try sema.resolveInst(last_ref);
2891 // We have to avoid the helper functions here because we cannot construct a LazySrcLoc
2892 // because we only have the switch AST node. Only if we know for sure we need to report
2893 // a compile error do we resolve the full source locations.
2894 const first_val = val: {
2895 if (first.value()) |val| {
2896 if (val.isUndef()) {
2897 const src = switch_prong_src.resolve(block.src_decl, src_node_offset, .first);
2898 return sema.failWithUseOfUndef(block, src);
2899 }
2900 break :val val;
2901 }
2902 const src = switch_prong_src.resolve(block.src_decl, src_node_offset, .first);
2903 return sema.failWithNeededComptime(block, src);
2904 };
2905 const last_val = val: {
2906 if (last.value()) |val| {
2907 if (val.isUndef()) {
2908 const src = switch_prong_src.resolve(block.src_decl, src_node_offset, .last);
2909 return sema.failWithUseOfUndef(block, src);
2910 }
2911 break :val val;
2912 }
2913 const src = switch_prong_src.resolve(block.src_decl, src_node_offset, .last);
2914 return sema.failWithNeededComptime(block, src);
2915 };
2914 const first_val = try sema.resolveSwitchItemVal(block, first_ref, src_node_offset, switch_prong_src, .first);
2915 const last_val = try sema.resolveSwitchItemVal(block, last_ref, src_node_offset, switch_prong_src, .last);
29162916 const maybe_prev_src = try range_set.add(first_val, last_val, switch_prong_src);
29172917 return sema.validateSwitchDupe(block, maybe_prev_src, switch_prong_src, src_node_offset);
29182918}
......@@ -2925,22 +2925,8 @@ fn validateSwitchItem(
29252925 src_node_offset: i32,
29262926 switch_prong_src: AstGen.SwitchProngSrc,
29272927) InnerError!void {
2928 const item = try sema.resolveInst(item_ref);
2929 // We have to avoid the helper functions here because we cannot construct a LazySrcLoc
2930 // because we only have the switch AST node. Only if we know for sure we need to report
2931 // a compile error do we resolve the full source locations.
2932 const value = val: {
2933 if (item.value()) |val| {
2934 if (val.isUndef()) {
2935 const src = switch_prong_src.resolve(block.src_decl, src_node_offset, .none);
2936 return sema.failWithUseOfUndef(block, src);
2937 }
2938 break :val val;
2939 }
2940 const src = switch_prong_src.resolve(block.src_decl, src_node_offset, .none);
2941 return sema.failWithNeededComptime(block, src);
2942 };
2943 const maybe_prev_src = try range_set.add(value, value, switch_prong_src);
2928 const item_val = try sema.resolveSwitchItemVal(block, item_ref, src_node_offset, switch_prong_src, .none);
2929 const maybe_prev_src = try range_set.add(item_val, item_val, switch_prong_src);
29442930 return sema.validateSwitchDupe(block, maybe_prev_src, switch_prong_src, src_node_offset);
29452931}
29462932
......@@ -2981,8 +2967,18 @@ fn validateSwitchItemBool(
29812967 false_count: *u8,
29822968 item_ref: zir.Inst.Ref,
29832969 src_node_offset: i32,
2970 switch_prong_src: AstGen.SwitchProngSrc,
29842971) InnerError!void {
2985 @panic("TODO");
2972 const item_val = try sema.resolveSwitchItemVal(block, item_ref, src_node_offset, switch_prong_src, .none);
2973 if (item_val.toBool()) {
2974 true_count.* += 1;
2975 } else {
2976 false_count.* += 1;
2977 }
2978 if (true_count.* + false_count.* > 2) {
2979 const src = switch_prong_src.resolve(block.src_decl, src_node_offset, .none);
2980 return sema.mod.fail(&block.base, src, "duplicate switch value", .{});
2981 }
29862982}
29872983
29882984fn validateSwitchItemSparse(
test/stage2/cbe.zig+15-1
......@@ -327,7 +327,7 @@ pub fn addCases(ctx: *TestContext) !void {
327327 \\}
328328 , "");
329329
330 // Switch expression has duplicate case value.
330 // Integer switch expression has duplicate case value.
331331 case.addError(
332332 \\export fn main() c_int {
333333 \\ var cond: c_int = 0;
......@@ -345,6 +345,20 @@ pub fn addCases(ctx: *TestContext) !void {
345345 ":8:13: error: duplicate switch value",
346346 ":6:15: note: previous value here",
347347 });
348
349 // Boolean switch expression has duplicate case value.
350 case.addError(
351 \\export fn main() c_int {
352 \\ var a: bool = false;
353 \\ const b: c_int = switch (a) {
354 \\ false => 1,
355 \\ true => 2,
356 \\ false => 3,
357 \\ };
358 \\}
359 , &.{
360 ":6:9: error: duplicate switch value",
361 });
348362 }
349363 //{
350364 // var case = ctx.exeFromCompiledC("optionals", .{});