diff --git a/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs b/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs index 0a660ef30c8..443626d14b9 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs @@ -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> { @@ -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 @@ -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>, + pub patterns: Vec>, } impl<'p, 'tcx> Matrix<'p, 'tcx> { @@ -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); } diff --git a/src/test/ui/or-patterns/inner-or-pat.or3.stderr b/src/test/ui/or-patterns/inner-or-pat.or3.stderr new file mode 100644 index 00000000000..2236a38c37b --- /dev/null +++ b/src/test/ui/or-patterns/inner-or-pat.or3.stderr @@ -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`. diff --git a/src/test/ui/or-patterns/inner-or-pat.or4.stderr b/src/test/ui/or-patterns/inner-or-pat.or4.stderr new file mode 100644 index 00000000000..058873ff5ff --- /dev/null +++ b/src/test/ui/or-patterns/inner-or-pat.or4.stderr @@ -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`. diff --git a/src/test/ui/or-patterns/inner-or-pat.rs b/src/test/ui/or-patterns/inner-or-pat.rs new file mode 100644 index 00000000000..f4cf4b0c188 --- /dev/null +++ b/src/test/ui/or-patterns/inner-or-pat.rs @@ -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(){}