aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDawer <[email protected]>2021-04-29 07:33:45 +0100
committerDawer <[email protected]>2021-05-31 20:03:45 +0100
commitf4c396036416eaa977876d8ff4afe7f58f93c09e (patch)
tree2030066c0f8e09c47008f86315e2e7a0163cbe61
parentf4a95c93fe4c1050b18b3c8be25baddd6972ed84 (diff)
List useless patterns in a useful match arm
-rw-r--r--crates/hir_ty/src/diagnostics/pattern/usefulness.rs67
1 files changed, 58 insertions, 9 deletions
diff --git a/crates/hir_ty/src/diagnostics/pattern/usefulness.rs b/crates/hir_ty/src/diagnostics/pattern/usefulness.rs
index 7d9ab849b..57a416bec 100644
--- a/crates/hir_ty/src/diagnostics/pattern/usefulness.rs
+++ b/crates/hir_ty/src/diagnostics/pattern/usefulness.rs
@@ -314,11 +314,28 @@ impl SubPatSet {
314 } 314 }
315 315
316 match (&mut *self, other) { 316 match (&mut *self, other) {
317 (Seq { .. }, Seq { .. }) => { 317 (Seq { subpats: s_set }, Seq { subpats: mut o_set }) => {
318 todo!() 318 s_set.retain(|i, s_sub_set| {
319 // Missing entries count as full.
320 let o_sub_set = o_set.remove(&i).unwrap_or(Full);
321 s_sub_set.union(o_sub_set);
322 // We drop full entries.
323 !s_sub_set.is_full()
324 });
325 // Everything left in `o_set` is missing from `s_set`, i.e. counts as full. Since
326 // unioning with full returns full, we can drop those entries.
319 } 327 }
320 (Alt { .. }, Alt { .. }) => { 328 (Alt { subpats: s_set, .. }, Alt { subpats: mut o_set, .. }) => {
321 todo!() 329 s_set.retain(|i, s_sub_set| {
330 // Missing entries count as empty.
331 let o_sub_set = o_set.remove(&i).unwrap_or(Empty);
332 s_sub_set.union(o_sub_set);
333 // We drop empty entries.
334 !s_sub_set.is_empty()
335 });
336 // Everything left in `o_set` is missing from `s_set`, i.e. counts as empty. Since
337 // unioning with empty changes nothing, we can take those entries as is.
338 s_set.extend(o_set);
322 } 339 }
323 _ => panic!("bug"), 340 _ => panic!("bug"),
324 } 341 }
@@ -328,9 +345,38 @@ impl SubPatSet {
328 } 345 }
329 } 346 }
330 347
331 /// Returns a list of the spans of the unreachable subpatterns. If `self` is empty (i.e. the 348 /// Returns a list of the unreachable subpatterns. If `self` is empty (i.e. the
332 /// whole pattern is unreachable) we return `None`. 349 /// whole pattern is unreachable) we return `None`.
333 fn list_unreachable_spans(&self) -> Option<Vec<()>> { 350 fn list_unreachable_subpatterns(&self, cx: &MatchCheckCtx<'_>) -> Option<Vec<PatId>> {
351 /// Panics if `set.is_empty()`.
352 fn fill_subpats(
353 set: &SubPatSet,
354 unreachable_pats: &mut Vec<PatId>,
355 cx: &MatchCheckCtx<'_>,
356 ) {
357 match set {
358 SubPatSet::Empty => panic!("bug"),
359 SubPatSet::Full => {}
360 SubPatSet::Seq { subpats } => {
361 for (_, sub_set) in subpats {
362 fill_subpats(sub_set, unreachable_pats, cx);
363 }
364 }
365 SubPatSet::Alt { subpats, pat, alt_count, .. } => {
366 let expanded = pat.expand_or_pat(cx);
367 for i in 0..*alt_count {
368 let sub_set = subpats.get(&i).unwrap_or(&SubPatSet::Empty);
369 if sub_set.is_empty() {
370 // Found a unreachable subpattern.
371 unreachable_pats.push(expanded[i]);
372 } else {
373 fill_subpats(sub_set, unreachable_pats, cx);
374 }
375 }
376 }
377 }
378 }
379
334 if self.is_empty() { 380 if self.is_empty() {
335 return None; 381 return None;
336 } 382 }
@@ -338,7 +384,9 @@ impl SubPatSet {
338 // No subpatterns are unreachable. 384 // No subpatterns are unreachable.
339 return Some(Vec::new()); 385 return Some(Vec::new());
340 } 386 }
341 todo!() 387 let mut unreachable_pats = Vec::new();
388 fill_subpats(self, &mut unreachable_pats, cx);
389 Some(unreachable_pats)
342 } 390 }
343 391
344 /// When `self` refers to a patstack that was obtained from specialization, after running 392 /// When `self` refers to a patstack that was obtained from specialization, after running
@@ -691,10 +739,11 @@ pub(crate) enum Reachability {
691 /// The arm is reachable. This additionally carries a set of or-pattern branches that have been 739 /// The arm is reachable. This additionally carries a set of or-pattern branches that have been
692 /// found to be unreachable despite the overall arm being reachable. Used only in the presence 740 /// found to be unreachable despite the overall arm being reachable. Used only in the presence
693 /// of or-patterns, otherwise it stays empty. 741 /// of or-patterns, otherwise it stays empty.
694 Reachable(Vec<()>), 742 Reachable(Vec<PatId>),
695 /// The arm is unreachable. 743 /// The arm is unreachable.
696 Unreachable, 744 Unreachable,
697} 745}
746
698/// The output of checking a match for exhaustiveness and arm reachability. 747/// The output of checking a match for exhaustiveness and arm reachability.
699pub(crate) struct UsefulnessReport { 748pub(crate) struct UsefulnessReport {
700 /// For each arm of the input, whether that arm is reachable after the arms above it. 749 /// For each arm of the input, whether that arm is reachable after the arms above it.
@@ -726,7 +775,7 @@ pub(crate) fn compute_match_usefulness(
726 let reachability = match usefulness { 775 let reachability = match usefulness {
727 NoWitnesses(subpats) if subpats.is_empty() => Reachability::Unreachable, 776 NoWitnesses(subpats) if subpats.is_empty() => Reachability::Unreachable,
728 NoWitnesses(subpats) => { 777 NoWitnesses(subpats) => {
729 Reachability::Reachable(subpats.list_unreachable_spans().unwrap()) 778 Reachability::Reachable(subpats.list_unreachable_subpatterns(cx).unwrap())
730 } 779 }
731 WithWitnesses(..) => panic!("bug"), 780 WithWitnesses(..) => panic!("bug"),
732 }; 781 };