712
712
//! I (Nadrieril) prefer to put new tests in `ui/pattern/usefulness` unless there's a specific
713
713
//! reason not to, for example if they crucially depend on a particular feature like `or_patterns`.
714
714
715
+ use rustc_hash:: FxHashSet ;
715
716
use rustc_index:: bit_set:: BitSet ;
716
717
use smallvec:: { smallvec, SmallVec } ;
717
718
use std:: fmt;
719
+ use std:: ops:: Deref ;
718
720
719
721
use crate :: constructor:: { Constructor , ConstructorSet , IntRange } ;
720
722
use crate :: pat:: { DeconstructedPat , PatOrWild , WitnessPat } ;
@@ -729,12 +731,36 @@ pub fn ensure_sufficient_stack<R>(f: impl FnOnce() -> R) -> R {
729
731
f ( )
730
732
}
731
733
734
+ /// Wrapper type for by-address hashing. Comparison and hashing of the wrapped pointer type will be
735
+ /// based on the address of its contents, rather than their value.
736
+ struct ByAddress < T > ( T ) ;
737
+
738
+ impl < T : Deref > ByAddress < T > {
739
+ fn addr ( & self ) -> * const T :: Target {
740
+ ( & * self . 0 ) as * const _
741
+ }
742
+ }
743
+ /// Raw pointer hashing and comparison.
744
+ impl < T : Deref > std:: hash:: Hash for ByAddress < T > {
745
+ fn hash < H : std:: hash:: Hasher > ( & self , state : & mut H ) {
746
+ self . addr ( ) . hash ( state)
747
+ }
748
+ }
749
+ impl < T : Deref > PartialEq for ByAddress < T > {
750
+ fn eq ( & self , other : & Self ) -> bool {
751
+ std:: ptr:: eq ( self . addr ( ) , other. addr ( ) )
752
+ }
753
+ }
754
+ impl < T : Deref > Eq for ByAddress < T > { }
755
+
732
756
/// Context that provides information for usefulness checking.
733
- #[ derive( derivative:: Derivative ) ]
734
- #[ derivative( Clone ( bound = "" ) , Copy ( bound = "" ) ) ]
735
- pub struct UsefulnessCtxt < ' a , Cx : TypeCx > {
757
+ struct UsefulnessCtxt < ' a , ' p , Cx : TypeCx > {
736
758
/// The context for type information.
737
- pub tycx : & ' a Cx ,
759
+ tycx : & ' a Cx ,
760
+ /// Collect the patterns found useful during usefulness checking. This is used to lint
761
+ /// unreachable (sub)patterns. We distinguish patterns by their address to avoid needing to
762
+ /// inspect the contents. They'll all be distinct anyway since they carry a `Span`.
763
+ useful_subpatterns : FxHashSet < ByAddress < & ' p DeconstructedPat < ' p , Cx > > > ,
738
764
}
739
765
740
766
/// Context that provides information local to a place under investigation.
@@ -1330,7 +1356,7 @@ impl<Cx: TypeCx> WitnessMatrix<Cx> {
1330
1356
/// We can however get false negatives because exhaustiveness does not explore all cases. See the
1331
1357
/// section on relevancy at the top of the file.
1332
1358
fn collect_overlapping_range_endpoints < ' p , Cx : TypeCx > (
1333
- mcx : UsefulnessCtxt < ' _ , Cx > ,
1359
+ mcx : & mut UsefulnessCtxt < ' _ , ' p , Cx > ,
1334
1360
overlap_range : IntRange ,
1335
1361
matrix : & Matrix < ' p , Cx > ,
1336
1362
specialized_matrix : & Matrix < ' p , Cx > ,
@@ -1403,7 +1429,7 @@ fn collect_overlapping_range_endpoints<'p, Cx: TypeCx>(
1403
1429
/// This is all explained at the top of the file.
1404
1430
#[ instrument( level = "debug" , skip( mcx, is_top_level) , ret) ]
1405
1431
fn compute_exhaustiveness_and_usefulness < ' a , ' p , Cx : TypeCx > (
1406
- mcx : UsefulnessCtxt < ' a , Cx > ,
1432
+ mcx : & mut UsefulnessCtxt < ' a , ' p , Cx > ,
1407
1433
matrix : & mut Matrix < ' p , Cx > ,
1408
1434
is_top_level : bool ,
1409
1435
) -> Result < WitnessMatrix < Cx > , Cx :: Error > {
@@ -1524,7 +1550,9 @@ fn compute_exhaustiveness_and_usefulness<'a, 'p, Cx: TypeCx>(
1524
1550
// Record usefulness in the patterns.
1525
1551
for row in matrix. rows ( ) {
1526
1552
if row. useful {
1527
- row. head ( ) . set_useful ( ) ;
1553
+ if let PatOrWild :: Pat ( pat) = row. head ( ) {
1554
+ mcx. useful_subpatterns . insert ( ByAddress ( pat) ) ;
1555
+ }
1528
1556
}
1529
1557
}
1530
1558
@@ -1545,12 +1573,17 @@ pub enum Usefulness<'p, Cx: TypeCx> {
1545
1573
1546
1574
/// Report whether this pattern was found useful, and its subpatterns that were not useful if any.
1547
1575
fn collect_pattern_usefulness < ' p , Cx : TypeCx > (
1576
+ useful_subpatterns : & FxHashSet < ByAddress < & ' p DeconstructedPat < ' p , Cx > > > ,
1548
1577
pat : & ' p DeconstructedPat < ' p , Cx > ,
1549
1578
) -> Usefulness < ' p , Cx > {
1550
- fn pat_is_useful < ' p , Cx : TypeCx > ( pat : & ' p DeconstructedPat < ' p , Cx > ) -> bool {
1551
- if pat. useful . get ( ) {
1579
+ fn pat_is_useful < ' p , Cx : TypeCx > (
1580
+ useful_subpatterns : & FxHashSet < ByAddress < & ' p DeconstructedPat < ' p , Cx > > > ,
1581
+ pat : & ' p DeconstructedPat < ' p , Cx > ,
1582
+ ) -> bool {
1583
+ if useful_subpatterns. contains ( & ByAddress ( pat) ) {
1552
1584
true
1553
- } else if pat. is_or_pat ( ) && pat. iter_fields ( ) . any ( |f| pat_is_useful ( f) ) {
1585
+ } else if pat. is_or_pat ( ) && pat. iter_fields ( ) . any ( |f| pat_is_useful ( useful_subpatterns, f) )
1586
+ {
1554
1587
// We always expand or patterns in the matrix, so we will never see the actual
1555
1588
// or-pattern (the one with constructor `Or`) in the column. As such, it will not be
1556
1589
// marked as useful itself, only its children will. We recover this information here.
@@ -1562,7 +1595,7 @@ fn collect_pattern_usefulness<'p, Cx: TypeCx>(
1562
1595
1563
1596
let mut subpats = Vec :: new ( ) ;
1564
1597
pat. walk ( & mut |p| {
1565
- if pat_is_useful ( p) {
1598
+ if pat_is_useful ( useful_subpatterns , p) {
1566
1599
// The pattern is useful, so we recurse to find redundant subpatterns.
1567
1600
true
1568
1601
} else {
@@ -1572,7 +1605,11 @@ fn collect_pattern_usefulness<'p, Cx: TypeCx>(
1572
1605
}
1573
1606
} ) ;
1574
1607
1575
- if pat_is_useful ( pat) { Usefulness :: Useful ( subpats) } else { Usefulness :: Redundant }
1608
+ if pat_is_useful ( useful_subpatterns, pat) {
1609
+ Usefulness :: Useful ( subpats)
1610
+ } else {
1611
+ Usefulness :: Redundant
1612
+ }
1576
1613
}
1577
1614
1578
1615
/// The output of checking a match for exhaustiveness and arm usefulness.
@@ -1592,18 +1629,18 @@ pub fn compute_match_usefulness<'p, Cx: TypeCx>(
1592
1629
scrut_ty : Cx :: Ty ,
1593
1630
scrut_validity : ValidityConstraint ,
1594
1631
) -> Result < UsefulnessReport < ' p , Cx > , Cx :: Error > {
1595
- let cx = UsefulnessCtxt { tycx } ;
1632
+ let mut cx = UsefulnessCtxt { tycx, useful_subpatterns : FxHashSet :: default ( ) } ;
1596
1633
let mut matrix = Matrix :: new ( arms, scrut_ty, scrut_validity) ;
1597
1634
let non_exhaustiveness_witnesses =
1598
- compute_exhaustiveness_and_usefulness ( cx, & mut matrix, true ) ?;
1635
+ compute_exhaustiveness_and_usefulness ( & mut cx, & mut matrix, true ) ?;
1599
1636
1600
1637
let non_exhaustiveness_witnesses: Vec < _ > = non_exhaustiveness_witnesses. single_column ( ) ;
1601
1638
let arm_usefulness: Vec < _ > = arms
1602
1639
. iter ( )
1603
1640
. copied ( )
1604
1641
. map ( |arm| {
1605
1642
debug ! ( ?arm) ;
1606
- let usefulness = collect_pattern_usefulness ( arm. pat ) ;
1643
+ let usefulness = collect_pattern_usefulness ( & cx . useful_subpatterns , arm. pat ) ;
1607
1644
( arm, usefulness)
1608
1645
} )
1609
1646
. collect ( ) ;
0 commit comments