466
466
//! first pattern of a row in the matrix is an or-pattern, we expand it by duplicating the rest of
467
467
//! the row as necessary. This is handled automatically in [`Matrix`].
468
468
//!
469
- //! This makes usefulness tracking subtle, because we also want to compute whether an alternative
470
- //! of an or-pattern is redundant, e.g. in `Some(_) | Some(0)`. We track usefulness of each
471
- //! subpattern by interior mutability in [`DeconstructedPat`] with `set_useful`/`is_useful`.
472
- //!
473
- //! It's unfortunate that we have to use interior mutability, but believe me (Nadrieril), I have
474
- //! tried [other](https://github.com/rust-lang/rust/pull/80104)
475
- //! [solutions](https://github.com/rust-lang/rust/pull/80632) and nothing is remotely as simple.
469
+ //! This makes usefulness tracking subtle, because we also want to compute whether an alternative of
470
+ //! an or-pattern is redundant, e.g. in `Some(_) | Some(0)`. We therefore track usefulness of each
471
+ //! subpattern of the match.
476
472
//!
477
473
//!
478
474
//!
713
709
//! I (Nadrieril) prefer to put new tests in `ui/pattern/usefulness` unless there's a specific
714
710
//! reason not to, for example if they crucially depend on a particular feature like `or_patterns`.
715
711
712
+ use rustc_hash:: FxHashSet ;
716
713
use rustc_index:: bit_set:: BitSet ;
717
714
use smallvec:: { smallvec, SmallVec } ;
718
715
use std:: fmt;
719
716
720
717
use crate :: constructor:: { Constructor , ConstructorSet , IntRange } ;
721
- use crate :: pat:: { DeconstructedPat , PatOrWild , WitnessPat } ;
718
+ use crate :: pat:: { DeconstructedPat , PatId , PatOrWild , WitnessPat } ;
722
719
use crate :: { Captures , MatchArm , TypeCx } ;
723
720
724
721
use self :: ValidityConstraint :: * ;
@@ -731,16 +728,12 @@ pub fn ensure_sufficient_stack<R>(f: impl FnOnce() -> R) -> R {
731
728
}
732
729
733
730
/// Context that provides information for usefulness checking.
734
- pub struct UsefulnessCtxt < ' a , Cx : TypeCx > {
731
+ struct UsefulnessCtxt < ' a , Cx : TypeCx > {
735
732
/// The context for type information.
736
- pub tycx : & ' a Cx ,
737
- }
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 }
743
- }
733
+ tycx : & ' a Cx ,
734
+ /// Collect the patterns found useful during usefulness checking. This is used to lint
735
+ /// unreachable (sub)patterns.
736
+ useful_subpatterns : FxHashSet < PatId > ,
744
737
}
745
738
746
739
/// Context that provides information local to a place under investigation.
@@ -1381,7 +1374,7 @@ impl<Cx: TypeCx> WitnessMatrix<Cx> {
1381
1374
/// We can however get false negatives because exhaustiveness does not explore all cases. See the
1382
1375
/// section on relevancy at the top of the file.
1383
1376
fn collect_overlapping_range_endpoints < ' p , Cx : TypeCx > (
1384
- mcx : UsefulnessCtxt < ' _ , Cx > ,
1377
+ mcx : & mut UsefulnessCtxt < ' _ , Cx > ,
1385
1378
overlap_range : IntRange ,
1386
1379
matrix : & Matrix < ' p , Cx > ,
1387
1380
specialized_matrix : & Matrix < ' p , Cx > ,
@@ -1441,8 +1434,8 @@ fn collect_overlapping_range_endpoints<'p, Cx: TypeCx>(
1441
1434
/// The core of the algorithm.
1442
1435
///
1443
1436
/// This recursively computes witnesses of the non-exhaustiveness of `matrix` (if any). Also tracks
1444
- /// usefulness of each row in the matrix (in `row.useful`). We track usefulness of each
1445
- /// subpattern using interior mutability in `DeconstructedPat `.
1437
+ /// usefulness of each row in the matrix (in `row.useful`). We track usefulness of each subpattern
1438
+ /// in `mcx.useful_subpatterns `.
1446
1439
///
1447
1440
/// The input `Matrix` and the output `WitnessMatrix` together match the type exhaustively.
1448
1441
///
@@ -1454,7 +1447,7 @@ fn collect_overlapping_range_endpoints<'p, Cx: TypeCx>(
1454
1447
/// This is all explained at the top of the file.
1455
1448
#[ instrument( level = "debug" , skip( mcx) , ret) ]
1456
1449
fn compute_exhaustiveness_and_usefulness < ' a , ' p , Cx : TypeCx > (
1457
- mcx : UsefulnessCtxt < ' a , Cx > ,
1450
+ mcx : & mut UsefulnessCtxt < ' a , Cx > ,
1458
1451
matrix : & mut Matrix < ' p , Cx > ,
1459
1452
) -> Result < WitnessMatrix < Cx > , Cx :: Error > {
1460
1453
debug_assert ! ( matrix. rows( ) . all( |r| r. len( ) == matrix. column_count( ) ) ) ;
@@ -1578,7 +1571,9 @@ fn compute_exhaustiveness_and_usefulness<'a, 'p, Cx: TypeCx>(
1578
1571
// Record usefulness in the patterns.
1579
1572
for row in matrix. rows ( ) {
1580
1573
if row. useful {
1581
- row. head ( ) . set_useful ( ) ;
1574
+ if let PatOrWild :: Pat ( pat) = row. head ( ) {
1575
+ mcx. useful_subpatterns . insert ( pat. uid ) ;
1576
+ }
1582
1577
}
1583
1578
}
1584
1579
@@ -1597,6 +1592,47 @@ pub enum Usefulness<'p, Cx: TypeCx> {
1597
1592
Redundant ,
1598
1593
}
1599
1594
1595
+ /// Report whether this pattern was found useful, and its subpatterns that were not useful if any.
1596
+ fn collect_pattern_usefulness < ' p , Cx : TypeCx > (
1597
+ useful_subpatterns : & FxHashSet < PatId > ,
1598
+ pat : & ' p DeconstructedPat < Cx > ,
1599
+ ) -> Usefulness < ' p , Cx > {
1600
+ fn pat_is_useful < ' p , Cx : TypeCx > (
1601
+ useful_subpatterns : & FxHashSet < PatId > ,
1602
+ pat : & ' p DeconstructedPat < Cx > ,
1603
+ ) -> bool {
1604
+ if useful_subpatterns. contains ( & pat. uid ) {
1605
+ true
1606
+ } else if pat. is_or_pat ( ) && pat. iter_fields ( ) . any ( |f| pat_is_useful ( useful_subpatterns, f) )
1607
+ {
1608
+ // We always expand or patterns in the matrix, so we will never see the actual
1609
+ // or-pattern (the one with constructor `Or`) in the column. As such, it will not be
1610
+ // marked as useful itself, only its children will. We recover this information here.
1611
+ true
1612
+ } else {
1613
+ false
1614
+ }
1615
+ }
1616
+
1617
+ let mut redundant_subpats = Vec :: new ( ) ;
1618
+ pat. walk ( & mut |p| {
1619
+ if pat_is_useful ( useful_subpatterns, p) {
1620
+ // The pattern is useful, so we recurse to find redundant subpatterns.
1621
+ true
1622
+ } else {
1623
+ // The pattern is redundant.
1624
+ redundant_subpats. push ( p) ;
1625
+ false // stop recursing
1626
+ }
1627
+ } ) ;
1628
+
1629
+ if pat_is_useful ( useful_subpatterns, pat) {
1630
+ Usefulness :: Useful ( redundant_subpats)
1631
+ } else {
1632
+ Usefulness :: Redundant
1633
+ }
1634
+ }
1635
+
1600
1636
/// The output of checking a match for exhaustiveness and arm usefulness.
1601
1637
pub struct UsefulnessReport < ' p , Cx : TypeCx > {
1602
1638
/// For each arm of the input, whether that arm is useful after the arms above it.
@@ -1614,22 +1650,17 @@ pub fn compute_match_usefulness<'p, Cx: TypeCx>(
1614
1650
scrut_ty : Cx :: Ty ,
1615
1651
scrut_validity : ValidityConstraint ,
1616
1652
) -> Result < UsefulnessReport < ' p , Cx > , Cx :: Error > {
1617
- let cx = UsefulnessCtxt { tycx } ;
1653
+ let mut cx = UsefulnessCtxt { tycx, useful_subpatterns : FxHashSet :: default ( ) } ;
1618
1654
let mut matrix = Matrix :: new ( arms, scrut_ty, scrut_validity) ;
1619
- let non_exhaustiveness_witnesses = compute_exhaustiveness_and_usefulness ( cx, & mut matrix) ?;
1655
+ let non_exhaustiveness_witnesses = compute_exhaustiveness_and_usefulness ( & mut cx, & mut matrix) ?;
1620
1656
1621
1657
let non_exhaustiveness_witnesses: Vec < _ > = non_exhaustiveness_witnesses. single_column ( ) ;
1622
1658
let arm_usefulness: Vec < _ > = arms
1623
1659
. iter ( )
1624
1660
. copied ( )
1625
1661
. map ( |arm| {
1626
1662
debug ! ( ?arm) ;
1627
- // We warn when a pattern is not useful.
1628
- let usefulness = if arm. pat . is_useful ( ) {
1629
- Usefulness :: Useful ( arm. pat . redundant_subpatterns ( ) )
1630
- } else {
1631
- Usefulness :: Redundant
1632
- } ;
1663
+ let usefulness = collect_pattern_usefulness ( & cx. useful_subpatterns , arm. pat ) ;
1633
1664
( arm, usefulness)
1634
1665
} )
1635
1666
. collect ( ) ;
0 commit comments