aboutsummaryrefslogtreecommitdiff
path: root/crates/hir_ty/src/diagnostics/pattern/usefulness.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/hir_ty/src/diagnostics/pattern/usefulness.rs')
-rw-r--r--crates/hir_ty/src/diagnostics/pattern/usefulness.rs74
1 files changed, 71 insertions, 3 deletions
diff --git a/crates/hir_ty/src/diagnostics/pattern/usefulness.rs b/crates/hir_ty/src/diagnostics/pattern/usefulness.rs
index 57a416bec..2e5d2fb6c 100644
--- a/crates/hir_ty/src/diagnostics/pattern/usefulness.rs
+++ b/crates/hir_ty/src/diagnostics/pattern/usefulness.rs
@@ -1,5 +1,5 @@
1// Based on rust-lang/rust 1.52.0-nightly (25c15cdbe 2021-04-22) 1// Based on rust-lang/rust 1.52.0-nightly (25c15cdbe 2021-04-22)
2// rust/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs 2// https://github.com/rust-lang/rust/blob/25c15cdbe/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs
3 3
4use std::{cell::RefCell, iter::FromIterator, ops::Index, sync::Arc}; 4use std::{cell::RefCell, iter::FromIterator, ops::Index, sync::Arc};
5 5
@@ -245,6 +245,33 @@ impl Matrix {
245 } 245 }
246} 246}
247 247
248/// Given a pattern or a pattern-stack, this struct captures a set of its subpatterns. We use that
249/// to track reachable sub-patterns arising from or-patterns. In the absence of or-patterns this
250/// will always be either `Empty` (the whole pattern is unreachable) or `Full` (the whole pattern
251/// is reachable). When there are or-patterns, some subpatterns may be reachable while others
252/// aren't. In this case the whole pattern still counts as reachable, but we will lint the
253/// unreachable subpatterns.
254///
255/// This supports a limited set of operations, so not all possible sets of subpatterns can be
256/// represented. That's ok, we only want the ones that make sense for our usage.
257///
258/// What we're doing is illustrated by this:
259/// ```
260/// match (true, 0) {
261/// (true, 0) => {}
262/// (_, 1) => {}
263/// (true | false, 0 | 1) => {}
264/// }
265/// ```
266/// When we try the alternatives of the `true | false` or-pattern, the last `0` is reachable in the
267/// `false` alternative but not the `true`. So overall it is reachable. By contrast, the last `1`
268/// is not reachable in either alternative, so we want to signal this to the user.
269/// Therefore we take the union of sets of reachable patterns coming from different alternatives in
270/// order to figure out which subpatterns are overall reachable.
271///
272/// Invariant: we try to construct the smallest representation we can. In particular if
273/// `self.is_empty()` we ensure that `self` is `Empty`, and same with `Full`. This is not important
274/// for correctness currently.
248#[derive(Debug, Clone)] 275#[derive(Debug, Clone)]
249enum SubPatSet { 276enum SubPatSet {
250 /// The empty set. This means the pattern is unreachable. 277 /// The empty set. This means the pattern is unreachable.
@@ -397,7 +424,24 @@ impl SubPatSet {
397 Full => Full, 424 Full => Full,
398 Empty => Empty, 425 Empty => Empty,
399 Seq { subpats } => { 426 Seq { subpats } => {
400 todo!() 427 // We gather the first `arity` subpatterns together and shift the remaining ones.
428 let mut new_subpats = FxHashMap::default();
429 let mut new_subpats_first_col = FxHashMap::default();
430 for (i, sub_set) in subpats {
431 if i < arity {
432 // The first `arity` indices are now part of the pattern in the first
433 // column.
434 new_subpats_first_col.insert(i, sub_set);
435 } else {
436 // Indices after `arity` are simply shifted
437 new_subpats.insert(i - arity + 1, sub_set);
438 }
439 }
440 // If `new_subpats_first_col` has no entries it counts as full, so we can omit it.
441 if !new_subpats_first_col.is_empty() {
442 new_subpats.insert(0, Seq { subpats: new_subpats_first_col });
443 }
444 Seq { subpats: new_subpats }
401 } 445 }
402 Alt { .. } => panic!("bug"), 446 Alt { .. } => panic!("bug"),
403 } 447 }
@@ -417,7 +461,31 @@ impl SubPatSet {
417 /// containing `false`. After `unsplit_or_pat`, we want the set to contain `None` and `false`. 461 /// containing `false`. After `unsplit_or_pat`, we want the set to contain `None` and `false`.
418 /// This is what this function does. 462 /// This is what this function does.
419 fn unsplit_or_pat(mut self, alt_id: usize, alt_count: usize, pat: PatId) -> Self { 463 fn unsplit_or_pat(mut self, alt_id: usize, alt_count: usize, pat: PatId) -> Self {
420 todo!() 464 use SubPatSet::*;
465 if self.is_empty() {
466 return Empty;
467 }
468
469 // Subpatterns coming from inside the or-pattern alternative itself, e.g. in `None | Some(0
470 // | 1)`.
471 let set_first_col = match &mut self {
472 Full => Full,
473 Seq { subpats } => subpats.remove(&0).unwrap_or(Full),
474 Empty => unreachable!(),
475 Alt { .. } => panic!("bug"), // `self` is a patstack
476 };
477 let mut subpats_first_col = FxHashMap::default();
478 subpats_first_col.insert(alt_id, set_first_col);
479 let set_first_col = Alt { subpats: subpats_first_col, pat, alt_count };
480
481 let mut subpats = match self {
482 Full => FxHashMap::default(),
483 Seq { subpats } => subpats,
484 Empty => unreachable!(),
485 Alt { .. } => panic!("bug"), // `self` is a patstack
486 };
487 subpats.insert(0, set_first_col);
488 Seq { subpats }
421 } 489 }
422} 490}
423 491