Merge pull request #1857 from vegecode/boolean-switch

Switching on bools with duplicate and missing value detection: Issue …
This commit is contained in:
Andrew Kelley 2018-12-27 18:14:33 -05:00 committed by GitHub
commit c464ecf3bf
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 108 additions and 0 deletions

View File

@ -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)));

View File

@ -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,
};
}

View File

@ -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 {