@@ -20,12 +20,18 @@ 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 > > ,
2935 /// The number of fields in this pattern. E.g. if the pattern is `SomeStruct { field12: true, ..
3036 /// }` this would be the total number of fields of the struct.
3137 /// This is also the same as `self.ctor.arity(self.ty)`.
@@ -39,27 +45,20 @@ pub struct DeconstructedPat<Cx: TypeCx> {
3945}
4046
4147impl < Cx : TypeCx > DeconstructedPat < Cx > {
42- pub fn wildcard ( ty : Cx :: Ty ) -> Self {
43- DeconstructedPat {
44- ctor : Wildcard ,
45- fields : Vec :: new ( ) ,
46- arity : 0 ,
47- ty,
48- data : None ,
49- uid : PatId :: new ( ) ,
50- }
51- }
52-
5348 pub fn new (
5449 ctor : Constructor < Cx > ,
55- fields : Vec < DeconstructedPat < Cx > > ,
50+ fields : Vec < IndexedPat < Cx > > ,
5651 arity : usize ,
5752 ty : Cx :: Ty ,
5853 data : Cx :: PatData ,
5954 ) -> Self {
6055 DeconstructedPat { ctor, fields, arity, ty, data : Some ( data) , uid : PatId :: new ( ) }
6156 }
6257
58+ pub fn at_index ( self , idx : usize ) -> IndexedPat < Cx > {
59+ IndexedPat { idx, pat : self }
60+ }
61+
6362 pub ( crate ) fn is_or_pat ( & self ) -> bool {
6463 matches ! ( self . ctor, Or )
6564 }
@@ -75,8 +74,11 @@ impl<Cx: TypeCx> DeconstructedPat<Cx> {
7574 pub fn data ( & self ) -> Option < & Cx :: PatData > {
7675 self . data . as_ref ( )
7776 }
77+ pub fn arity ( & self ) -> usize {
78+ self . arity
79+ }
7880
79- pub fn iter_fields < ' a > ( & ' a self ) -> impl Iterator < Item = & ' a DeconstructedPat < Cx > > {
81+ pub fn iter_fields < ' a > ( & ' a self ) -> impl Iterator < Item = & ' a IndexedPat < Cx > > {
8082 self . fields . iter ( )
8183 }
8284
@@ -85,36 +87,40 @@ impl<Cx: TypeCx> DeconstructedPat<Cx> {
8587 pub ( crate ) fn specialize < ' a > (
8688 & ' a self ,
8789 other_ctor : & Constructor < Cx > ,
88- ctor_arity : usize ,
90+ other_ctor_arity : usize ,
8991 ) -> SmallVec < [ PatOrWild < ' a , Cx > ; 2 ] > {
90- let wildcard_sub_tys = || ( 0 ..ctor_arity) . map ( |_| PatOrWild :: Wild ) . collect ( ) ;
91- match ( & self . ctor , other_ctor) {
92- // Return a wildcard for each field of `other_ctor`.
93- ( Wildcard , _) => wildcard_sub_tys ( ) ,
92+ if matches ! ( other_ctor, PrivateUninhabited ) {
9493 // Skip this column.
95- ( _, PrivateUninhabited ) => smallvec ! [ ] ,
96- // The only non-trivial case: two slices of different arity. `other_slice` is
97- // guaranteed to have a larger arity, so we fill the middle part with enough
98- // wildcards to reach the length of the new, larger slice.
99- (
100- & Slice ( self_slice @ Slice { kind : SliceKind :: VarLen ( prefix, suffix) , .. } ) ,
101- & Slice ( other_slice) ,
102- ) if self_slice. arity ( ) != other_slice. arity ( ) => {
103- // Start with a slice of wildcards of the appropriate length.
104- let mut fields: SmallVec < [ _ ; 2 ] > = wildcard_sub_tys ( ) ;
105- // Fill in the fields from both ends.
106- let new_arity = fields. len ( ) ;
107- for i in 0 ..prefix {
108- fields[ i] = PatOrWild :: Pat ( & self . fields [ i] ) ;
94+ return smallvec ! [ ] ;
95+ }
96+
97+ // Start with a slice of wildcards of the appropriate length.
98+ let mut fields: SmallVec < [ _ ; 2 ] > = ( 0 ..other_ctor_arity) . map ( |_| PatOrWild :: Wild ) . collect ( ) ;
99+ // Fill `fields` with our fields. The arities are known to be compatible.
100+ match self . ctor {
101+ // The only non-trivial case: two slices of different arity. `other_ctor` is guaranteed
102+ // to have a larger arity, so we adjust the indices of the patterns in the suffix so
103+ // that they are correctly positioned in the larger slice.
104+ Slice ( Slice { kind : SliceKind :: VarLen ( prefix, _) , .. } )
105+ if self . arity != other_ctor_arity =>
106+ {
107+ for ipat in & self . fields {
108+ let new_idx = if ipat. idx < prefix {
109+ ipat. idx
110+ } else {
111+ // Adjust the indices in the suffix.
112+ ipat. idx + other_ctor_arity - self . arity
113+ } ;
114+ fields[ new_idx] = PatOrWild :: Pat ( & ipat. pat ) ;
109115 }
110- for i in 0 ..suffix {
111- fields[ new_arity - 1 - i] =
112- PatOrWild :: Pat ( & self . fields [ self . fields . len ( ) - 1 - i] ) ;
116+ }
117+ _ => {
118+ for ipat in & self . fields {
119+ fields[ ipat. idx ] = PatOrWild :: Pat ( & ipat. pat ) ;
113120 }
114- fields
115121 }
116- _ => self . fields . iter ( ) . map ( PatOrWild :: Pat ) . collect ( ) ,
117122 }
123+ fields
118124 }
119125
120126 /// Walk top-down and call `it` in each place where a pattern occurs
@@ -126,7 +132,7 @@ impl<Cx: TypeCx> DeconstructedPat<Cx> {
126132 }
127133
128134 for p in self . iter_fields ( ) {
129- p. walk ( it)
135+ p. pat . walk ( it)
130136 }
131137 }
132138}
@@ -146,14 +152,19 @@ impl<Cx: TypeCx> fmt::Debug for DeconstructedPat<Cx> {
146152 } ;
147153 let mut start_or_comma = || start_or_continue ( ", " ) ;
148154
155+ let mut fields: Vec < _ > = ( 0 ..self . arity ) . map ( |_| PatOrWild :: Wild ) . collect ( ) ;
156+ for ipat in self . iter_fields ( ) {
157+ fields[ ipat. idx ] = PatOrWild :: Pat ( & ipat. pat ) ;
158+ }
159+
149160 match pat. ctor ( ) {
150161 Struct | Variant ( _) | UnionField => {
151162 Cx :: write_variant_name ( f, pat) ?;
152163 // Without `cx`, we can't know which field corresponds to which, so we can't
153164 // get the names of the fields. Instead we just display everything as a tuple
154165 // struct, which should be good enough.
155166 write ! ( f, "(" ) ?;
156- for p in pat . iter_fields ( ) {
167+ for p in fields {
157168 write ! ( f, "{}" , start_or_comma( ) ) ?;
158169 write ! ( f, "{p:?}" ) ?;
159170 }
@@ -163,25 +174,23 @@ impl<Cx: TypeCx> fmt::Debug for DeconstructedPat<Cx> {
163174 // be careful to detect strings here. However a string literal pattern will never
164175 // be reported as a non-exhaustiveness witness, so we can ignore this issue.
165176 Ref => {
166- let subpattern = pat. iter_fields ( ) . next ( ) . unwrap ( ) ;
167- write ! ( f, "&{:?}" , subpattern)
177+ write ! ( f, "&{:?}" , & fields[ 0 ] )
168178 }
169179 Slice ( slice) => {
170- let mut subpatterns = pat. iter_fields ( ) ;
171180 write ! ( f, "[" ) ?;
172181 match slice. kind {
173182 SliceKind :: FixedLen ( _) => {
174- for p in subpatterns {
183+ for p in fields {
175184 write ! ( f, "{}{:?}" , start_or_comma( ) , p) ?;
176185 }
177186 }
178187 SliceKind :: VarLen ( prefix_len, _) => {
179- for p in subpatterns . by_ref ( ) . take ( prefix_len) {
188+ for p in & fields [ .. prefix_len] {
180189 write ! ( f, "{}{:?}" , start_or_comma( ) , p) ?;
181190 }
182191 write ! ( f, "{}" , start_or_comma( ) ) ?;
183192 write ! ( f, ".." ) ?;
184- for p in subpatterns {
193+ for p in & fields [ prefix_len.. ] {
185194 write ! ( f, "{}{:?}" , start_or_comma( ) , p) ?;
186195 }
187196 }
@@ -196,7 +205,7 @@ impl<Cx: TypeCx> fmt::Debug for DeconstructedPat<Cx> {
196205 Str ( value) => write ! ( f, "{value:?}" ) ,
197206 Opaque ( ..) => write ! ( f, "<constant pattern>" ) ,
198207 Or => {
199- for pat in pat . iter_fields ( ) {
208+ for pat in fields {
200209 write ! ( f, "{}{:?}" , start_or_continue( " | " ) , pat) ?;
201210 }
202211 Ok ( ( ) )
@@ -254,9 +263,10 @@ impl<'p, Cx: TypeCx> PatOrWild<'p, Cx> {
254263 /// Expand this (possibly-nested) or-pattern into its alternatives.
255264 pub ( crate ) fn flatten_or_pat ( self ) -> SmallVec < [ Self ; 1 ] > {
256265 match self {
257- PatOrWild :: Pat ( pat) if pat. is_or_pat ( ) => {
258- pat. iter_fields ( ) . flat_map ( |p| PatOrWild :: Pat ( p) . flatten_or_pat ( ) ) . collect ( )
259- }
266+ PatOrWild :: Pat ( pat) if pat. is_or_pat ( ) => pat
267+ . iter_fields ( )
268+ . flat_map ( |ipat| PatOrWild :: Pat ( & ipat. pat ) . flatten_or_pat ( ) )
269+ . collect ( ) ,
260270 _ => smallvec ! [ self ] ,
261271 }
262272 }
0 commit comments