Skip to content

Commit

Permalink
Auto merge of #66129 - Nadrieril:refactor-slice-pat-usefulness, r=varkor
Browse files Browse the repository at this point in the history
Refactor slice pattern usefulness checking

As a follow up to #65874, this PR changes how variable-length slice patterns are handled in usefulness checking. The objectives are: cleaning up that code to make it easier to understand, and paving the way to handling fixed-length slices more cleverly too, for #53820.

Before this, variable-length slice patterns were eagerly expanded into a union of fixed-length slices. Now they have their own special constructor, which allows expanding them a bit more lazily.
As a nice side-effect, this improves diagnostics.

This PR shows a slight performance improvement, mostly due to 149792b. This will probably have to be reverted in some way when we implement or-patterns.
  • Loading branch information
bors committed Nov 12, 2019
2 parents e931f00 + fd9921b commit e3d9984
Show file tree
Hide file tree
Showing 21 changed files with 627 additions and 264 deletions.
593 changes: 344 additions & 249 deletions src/librustc_mir/hair/pattern/_match.rs

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions src/librustc_mir/hair/pattern/check_match.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ use rustc::hir::{self, Pat};

use std::slice;

use syntax_pos::{MultiSpan, Span, DUMMY_SP};
use syntax_pos::{MultiSpan, Span};

