authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2018-12-27 18:14:33-05:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2018-12-27 18:14:33-05:00
logc464ecf3bf6d764ad06a20f10efc386e26fb7fa2
tree158d169774098e271771c9462b86fb68a10c6990
parentaaef6259c32ff43be912c31f70e005170ee86efd
parent64061cc1bfb8e925d20f5824aa178b61eb2e5f11
signature Signed by PGP key 4AEE18F83AFDEB23

Merge pull request #1857 from vegecode/boolean-switch

Switching on bools with duplicate and missing value detection: Issue …

3 files changed, 108 insertions(+), 0 deletions(-)

src/ir.cpp+33
......@@ -19787,6 +19787,39 @@ static IrInstruction *ir_analyze_instruction_check_switch_prongs(IrAnalyze *ira,
1978719787 return ira->codegen->invalid_instruction;
1978819788 }
1978919789 }
19790 } else if (switch_type->id == ZigTypeIdBool) {
19791 int seenTrue = 0;
19792 int seenFalse = 0;
19793 for (size_t range_i = 0; range_i < instruction->range_count; range_i += 1) {
19794 IrInstructionCheckSwitchProngsRange *range = &instruction->ranges[range_i];
19795
19796 IrInstruction *value = range->start->child;
19797
19798 IrInstruction *casted_value = ir_implicit_cast(ira, value, switch_type);
19799 if (type_is_invalid(casted_value->value.type))
19800 return ira->codegen->invalid_instruction;
19801
19802 ConstExprValue *const_expr_val = ir_resolve_const(ira, casted_value, UndefBad);
19803 if (!const_expr_val)
19804 return ira->codegen->invalid_instruction;
19805
19806 assert(const_expr_val->type->id == ZigTypeIdBool);
19807
19808 if (const_expr_val->data.x_bool == true) {
19809 seenTrue += 1;
19810 } else {
19811 seenFalse += 1;
19812 }
19813
19814 if ((seenTrue > 1) || (seenFalse > 1)) {
19815 ir_add_error(ira, value, buf_sprintf("duplicate switch value"));
19816 return ira->codegen->invalid_instruction;
19817 }
19818 }
19819 if (((seenTrue < 1) || (seenFalse < 1)) && !instruction->have_else_prong) {
19820 ir_add_error(ira, &instruction->base, buf_sprintf("switch must handle all possibilities"));
19821 return ira->codegen->invalid_instruction;
19822 }
1979019823 } else if (!instruction->have_else_prong) {
1979119824 ir_add_error(ira, &instruction->base,
1979219825 buf_sprintf("else prong required when switching on type '%s'", buf_ptr(&switch_type->name)));
test/cases/switch.zig+37
......@@ -232,3 +232,40 @@ test "capture value of switch with all unreachable prongs" {
232232 };
233233 assert(x == 1);
234234}
235
236test "switching on booleans" {
237 testSwitchOnBools();
238 comptime testSwitchOnBools();
239}
240
241fn testSwitchOnBools() void {
242 assert(testSwitchOnBoolsTrueAndFalse(true) == false);
243 assert(testSwitchOnBoolsTrueAndFalse(false) == true);
244
245 assert(testSwitchOnBoolsTrueWithElse(true) == false);
246 assert(testSwitchOnBoolsTrueWithElse(false) == true);
247
248 assert(testSwitchOnBoolsFalseWithElse(true) == false);
249 assert(testSwitchOnBoolsFalseWithElse(false) == true);
250}
251
252fn testSwitchOnBoolsTrueAndFalse(x: bool) bool {
253 return switch (x) {
254 true => false,
255 false => true,
256 };
257}
258
259fn testSwitchOnBoolsTrueWithElse(x: bool) bool {
260 return switch (x) {
261 true => false,
262 else => true,
263 };
264}
265
266fn testSwitchOnBoolsFalseWithElse(x: bool) bool {
267 return switch (x) {
268 false => true,
269 else => false,
270 };
271}
test/compile_errors.zig+38
......@@ -1,6 +1,44 @@
11const tests = @import("tests.zig");
22
33pub fn addCases(cases: *tests.CompileErrorContext) void {
4 cases.add(
5 "duplicate boolean switch value",
6 \\comptime {
7 \\ const x = switch (true) {
8 \\ true => false,
9 \\ false => true,
10 \\ true => false,
11 \\ };
12 \\}
13 \\comptime {
14 \\ const x = switch (true) {
15 \\ false => true,
16 \\ true => false,
17 \\ false => true,
18 \\ };
19 \\}
20 ,
21 ".tmp_source.zig:5:9: error: duplicate switch value",
22 ".tmp_source.zig:12:9: error: duplicate switch value",
23 );
24
25 cases.add(
26 "missing boolean switch value",
27 \\comptime {
28 \\ const x = switch (true) {
29 \\ true => false,
30 \\ };
31 \\}
32 \\comptime {
33 \\ const x = switch (true) {
34 \\ false => true,
35 \\ };
36 \\}
37 ,
38 ".tmp_source.zig:2:15: error: switch must handle all possibilities",
39 ".tmp_source.zig:7:15: error: switch must handle all possibilities",
40 );
41
442 cases.add(
543 "reading past end of pointer casted array",
644 \\comptime {