From 6319d737e07d732aa044864933b69a39fdbeec0a Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Thu, 17 Dec 2020 01:25:53 +0000 Subject: [PATCH] Merge unreachable subpatterns correctly --- .../src/thir/pattern/usefulness.rs | 31 +++++++++++++++++-- .../exhaustiveness-unreachable-pattern.rs | 4 +-- .../exhaustiveness-unreachable-pattern.stderr | 20 +++++------- 3 files changed, 36 insertions(+), 19 deletions(-) diff --git a/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs b/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs index 02b5e0eb3b22b..c07d4c9b8f74b 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs @@ -788,13 +788,32 @@ impl<'tcx> Usefulness<'tcx> { /// When trying several branches and each returns a `Usefulness`, we need to combine the /// results together. fn merge_split_constructors(usefulnesses: impl Iterator) -> Self { + // If we have detected some unreachable sub-branches, we only want to keep them when they + // were unreachable in _all_ branches. So we take a big intersection. + + // Is `None` when no branch was useful. Will often be `Some(Spanset::new())` because the + // sets are only non-empty in the diagnostic path. + let mut unreachables: Option = None; // Witnesses of usefulness, if any. let mut witnesses = Vec::new(); for u in usefulnesses { match u { - Useful(..) => { - return u; + Useful(spans) if spans.is_empty() => { + // Once we reach the empty set, more intersections won't change the result. + return Useful(SpanSet::new()); + } + Useful(spans) => { + if let Some(unreachables) = &mut unreachables { + if !unreachables.is_empty() { + unreachables.intersection_mut(&spans); + } + if unreachables.is_empty() { + return Useful(SpanSet::new()); + } + } else { + unreachables = Some(spans); + } } NotUseful => {} UsefulWithWitness(wits) => { @@ -803,7 +822,13 @@ impl<'tcx> Usefulness<'tcx> { } } - if !witnesses.is_empty() { UsefulWithWitness(witnesses) } else { NotUseful } + if !witnesses.is_empty() { + UsefulWithWitness(witnesses) + } else if let Some(unreachables) = unreachables { + Useful(unreachables) + } else { + NotUseful + } } fn apply_constructor<'p>( diff --git a/src/test/ui/or-patterns/exhaustiveness-unreachable-pattern.rs b/src/test/ui/or-patterns/exhaustiveness-unreachable-pattern.rs index 3e242a797a201..184ffa85c40e2 100644 --- a/src/test/ui/or-patterns/exhaustiveness-unreachable-pattern.rs +++ b/src/test/ui/or-patterns/exhaustiveness-unreachable-pattern.rs @@ -64,11 +64,9 @@ fn main() { | 2, ..] => {} _ => {} } - // FIXME: incorrect match &[][..] { [true] => {} - [true //~ ERROR unreachable - | false, ..] => {} + [true | false, ..] => {} _ => {} } match &[][..] { diff --git a/src/test/ui/or-patterns/exhaustiveness-unreachable-pattern.stderr b/src/test/ui/or-patterns/exhaustiveness-unreachable-pattern.stderr index ac0b34c2bd541..8b1003b5514a6 100644 --- a/src/test/ui/or-patterns/exhaustiveness-unreachable-pattern.stderr +++ b/src/test/ui/or-patterns/exhaustiveness-unreachable-pattern.stderr @@ -95,46 +95,40 @@ LL | [1 | ^ error: unreachable pattern - --> $DIR/exhaustiveness-unreachable-pattern.rs:70:10 + --> $DIR/exhaustiveness-unreachable-pattern.rs:75:10 | LL | [true | ^^^^ error: unreachable pattern - --> $DIR/exhaustiveness-unreachable-pattern.rs:77:10 - | -LL | [true - | ^^^^ - -error: unreachable pattern - --> $DIR/exhaustiveness-unreachable-pattern.rs:84:36 + --> $DIR/exhaustiveness-unreachable-pattern.rs:82:36 | LL | (true | false, None | Some(true | ^^^^ error: unreachable pattern - --> $DIR/exhaustiveness-unreachable-pattern.rs:100:14 + --> $DIR/exhaustiveness-unreachable-pattern.rs:98:14 | LL | Some(0 | ^ error: unreachable pattern - --> $DIR/exhaustiveness-unreachable-pattern.rs:119:19 + --> $DIR/exhaustiveness-unreachable-pattern.rs:117:19 | LL | | false) => {} | ^^^^^ error: unreachable pattern - --> $DIR/exhaustiveness-unreachable-pattern.rs:127:15 + --> $DIR/exhaustiveness-unreachable-pattern.rs:125:15 | LL | | true) => {} | ^^^^ error: unreachable pattern - --> $DIR/exhaustiveness-unreachable-pattern.rs:133:15 + --> $DIR/exhaustiveness-unreachable-pattern.rs:131:15 | LL | | true, | ^^^^ -error: aborting due to 22 previous errors +error: aborting due to 21 previous errors