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 @@...@@ -1,7 +1,6 @@
1this is my WIP branch scratch pad, to be deleted before merging into master1this is my WIP branch scratch pad, to be deleted before merging into master
22
3Merge TODO list:3Merge TODO list:
4 * uncomment the commented out stage2 tests
5 * remove the LazySrcLoc.todo tag4 * remove the LazySrcLoc.todo tag
6 * update astgen.zig5 * update astgen.zig
7 * finish updating Sema.zig6 * finish updating Sema.zig
...@@ -38,17 +37,6 @@ Performance optimizations to look into:...@@ -38,17 +37,6 @@ Performance optimizations to look into:
38 * 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
39 instead of duplicating *Decl entries in zir.Code.38 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
53 for (inst.positionals.items) |item| {41 for (inst.positionals.items) |item| {
54 const resolved = try sema.resolveInst(item);42 const resolved = try sema.resolveInst(item);
src/AstGen.zig+3-1
...@@ -2551,13 +2551,15 @@ pub const SwitchProngSrc = union(enum) {...@@ -2551,13 +2551,15 @@ pub const SwitchProngSrc = union(enum) {
2551 item: u32,2551 item: u32,
2552 };2552 };
25532553
2554 pub const RangeExpand = enum { none, first, last };
2555
2554 /// This function is intended to be called only when it is certain that we need2556 /// This function is intended to be called only when it is certain that we need
2555 /// the LazySrcLoc in order to emit a compile error.2557 /// the LazySrcLoc in order to emit a compile error.
2556 pub fn resolve(2558 pub fn resolve(
2557 prong_src: SwitchProngSrc,2559 prong_src: SwitchProngSrc,
2558 decl: *Decl,2560 decl: *Decl,
2559 switch_node_offset: i32,2561 switch_node_offset: i32,
2560 range_expand: enum { none, first, last },2562 range_expand: RangeExpand,
2561 ) LazySrcLoc {2563 ) LazySrcLoc {
2562 @setCold(true);2564 @setCold(true);
2563 const switch_node = decl.relativeToNodeIndex(switch_node_offset);2565 const switch_node = decl.relativeToNodeIndex(switch_node_offset);
src/Sema.zig+43-47
...@@ -2474,7 +2474,7 @@ fn analyzeSwitch(...@@ -2474,7 +2474,7 @@ fn analyzeSwitch(
24742474
2475 var extra_index: usize = special.end;2475 var extra_index: usize = special.end;
2476 {2476 {
2477 var scalar_i: usize = 0;2477 var scalar_i: u32 = 0;
2478 while (scalar_i < scalar_cases_len) : (scalar_i += 1) {2478 while (scalar_i < scalar_cases_len) : (scalar_i += 1) {
2479 const item_ref = @intToEnum(zir.Inst.Ref, sema.code.extra[extra_index]);2479 const item_ref = @intToEnum(zir.Inst.Ref, sema.code.extra[extra_index]);
2480 extra_index += 1;2480 extra_index += 1;
...@@ -2489,11 +2489,12 @@ fn analyzeSwitch(...@@ -2489,11 +2489,12 @@ fn analyzeSwitch(
2489 &false_count,2489 &false_count,
2490 item_ref,2490 item_ref,
2491 src_node_offset,2491 src_node_offset,
2492 .{ .scalar = scalar_i },
2492 );2493 );
2493 }2494 }
2494 }2495 }
2495 {2496 {
2496 var multi_i: usize = 0;2497 var multi_i: u32 = 0;
2497 while (multi_i < multi_cases_len) : (multi_i += 1) {2498 while (multi_i < multi_cases_len) : (multi_i += 1) {
2498 const items_len = sema.code.extra[extra_index];2499 const items_len = sema.code.extra[extra_index];
2499 extra_index += 1;2500 extra_index += 1;
...@@ -2504,13 +2505,14 @@ fn analyzeSwitch(...@@ -2504,13 +2505,14 @@ fn analyzeSwitch(
2504 const items = sema.code.refSlice(extra_index, items_len);2505 const items = sema.code.refSlice(extra_index, items_len);
2505 extra_index += items_len + body_len;2506 extra_index += items_len + body_len;
25062507
2507 for (items) |item_ref| {2508 for (items) |item_ref, item_i| {
2508 try sema.validateSwitchItemBool(2509 try sema.validateSwitchItemBool(
2509 block,2510 block,
2510 &true_count,2511 &true_count,
2511 &false_count,2512 &false_count,
2512 item_ref,2513 item_ref,
2513 src_node_offset,2514 src_node_offset,
2515 .{ .multi = .{ .prong = multi_i, .item = @intCast(u32, item_i) } },
2514 );2516 );
2515 }2517 }
25162518
...@@ -2877,6 +2879,29 @@ fn analyzeSwitch(...@@ -2877,6 +2879,29 @@ fn analyzeSwitch(
2877 return sema.analyzeBlockBody(block, &child_block, merges);2879 return sema.analyzeBlockBody(block, &child_block, merges);
2878}2880}
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
2880fn validateSwitchRange(2905fn validateSwitchRange(
2881 sema: *Sema,2906 sema: *Sema,
2882 block: *Scope.Block,2907 block: *Scope.Block,
...@@ -2886,33 +2911,8 @@ fn validateSwitchRange(...@@ -2886,33 +2911,8 @@ fn validateSwitchRange(
2886 src_node_offset: i32,2911 src_node_offset: i32,
2887 switch_prong_src: AstGen.SwitchProngSrc,2912 switch_prong_src: AstGen.SwitchProngSrc,
2888) InnerError!void {2913) InnerError!void {
2889 const first = try sema.resolveInst(first_ref);2914 const first_val = try sema.resolveSwitchItemVal(block, first_ref, src_node_offset, switch_prong_src, .first);
2890 const last = try sema.resolveInst(last_ref);2915 const last_val = try sema.resolveSwitchItemVal(block, last_ref, src_node_offset, switch_prong_src, .last);
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 };
2916 const maybe_prev_src = try range_set.add(first_val, last_val, switch_prong_src);2916 const maybe_prev_src = try range_set.add(first_val, last_val, switch_prong_src);
2917 return sema.validateSwitchDupe(block, maybe_prev_src, switch_prong_src, src_node_offset);2917 return sema.validateSwitchDupe(block, maybe_prev_src, switch_prong_src, src_node_offset);
2918}2918}
...@@ -2925,22 +2925,8 @@ fn validateSwitchItem(...@@ -2925,22 +2925,8 @@ fn validateSwitchItem(
2925 src_node_offset: i32,2925 src_node_offset: i32,
2926 switch_prong_src: AstGen.SwitchProngSrc,2926 switch_prong_src: AstGen.SwitchProngSrc,
2927) InnerError!void {2927) InnerError!void {
2928 const item = try sema.resolveInst(item_ref);2928 const item_val = try sema.resolveSwitchItemVal(block, item_ref, src_node_offset, switch_prong_src, .none);
2929 // We have to avoid the helper functions here because we cannot construct a LazySrcLoc2929 const maybe_prev_src = try range_set.add(item_val, item_val, switch_prong_src);
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);
2944 return sema.validateSwitchDupe(block, maybe_prev_src, switch_prong_src, src_node_offset);2930 return sema.validateSwitchDupe(block, maybe_prev_src, switch_prong_src, src_node_offset);
2945}2931}
29462932
...@@ -2981,8 +2967,18 @@ fn validateSwitchItemBool(...@@ -2981,8 +2967,18 @@ fn validateSwitchItemBool(
2981 false_count: *u8,2967 false_count: *u8,
2982 item_ref: zir.Inst.Ref,2968 item_ref: zir.Inst.Ref,
2983 src_node_offset: i32,2969 src_node_offset: i32,
2970 switch_prong_src: AstGen.SwitchProngSrc,
2984) InnerError!void {2971) 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 }
2986}2982}
29872983
2988fn validateSwitchItemSparse(2984fn validateSwitchItemSparse(
test/stage2/cbe.zig+15-1
...@@ -327,7 +327,7 @@ pub fn addCases(ctx: *TestContext) !void {...@@ -327,7 +327,7 @@ pub fn addCases(ctx: *TestContext) !void {
327 \\}327 \\}
328 , "");328 , "");
329329
330 // Switch expression has duplicate case value.330 // Integer switch expression has duplicate case value.
331 case.addError(331 case.addError(
332 \\export fn main() c_int {332 \\export fn main() c_int {
333 \\ var cond: c_int = 0;333 \\ var cond: c_int = 0;
...@@ -345,6 +345,20 @@ pub fn addCases(ctx: *TestContext) !void {...@@ -345,6 +345,20 @@ pub fn addCases(ctx: *TestContext) !void {
345 ":8:13: error: duplicate switch value",345 ":8:13: error: duplicate switch value",
346 ":6:15: note: previous value here",346 ":6:15: note: previous value here",
347 });347 });
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 });
348 }362 }
349 //{363 //{
350 // var case = ctx.exeFromCompiledC("optionals", .{});364 // var case = ctx.exeFromCompiledC("optionals", .{});