@@ -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 }
@@ -76,7 +75,7 @@ impl<Cx: TypeCx> DeconstructedPat<Cx> {
7675 self . data . as_ref ( )
7776 }
7877
79- pub fn iter_fields < ' a > ( & ' a self ) -> impl Iterator < Item = & ' a DeconstructedPat < Cx > > {
78+ pub fn iter_fields < ' a > ( & ' a self ) -> impl Iterator < Item = & ' a IndexedPat < Cx > > {
8079 self . fields . iter ( )
8180 }
8281
@@ -85,36 +84,40 @@ impl<Cx: TypeCx> DeconstructedPat<Cx> {
8584 pub ( crate ) fn specialize < ' a > (
8685 & ' a self ,
8786 other_ctor : & Constructor < Cx > ,
88- ctor_arity : usize ,
87+ other_ctor_arity : usize ,
8988 ) -> 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 ( ) ,
89+ if matches ! ( other_ctor, PrivateUninhabited ) {
9490 // 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] ) ;
91+ return smallvec ! [ ] ;
92+ }
93+
94+ // Start with a slice of wildcards of the appropriate length.
95+ let mut fields: SmallVec < [ _ ; 2 ] > = ( 0 ..other_ctor_arity) . map ( |_| PatOrWild :: Wild ) . collect ( ) ;
96+ // Fill `fields` with our fields. The arities are known to be compatible.
97+ match self . ctor {
98+ // The only non-trivial case: two slices of different arity. `other_ctor` is guaranteed
99+ // to have a larger arity, so we adjust the indices of the patterns in the suffix so
100+ // that they are correctly positioned in the larger slice.
101+ Slice ( Slice { kind : SliceKind :: VarLen ( prefix, _) , .. } )
102+ if self . arity != other_ctor_arity =>
103+ {
104+ for ipat in & self . fields {
105+ let new_idx = if ipat. idx < prefix {
106+ ipat. idx
107+ } else {
108+ // Adjust the indices in the suffix.
109+ ipat. idx + other_ctor_arity - self . arity
110+ } ;
111+ fields[ new_idx] = PatOrWild :: Pat ( & ipat. pat ) ;
109112 }
110- for i in 0 ..suffix {
111- fields[ new_arity - 1 - i] =
112- PatOrWild :: Pat ( & self . fields [ self . fields . len ( ) - 1 - i] ) ;
113+ }
114+ _ => {
115+ for ipat in & self . fields {
116+ fields[ ipat. idx ] = PatOrWild :: Pat ( & ipat. pat ) ;
113117 }
114- fields
115118 }
116- _ => self . fields . iter ( ) . map ( PatOrWild :: Pat ) . collect ( ) ,
117119 }
120+ fields
118121 }
119122
120123 /// Walk top-down and call `it` in each place where a pattern occurs
@@ -126,7 +129,7 @@ impl<Cx: TypeCx> DeconstructedPat<Cx> {
126129 }
127130
128131 for p in self . iter_fields ( ) {
129- p. walk ( it)
132+ p. pat . walk ( it)
130133 }
131134 }
132135}
@@ -146,14 +149,19 @@ impl<Cx: TypeCx> fmt::Debug for DeconstructedPat<Cx> {
146149 } ;
147150 let mut start_or_comma = || start_or_continue ( ", " ) ;
148151
152+ let mut fields: Vec < _ > = ( 0 ..self . arity ) . map ( |_| PatOrWild :: Wild ) . collect ( ) ;
153+ for ipat in self . iter_fields ( ) {
154+ fields[ ipat. idx ] = PatOrWild :: Pat ( & ipat. pat ) ;
155+ }
156+
149157 match pat. ctor ( ) {
150158 Struct | Variant ( _) | UnionField => {
151159 Cx :: write_variant_name ( f, pat) ?;
152160 // Without `cx`, we can't know which field corresponds to which, so we can't
153161 // get the names of the fields. Instead we just display everything as a tuple
154162 // struct, which should be good enough.
155163 write ! ( f, "(" ) ?;
156- for p in pat . iter_fields ( ) {
164+ for p in fields {
157165 write ! ( f, "{}" , start_or_comma( ) ) ?;
158166 write ! ( f, "{p:?}" ) ?;
159167 }
@@ -163,25 +171,23 @@ impl<Cx: TypeCx> fmt::Debug for DeconstructedPat<Cx> {
163171 // be careful to detect strings here. However a string literal pattern will never
164172 // be reported as a non-exhaustiveness witness, so we can ignore this issue.
165173 Ref => {
166- let subpattern = pat. iter_fields ( ) . next ( ) . unwrap ( ) ;
167- write ! ( f, "&{:?}" , subpattern)
174+ write ! ( f, "&{:?}" , & fields[ 0 ] )
168175 }
169176 Slice ( slice) => {
170- let mut subpatterns = pat. iter_fields ( ) ;
171177 write ! ( f, "[" ) ?;
172178 match slice. kind {
173179 SliceKind :: FixedLen ( _) => {
174- for p in subpatterns {
180+ for p in fields {
175181 write ! ( f, "{}{:?}" , start_or_comma( ) , p) ?;
176182 }
177183 }
178184 SliceKind :: VarLen ( prefix_len, _) => {
179- for p in subpatterns . by_ref ( ) . take ( prefix_len) {
185+ for p in & fields [ .. prefix_len] {
180186 write ! ( f, "{}{:?}" , start_or_comma( ) , p) ?;
181187 }
182188 write ! ( f, "{}" , start_or_comma( ) ) ?;
183189 write ! ( f, ".." ) ?;
184- for p in subpatterns {
190+ for p in & fields [ prefix_len.. ] {
185191 write ! ( f, "{}{:?}" , start_or_comma( ) , p) ?;
186192 }
187193 }
@@ -196,7 +202,7 @@ impl<Cx: TypeCx> fmt::Debug for DeconstructedPat<Cx> {
196202 Str ( value) => write ! ( f, "{value:?}" ) ,
197203 Opaque ( ..) => write ! ( f, "<constant pattern>" ) ,
198204 Or => {
199- for pat in pat . iter_fields ( ) {
205+ for pat in fields {
200206 write ! ( f, "{}{:?}" , start_or_continue( " | " ) , pat) ?;
201207 }
202208 Ok ( ( ) )
@@ -254,9 +260,10 @@ impl<'p, Cx: TypeCx> PatOrWild<'p, Cx> {
254260 /// Expand this (possibly-nested) or-pattern into its alternatives.
255261 pub ( crate ) fn flatten_or_pat ( self ) -> SmallVec < [ Self ; 1 ] > {
256262 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- }
263+ PatOrWild :: Pat ( pat) if pat. is_or_pat ( ) => pat
264+ . iter_fields ( )
265+ . flat_map ( |ipat| PatOrWild :: Pat ( & ipat. pat ) . flatten_or_pat ( ) )
266+ . collect ( ) ,
260267 _ => smallvec ! [ self ] ,
261268 }
262269 }
0 commit comments