Skip to content

Commit dcc406d

Browse files
committed
Add new error message for unreachable else prongs
* Adds error message for types: enum, int and bool * Adds compile error tests
1 parent e60be30 commit dcc406d

File tree

2 files changed

+113
-3
lines changed

2 files changed

+113
-3
lines changed

src/ir.cpp

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28700,6 +28700,10 @@ static IrInstGen *ir_analyze_instruction_check_switch_prongs(IrAnalyze *ira,
2870028700
buf_ptr(enum_field->name)));
2870128701
}
2870228702
}
28703+
} else if(!switch_type->data.enumeration.non_exhaustive && switch_type->data.enumeration.src_field_count == instruction->range_count) {
28704+
ir_add_error_node(ira, instruction->else_prong,
28705+
buf_sprintf("unreachable else prong, all cases already handled"));
28706+
return ira->codegen->invalid_inst_gen;
2870328707
}
2870428708
} else if (switch_type->id == ZigTypeIdErrorSet) {
2870528709
if (!resolve_inferred_error_set(ira->codegen, switch_type, target_value->base.source_node)) {
@@ -28808,16 +28812,20 @@ static IrInstGen *ir_analyze_instruction_check_switch_prongs(IrAnalyze *ira,
2880828812
return ira->codegen->invalid_inst_gen;
2880928813
}
2881028814
}
28811-
if (instruction->else_prong == nullptr) {
28815+
2881228816
BigInt min_val;
2881328817
eval_min_max_value_int(ira->codegen, switch_type, &min_val, false);
2881428818
BigInt max_val;
2881528819
eval_min_max_value_int(ira->codegen, switch_type, &max_val, true);
28816-
if (!rangeset_spans(&rs, &min_val, &max_val)) {
28820+
bool handles_all_cases = rangeset_spans(&rs, &min_val, &max_val);
28821+
if (!handles_all_cases && instruction->else_prong == nullptr) {
2881728822
ir_add_error(ira, &instruction->base.base, buf_sprintf("switch must handle all possibilities"));
2881828823
return ira->codegen->invalid_inst_gen;
28824+
} else if(handles_all_cases && instruction->else_prong != nullptr) {
28825+
ir_add_error_node(ira, instruction->else_prong,
28826+
buf_sprintf("unreachable else prong, all cases already handled"));
28827+
return ira->codegen->invalid_inst_gen;
2881928828
}
28820-
}
2882128829
} else if (switch_type->id == ZigTypeIdBool) {
2882228830
int seenTrue = 0;
2882328831
int seenFalse = 0;
@@ -28851,6 +28859,12 @@ static IrInstGen *ir_analyze_instruction_check_switch_prongs(IrAnalyze *ira,
2885128859
ir_add_error(ira, &instruction->base.base, buf_sprintf("switch must handle all possibilities"));
2885228860
return ira->codegen->invalid_inst_gen;
2885328861
}
28862+
28863+
if(seenTrue == 1 && seenFalse == 1 && instruction->else_prong != nullptr) {
28864+
ir_add_error_node(ira, instruction->else_prong,
28865+
buf_sprintf("unreachable else prong, all cases already handled"));
28866+
return ira->codegen->invalid_inst_gen;
28867+
}
2885428868
} else if (instruction->else_prong == nullptr) {
2885528869
ir_add_error(ira, &instruction->base.base,
2885628870
buf_sprintf("else prong required when switching on type '%s'", buf_ptr(&switch_type->name)));

test/compile_errors.zig

Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -468,6 +468,102 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
468468
"tmp.zig:12:5: error: switch on non-exhaustive enum must include `else` or `_` prong",
469469
});
470470

471+
cases.add("switch expression - unreachable else prong (bool)",
472+
\\fn foo(x: bool) void {
473+
\\ switch (x) {
474+
\\ true => {},
475+
\\ false => {},
476+
\\ else => {},
477+
\\ }
478+
\\}
479+
\\export fn entry() usize { return @sizeOf(@TypeOf(foo)); }
480+
, &[_][]const u8{
481+
"tmp.zig:5:9: error: unreachable else prong, all cases already handled",
482+
});
483+
484+
cases.add("switch expression - unreachable else prong (u1)",
485+
\\fn foo(x: u1) void {
486+
\\ switch (x) {
487+
\\ 0 => {},
488+
\\ 1 => {},
489+
\\ else => {},
490+
\\ }
491+
\\}
492+
\\export fn entry() usize { return @sizeOf(@TypeOf(foo)); }
493+
, &[_][]const u8{
494+
"tmp.zig:5:9: error: unreachable else prong, all cases already handled",
495+
});
496+
497+
cases.add("switch expression - unreachable else prong (u2)",
498+
\\fn foo(x: u2) void {
499+
\\ switch (x) {
500+
\\ 0 => {},
501+
\\ 1 => {},
502+
\\ 2 => {},
503+
\\ 3 => {},
504+
\\ else => {},
505+
\\ }
506+
\\}
507+
\\export fn entry() usize { return @sizeOf(@TypeOf(foo)); }
508+
, &[_][]const u8{
509+
"tmp.zig:7:9: error: unreachable else prong, all cases already handled",
510+
});
511+
512+
cases.add("switch expression - unreachable else prong (range u8)",
513+
\\fn foo(x: u8) void {
514+
\\ switch (x) {
515+
\\ 0 => {},
516+
\\ 1 => {},
517+
\\ 2 => {},
518+
\\ 3 => {},
519+
\\ 4...255 => {},
520+
\\ else => {},
521+
\\ }
522+
\\}
523+
\\export fn entry() usize { return @sizeOf(@TypeOf(foo)); }
524+
, &[_][]const u8{
525+
"tmp.zig:8:9: error: unreachable else prong, all cases already handled",
526+
});
527+
528+
cases.add("switch expression - unreachable else prong (range i8)",
529+
\\fn foo(x: i8) void {
530+
\\ switch (x) {
531+
\\ -128...0 => {},
532+
\\ 1 => {},
533+
\\ 2 => {},
534+
\\ 3 => {},
535+
\\ 4...127 => {},
536+
\\ else => {},
537+
\\ }
538+
\\}
539+
\\export fn entry() usize { return @sizeOf(@TypeOf(foo)); }
540+
, &[_][]const u8{
541+
"tmp.zig:8:9: error: unreachable else prong, all cases already handled",
542+
});
543+
544+
cases.add("switch expression - unreachable else prong (enum)",
545+
\\const TestEnum = enum{ T1, T2 };
546+
\\
547+
\\fn err(x: u8) TestEnum {
548+
\\ switch (x) {
549+
\\ 0 => return TestEnum.T1,
550+
\\ else => return TestEnum.T2,
551+
\\ }
552+
\\}
553+
\\
554+
\\fn foo(x: u8) void {
555+
\\ switch (err(x)) {
556+
\\ TestEnum.T1 => {},
557+
\\ TestEnum.T2 => {},
558+
\\ else => {},
559+
\\ }
560+
\\}
561+
\\
562+
\\export fn entry() usize { return @sizeOf(@TypeOf(foo)); }
563+
, &[_][]const u8{
564+
"tmp.zig:14:9: error: unreachable else prong, all cases already handled",
565+
});
566+
471567
cases.addTest("@export with empty name string",
472568
\\pub export fn entry() void { }
473569
\\comptime {

0 commit comments

Comments
 (0)