From 4a1f0e141893fe56f540709c8fb12b8b8dc22218 Mon Sep 17 00:00:00 2001 From: alexander Date: Wed, 26 Dec 2018 10:31:45 -0600 Subject: [PATCH 1/2] Switching on bools with duplicate and missing value detection: Issue 1768 --- src/ir.cpp | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/src/ir.cpp b/src/ir.cpp index 83960f2eee..b1429ae8ac 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -19787,6 +19787,39 @@ static IrInstruction *ir_analyze_instruction_check_switch_prongs(IrAnalyze *ira, return ira->codegen->invalid_instruction; } } + } else if (switch_type->id == ZigTypeIdBool) { + int seenTrue = 0; + int seenFalse = 0; + for (size_t range_i = 0; range_i < instruction->range_count; range_i += 1) { + IrInstructionCheckSwitchProngsRange *range = &instruction->ranges[range_i]; + + IrInstruction *value = range->start->child; + + IrInstruction *casted_value = ir_implicit_cast(ira, value, switch_type); + if (type_is_invalid(casted_value->value.type)) + return ira->codegen->invalid_instruction; + + ConstExprValue *const_expr_val = ir_resolve_const(ira, casted_value, UndefBad); + if (!const_expr_val) + return ira->codegen->invalid_instruction; + + assert(const_expr_val->type->id == ZigTypeIdBool); + + if (const_expr_val->data.x_bool == true) { + seenTrue += 1; + } else { + seenFalse += 1; + } + + if ((seenTrue > 1) || (seenFalse > 1)) { + ir_add_error(ira, value, buf_sprintf("duplicate switch value")); + return ira->codegen->invalid_instruction; + } + } + if (((seenTrue < 1) || (seenFalse < 1)) && !instruction->have_else_prong) { + ir_add_error(ira, &instruction->base, buf_sprintf("switch must handle all possibilities")); + return ira->codegen->invalid_instruction; + } } else if (!instruction->have_else_prong) { ir_add_error(ira, &instruction->base, buf_sprintf("else prong required when switching on type '%s'", buf_ptr(&switch_type->name))); From 64061cc1bfb8e925d20f5824aa178b61eb2e5f11 Mon Sep 17 00:00:00 2001 From: alexander Date: Thu, 27 Dec 2018 13:46:32 -0600 Subject: [PATCH 2/2] Test cases for compiler error and working behavior for switching on booleans --- test/cases/switch.zig | 37 +++++++++++++++++++++++++++++++++++++ test/compile_errors.zig | 38 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 75 insertions(+) diff --git a/test/cases/switch.zig b/test/cases/switch.zig index d5258f0bb1..1162fdd4b2 100644 --- a/test/cases/switch.zig +++ b/test/cases/switch.zig @@ -232,3 +232,40 @@ test "capture value of switch with all unreachable prongs" { }; assert(x == 1); } + +test "switching on booleans" { + testSwitchOnBools(); + comptime testSwitchOnBools(); +} + +fn testSwitchOnBools() void { + assert(testSwitchOnBoolsTrueAndFalse(true) == false); + assert(testSwitchOnBoolsTrueAndFalse(false) == true); + + assert(testSwitchOnBoolsTrueWithElse(true) == false); + assert(testSwitchOnBoolsTrueWithElse(false) == true); + + assert(testSwitchOnBoolsFalseWithElse(true) == false); + assert(testSwitchOnBoolsFalseWithElse(false) == true); +} + +fn testSwitchOnBoolsTrueAndFalse(x: bool) bool { + return switch (x) { + true => false, + false => true, + }; +} + +fn testSwitchOnBoolsTrueWithElse(x: bool) bool { + return switch (x) { + true => false, + else => true, + }; +} + +fn testSwitchOnBoolsFalseWithElse(x: bool) bool { + return switch (x) { + false => true, + else => false, + }; +} diff --git a/test/compile_errors.zig b/test/compile_errors.zig index ee3741ee6b..880a96a322 100644 --- a/test/compile_errors.zig +++ b/test/compile_errors.zig @@ -1,6 +1,44 @@ const tests = @import("tests.zig"); pub fn addCases(cases: *tests.CompileErrorContext) void { + cases.add( + "duplicate boolean switch value", + \\comptime { + \\ const x = switch (true) { + \\ true => false, + \\ false => true, + \\ true => false, + \\ }; + \\} + \\comptime { + \\ const x = switch (true) { + \\ false => true, + \\ true => false, + \\ false => true, + \\ }; + \\} + , + ".tmp_source.zig:5:9: error: duplicate switch value", + ".tmp_source.zig:12:9: error: duplicate switch value", + ); + + cases.add( + "missing boolean switch value", + \\comptime { + \\ const x = switch (true) { + \\ true => false, + \\ }; + \\} + \\comptime { + \\ const x = switch (true) { + \\ false => true, + \\ }; + \\} + , + ".tmp_source.zig:2:15: error: switch must handle all possibilities", + ".tmp_source.zig:7:15: error: switch must handle all possibilities", + ); + cases.add( "reading past end of pointer casted array", \\comptime {