authorgravatar for thatlemon@gmail.comLemonBoy <thatlemon@gmail.com> 2019-09-23 11:14:36+02:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2019-09-23 16:13:28-04:00
logdb988f42a7ac1ce0ec65fde0e7ea94009b1d7238
tree540a7ffaffbb430b9b8e440c06f9ebbcb5fef06e
parent53ae03ebe9e0aa56bca1c9219a47d124b0435258

Fix computation of switch coverage

Closes #3258

3 files changed, 63 insertions(+), 49 deletions(-)

src/range_set.cpp+41-49
......@@ -4,8 +4,12 @@ AstNode *rangeset_add_range(RangeSet *rs, BigInt *first, BigInt *last, AstNode *
44 for (size_t i = 0; i < rs->src_range_list.length; i += 1) {
55 RangeWithSrc *range_with_src = &rs->src_range_list.at(i);
66 Range *range = &range_with_src->range;
7 if ((bigint_cmp(first, &range->first) != CmpLT && bigint_cmp(first, &range->last) != CmpGT) ||
8 (bigint_cmp(last, &range->first) != CmpLT && bigint_cmp(last, &range->last) != CmpGT))
7 if ((bigint_cmp(first, &range->first) == CmpLT && bigint_cmp(last, &range->first) == CmpLT) ||
8 (bigint_cmp(first, &range->last) == CmpGT && bigint_cmp(last, &range->last) == CmpGT))
9 {
10 // first...last is completely before/after `range`
11 }
12 else
913 {
1014 return range_with_src->source_node;
1115 }
......@@ -16,64 +20,52 @@ AstNode *rangeset_add_range(RangeSet *rs, BigInt *first, BigInt *last, AstNode *
1620
1721}
1822
19static bool add_range(ZigList<Range> *list, Range *new_range, BigInt *one) {
20 for (size_t i = 0; i < list->length; i += 1) {
21 Range *range = &list->at(i);
22
23 BigInt first_minus_one;
24 bigint_sub(&first_minus_one, &range->first, one);
25
26 if (bigint_cmp(&new_range->last, &first_minus_one) == CmpEQ) {
27 range->first = new_range->first;
28 return true;
29 }
30
31 BigInt last_plus_one;
32 bigint_add(&last_plus_one, &range->last, one);
23static int compare_rangeset(const void *a, const void *b) {
24 const Range *r1 = &static_cast<const RangeWithSrc*>(a)->range;
25 const Range *r2 = &static_cast<const RangeWithSrc*>(b)->range;
26 // Assume no two ranges overlap
27 switch (bigint_cmp(&r1->first, &r2->first)) {
28 case CmpLT: return -1;
29 case CmpGT: return 1;
30 case CmpEQ: return 0;
31 }
32 zig_unreachable();
33}
3334
34 if (bigint_cmp(&new_range->first, &last_plus_one) == CmpEQ) {
35 range->last = new_range->last;
36 return true;
37 }
35void rangeset_sort(RangeSet *rs) {
36 if (rs->src_range_list.length > 1) {
37 qsort(rs->src_range_list.items, rs->src_range_list.length,
38 sizeof(RangeWithSrc), compare_rangeset);
3839 }
39 list->append({new_range->first, new_range->last});
40 return false;
4140}
4241
4342bool rangeset_spans(RangeSet *rs, BigInt *first, BigInt *last) {
44 ZigList<Range> cur_list_value = {0};
45 ZigList<Range> other_list_value = {0};
46 ZigList<Range> *cur_list = &cur_list_value;
47 ZigList<Range> *other_list = &other_list_value;
43 rangeset_sort(rs);
4844
49 for (size_t i = 0; i < rs->src_range_list.length; i += 1) {
50 RangeWithSrc *range_with_src = &rs->src_range_list.at(i);
51 Range *range = &range_with_src->range;
52 cur_list->append({range->first, range->last});
53 }
45 const Range *first_range = &rs->src_range_list.at(0).range;
46 if (bigint_cmp(&first_range->first, first) != CmpEQ)
47 return false;
48
49 const Range *last_range = &rs->src_range_list.last().range;
50 if (bigint_cmp(&last_range->last, last) != CmpEQ)
51 return false;
5452
5553 BigInt one;
5654 bigint_init_unsigned(&one, 1);
5755
58 bool changes_made = true;
59 while (changes_made) {
60 changes_made = false;
61 for (size_t cur_i = 0; cur_i < cur_list->length; cur_i += 1) {
62 Range *range = &cur_list->at(cur_i);
63 changes_made = add_range(other_list, range, &one) || changes_made;
64 }
65 ZigList<Range> *tmp = cur_list;
66 cur_list = other_list;
67 other_list = tmp;
68 other_list->resize(0);
56 // Make sure there are no holes in the first...last range
57 for (size_t i = 1; i < rs->src_range_list.length; i++) {
58 const Range *range = &rs->src_range_list.at(i).range;
59 const Range *prev_range = &rs->src_range_list.at(i - 1).range;
60
61 assert(bigint_cmp(&prev_range->last, &range->first) == CmpLT);
62
63 BigInt last_plus_one;
64 bigint_add(&last_plus_one, &prev_range->last, &one);
65
66 if (bigint_cmp(&last_plus_one, &range->first) != CmpEQ)
67 return false;
6968 }
7069
71 if (cur_list->length != 1)
72 return false;
73 Range *range = &cur_list->at(0);
74 if (bigint_cmp(&range->first, first) != CmpEQ)
75 return false;
76 if (bigint_cmp(&range->last, last) != CmpEQ)
77 return false;
7870 return true;
7971}
test/compile_errors.zig+13
......@@ -2,6 +2,19 @@ const tests = @import("tests.zig");
22const builtin = @import("builtin");
33
44pub fn addCases(cases: *tests.CompileErrorContext) void {
5 cases.add(
6 "switch with overlapping case ranges",
7 \\export fn entry() void {
8 \\ var q: u8 = 0;
9 \\ switch (q) {
10 \\ 1...2 => {},
11 \\ 0...255 => {},
12 \\ }
13 \\}
14 ,
15 "tmp.zig:5:9: error: duplicate switch value",
16 );
17
518 cases.add(
619 "attempt to negate a non-integer, non-float or non-vector type",
720 \\fn foo() anyerror!u32 {
test/stage1/behavior/switch.zig+9
......@@ -425,3 +425,12 @@ test "switch prongs with cases with identical payload types" {
425425 S.doTheTest();
426426 comptime S.doTheTest();
427427}
428
429test "switch with disjoint range" {
430 var q: u8 = 0;
431 switch (q) {
432 0...125 => {},
433 127...255 => {},
434 126...126 => {},
435 }
436}