@@ -1312,9 +1312,10 @@ impl<'p, 'tcx> Fields<'p, 'tcx> {
1312
1312
1313
1313
/// Values and patterns can be represented as a constructor applied to some fields. This represents
1314
1314
/// a pattern in this form.
1315
- /// This also keeps track of whether the pattern has been found reachable during analysis. For this
1316
- /// reason we should be careful not to clone patterns for which we care about that. Use
1317
- /// `clone_and_forget_reachability` if you're sure.
1315
+ /// This also uses interior mutability to keep track of whether the pattern has been found reachable
1316
+ /// during analysis. For this reason they cannot be cloned.
1317
+ /// A `DeconstructedPat` will almost always come from user input; the only exception are some
1318
+ /// `Wildcard`s introduced during specialization.
1318
1319
pub ( crate ) struct DeconstructedPat < ' p , ' tcx > {
1319
1320
ctor : Constructor < ' tcx > ,
1320
1321
fields : Fields < ' p , ' tcx > ,
@@ -1337,20 +1338,6 @@ impl<'p, 'tcx> DeconstructedPat<'p, 'tcx> {
1337
1338
DeconstructedPat { ctor, fields, ty, span, reachable : Cell :: new ( false ) }
1338
1339
}
1339
1340
1340
- /// Construct a pattern that matches everything that starts with this constructor.
1341
- /// For example, if `ctor` is a `Constructor::Variant` for `Option::Some`, we get the pattern
1342
- /// `Some(_)`.
1343
- pub ( super ) fn wild_from_ctor ( pcx : & PatCtxt < ' _ , ' p , ' tcx > , ctor : Constructor < ' tcx > ) -> Self {
1344
- let fields = Fields :: wildcards ( pcx, & ctor) ;
1345
- DeconstructedPat :: new ( ctor, fields, pcx. ty , pcx. span )
1346
- }
1347
-
1348
- /// Clone this value. This method emphasizes that cloning loses reachability information and
1349
- /// should be done carefully.
1350
- pub ( super ) fn clone_and_forget_reachability ( & self ) -> Self {
1351
- DeconstructedPat :: new ( self . ctor . clone ( ) , self . fields , self . ty , self . span )
1352
- }
1353
-
1354
1341
pub ( crate ) fn from_pat ( cx : & MatchCheckCtxt < ' p , ' tcx > , pat : & Pat < ' tcx > ) -> Self {
1355
1342
let mkpat = |pat| DeconstructedPat :: from_pat ( cx, pat) ;
1356
1343
let ctor;
@@ -1529,95 +1516,6 @@ impl<'p, 'tcx> DeconstructedPat<'p, 'tcx> {
1529
1516
DeconstructedPat :: new ( ctor, fields, pat. ty , pat. span )
1530
1517
}
1531
1518
1532
- pub ( crate ) fn to_pat ( & self , cx : & MatchCheckCtxt < ' p , ' tcx > ) -> Pat < ' tcx > {
1533
- let is_wildcard = |pat : & Pat < ' _ > | {
1534
- matches ! ( pat. kind, PatKind :: Binding { subpattern: None , .. } | PatKind :: Wild )
1535
- } ;
1536
- let mut subpatterns = self . iter_fields ( ) . map ( |p| Box :: new ( p. to_pat ( cx) ) ) ;
1537
- let kind = match & self . ctor {
1538
- Single | Variant ( _) => match self . ty . kind ( ) {
1539
- ty:: Tuple ( ..) => PatKind :: Leaf {
1540
- subpatterns : subpatterns
1541
- . enumerate ( )
1542
- . map ( |( i, pattern) | FieldPat { field : FieldIdx :: new ( i) , pattern } )
1543
- . collect ( ) ,
1544
- } ,
1545
- ty:: Adt ( adt_def, _) if adt_def. is_box ( ) => {
1546
- // Without `box_patterns`, the only legal pattern of type `Box` is `_` (outside
1547
- // of `std`). So this branch is only reachable when the feature is enabled and
1548
- // the pattern is a box pattern.
1549
- PatKind :: Deref { subpattern : subpatterns. next ( ) . unwrap ( ) }
1550
- }
1551
- ty:: Adt ( adt_def, args) => {
1552
- let variant_index = self . ctor . variant_index_for_adt ( * adt_def) ;
1553
- let variant = & adt_def. variant ( variant_index) ;
1554
- let subpatterns = Fields :: list_variant_nonhidden_fields ( cx, self . ty , variant)
1555
- . zip ( subpatterns)
1556
- . map ( |( ( field, _ty) , pattern) | FieldPat { field, pattern } )
1557
- . collect ( ) ;
1558
-
1559
- if adt_def. is_enum ( ) {
1560
- PatKind :: Variant { adt_def : * adt_def, args, variant_index, subpatterns }
1561
- } else {
1562
- PatKind :: Leaf { subpatterns }
1563
- }
1564
- }
1565
- // Note: given the expansion of `&str` patterns done in `expand_pattern`, we should
1566
- // be careful to reconstruct the correct constant pattern here. However a string
1567
- // literal pattern will never be reported as a non-exhaustiveness witness, so we
1568
- // ignore this issue.
1569
- ty:: Ref ( ..) => PatKind :: Deref { subpattern : subpatterns. next ( ) . unwrap ( ) } ,
1570
- _ => bug ! ( "unexpected ctor for type {:?} {:?}" , self . ctor, self . ty) ,
1571
- } ,
1572
- Slice ( slice) => {
1573
- match slice. kind {
1574
- FixedLen ( _) => PatKind :: Slice {
1575
- prefix : subpatterns. collect ( ) ,
1576
- slice : None ,
1577
- suffix : Box :: new ( [ ] ) ,
1578
- } ,
1579
- VarLen ( prefix, _) => {
1580
- let mut subpatterns = subpatterns. peekable ( ) ;
1581
- let mut prefix: Vec < _ > = subpatterns. by_ref ( ) . take ( prefix) . collect ( ) ;
1582
- if slice. array_len . is_some ( ) {
1583
- // Improves diagnostics a bit: if the type is a known-size array, instead
1584
- // of reporting `[x, _, .., _, y]`, we prefer to report `[x, .., y]`.
1585
- // This is incorrect if the size is not known, since `[_, ..]` captures
1586
- // arrays of lengths `>= 1` whereas `[..]` captures any length.
1587
- while !prefix. is_empty ( ) && is_wildcard ( prefix. last ( ) . unwrap ( ) ) {
1588
- prefix. pop ( ) ;
1589
- }
1590
- while subpatterns. peek ( ) . is_some ( )
1591
- && is_wildcard ( subpatterns. peek ( ) . unwrap ( ) )
1592
- {
1593
- subpatterns. next ( ) ;
1594
- }
1595
- }
1596
- let suffix: Box < [ _ ] > = subpatterns. collect ( ) ;
1597
- let wild = Pat :: wildcard_from_ty ( self . ty ) ;
1598
- PatKind :: Slice {
1599
- prefix : prefix. into_boxed_slice ( ) ,
1600
- slice : Some ( Box :: new ( wild) ) ,
1601
- suffix,
1602
- }
1603
- }
1604
- }
1605
- }
1606
- & Str ( value) => PatKind :: Constant { value } ,
1607
- IntRange ( range) => return range. to_pat ( cx. tcx , self . ty ) ,
1608
- Wildcard | NonExhaustive | Hidden => PatKind :: Wild ,
1609
- Missing { .. } => bug ! (
1610
- "trying to convert a `Missing` constructor into a `Pat`; this is probably a bug,
1611
- `Missing` should have been processed in `apply_constructors`"
1612
- ) ,
1613
- F32Range ( ..) | F64Range ( ..) | Opaque | Or => {
1614
- bug ! ( "can't convert to pattern: {:?}" , self )
1615
- }
1616
- } ;
1617
-
1618
- Pat { ty : self . ty , span : DUMMY_SP , kind }
1619
- }
1620
-
1621
1519
pub ( super ) fn is_or_pat ( & self ) -> bool {
1622
1520
matches ! ( self . ctor, Or )
1623
1521
}
@@ -1800,3 +1698,131 @@ impl<'p, 'tcx> fmt::Debug for DeconstructedPat<'p, 'tcx> {
1800
1698
}
1801
1699
}
1802
1700
}
1701
+
1702
+ /// Same idea as `DeconstructedPat`, except this is a fictitious pattern built up for diagnostics
1703
+ /// purposes. As such they don't use interning and can be cloned.
1704
+ #[ derive( Debug , Clone ) ]
1705
+ pub ( crate ) struct WitnessPat < ' tcx > {
1706
+ ctor : Constructor < ' tcx > ,
1707
+ fields : Vec < WitnessPat < ' tcx > > ,
1708
+ ty : Ty < ' tcx > ,
1709
+ }
1710
+
1711
+ impl < ' tcx > WitnessPat < ' tcx > {
1712
+ pub ( super ) fn new ( ctor : Constructor < ' tcx > , fields : Vec < Self > , ty : Ty < ' tcx > ) -> Self {
1713
+ Self { ctor, fields, ty }
1714
+ }
1715
+ pub ( super ) fn wildcard ( ty : Ty < ' tcx > ) -> Self {
1716
+ Self :: new ( Wildcard , Vec :: new ( ) , ty)
1717
+ }
1718
+
1719
+ /// Construct a pattern that matches everything that starts with this constructor.
1720
+ /// For example, if `ctor` is a `Constructor::Variant` for `Option::Some`, we get the pattern
1721
+ /// `Some(_)`.
1722
+ pub ( super ) fn wild_from_ctor ( pcx : & PatCtxt < ' _ , ' _ , ' tcx > , ctor : Constructor < ' tcx > ) -> Self {
1723
+ // Reuse `Fields::wildcards` to get the types.
1724
+ let fields = Fields :: wildcards ( pcx, & ctor)
1725
+ . iter_patterns ( )
1726
+ . map ( |deco_pat| Self :: wildcard ( deco_pat. ty ( ) ) )
1727
+ . collect ( ) ;
1728
+ Self :: new ( ctor, fields, pcx. ty )
1729
+ }
1730
+
1731
+ pub ( super ) fn ctor ( & self ) -> & Constructor < ' tcx > {
1732
+ & self . ctor
1733
+ }
1734
+ pub ( super ) fn ty ( & self ) -> Ty < ' tcx > {
1735
+ self . ty
1736
+ }
1737
+
1738
+ pub ( crate ) fn to_pat ( & self , cx : & MatchCheckCtxt < ' _ , ' tcx > ) -> Pat < ' tcx > {
1739
+ let is_wildcard = |pat : & Pat < ' _ > | matches ! ( pat. kind, PatKind :: Wild ) ;
1740
+ let mut subpatterns = self . iter_fields ( ) . map ( |p| Box :: new ( p. to_pat ( cx) ) ) ;
1741
+ let kind = match & self . ctor {
1742
+ Single | Variant ( _) => match self . ty . kind ( ) {
1743
+ ty:: Tuple ( ..) => PatKind :: Leaf {
1744
+ subpatterns : subpatterns
1745
+ . enumerate ( )
1746
+ . map ( |( i, pattern) | FieldPat { field : FieldIdx :: new ( i) , pattern } )
1747
+ . collect ( ) ,
1748
+ } ,
1749
+ ty:: Adt ( adt_def, _) if adt_def. is_box ( ) => {
1750
+ // Without `box_patterns`, the only legal pattern of type `Box` is `_` (outside
1751
+ // of `std`). So this branch is only reachable when the feature is enabled and
1752
+ // the pattern is a box pattern.
1753
+ PatKind :: Deref { subpattern : subpatterns. next ( ) . unwrap ( ) }
1754
+ }
1755
+ ty:: Adt ( adt_def, args) => {
1756
+ let variant_index = self . ctor . variant_index_for_adt ( * adt_def) ;
1757
+ let variant = & adt_def. variant ( variant_index) ;
1758
+ let subpatterns = Fields :: list_variant_nonhidden_fields ( cx, self . ty , variant)
1759
+ . zip ( subpatterns)
1760
+ . map ( |( ( field, _ty) , pattern) | FieldPat { field, pattern } )
1761
+ . collect ( ) ;
1762
+
1763
+ if adt_def. is_enum ( ) {
1764
+ PatKind :: Variant { adt_def : * adt_def, args, variant_index, subpatterns }
1765
+ } else {
1766
+ PatKind :: Leaf { subpatterns }
1767
+ }
1768
+ }
1769
+ // Note: given the expansion of `&str` patterns done in `expand_pattern`, we should
1770
+ // be careful to reconstruct the correct constant pattern here. However a string
1771
+ // literal pattern will never be reported as a non-exhaustiveness witness, so we
1772
+ // ignore this issue.
1773
+ ty:: Ref ( ..) => PatKind :: Deref { subpattern : subpatterns. next ( ) . unwrap ( ) } ,
1774
+ _ => bug ! ( "unexpected ctor for type {:?} {:?}" , self . ctor, self . ty) ,
1775
+ } ,
1776
+ Slice ( slice) => {
1777
+ match slice. kind {
1778
+ FixedLen ( _) => PatKind :: Slice {
1779
+ prefix : subpatterns. collect ( ) ,
1780
+ slice : None ,
1781
+ suffix : Box :: new ( [ ] ) ,
1782
+ } ,
1783
+ VarLen ( prefix, _) => {
1784
+ let mut subpatterns = subpatterns. peekable ( ) ;
1785
+ let mut prefix: Vec < _ > = subpatterns. by_ref ( ) . take ( prefix) . collect ( ) ;
1786
+ if slice. array_len . is_some ( ) {
1787
+ // Improves diagnostics a bit: if the type is a known-size array, instead
1788
+ // of reporting `[x, _, .., _, y]`, we prefer to report `[x, .., y]`.
1789
+ // This is incorrect if the size is not known, since `[_, ..]` captures
1790
+ // arrays of lengths `>= 1` whereas `[..]` captures any length.
1791
+ while !prefix. is_empty ( ) && is_wildcard ( prefix. last ( ) . unwrap ( ) ) {
1792
+ prefix. pop ( ) ;
1793
+ }
1794
+ while subpatterns. peek ( ) . is_some ( )
1795
+ && is_wildcard ( subpatterns. peek ( ) . unwrap ( ) )
1796
+ {
1797
+ subpatterns. next ( ) ;
1798
+ }
1799
+ }
1800
+ let suffix: Box < [ _ ] > = subpatterns. collect ( ) ;
1801
+ let wild = Pat :: wildcard_from_ty ( self . ty ) ;
1802
+ PatKind :: Slice {
1803
+ prefix : prefix. into_boxed_slice ( ) ,
1804
+ slice : Some ( Box :: new ( wild) ) ,
1805
+ suffix,
1806
+ }
1807
+ }
1808
+ }
1809
+ }
1810
+ & Str ( value) => PatKind :: Constant { value } ,
1811
+ IntRange ( range) => return range. to_pat ( cx. tcx , self . ty ) ,
1812
+ Wildcard | NonExhaustive | Hidden => PatKind :: Wild ,
1813
+ Missing { .. } => bug ! (
1814
+ "trying to convert a `Missing` constructor into a `Pat`; this is probably a bug,
1815
+ `Missing` should have been processed in `apply_constructors`"
1816
+ ) ,
1817
+ F32Range ( ..) | F64Range ( ..) | Opaque | Or => {
1818
+ bug ! ( "can't convert to pattern: {:?}" , self )
1819
+ }
1820
+ } ;
1821
+
1822
+ Pat { ty : self . ty , span : DUMMY_SP , kind }
1823
+ }
1824
+
1825
+ pub ( super ) fn iter_fields < ' a > ( & ' a self ) -> impl Iterator < Item = & ' a WitnessPat < ' tcx > > {
1826
+ self . fields . iter ( )
1827
+ }
1828
+ }
0 commit comments