713
713
//! I (Nadrieril) prefer to put new tests in `ui/pattern/usefulness` unless there's a specific
714
714
//! reason not to, for example if they crucially depend on a particular feature like `or_patterns`.
715
715
716
+ use rustc_hash:: FxHashSet ;
716
717
use rustc_index:: bit_set:: BitSet ;
717
718
use smallvec:: { smallvec, SmallVec } ;
718
719
use std:: fmt;
720
+ use std:: ops:: Deref ;
719
721
720
722
use crate :: constructor:: { Constructor , ConstructorSet , IntRange } ;
721
723
use crate :: pat:: { DeconstructedPat , PatOrWild , WitnessPat } ;
@@ -730,18 +732,37 @@ pub fn ensure_sufficient_stack<R>(f: impl FnOnce() -> R) -> R {
730
732
f ( )
731
733
}
732
734
733
- /// Context that provides information for usefulness checking.
734
- pub struct UsefulnessCtxt < ' a , Cx : TypeCx > {
735
- /// The context for type information.
736
- pub tycx : & ' a Cx ,
737
- }
735
+ /// Wrapper type for by-address hashing. Comparison and hashing of the wrapped pointer type will be
736
+ /// based on the address of its contents, rather than their value.
737
+ struct ByAddress < T > ( T ) ;
738
738
739
- impl < ' a , Cx : TypeCx > Copy for UsefulnessCtxt < ' a , Cx > { }
740
- impl < ' a , Cx : TypeCx > Clone for UsefulnessCtxt < ' a , Cx > {
741
- fn clone ( & self ) -> Self {
742
- Self { tycx : self . tycx }
739
+ impl < T : Deref > ByAddress < T > {
740
+ fn addr ( & self ) -> * const T :: Target {
741
+ ( & * self . 0 ) as * const _
742
+ }
743
+ }
744
+ /// Raw pointer hashing and comparison.
745
+ impl < T : Deref > std:: hash:: Hash for ByAddress < T > {
746
+ fn hash < H : std:: hash:: Hasher > ( & self , state : & mut H ) {
747
+ self . addr ( ) . hash ( state)
748
+ }
749
+ }
750
+ impl < T : Deref > PartialEq for ByAddress < T > {
751
+ fn eq ( & self , other : & Self ) -> bool {
752
+ std:: ptr:: eq ( self . addr ( ) , other. addr ( ) )
743
753
}
744
754
}
755
+ impl < T : Deref > Eq for ByAddress < T > { }
756
+
757
+ /// Context that provides information for usefulness checking.
758
+ struct UsefulnessCtxt < ' a , ' p , Cx : TypeCx > {
759
+ /// The context for type information.
760
+ tycx : & ' a Cx ,
761
+ /// Collect the patterns found useful during usefulness checking. This is used to lint
762
+ /// unreachable (sub)patterns. We distinguish patterns by their address to avoid needing to
763
+ /// inspect the contents. They'll all be distinct anyway since they carry a `Span`.
764
+ useful_subpatterns : FxHashSet < ByAddress < & ' p DeconstructedPat < Cx > > > ,
765
+ }
745
766
746
767
/// Context that provides information local to a place under investigation.
747
768
struct PlaceCtxt < ' a , Cx : TypeCx > {
@@ -1381,7 +1402,7 @@ impl<Cx: TypeCx> WitnessMatrix<Cx> {
1381
1402
/// We can however get false negatives because exhaustiveness does not explore all cases. See the
1382
1403
/// section on relevancy at the top of the file.
1383
1404
fn collect_overlapping_range_endpoints < ' p , Cx : TypeCx > (
1384
- mcx : UsefulnessCtxt < ' _ , Cx > ,
1405
+ mcx : & mut UsefulnessCtxt < ' _ , ' p , Cx > ,
1385
1406
overlap_range : IntRange ,
1386
1407
matrix : & Matrix < ' p , Cx > ,
1387
1408
specialized_matrix : & Matrix < ' p , Cx > ,
@@ -1454,7 +1475,7 @@ fn collect_overlapping_range_endpoints<'p, Cx: TypeCx>(
1454
1475
/// This is all explained at the top of the file.
1455
1476
#[ instrument( level = "debug" , skip( mcx) , ret) ]
1456
1477
fn compute_exhaustiveness_and_usefulness < ' a , ' p , Cx : TypeCx > (
1457
- mcx : UsefulnessCtxt < ' a , Cx > ,
1478
+ mcx : & mut UsefulnessCtxt < ' a , ' p , Cx > ,
1458
1479
matrix : & mut Matrix < ' p , Cx > ,
1459
1480
) -> Result < WitnessMatrix < Cx > , Cx :: Error > {
1460
1481
debug_assert ! ( matrix. rows( ) . all( |r| r. len( ) == matrix. column_count( ) ) ) ;
@@ -1580,7 +1601,9 @@ fn compute_exhaustiveness_and_usefulness<'a, 'p, Cx: TypeCx>(
1580
1601
// Record usefulness in the patterns.
1581
1602
for row in matrix. rows ( ) {
1582
1603
if row. useful {
1583
- row. head ( ) . set_useful ( ) ;
1604
+ if let PatOrWild :: Pat ( pat) = row. head ( ) {
1605
+ mcx. useful_subpatterns . insert ( ByAddress ( pat) ) ;
1606
+ }
1584
1607
}
1585
1608
}
1586
1609
@@ -1600,11 +1623,18 @@ pub enum Usefulness<'p, Cx: TypeCx> {
1600
1623
}
1601
1624
1602
1625
/// Report whether this pattern was found useful, and its subpatterns that were not useful if any.
1603
- fn collect_pattern_usefulness < ' p , Cx : TypeCx > ( pat : & ' p DeconstructedPat < Cx > ) -> Usefulness < ' p , Cx > {
1604
- fn pat_is_useful < ' p , Cx : TypeCx > ( pat : & ' p DeconstructedPat < Cx > ) -> bool {
1605
- if pat. useful . get ( ) {
1626
+ fn collect_pattern_usefulness < ' p , Cx : TypeCx > (
1627
+ useful_subpatterns : & FxHashSet < ByAddress < & ' p DeconstructedPat < Cx > > > ,
1628
+ pat : & ' p DeconstructedPat < Cx > ,
1629
+ ) -> Usefulness < ' p , Cx > {
1630
+ fn pat_is_useful < ' p , Cx : TypeCx > (
1631
+ useful_subpatterns : & FxHashSet < ByAddress < & ' p DeconstructedPat < Cx > > > ,
1632
+ pat : & ' p DeconstructedPat < Cx > ,
1633
+ ) -> bool {
1634
+ if useful_subpatterns. contains ( & ByAddress ( pat) ) {
1606
1635
true
1607
- } else if pat. is_or_pat ( ) && pat. iter_fields ( ) . any ( |f| pat_is_useful ( f) ) {
1636
+ } else if pat. is_or_pat ( ) && pat. iter_fields ( ) . any ( |f| pat_is_useful ( useful_subpatterns, f) )
1637
+ {
1608
1638
// We always expand or patterns in the matrix, so we will never see the actual
1609
1639
// or-pattern (the one with constructor `Or`) in the column. As such, it will not be
1610
1640
// marked as useful itself, only its children will. We recover this information here.
@@ -1616,7 +1646,7 @@ fn collect_pattern_usefulness<'p, Cx: TypeCx>(pat: &'p DeconstructedPat<Cx>) ->
1616
1646
1617
1647
let mut redundant_subpats = Vec :: new ( ) ;
1618
1648
pat. walk ( & mut |p| {
1619
- if pat_is_useful ( p) {
1649
+ if pat_is_useful ( useful_subpatterns , p) {
1620
1650
// The pattern is useful, so we recurse to find redundant subpatterns.
1621
1651
true
1622
1652
} else {
@@ -1626,7 +1656,11 @@ fn collect_pattern_usefulness<'p, Cx: TypeCx>(pat: &'p DeconstructedPat<Cx>) ->
1626
1656
}
1627
1657
} ) ;
1628
1658
1629
- if pat_is_useful ( pat) { Usefulness :: Useful ( redundant_subpats) } else { Usefulness :: Redundant }
1659
+ if pat_is_useful ( useful_subpatterns, pat) {
1660
+ Usefulness :: Useful ( redundant_subpats)
1661
+ } else {
1662
+ Usefulness :: Redundant
1663
+ }
1630
1664
}
1631
1665
1632
1666
/// The output of checking a match for exhaustiveness and arm usefulness.
@@ -1646,17 +1680,17 @@ pub fn compute_match_usefulness<'p, Cx: TypeCx>(
1646
1680
scrut_ty : Cx :: Ty ,
1647
1681
scrut_validity : ValidityConstraint ,
1648
1682
) -> Result < UsefulnessReport < ' p , Cx > , Cx :: Error > {
1649
- let cx = UsefulnessCtxt { tycx } ;
1683
+ let mut cx = UsefulnessCtxt { tycx, useful_subpatterns : FxHashSet :: default ( ) } ;
1650
1684
let mut matrix = Matrix :: new ( arms, scrut_ty, scrut_validity) ;
1651
- let non_exhaustiveness_witnesses = compute_exhaustiveness_and_usefulness ( cx, & mut matrix) ?;
1685
+ let non_exhaustiveness_witnesses = compute_exhaustiveness_and_usefulness ( & mut cx, & mut matrix) ?;
1652
1686
1653
1687
let non_exhaustiveness_witnesses: Vec < _ > = non_exhaustiveness_witnesses. single_column ( ) ;
1654
1688
let arm_usefulness: Vec < _ > = arms
1655
1689
. iter ( )
1656
1690
. copied ( )
1657
1691
. map ( |arm| {
1658
1692
debug ! ( ?arm) ;
1659
- let usefulness = collect_pattern_usefulness ( arm. pat ) ;
1693
+ let usefulness = collect_pattern_usefulness ( & cx . useful_subpatterns , arm. pat ) ;
1660
1694
( arm, usefulness)
1661
1695
} )
1662
1696
. collect ( ) ;
0 commit comments