Skip to content

Commit 6b4426a

Browse files
committed
Splitting variable-length slices now respects the required invariant
The previous behaviour did not respect the invariant specified in the description of the algorithm. As a nice side-effect, exhaustiveness errors have improved when slice_patterns is enabled; they now capture all missing lengths instead of the shortest. Note: this changes diagnostics, but only when slice_patterns is enabled.
1 parent 0c0fe9f commit 6b4426a

File tree

5 files changed

+42
-31
lines changed

5 files changed

+42
-31
lines changed

src/librustc_mir/hair/pattern/_match.rs

Lines changed: 21 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -596,7 +596,7 @@ enum Constructor<'tcx> {
596596
impl<'tcx> Constructor<'tcx> {
597597
fn is_slice(&self) -> bool {
598598
match self {
599-
FixedLenSlice { .. } => true,
599+
FixedLenSlice(..) | VarLenSlice(..) => true,
600600
_ => false,
601601
}
602602
}
@@ -792,12 +792,16 @@ impl<'tcx> Constructor<'tcx> {
792792
//
793793
// Of course, if fixed-length patterns exist, we must be sure
794794
// that our length is large enough to miss them all, so
795-
// we can pick `L = max(FIXED_LEN+1 ∪ {max(PREFIX_LEN) + max(SUFFIX_LEN)})`
795+
// we can pick `L = max(max(FIXED_LEN)+1, max(PREFIX_LEN) + max(SUFFIX_LEN))`
796796
//
797797
// For example, with the above pair of patterns, all elements
798798
// but the first and last can be added/removed, so any
799799
// witness of length ≥2 (say, `[false, false, true]`) can be
800800
// turned to a witness from any other length ≥2.
801+
//
802+
// For diagnostics, we keep the prefix and suffix lengths separate, so in the case
803+
// where `max(FIXED_LEN)+1` is the largest, we adapt `max(PREFIX_LEN)` accordingly,
804+
// so that `max(PREFIX_LEN) + max(SUFFIX_LEN) = L`.
801805

802806
let mut max_prefix_len = self_prefix;
803807
let mut max_suffix_len = self_suffix;
@@ -829,9 +833,14 @@ impl<'tcx> Constructor<'tcx> {
829833
}
830834
}
831835

832-
let max_slice_length = cmp::max(max_fixed_len + 1, max_prefix_len + max_suffix_len);
836+
if max_fixed_len + 1 >= max_prefix_len + max_suffix_len {
837+
max_prefix_len = cmp::max(max_prefix_len, max_fixed_len + 1 - max_suffix_len);
838+
}
833839

834-
(self_prefix + self_suffix..=max_slice_length).map(FixedLenSlice).collect()
840+
(self_prefix + self_suffix..max_prefix_len + max_suffix_len)
841+
.map(FixedLenSlice)
842+
.chain(Some(VarLenSlice(max_prefix_len, max_suffix_len)))
843+
.collect()
835844
}
836845
Wildcard => {
837846
let is_declared_nonexhaustive =
@@ -1020,7 +1029,8 @@ impl<'tcx> Constructor<'tcx> {
10201029
Start => self_len,
10211030
Boundary(n) => n + 1,
10221031
};
1023-
remaining_ctors.push(VarLenSlice(final_length, 0));
1032+
// We know final_length >= self_len >= self_suffix
1033+
remaining_ctors.push(VarLenSlice(final_length - self_suffix, self_suffix));
10241034
}
10251035

