Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fully destructure slice and array constants into patterns #77390

Closed
wants to merge 7 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
322 changes: 36 additions & 286 deletions compiler/rustc_mir_build/src/thir/pattern/_match.rs

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion compiler/rustc_mir_build/src/thir/pattern/check_match.rs
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,7 @@ impl<'tcx> MatchVisitor<'_, 'tcx> {
patcx.include_lint_checks();
let pattern = patcx.lower_pattern(pat);
let pattern_ty = pattern.ty;
let pattern: &_ = cx.pattern_arena.alloc(expand_pattern(cx, pattern));
let pattern: &_ = cx.pattern_arena.alloc(expand_pattern(pattern));
if !patcx.errors.is_empty() {
*have_errors = true;
patcx.report_inlining_errors(pat.span);
Expand Down
12 changes: 7 additions & 5 deletions compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs
Original file line number Diff line number Diff line change
Expand Up @@ -387,14 +387,16 @@ impl<'a, 'tcx> ConstToPat<'a, 'tcx> {
// `&str` and `&[u8]` are represented as `ConstValue::Slice`, let's keep using this
// optimization for now.
ty::Str => PatKind::Constant { value: cv },
ty::Slice(elem_ty) if elem_ty == tcx.types.u8 => PatKind::Constant { value: cv },
// `b"foo"` produces a `&[u8; 3]`, but you can't use constants of array type when
// matching against references, you can only use byte string literals.
// FIXME: clean this up, likely by permitting array patterns when matching on slices
ty::Array(elem_ty, _) if elem_ty == tcx.types.u8 => PatKind::Constant { value: cv },
// The typechecker has a special case for byte string literals, by treating them
// as slices. This means we turn `&[T; N]` constants into slice patterns, which
// has no negative effects on pattern matching, even if we're actually matching on
// arrays.
ty::Array(..) |
// Cannot merge this with the catch all branch below, because the `const_deref`
// changes the type from slice to array, and slice patterns behave differently from
// array patterns.
// changes the type from slice to array, we need to keep the original type in the
// pattern.
ty::Slice(..) => {
let old = self.behind_reference.replace(true);
let array = tcx.deref_const(self.param_env.and(cv));
Expand Down
6 changes: 6 additions & 0 deletions compiler/rustc_mir_build/src/thir/pattern/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,12 @@ crate enum PatKind<'tcx> {
subpattern: Pat<'tcx>,
},

/// One of the following:
/// * `&str`, which will be handled as a string pattern and thus exhaustiveness
/// checking will detect if you use the same string twice in different patterns.
/// * integer, bool, char or float, which will be handled by exhaustivenes to cover exactly
/// its own value, similar to `&str`, but these values are much simpler.
/// * Opaque constants. So anything that does not derive `PartialEq` and `Eq`.
Constant {
Copy link
Member

@Nadrieril Nadrieril Oct 12, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This comment should also mention int ranges etc then

value: &'tcx ty::Const<'tcx>,
},
Expand Down
16 changes: 16 additions & 0 deletions src/test/ui/consts/const_in_pattern/ice-regression.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@


#[derive(PartialEq)]
struct Opaque(i32);

impl Eq for Opaque {}

const FOO: &&Opaque = &&Opaque(42);

fn main() {
match FOO {
FOO => {}, //~ WARN must be annotated with
// The following should not lint about unreachable
Opaque(42) => {}
}
}
8 changes: 8 additions & 0 deletions src/test/ui/consts/const_in_pattern/ice-regression.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
error: expected item, found keyword `match`
--> $DIR/ice-regression.rs:8:1
|
LL | match FOO {
| ^^^^^ expected item

error: aborting due to previous error

10 changes: 9 additions & 1 deletion src/test/ui/issues/issue-44333.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -21,5 +21,13 @@ LL | BAR => println!("bar"),
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #62411 <https://github.com/rust-lang/rust/issues/70861>

warning: 2 warnings emitted
warning: unreachable pattern
--> $DIR/issue-44333.rs:21:9
|
LL | BAR => println!("bar"),
| ^^^
|
= note: `#[warn(unreachable_patterns)]` on by default

warning: 3 warnings emitted

Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,11 @@ LL | match buf {
= help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `&[u8; 4]`

error[E0004]: non-exhaustive patterns: `&[]`, `&[_]`, `&[_, _]` and 2 more not covered
error[E0004]: non-exhaustive patterns: `&[0_u8..=64_u8, _, _, _]` and `&[66_u8..=u8::MAX, _, _, _]` not covered
--> $DIR/match-byte-array-patterns-2.rs:10:11
|
LL | match buf {
| ^^^ patterns `&[]`, `&[_]`, `&[_, _]` and 2 more not covered
| ^^^ patterns `&[0_u8..=64_u8, _, _, _]` and `&[66_u8..=u8::MAX, _, _, _]` not covered
|
= help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `&[u8]`
Expand Down