diff options
Diffstat (limited to 'crates/hir_ty')
-rw-r--r-- | crates/hir_ty/src/diagnostics/pattern/usefulness.rs | 67 |
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. |
699 | pub(crate) struct UsefulnessReport { | 748 | pub(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 | }; |