commit c464ecf3bf6d764ad06a20f10efc386e26fb7fa2 (tree)
parent aaef6259c32ff43be912c31f70e005170ee86efd
Author: Andrew Kelley <andrew@ziglang.org>
Date: Thu, 27 Dec 2018 18:14:33 -0500
Merge pull request #1857 from vegecode/boolean-switch
Switching on bools with duplicate and missing value detection: Issue …
Diffstat:
3 files changed, 108 insertions(+), 0 deletions(-)
diff --git 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)));
diff --git 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
@@ -2,6 +2,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 {
\\ const array = "aoeu";