From 90abfe9ce27c81808e3f74861072df6734f6a45d Mon Sep 17 00:00:00 2001 From: ouz-a Date: Fri, 17 Jun 2022 16:34:00 +0300 Subject: [PATCH 1/3] expand inner `or` pattern --- .../src/thir/pattern/usefulness.rs | 12 +++++++++++- src/test/ui/or-patterns/inner-or-pat-2.rs | 13 +++++++++++++ src/test/ui/or-patterns/inner-or-pat-2.stderr | 11 +++++++++++ src/test/ui/or-patterns/inner-or-pat-3.rs | 15 +++++++++++++++ src/test/ui/or-patterns/inner-or-pat-4.rs | 13 +++++++++++++ src/test/ui/or-patterns/inner-or-pat-4.stderr | 11 +++++++++++ src/test/ui/or-patterns/inner-or-pat.rs | 14 ++++++++++++++ 7 files changed, 88 insertions(+), 1 deletion(-) create mode 100644 src/test/ui/or-patterns/inner-or-pat-2.rs create mode 100644 src/test/ui/or-patterns/inner-or-pat-2.stderr create mode 100644 src/test/ui/or-patterns/inner-or-pat-3.rs create mode 100644 src/test/ui/or-patterns/inner-or-pat-4.rs create mode 100644 src/test/ui/or-patterns/inner-or-pat-4.stderr create mode 100644 src/test/ui/or-patterns/inner-or-pat.rs diff --git a/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs b/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs index 9e7a267ecbd..5bb2f00d3cf 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 00000000000..3053d973453 --- /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 00000000000..505b6c64a22 --- /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 00000000000..f6fe8a4dd59 --- /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 00000000000..fe771e2e930 --- /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 00000000000..177c7f98312 --- /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 00000000000..c49b04aa65b --- /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") => { + } + _ => (), + } +} From 661d488bfd7cd4888400a23b9f6ea9bb15cacaf5 Mon Sep 17 00:00:00 2001 From: ouz-a Date: Fri, 24 Jun 2022 14:16:48 +0300 Subject: [PATCH 2/3] use true recursion --- .../src/thir/pattern/usefulness.rs | 33 +++++++++++-------- 1 file changed, 19 insertions(+), 14 deletions(-) diff --git a/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs b/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs index 5bb2f00d3cf..5773ba8065c 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,17 +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() { - 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()); - } + row.expand_and_extend(self); } else { self.patterns.push(row); } From ddf23cbebaa74897a3b1d1f14463fe21b171fdeb Mon Sep 17 00:00:00 2001 From: ouz-a Date: Wed, 17 Aug 2022 13:21:03 +0300 Subject: [PATCH 3/3] add new test and combine old ones --- src/test/ui/or-patterns/inner-or-pat-2.rs | 13 ---- src/test/ui/or-patterns/inner-or-pat-3.rs | 15 ----- src/test/ui/or-patterns/inner-or-pat-4.rs | 13 ---- ...r-pat-2.stderr => inner-or-pat.or3.stderr} | 2 +- ...r-pat-4.stderr => inner-or-pat.or4.stderr} | 2 +- src/test/ui/or-patterns/inner-or-pat.rs | 67 +++++++++++++++++-- 6 files changed, 65 insertions(+), 47 deletions(-) delete mode 100644 src/test/ui/or-patterns/inner-or-pat-2.rs delete mode 100644 src/test/ui/or-patterns/inner-or-pat-3.rs delete mode 100644 src/test/ui/or-patterns/inner-or-pat-4.rs rename src/test/ui/or-patterns/{inner-or-pat-2.stderr => inner-or-pat.or3.stderr} (91%) rename src/test/ui/or-patterns/{inner-or-pat-4.stderr => inner-or-pat.or4.stderr} (91%) diff --git a/src/test/ui/or-patterns/inner-or-pat-2.rs b/src/test/ui/or-patterns/inner-or-pat-2.rs deleted file mode 100644 index 3053d973453..00000000000 --- a/src/test/ui/or-patterns/inner-or-pat-2.rs +++ /dev/null @@ -1,13 +0,0 @@ -#[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-3.rs b/src/test/ui/or-patterns/inner-or-pat-3.rs deleted file mode 100644 index f6fe8a4dd59..00000000000 --- a/src/test/ui/or-patterns/inner-or-pat-3.rs +++ /dev/null @@ -1,15 +0,0 @@ -// 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 deleted file mode 100644 index fe771e2e930..00000000000 --- a/src/test/ui/or-patterns/inner-or-pat-4.rs +++ /dev/null @@ -1,13 +0,0 @@ -#[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-2.stderr b/src/test/ui/or-patterns/inner-or-pat.or3.stderr similarity index 91% rename from src/test/ui/or-patterns/inner-or-pat-2.stderr rename to src/test/ui/or-patterns/inner-or-pat.or3.stderr index 505b6c64a22..2236a38c37b 100644 --- a/src/test/ui/or-patterns/inner-or-pat-2.stderr +++ b/src/test/ui/or-patterns/inner-or-pat.or3.stderr @@ -1,5 +1,5 @@ error[E0308]: mismatched types - --> $DIR/inner-or-pat-2.rs:6:54 + --> $DIR/inner-or-pat.rs:38:54 | LL | match x { | - this expression has type `&str` diff --git a/src/test/ui/or-patterns/inner-or-pat-4.stderr b/src/test/ui/or-patterns/inner-or-pat.or4.stderr similarity index 91% rename from src/test/ui/or-patterns/inner-or-pat-4.stderr rename to src/test/ui/or-patterns/inner-or-pat.or4.stderr index 177c7f98312..058873ff5ff 100644 --- a/src/test/ui/or-patterns/inner-or-pat-4.stderr +++ b/src/test/ui/or-patterns/inner-or-pat.or4.stderr @@ -1,5 +1,5 @@ error[E0408]: variable `x` is not bound in all patterns - --> $DIR/inner-or-pat-4.rs:8:37 + --> $DIR/inner-or-pat.rs:53:37 | LL | (x @ "red" | (x @ "blue" | "red")) => { | - ^^^^^ pattern doesn't bind `x` diff --git a/src/test/ui/or-patterns/inner-or-pat.rs b/src/test/ui/or-patterns/inner-or-pat.rs index c49b04aa65b..f4cf4b0c188 100644 --- a/src/test/ui/or-patterns/inner-or-pat.rs +++ b/src/test/ui/or-patterns/inner-or-pat.rs @@ -1,8 +1,16 @@ -// run-pass +// revisions: or1 or2 or3 or4 or5 +// [or1] run-pass +// [or2] run-pass +// [or5] run-pass -#[allow(unused_variables)] -#[allow(unused_parens)] -fn main() { +#![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")) | @@ -12,3 +20,54 @@ fn main() { _ => (), } } + +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(){}