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