10261036
remaining_ctors
@@ -1194,19 +1204,20 @@ impl<'tcx> Constructor<'tcx> {
11941204
FixedLenSlice(_) => {
11951205
PatKind::Slice { prefix: pats.collect(), slice: None, suffix: vec![] }
11961206
}
1197-
VarLenSlice(_, _) => match ty.kind {
1207+
VarLenSlice(prefix_len, _suffix_len) => match ty.kind {
11981208
ty::Slice(ty) | ty::Array(ty, _) => {
1199-
let prefix = pats.collect();
12001209
if cx.tcx.features().slice_patterns {
1210+
let prefix = pats.by_ref().take(*prefix_len as usize).collect();
1211+
let suffix = pats.collect();
12011212
let wild = Pat { ty, span: DUMMY_SP, kind: Box::new(PatKind::Wild) };
1202-
PatKind::Slice { prefix, slice: Some(wild), suffix: vec![] }
1213+
PatKind::Slice { prefix, slice: Some(wild), suffix }
12031214
} else {
12041215
// We don't want to output a variable-length slice pattern if the
12051216
// slice_patterns feature is not enabled.
12061217
// The constructor covers infinitely many slice lengths, but for diagnostic
12071218
// purposes it is correct to return only some examples of non-covered
12081219
// patterns. So we just return the smallest length pattern here.
1209-
PatKind::Slice { prefix, slice: None, suffix: vec![] }
1220+
PatKind::Slice { prefix: pats.collect(), slice: None, suffix: vec![] }
12101221
}
12111222
}
12121223
_ => bug!("bad slice pattern {:?} {:?}", self, ty),
@@ -2159,7 +2170,7 @@ fn specialize_one_pattern<'p, 'a: 'p, 'p2: 'p, 'tcx>(
21592170

21602171
PatKind::Array { ref prefix, ref slice, ref suffix }
21612172
| PatKind::Slice { ref prefix, ref slice, ref suffix } => match *constructor {
2162-
FixedLenSlice(..) => {
2173+
FixedLenSlice(..) | VarLenSlice(..) => {
21632174
let pat_len = prefix.len() + suffix.len();
21642175
if let Some(slice_count) = ctor_wild_subpatterns.len().checked_sub(pat_len) {
21652176
if slice_count == 0 || slice.is_some() {

src/test/ui/pattern/usefulness/match-slice-patterns.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
fn check(list: &[Option<()>]) {
44
match list {
5-
//~^ ERROR `&[_, Some(_), None, _]` not covered
5+
//~^ ERROR `&[_, Some(_), .., None, _]` not covered
66
&[] => {},
77
&[_] => {},
88
&[_, _] => {},

src/test/ui/pattern/usefulness/match-slice-patterns.stderr

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1-
error[E0004]: non-exhaustive patterns: `&[_, Some(_), None, _]` not covered
1+
error[E0004]: non-exhaustive patterns: `&[_, Some(_), .., None, _]` not covered
22
--> $DIR/match-slice-patterns.rs:4:11
33
|
44
LL | match list {
5-
| ^^^^ pattern `&[_, Some(_), None, _]` not covered
5+
| ^^^^ pattern `&[_, Some(_), .., None, _]` not covered
66
|
77
= help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
88

src/test/ui/pattern/usefulness/slice-patterns.rs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ fn main() {
3737
[.., false] => {}
3838
}
3939
match s {
40-
//~^ ERROR `&[false, true]` not covered
40+
//~^ ERROR `&[false, .., true]` not covered
4141
[] => {}
4242
[true, ..] => {}
4343
[.., false] => {}
@@ -57,18 +57,18 @@ fn main() {
5757
[_] => {}
5858
}
5959
match s {
60-
//~^ ERROR `&[false]` not covered
60+
//~^ ERROR `&[false, ..]` not covered
6161
[] => {}
6262
[true, ..] => {}
6363
}
6464
match s {
65-
//~^ ERROR `&[false, _]` not covered
65+
//~^ ERROR `&[false, _, ..]` not covered
6666
[] => {}
6767
[_] => {}
6868
[true, ..] => {}
6969
}
7070
match s {
71-
//~^ ERROR `&[_, false]` not covered
71+
//~^ ERROR `&[_, .., false]` not covered
7272
[] => {}
7373
[_] => {}
7474
[.., true] => {}
@@ -94,14 +94,14 @@ fn main() {
9494
[..] => {}
9595
}
9696
match s {
97-
//~^ ERROR `&[_, _, true]` not covered
97+
//~^ ERROR `&[_, _, .., true]` not covered
9898
[] => {}
9999
[_] => {}
100100
[_, _] => {}
101101
[.., false] => {}
102102
}
103103
match s {
104-
//~^ ERROR `&[true, _, _]` not covered
104+
//~^ ERROR `&[true, _, .., _]` not covered
105105
[] => {}
106106
[_] => {}
107107
[_, _] => {}

src/test/ui/pattern/usefulness/slice-patterns.stderr

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -14,11 +14,11 @@ LL | match s3 {
1414
|
1515
= help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
1616

17-
error[E0004]: non-exhaustive patterns: `&[false, true]` not covered
17+
error[E0004]: non-exhaustive patterns: `&[false, .., true]` not covered
1818
--> $DIR/slice-patterns.rs:39:11
1919
|
2020
LL | match s {
21-
| ^ pattern `&[false, true]` not covered
21+
| ^ pattern `&[false, .., true]` not covered
2222
|
2323
= help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
2424

@@ -46,27 +46,27 @@ LL | match s {
4646
|
4747
= help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
4848

49-
error[E0004]: non-exhaustive patterns: `&[false]` not covered
49+
error[E0004]: non-exhaustive patterns: `&[false, ..]` not covered
5050
--> $DIR/slice-patterns.rs:59:11
5151
|
5252
LL | match s {
53-
| ^ pattern `&[false]` not covered
53+
| ^ pattern `&[false, ..]` not covered
5454
|
5555
= help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
5656

57-
error[E0004]: non-exhaustive patterns: `&[false, _]` not covered
57+
error[E0004]: non-exhaustive patterns: `&[false, _, ..]` not covered
5858
--> $DIR/slice-patterns.rs:64:11
5959
|
6060
LL | match s {
61-
| ^ pattern `&[false, _]` not covered
61+
| ^ pattern `&[false, _, ..]` not covered
6262
|
6363
= help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
6464

65-
error[E0004]: non-exhaustive patterns: `&[_, false]` not covered
65+
error[E0004]: non-exhaustive patterns: `&[_, .., false]` not covered
6666
--> $DIR/slice-patterns.rs:70:11
6767
|
6868
LL | match s {
69-
| ^ pattern `&[_, false]` not covered
69+
| ^ pattern `&[_, .., false]` not covered
7070
|
7171
= help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
7272

@@ -112,19 +112,19 @@ error: unreachable pattern
112112
LL | [false, true] => {}
113113
| ^^^^^^^^^^^^^
114114

115-
error[E0004]: non-exhaustive patterns: `&[_, _, true]` not covered
115+
error[E0004]: non-exhaustive patterns: `&[_, _, .., true]` not covered
116116
--> $DIR/slice-patterns.rs:96:11
117117
|
118118
LL | match s {
119-
| ^ pattern `&[_, _, true]` not covered
119+
| ^ pattern `&[_, _, .., true]` not covered
120120
|
121121
= help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
122122

123-
error[E0004]: non-exhaustive patterns: `&[true, _, _]` not covered
123+
error[E0004]: non-exhaustive patterns: `&[true, _, .., _]` not covered
124124
--> $DIR/slice-patterns.rs:103:11
125125
|
126126
LL | match s {
127-
| ^ pattern `&[true, _, _]` not covered
127+
| ^ pattern `&[true, _, .., _]` not covered
128128
|
129129
= help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
130130

0 commit comments

Comments
 (0)