Skip to content

Commit c464ecf

Browse files
authored
Merge pull request #1857 from vegecode/boolean-switch
Switching on bools with duplicate and missing value detection: Issue …
2 parents aaef625 + 64061cc commit c464ecf

File tree

3 files changed

+108
-0
lines changed

3 files changed

+108
-0
lines changed

src/ir.cpp

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -232,3 +232,40 @@ test "capture value of switch with all unreachable prongs" {
232232
};
233233
assert(x == 1);
234234
}
235+
236+
test "switching on booleans" {
237+
testSwitchOnBools();
238+
comptime testSwitchOnBools();
239+
}
240+
241+
fn 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+
252+
fn testSwitchOnBoolsTrueAndFalse(x: bool) bool {
253+
return switch (x) {
254+
true => false,
255+
false => true,
256+
};
257+
}
258+
259+
fn testSwitchOnBoolsTrueWithElse(x: bool) bool {
260+
return switch (x) {
261+
true => false,
262+
else => true,
263+
};
264+
}
265+
266+
fn testSwitchOnBoolsFalseWithElse(x: bool) bool {
267+
return switch (x) {
268+
false => true,
269+
else => false,
270+
};
271+
}

test/compile_errors.zig

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,44 @@
11
const tests = @import("tests.zig");
22

33
pub 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 {

0 commit comments

Comments
 (0)