crate fn check_match(tcx: TyCtxt<'_>, def_id: DefId) {
let body_id = match tcx.hir().as_local_hir_id(def_id) {
Expand Down Expand Up @@ -491,7 +491,7 @@ fn check_not_useful(
matrix: &Matrix<'_, 'tcx>,
hir_id: HirId,
) -> Result<(), Vec<super::Pat<'tcx>>> {
let wild_pattern = super::Pat { ty, span: DUMMY_SP, kind: box PatKind::Wild };
let wild_pattern = super::Pat::wildcard_from_ty(ty);
match is_useful(cx, matrix, &PatStack::from_pattern(&wild_pattern), ConstructWitness, hir_id) {
NotUseful => Ok(()), // This is good, wildcard pattern isn't reachable.
UsefulWithWitness(pats) => Err(if pats.is_empty() {
Expand Down
7 changes: 6 additions & 1 deletion src/librustc_mir/hair/pattern/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ use rustc_index::vec::Idx;
use std::cmp::Ordering;
use std::fmt;
use syntax::ast;
use syntax_pos::Span;
use syntax_pos::{Span, DUMMY_SP};

#[derive(Clone, Debug)]
pub enum PatternError {
Expand Down Expand Up @@ -55,6 +55,11 @@ pub struct Pat<'tcx> {
pub kind: Box<PatKind<'tcx>>,
}

impl<'tcx> Pat<'tcx> {
pub(crate) fn wildcard_from_ty(ty: Ty<'tcx>) -> Self {
Pat { ty, span: DUMMY_SP, kind: Box::new(PatKind::Wild) }
}
}

#[derive(Copy, Clone, Debug, PartialEq)]
pub struct PatTyProj<'tcx> {
Expand Down
4 changes: 2 additions & 2 deletions src/test/ui/consts/const_let_refutable.stderr
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
error[E0005]: refutable pattern in function argument: `&[]`, `&[_]` and `&[_, _, _]` not covered
error[E0005]: refutable pattern in function argument: `&[]`, `&[_]` and `&[_, _, _, ..]` not covered
--> $DIR/const_let_refutable.rs:3:16
|
LL | const fn slice([a, b]: &[i32]) -> i32 {
| ^^^^^^ patterns `&[]`, `&[_]` and `&[_, _, _]` not covered
| ^^^^^^ patterns `&[]`, `&[_]` and `&[_, _, _, ..]` not covered

error[E0723]: can only call other `const fn` within a `const fn`, but `const <&i32 as std::ops::Add>::add` is not stable as `const fn`
--> $DIR/const_let_refutable.rs:4:5
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,11 @@ LL | match buf {
|
= help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms

error[E0004]: non-exhaustive patterns: `&[]`, `&[_]`, `&[_, _]` and 3 more not covered
error[E0004]: non-exhaustive patterns: `&[..]` not covered
--> $DIR/match-byte-array-patterns-2.rs:10:11
|
LL | match buf {
| ^^^ patterns `&[]`, `&[_]`, `&[_, _]` and 3 more not covered
| ^^^ pattern `&[..]` not covered
|
= help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms

Expand Down
2 changes: 1 addition & 1 deletion src/test/ui/pattern/usefulness/match-slice-patterns.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

fn check(list: &[Option<()>]) {
match list {
//~^ ERROR `&[_, Some(_), None, _]` not covered
//~^ ERROR `&[_, Some(_), .., None, _]` not covered
&[] => {},
&[_] => {},
&[_, _] => {},
Expand Down
4 changes: 2 additions & 2 deletions src/test/ui/pattern/usefulness/match-slice-patterns.stderr
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
error[E0004]: non-exhaustive patterns: `&[_, Some(_), None, _]` not covered
error[E0004]: non-exhaustive patterns: `&[_, Some(_), .., None, _]` not covered
--> $DIR/match-slice-patterns.rs:4:11
|
LL | match list {
| ^^^^ pattern `&[_, Some(_), None, _]` not covered
| ^^^^ pattern `&[_, Some(_), .., None, _]` not covered
|
= help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms

Expand Down
2 changes: 1 addition & 1 deletion src/test/ui/pattern/usefulness/non-exhaustive-match.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ fn main() {
}
let vec = vec![0.5f32];
let vec: &[f32] = &vec;
match *vec { //~ ERROR non-exhaustive patterns: `[_, _, _, _]` not covered
match *vec { //~ ERROR non-exhaustive patterns: `[_, _, _, _, ..]` not covered
[0.1, 0.2, 0.3] => (),
[0.1, 0.2] => (),
[0.1] => (),
Expand Down
4 changes: 2 additions & 2 deletions src/test/ui/pattern/usefulness/non-exhaustive-match.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -66,11 +66,11 @@ LL | match *vec {
|
= help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms

error[E0004]: non-exhaustive patterns: `[_, _, _, _]` not covered
error[E0004]: non-exhaustive patterns: `[_, _, _, _, ..]` not covered
--> $DIR/non-exhaustive-match.rs:47:11
|
LL | match *vec {
| ^^^^ pattern `[_, _, _, _]` not covered
| ^^^^ pattern `[_, _, _, _, ..]` not covered
|
= help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms

Expand Down
File renamed without changes.
75 changes: 75 additions & 0 deletions src/test/ui/pattern/usefulness/slice-patterns-exhaustiveness.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
#![feature(slice_patterns)]

fn main() {
let s: &[bool] = &[true; 0];
let s1: &[bool; 1] = &[false; 1];
let s2: &[bool; 2] = &[false; 2];
let s3: &[bool; 3] = &[false; 3];

match s1 {
[true, ..] => {}
[.., false] => {}
}
match s2 {
//~^ ERROR `&[false, true]` not covered
[true, ..] => {}
[.., false] => {}
}
match s3 {
//~^ ERROR `&[false, _, true]` not covered
[true, ..] => {}
[.., false] => {}
}
match s {
//~^ ERROR `&[false, .., true]` not covered
[] => {}
[true, ..] => {}
[.., false] => {}
}

match s3 {
//~^ ERROR `&[false, _, _]` not covered
[true, .., true] => {}
}
match s {
//~^ ERROR `&[_, ..]` not covered
[] => {}
}
match s {
//~^ ERROR `&[_, _, ..]` not covered
[] => {}
[_] => {}
}
match s {
//~^ ERROR `&[false, ..]` not covered
[] => {}
[true, ..] => {}
}
match s {
//~^ ERROR `&[false, _, ..]` not covered
[] => {}
[_] => {}
[true, ..] => {}
}
match s {
//~^ ERROR `&[_, .., false]` not covered
[] => {}
[_] => {}
[.., true] => {}
}

match s {
//~^ ERROR `&[_, _, .., true]` not covered
[] => {}
[_] => {}
[_, _] => {}
[.., false] => {}
}
match s {
//~^ ERROR `&[true, _, .., _]` not covered
[] => {}
[_] => {}
[_, _] => {}
[false, .., false] => {}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
error[E0004]: non-exhaustive patterns: `&[false, true]` not covered
--> $DIR/slice-patterns-exhaustiveness.rs:13:11
|
LL | match s2 {
| ^^ pattern `&[false, true]` not covered
|
= help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms

error[E0004]: non-exhaustive patterns: `&[false, _, true]` not covered
--> $DIR/slice-patterns-exhaustiveness.rs:18:11
|
LL | match s3 {
| ^^ pattern `&[false, _, true]` not covered
|
= help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms

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

error[E0004]: non-exhaustive patterns: `&[false, _, _]` not covered
--> $DIR/slice-patterns-exhaustiveness.rs:30:11
|
LL | match s3 {
| ^^ pattern `&[false, _, _]` not covered
|
= help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms

error[E0004]: non-exhaustive patterns: `&[_, ..]` not covered
--> $DIR/slice-patterns-exhaustiveness.rs:34:11
|
LL | match s {
| ^ pattern `&[_, ..]` not covered
|
= help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms

error[E0004]: non-exhaustive patterns: `&[_, _, ..]` not covered
--> $DIR/slice-patterns-exhaustiveness.rs:38:11
|
LL | match s {
| ^ pattern `&[_, _, ..]` not covered
|
= help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms

error[E0004]: non-exhaustive patterns: `&[false, ..]` not covered
--> $DIR/slice-patterns-exhaustiveness.rs:43:11
|
LL | match s {
| ^ pattern `&[false, ..]` not covered
|
= help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms

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

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

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

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

error: aborting due to 11 previous errors

For more information about this error, try `rustc --explain E0004`.
27 changes: 27 additions & 0 deletions src/test/ui/pattern/usefulness/slice-patterns-irrefutable.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
// check-pass
#![feature(slice_patterns)]

fn main() {
let s: &[bool] = &[true; 0];
let s0: &[bool; 0] = &[];
let s1: &[bool; 1] = &[false; 1];
let s2: &[bool; 2] = &[false; 2];

let [] = s0;
let [_] = s1;
let [_, _] = s2;

let [..] = s;
let [..] = s0;
let [..] = s1;
let [..] = s2;

let [_, ..] = s1;
let [.., _] = s1;
let [_, ..] = s2;
let [.., _] = s2;

let [_, _, ..] = s2;
let [_, .., _] = s2;
let [.., _, _] = s2;
}
26 changes: 26 additions & 0 deletions src/test/ui/pattern/usefulness/slice-patterns-reachability.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
#![feature(slice_patterns)]
#![deny(unreachable_patterns)]

fn main() {
let s: &[bool] = &[true; 0];

match s {
[true, ..] => {}
[true, ..] => {} //~ ERROR unreachable pattern
[true] => {} //~ ERROR unreachable pattern
[..] => {}
}
match s {
[.., true] => {}
[.., true] => {} //~ ERROR unreachable pattern
[true] => {} //~ ERROR unreachable pattern
[..] => {}
}
match s {
[false, .., true] => {}
[false, .., true] => {} //~ ERROR unreachable pattern
[false, true] => {} //~ ERROR unreachable pattern
[false] => {}
[..] => {}
}
}
44 changes: 44 additions & 0 deletions src/test/ui/pattern/usefulness/slice-patterns-reachability.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
error: unreachable pattern
--> $DIR/slice-patterns-reachability.rs:9:9
|
LL | [true, ..] => {}
| ^^^^^^^^^^
|
note: lint level defined here
--> $DIR/slice-patterns-reachability.rs:2:9
|
LL | #![deny(unreachable_patterns)]
| ^^^^^^^^^^^^^^^^^^^^

error: unreachable pattern
--> $DIR/slice-patterns-reachability.rs:10:9
|
LL | [true] => {}
| ^^^^^^

error: unreachable pattern
--> $DIR/slice-patterns-reachability.rs:15:9
|
LL | [.., true] => {}
| ^^^^^^^^^^

error: unreachable pattern
--> $DIR/slice-patterns-reachability.rs:16:9
|
LL | [true] => {}
| ^^^^^^

error: unreachable pattern
--> $DIR/slice-patterns-reachability.rs:21:9
|
LL | [false, .., true] => {}
| ^^^^^^^^^^^^^^^^^

error: unreachable pattern
--> $DIR/slice-patterns-reachability.rs:22:9
|
LL | [false, true] => {}
| ^^^^^^^^^^^^^

error: aborting due to 6 previous errors

Original file line number Diff line number Diff line change
Expand Up @@ -30,11 +30,11 @@ LL | let _ = match x {};
|
= help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms

error[E0004]: non-exhaustive patterns: `&[_]` not covered
error[E0004]: non-exhaustive patterns: `&[_, ..]` not covered
--> $DIR/uninhabited-matches-feature-gated.rs:21:19
|
LL | let _ = match x {
| ^ pattern `&[_]` not covered
| ^ pattern `&[_, ..]` not covered
|
= help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms

Expand Down

0 comments on commit e3d9984

Please sign in to comment.