Rollup merge of #98200 - ouz-a:issue-98177, r=oli-obk

Expand potential inner `Or` pattern for THIR

Code assumed there wouldn't be a deeper `Or` pattern inside expanded `PatStack` this fixes it by looking for the `Or` pattern inside expanded `PatStack`.

A more ideal solution would be recursively doing this but I haven't found a good way to do that.
_fixes #97898_
This commit is contained in:
Dylan DPC 2022-08-22 20:34:08 +05:30 committed by GitHub
commit 56ba13ac7f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 114 additions and 4 deletions

View File

@ -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<PatStack<'p, 'tcx>>,
pub patterns: Vec<PatStack<'p, 'tcx>>,
}
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);
}

View File

@ -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`.

View File

@ -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`.

View File

@ -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(){}