Skip to content
Merged
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
23 changes: 19 additions & 4 deletions compiler/rustc_mir_build/src/thir/pattern/usefulness.rs
Original file line number Diff line number Diff line change
Expand Up @@ -364,8 +364,8 @@ impl<'a, 'p, 'tcx> fmt::Debug for PatCtxt<'a, 'p, 'tcx> {
/// A row of a matrix. Rows of len 1 are very common, which is why `SmallVec[_; 2]`
/// works well.
#[derive(Clone)]
struct PatStack<'p, 'tcx> {
pats: SmallVec<[&'p DeconstructedPat<'p, 'tcx>; 2]>,
pub(crate) struct PatStack<'p, 'tcx> {
pub(crate) pats: SmallVec<[&'p DeconstructedPat<'p, 'tcx>; 2]>,
}

impl<'p, 'tcx> PatStack<'p, 'tcx> {
Expand Down Expand Up @@ -403,6 +403,21 @@ impl<'p, 'tcx> PatStack<'p, 'tcx> {
})
}

// Recursively expand all patterns into their subpatterns and push each `PatStack` to matrix.
fn expand_and_extend<'a>(&'a self, matrix: &mut Matrix<'p, 'tcx>) {
if !self.is_empty() && self.head().is_or_pat() {
for pat in self.head().iter_fields() {
let mut new_patstack = PatStack::from_pattern(pat);
new_patstack.pats.extend_from_slice(&self.pats[1..]);
if !new_patstack.is_empty() && new_patstack.head().is_or_pat() {
new_patstack.expand_and_extend(matrix);
} else if !new_patstack.is_empty() {
matrix.push(new_patstack);
}
}
}
}

/// This computes `S(self.head().ctor(), self)`. See top of the file for explanations.
///
/// Structure patterns with a partial wild pattern (Foo { a: 42, .. }) have their missing
Expand Down Expand Up @@ -436,7 +451,7 @@ impl<'p, 'tcx> fmt::Debug for PatStack<'p, 'tcx> {
/// A 2D matrix.
#[derive(Clone)]
pub(super) struct Matrix<'p, 'tcx> {
patterns: Vec<PatStack<'p, 'tcx>>,
pub patterns: Vec<PatStack<'p, 'tcx>>,
}

impl<'p, 'tcx> Matrix<'p, 'tcx> {
Expand All @@ -453,7 +468,7 @@ impl<'p, 'tcx> Matrix<'p, 'tcx> {
/// expands it.
fn push(&mut self, row: PatStack<'p, 'tcx>) {
if !row.is_empty() && row.head().is_or_pat() {
self.patterns.extend(row.expand_or_pat());
row.expand_and_extend(self);
} else {
self.patterns.push(row);
}
Expand Down
11 changes: 11 additions & 0 deletions src/test/ui/or-patterns/inner-or-pat.or3.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
error[E0308]: mismatched types
--> $DIR/inner-or-pat.rs:38:54
|
LL | match x {
| - this expression has type `&str`
LL | x @ ((("h" | "ho" | "yo" | ("dude" | "w")) | () | "nop") | ("hey" | "gg")) |
| ^^ expected `str`, found `()`

error: aborting due to previous error

For more information about this error, try `rustc --explain E0308`.
11 changes: 11 additions & 0 deletions src/test/ui/or-patterns/inner-or-pat.or4.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
error[E0408]: variable `x` is not bound in all patterns
--> $DIR/inner-or-pat.rs:53:37
|
LL | (x @ "red" | (x @ "blue" | "red")) => {
| - ^^^^^ pattern doesn't bind `x`
| |
| variable not in all patterns

error: aborting due to previous error

For more information about this error, try `rustc --explain E0408`.
73 changes: 73 additions & 0 deletions src/test/ui/or-patterns/inner-or-pat.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
// revisions: or1 or2 or3 or4 or5
// [or1] run-pass
// [or2] run-pass
// [or5] run-pass

#![allow(unreachable_patterns)]
#![allow(unused_variables)]
#![allow(unused_parens)]
#![allow(dead_code)]



fn foo() {
let x = "foo";
match x {
x @ ((("h" | "ho" | "yo" | ("dude" | "w")) | "no" | "nop") | ("hey" | "gg")) |
x @ ("black" | "pink") |
x @ ("red" | "blue") => {
}
_ => (),
}
}

fn bar() {
let x = "foo";
match x {
x @ ("foo" | "bar") |
(x @ "red" | (x @ "blue" | x @ "red")) => {
}
_ => (),
}
}

#[cfg(or3)]
fn zot() {
let x = "foo";
match x {
x @ ((("h" | "ho" | "yo" | ("dude" | "w")) | () | "nop") | ("hey" | "gg")) |
//[or3]~^ ERROR mismatched types
x @ ("black" | "pink") |
x @ ("red" | "blue") => {
}
_ => (),
}
}


#[cfg(or4)]
fn hey() {
let x = "foo";
match x {
x @ ("foo" | "bar") |
(x @ "red" | (x @ "blue" | "red")) => {
//[or4]~^ variable `x` is not bound in all patterns
}
_ => (),
}
}

fn don() {
enum Foo {
A,
B,
C,
}

match Foo::A {
| _foo @ (Foo::A | Foo::B) => {}
Foo::C => {}
};
}

fn main(){}