713713//! I (Nadrieril) prefer to put new tests in `ui/pattern/usefulness` unless there's a specific
714714//! reason not to, for example if they crucially depend on a particular feature like `or_patterns`.
715715
716+ use rustc_hash:: FxHashSet ;
716717use rustc_index:: bit_set:: BitSet ;
717718use smallvec:: { smallvec, SmallVec } ;
718719use std:: fmt;
720+ use std:: ops:: Deref ;
719721
720722use crate :: constructor:: { Constructor , ConstructorSet , IntRange } ;
721723use crate :: pat:: { DeconstructedPat , PatOrWild , WitnessPat } ;
@@ -730,18 +732,37 @@ pub fn ensure_sufficient_stack<R>(f: impl FnOnce() -> R) -> R {
730732 f ( )
731733}
732734
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 ) ;
738738
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 ( ) )
743753 }
744754}
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+ }
745766
746767/// Context that provides information local to a place under investigation.
747768struct PlaceCtxt < ' a , Cx : TypeCx > {
@@ -1361,7 +1382,7 @@ impl<Cx: TypeCx> WitnessMatrix<Cx> {
13611382/// We can however get false negatives because exhaustiveness does not explore all cases. See the
13621383/// section on relevancy at the top of the file.
13631384fn collect_overlapping_range_endpoints < ' p , Cx : TypeCx > (
1364- mcx : UsefulnessCtxt < ' _ , Cx > ,
1385+ mcx : & mut UsefulnessCtxt < ' _ , ' p , Cx > ,
13651386 overlap_range : IntRange ,
13661387 matrix : & Matrix < ' p , Cx > ,
13671388 specialized_matrix : & Matrix < ' p , Cx > ,
@@ -1434,7 +1455,7 @@ fn collect_overlapping_range_endpoints<'p, Cx: TypeCx>(
14341455/// This is all explained at the top of the file.
14351456#[ instrument( level = "debug" , skip( mcx, is_top_level) , ret) ]
14361457fn compute_exhaustiveness_and_usefulness < ' a , ' p , Cx : TypeCx > (
1437- mcx : UsefulnessCtxt < ' a , Cx > ,
1458+ mcx : & mut UsefulnessCtxt < ' a , ' p , Cx > ,
14381459 matrix : & mut Matrix < ' p , Cx > ,
14391460 is_top_level : bool ,
14401461) -> Result < WitnessMatrix < Cx > , Cx :: Error > {
@@ -1562,7 +1583,9 @@ fn compute_exhaustiveness_and_usefulness<'a, 'p, Cx: TypeCx>(
15621583 // Record usefulness in the patterns.
15631584 for row in matrix. rows ( ) {
15641585 if row. useful {
1565- row. head ( ) . set_useful ( ) ;
1586+ if let PatOrWild :: Pat ( pat) = row. head ( ) {
1587+ mcx. useful_subpatterns . insert ( ByAddress ( pat) ) ;
1588+ }
15661589 }
15671590 }
15681591
@@ -1582,11 +1605,18 @@ pub enum Usefulness<'p, Cx: TypeCx> {
15821605}
15831606
15841607/// Report whether this pattern was found useful, and its subpatterns that were not useful if any.
1585- fn collect_pattern_usefulness < ' p , Cx : TypeCx > ( pat : & ' p DeconstructedPat < Cx > ) -> Usefulness < ' p , Cx > {
1586- fn pat_is_useful < ' p , Cx : TypeCx > ( pat : & ' p DeconstructedPat < Cx > ) -> bool {
1587- if pat. useful . get ( ) {
1608+ fn collect_pattern_usefulness < ' p , Cx : TypeCx > (
1609+ useful_subpatterns : & FxHashSet < ByAddress < & ' p DeconstructedPat < Cx > > > ,
1610+ pat : & ' p DeconstructedPat < Cx > ,
1611+ ) -> Usefulness < ' p , Cx > {
1612+ fn pat_is_useful < ' p , Cx : TypeCx > (
1613+ useful_subpatterns : & FxHashSet < ByAddress < & ' p DeconstructedPat < Cx > > > ,
1614+ pat : & ' p DeconstructedPat < Cx > ,
1615+ ) -> bool {
1616+ if useful_subpatterns. contains ( & ByAddress ( pat) ) {
15881617 true
1589- } else if pat. is_or_pat ( ) && pat. iter_fields ( ) . any ( |f| pat_is_useful ( f) ) {
1618+ } else if pat. is_or_pat ( ) && pat. iter_fields ( ) . any ( |f| pat_is_useful ( useful_subpatterns, f) )
1619+ {
15901620 // We always expand or patterns in the matrix, so we will never see the actual
15911621 // or-pattern (the one with constructor `Or`) in the column. As such, it will not be
15921622 // marked as useful itself, only its children will. We recover this information here.
@@ -1598,7 +1628,7 @@ fn collect_pattern_usefulness<'p, Cx: TypeCx>(pat: &'p DeconstructedPat<Cx>) ->
15981628
15991629 let mut redundant_subpats = Vec :: new ( ) ;
16001630 pat. walk ( & mut |p| {
1601- if pat_is_useful ( p) {
1631+ if pat_is_useful ( useful_subpatterns , p) {
16021632 // The pattern is useful, so we recurse to find redundant subpatterns.
16031633 true
16041634 } else {
@@ -1608,7 +1638,11 @@ fn collect_pattern_usefulness<'p, Cx: TypeCx>(pat: &'p DeconstructedPat<Cx>) ->
16081638 }
16091639 } ) ;
16101640
1611- if pat_is_useful ( pat) { Usefulness :: Useful ( redundant_subpats) } else { Usefulness :: Redundant }
1641+ if pat_is_useful ( useful_subpatterns, pat) {
1642+ Usefulness :: Useful ( redundant_subpats)
1643+ } else {
1644+ Usefulness :: Redundant
1645+ }
16121646}
16131647
16141648/// The output of checking a match for exhaustiveness and arm usefulness.
@@ -1628,18 +1662,18 @@ pub fn compute_match_usefulness<'p, Cx: TypeCx>(
16281662 scrut_ty : Cx :: Ty ,
16291663 scrut_validity : ValidityConstraint ,
16301664) -> Result < UsefulnessReport < ' p , Cx > , Cx :: Error > {
1631- let cx = UsefulnessCtxt { tycx } ;
1665+ let mut cx = UsefulnessCtxt { tycx, useful_subpatterns : FxHashSet :: default ( ) } ;
16321666 let mut matrix = Matrix :: new ( arms, scrut_ty, scrut_validity) ;
16331667 let non_exhaustiveness_witnesses =
1634- compute_exhaustiveness_and_usefulness ( cx, & mut matrix, true ) ?;
1668+ compute_exhaustiveness_and_usefulness ( & mut cx, & mut matrix, true ) ?;
16351669
16361670 let non_exhaustiveness_witnesses: Vec < _ > = non_exhaustiveness_witnesses. single_column ( ) ;
16371671 let arm_usefulness: Vec < _ > = arms
16381672 . iter ( )
16391673 . copied ( )
16401674 . map ( |arm| {
16411675 debug ! ( ?arm) ;
1642- let usefulness = collect_pattern_usefulness ( arm. pat ) ;
1676+ let usefulness = collect_pattern_usefulness ( & cx . useful_subpatterns , arm. pat ) ;
16431677 ( arm, usefulness)
16441678 } )
16451679 . collect ( ) ;
0 commit comments