diff --git a/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs b/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs index 9e7a267ecbd7..5bb2f00d3cf4 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs @@ -453,7 +453,17 @@ 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()); + let pats = row.expand_or_pat(); + let mut no_inner_or = true; + for pat in pats { + if !pat.is_empty() && pat.head().is_or_pat() { + self.patterns.extend(pat.expand_or_pat()); + no_inner_or = false; + } + } + if no_inner_or { + self.patterns.extend(row.expand_or_pat()); + } } else { self.patterns.push(row); } diff --git a/src/test/ui/or-patterns/inner-or-pat-2.rs b/src/test/ui/or-patterns/inner-or-pat-2.rs new file mode 100644 index 000000000000..3053d9734532 --- /dev/null +++ b/src/test/ui/or-patterns/inner-or-pat-2.rs @@ -0,0 +1,13 @@ +#[allow(unused_variables)] +#[allow(unused_parens)] +fn main() { + let x = "foo"; + match x { + x @ ((("h" | "ho" | "yo" | ("dude" | "w")) | () | "nop") | ("hey" | "gg")) | + //~^ ERROR mismatched types + x @ ("black" | "pink") | + x @ ("red" | "blue") => { + } + _ => (), + } +} diff --git a/src/test/ui/or-patterns/inner-or-pat-2.stderr b/src/test/ui/or-patterns/inner-or-pat-2.stderr new file mode 100644 index 000000000000..505b6c64a222 --- /dev/null +++ b/src/test/ui/or-patterns/inner-or-pat-2.stderr @@ -0,0 +1,11 @@ +error[E0308]: mismatched types + --> $DIR/inner-or-pat-2.rs:6: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-3.rs b/src/test/ui/or-patterns/inner-or-pat-3.rs new file mode 100644 index 000000000000..f6fe8a4dd59d --- /dev/null +++ b/src/test/ui/or-patterns/inner-or-pat-3.rs @@ -0,0 +1,15 @@ +// run-pass + +#[allow(unreachable_patterns)] +#[allow(unused_variables)] +#[allow(unused_parens)] +fn main() { + let x = "foo"; + + match x { + x @ ("foo" | "bar") | + (x @ "red" | (x @ "blue" | x @ "red")) => { + } + _ => (), + } +} diff --git a/src/test/ui/or-patterns/inner-or-pat-4.rs b/src/test/ui/or-patterns/inner-or-pat-4.rs new file mode 100644 index 000000000000..fe771e2e9301 --- /dev/null +++ b/src/test/ui/or-patterns/inner-or-pat-4.rs @@ -0,0 +1,13 @@ +#[allow(unused_variables)] +#[allow(unused_parens)] +fn main() { + let x = "foo"; + + match x { + x @ ("foo" | "bar") | + (x @ "red" | (x @ "blue" | "red")) => { + //~^ variable `x` is not bound in all patterns + } + _ => (), + } +} diff --git a/src/test/ui/or-patterns/inner-or-pat-4.stderr b/src/test/ui/or-patterns/inner-or-pat-4.stderr new file mode 100644 index 000000000000..177c7f983125 --- /dev/null +++ b/src/test/ui/or-patterns/inner-or-pat-4.stderr @@ -0,0 +1,11 @@ +error[E0408]: variable `x` is not bound in all patterns + --> $DIR/inner-or-pat-4.rs:8: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 000000000000..c49b04aa65b1 --- /dev/null +++ b/src/test/ui/or-patterns/inner-or-pat.rs @@ -0,0 +1,14 @@ +// run-pass + +#[allow(unused_variables)] +#[allow(unused_parens)] +fn main() { + let x = "foo"; + match x { + x @ ((("h" | "ho" | "yo" | ("dude" | "w")) | "no" | "nop") | ("hey" | "gg")) | + x @ ("black" | "pink") | + x @ ("red" | "blue") => { + } + _ => (), + } +}