@@ -20,32 +20,42 @@ impl PatId {
2020 }
2121}
2222
23+ /// A pattern with an index denoting which field it corresponds to.
24+ pub struct IndexedPat < Cx : TypeCx > {
25+ pub idx : usize ,
26+ pub pat : DeconstructedPat < Cx > ,
27+ }
28+
2329/// Values and patterns can be represented as a constructor applied to some fields. This represents
2430/// a pattern in this form. A `DeconstructedPat` will almost always come from user input; the only
2531/// exception are some `Wildcard`s introduced during pattern lowering.
2632pub struct DeconstructedPat < Cx : TypeCx > {
2733 ctor : Constructor < Cx > ,
28- fields : Vec < DeconstructedPat < Cx > > ,
34+ fields : Vec < IndexedPat < Cx > > ,
35+ /// The number of fields in this pattern. E.g. if the pattern is `SomeStruct { field12: true, ..
36+ /// }` this would be the total number of fields of the struct.
37+ /// This is also the same as `self.ctor.arity(self.ty)`.
38+ arity : usize ,
2939 ty : Cx :: Ty ,
30- /// Extra data to store in a pattern. `None` if the pattern is a wildcard that does not
31- /// correspond to a user-supplied pattern.
32- data : Option < Cx :: PatData > ,
40+ /// Extra data to store in a pattern.
41+ data : Cx :: PatData ,
3342 /// Globally-unique id used to track usefulness at the level of subpatterns.
3443 pub ( crate ) uid : PatId ,
3544}
3645
3746impl < Cx : TypeCx > DeconstructedPat < Cx > {
38- pub fn wildcard ( ty : Cx :: Ty ) -> Self {
39- DeconstructedPat { ctor : Wildcard , fields : Vec :: new ( ) , ty, data : None , uid : PatId :: new ( ) }
40- }
41-
4247 pub fn new (
4348 ctor : Constructor < Cx > ,
44- fields : Vec < DeconstructedPat < Cx > > ,
49+ fields : Vec < IndexedPat < Cx > > ,
50+ arity : usize ,
4551 ty : Cx :: Ty ,
4652 data : Cx :: PatData ,
4753 ) -> Self {
48- DeconstructedPat { ctor, fields, ty, data : Some ( data) , uid : PatId :: new ( ) }
54+ DeconstructedPat { ctor, fields, arity, ty, data, uid : PatId :: new ( ) }
55+ }
56+
57+ pub fn at_index ( self , idx : usize ) -> IndexedPat < Cx > {
58+ IndexedPat { idx, pat : self }
4959 }
5060
5161 pub ( crate ) fn is_or_pat ( & self ) -> bool {
@@ -58,13 +68,15 @@ impl<Cx: TypeCx> DeconstructedPat<Cx> {
5868 pub fn ty ( & self ) -> & Cx :: Ty {
5969 & self . ty
6070 }
61- /// Returns the extra data stored in a pattern. Returns `None` if the pattern is a wildcard that
62- /// does not correspond to a user-supplied pattern.
63- pub fn data ( & self ) -> Option < & Cx :: PatData > {
64- self . data . as_ref ( )
71+ /// Returns the extra data stored in a pattern.
72+ pub fn data ( & self ) -> & Cx :: PatData {
73+ & self . data
74+ }
75+ pub fn arity ( & self ) -> usize {
76+ self . arity
6577 }
6678
67- pub fn iter_fields < ' a > ( & ' a self ) -> impl Iterator < Item = & ' a DeconstructedPat < Cx > > {
79+ pub fn iter_fields < ' a > ( & ' a self ) -> impl Iterator < Item = & ' a IndexedPat < Cx > > {
6880 self . fields . iter ( )
6981 }
7082
@@ -73,36 +85,40 @@ impl<Cx: TypeCx> DeconstructedPat<Cx> {
7385 pub ( crate ) fn specialize < ' a > (
7486 & ' a self ,
7587 other_ctor : & Constructor < Cx > ,
76- ctor_arity : usize ,
88+ other_ctor_arity : usize ,
7789 ) -> SmallVec < [ PatOrWild < ' a , Cx > ; 2 ] > {
78- let wildcard_sub_tys = || ( 0 ..ctor_arity) . map ( |_| PatOrWild :: Wild ) . collect ( ) ;
79- match ( & self . ctor , other_ctor) {
80- // Return a wildcard for each field of `other_ctor`.
81- ( Wildcard , _) => wildcard_sub_tys ( ) ,
90+ if matches ! ( other_ctor, PrivateUninhabited ) {
8291 // Skip this column.
83- ( _, PrivateUninhabited ) => smallvec ! [ ] ,
84- // The only non-trivial case: two slices of different arity. `other_slice` is
85- // guaranteed to have a larger arity, so we fill the middle part with enough
86- // wildcards to reach the length of the new, larger slice.
87- (
88- & Slice ( self_slice @ Slice { kind : SliceKind :: VarLen ( prefix, suffix) , .. } ) ,
89- & Slice ( other_slice) ,
90- ) if self_slice. arity ( ) != other_slice. arity ( ) => {
91- // Start with a slice of wildcards of the appropriate length.
92- let mut fields: SmallVec < [ _ ; 2 ] > = wildcard_sub_tys ( ) ;
93- // Fill in the fields from both ends.
94- let new_arity = fields. len ( ) ;
95- for i in 0 ..prefix {
96- fields[ i] = PatOrWild :: Pat ( & self . fields [ i] ) ;
92+ return smallvec ! [ ] ;
93+ }
94+
95+ // Start with a slice of wildcards of the appropriate length.
96+ let mut fields: SmallVec < [ _ ; 2 ] > = ( 0 ..other_ctor_arity) . map ( |_| PatOrWild :: Wild ) . collect ( ) ;
97+ // Fill `fields` with our fields. The arities are known to be compatible.
98+ match self . ctor {
99+ // The only non-trivial case: two slices of different arity. `other_ctor` is guaranteed
100+ // to have a larger arity, so we adjust the indices of the patterns in the suffix so
101+ // that they are correctly positioned in the larger slice.
102+ Slice ( Slice { kind : SliceKind :: VarLen ( prefix, _) , .. } )
103+ if self . arity != other_ctor_arity =>
104+ {
105+ for ipat in & self . fields {
106+ let new_idx = if ipat. idx < prefix {
107+ ipat. idx
108+ } else {
109+ // Adjust the indices in the suffix.
110+ ipat. idx + other_ctor_arity - self . arity
111+ } ;
112+ fields[ new_idx] = PatOrWild :: Pat ( & ipat. pat ) ;
97113 }
98- for i in 0 ..suffix {
99- fields[ new_arity - 1 - i] =
100- PatOrWild :: Pat ( & self . fields [ self . fields . len ( ) - 1 - i] ) ;
114+ }
115+ _ => {
116+ for ipat in & self . fields {
117+ fields[ ipat. idx ] = PatOrWild :: Pat ( & ipat. pat ) ;
101118 }
102- fields
103119 }
104- _ => self . fields . iter ( ) . map ( PatOrWild :: Pat ) . collect ( ) ,
105120 }
121+ fields
106122 }
107123
108124 /// Walk top-down and call `it` in each place where a pattern occurs
@@ -114,7 +130,7 @@ impl<Cx: TypeCx> DeconstructedPat<Cx> {
114130 }
115131
116132 for p in self . iter_fields ( ) {
117- p. walk ( it)
133+ p. pat . walk ( it)
118134 }
119135 }
120136}
@@ -134,14 +150,19 @@ impl<Cx: TypeCx> fmt::Debug for DeconstructedPat<Cx> {
134150 } ;
135151 let mut start_or_comma = || start_or_continue ( ", " ) ;
136152
153+ let mut fields: Vec < _ > = ( 0 ..self . arity ) . map ( |_| PatOrWild :: Wild ) . collect ( ) ;
154+ for ipat in self . iter_fields ( ) {
155+ fields[ ipat. idx ] = PatOrWild :: Pat ( & ipat. pat ) ;
156+ }
157+
137158 match pat. ctor ( ) {
138159 Struct | Variant ( _) | UnionField => {
139160 Cx :: write_variant_name ( f, pat) ?;
140161 // Without `cx`, we can't know which field corresponds to which, so we can't
141162 // get the names of the fields. Instead we just display everything as a tuple
142163 // struct, which should be good enough.
143164 write ! ( f, "(" ) ?;
144- for p in pat . iter_fields ( ) {
165+ for p in fields {
145166 write ! ( f, "{}" , start_or_comma( ) ) ?;
146167 write ! ( f, "{p:?}" ) ?;
147168 }
@@ -151,25 +172,23 @@ impl<Cx: TypeCx> fmt::Debug for DeconstructedPat<Cx> {
151172 // be careful to detect strings here. However a string literal pattern will never
152173 // be reported as a non-exhaustiveness witness, so we can ignore this issue.
153174 Ref => {
154- let subpattern = pat. iter_fields ( ) . next ( ) . unwrap ( ) ;
155- write ! ( f, "&{:?}" , subpattern)
175+ write ! ( f, "&{:?}" , & fields[ 0 ] )
156176 }
157177 Slice ( slice) => {
158- let mut subpatterns = pat. iter_fields ( ) ;
159178 write ! ( f, "[" ) ?;
160179 match slice. kind {
161180 SliceKind :: FixedLen ( _) => {
162- for p in subpatterns {
181+ for p in fields {
163182 write ! ( f, "{}{:?}" , start_or_comma( ) , p) ?;
164183 }
165184 }
166185 SliceKind :: VarLen ( prefix_len, _) => {
167- for p in subpatterns . by_ref ( ) . take ( prefix_len) {
186+ for p in & fields [ .. prefix_len] {
168187 write ! ( f, "{}{:?}" , start_or_comma( ) , p) ?;
169188 }
170189 write ! ( f, "{}" , start_or_comma( ) ) ?;
171190 write ! ( f, ".." ) ?;
172- for p in subpatterns {
191+ for p in & fields [ prefix_len.. ] {
173192 write ! ( f, "{}{:?}" , start_or_comma( ) , p) ?;
174193 }
175194 }
@@ -184,7 +203,7 @@ impl<Cx: TypeCx> fmt::Debug for DeconstructedPat<Cx> {
184203 Str ( value) => write ! ( f, "{value:?}" ) ,
185204 Opaque ( ..) => write ! ( f, "<constant pattern>" ) ,
186205 Or => {
187- for pat in pat . iter_fields ( ) {
206+ for pat in fields {
188207 write ! ( f, "{}{:?}" , start_or_continue( " | " ) , pat) ?;
189208 }
190209 Ok ( ( ) )
@@ -242,9 +261,10 @@ impl<'p, Cx: TypeCx> PatOrWild<'p, Cx> {
242261 /// Expand this (possibly-nested) or-pattern into its alternatives.
243262 pub ( crate ) fn flatten_or_pat ( self ) -> SmallVec < [ Self ; 1 ] > {
244263 match self {
245- PatOrWild :: Pat ( pat) if pat. is_or_pat ( ) => {
246- pat. iter_fields ( ) . flat_map ( |p| PatOrWild :: Pat ( p) . flatten_or_pat ( ) ) . collect ( )
247- }
264+ PatOrWild :: Pat ( pat) if pat. is_or_pat ( ) => pat
265+ . iter_fields ( )
266+ . flat_map ( |ipat| PatOrWild :: Pat ( & ipat. pat ) . flatten_or_pat ( ) )
267+ . collect ( ) ,
248268 _ => smallvec ! [ self ] ,
249269 }
250270 }
0 commit comments