@@ -20,12 +20,18 @@ impl PatId {
20
20
}
21
21
}
22
22
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
+
23
29
/// Values and patterns can be represented as a constructor applied to some fields. This represents
24
30
/// a pattern in this form. A `DeconstructedPat` will almost always come from user input; the only
25
31
/// exception are some `Wildcard`s introduced during pattern lowering.
26
32
pub struct DeconstructedPat < Cx : TypeCx > {
27
33
ctor : Constructor < Cx > ,
28
- fields : Vec < DeconstructedPat < Cx > > ,
34
+ fields : Vec < IndexedPat < Cx > > ,
29
35
/// The number of fields in this pattern. E.g. if the pattern is `SomeStruct { field12: true, ..
30
36
/// }` this would be the total number of fields of the struct.
31
37
/// This is also the same as `self.ctor.arity(self.ty)`.
@@ -39,27 +45,20 @@ pub struct DeconstructedPat<Cx: TypeCx> {
39
45
}
40
46
41
47
impl < 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
-
53
48
pub fn new (
54
49
ctor : Constructor < Cx > ,
55
- fields : Vec < DeconstructedPat < Cx > > ,
50
+ fields : Vec < IndexedPat < Cx > > ,
56
51
arity : usize ,
57
52
ty : Cx :: Ty ,
58
53
data : Cx :: PatData ,
59
54
) -> Self {
60
55
DeconstructedPat { ctor, fields, arity, ty, data : Some ( data) , uid : PatId :: new ( ) }
61
56
}
62
57
58
+ pub fn at_index ( self , idx : usize ) -> IndexedPat < Cx > {
59
+ IndexedPat { idx, pat : self }
60
+ }
61
+
63
62
pub ( crate ) fn is_or_pat ( & self ) -> bool {
64
63
matches ! ( self . ctor, Or )
65
64
}
@@ -75,8 +74,11 @@ impl<Cx: TypeCx> DeconstructedPat<Cx> {
75
74
pub fn data ( & self ) -> Option < & Cx :: PatData > {
76
75
self . data . as_ref ( )
77
76
}
77
+ pub fn arity ( & self ) -> usize {
78
+ self . arity
79
+ }
78
80
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 > > {
80
82
self . fields . iter ( )
81
83
}
82
84
@@ -85,36 +87,40 @@ impl<Cx: TypeCx> DeconstructedPat<Cx> {
85
87
pub ( crate ) fn specialize < ' a > (
86
88
& ' a self ,
87
89
other_ctor : & Constructor < Cx > ,
88
- ctor_arity : usize ,
90
+ other_ctor_arity : usize ,
89
91
) -> 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 ) {
94
93
// 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 ) ;
109
115
}
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 ) ;
113
120
}
114
- fields
115
121
}
116
- _ => self . fields . iter ( ) . map ( PatOrWild :: Pat ) . collect ( ) ,
117
122
}
123
+ fields
118
124
}
119
125
120
126
/// Walk top-down and call `it` in each place where a pattern occurs
@@ -126,7 +132,7 @@ impl<Cx: TypeCx> DeconstructedPat<Cx> {
126
132
}
127
133
128
134
for p in self . iter_fields ( ) {
129
- p. walk ( it)
135
+ p. pat . walk ( it)
130
136
}
131
137
}
132
138
}
@@ -146,14 +152,19 @@ impl<Cx: TypeCx> fmt::Debug for DeconstructedPat<Cx> {
146
152
} ;
147
153
let mut start_or_comma = || start_or_continue ( ", " ) ;
148
154
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
+
149
160
match pat. ctor ( ) {
150
161
Struct | Variant ( _) | UnionField => {
151
162
Cx :: write_variant_name ( f, pat) ?;
152
163
// Without `cx`, we can't know which field corresponds to which, so we can't
153
164
// get the names of the fields. Instead we just display everything as a tuple
154
165
// struct, which should be good enough.
155
166
write ! ( f, "(" ) ?;
156
- for p in pat . iter_fields ( ) {
167
+ for p in fields {
157
168
write ! ( f, "{}" , start_or_comma( ) ) ?;
158
169
write ! ( f, "{p:?}" ) ?;
159
170
}
@@ -163,25 +174,23 @@ impl<Cx: TypeCx> fmt::Debug for DeconstructedPat<Cx> {
163
174
// be careful to detect strings here. However a string literal pattern will never
164
175
// be reported as a non-exhaustiveness witness, so we can ignore this issue.
165
176
Ref => {
166
- let subpattern = pat. iter_fields ( ) . next ( ) . unwrap ( ) ;
167
- write ! ( f, "&{:?}" , subpattern)
177
+ write ! ( f, "&{:?}" , & fields[ 0 ] )
168
178
}
169
179
Slice ( slice) => {
170
- let mut subpatterns = pat. iter_fields ( ) ;
171
180
write ! ( f, "[" ) ?;
172
181
match slice. kind {
173
182
SliceKind :: FixedLen ( _) => {
174
- for p in subpatterns {
183
+ for p in fields {
175
184
write ! ( f, "{}{:?}" , start_or_comma( ) , p) ?;
176
185
}
177
186
}
178
187
SliceKind :: VarLen ( prefix_len, _) => {
179
- for p in subpatterns . by_ref ( ) . take ( prefix_len) {
188
+ for p in & fields [ .. prefix_len] {
180
189
write ! ( f, "{}{:?}" , start_or_comma( ) , p) ?;
181
190
}
182
191
write ! ( f, "{}" , start_or_comma( ) ) ?;
183
192
write ! ( f, ".." ) ?;
184
- for p in subpatterns {
193
+ for p in & fields [ prefix_len.. ] {
185
194
write ! ( f, "{}{:?}" , start_or_comma( ) , p) ?;
186
195
}
187
196
}
@@ -196,7 +205,7 @@ impl<Cx: TypeCx> fmt::Debug for DeconstructedPat<Cx> {
196
205
Str ( value) => write ! ( f, "{value:?}" ) ,
197
206
Opaque ( ..) => write ! ( f, "<constant pattern>" ) ,
198
207
Or => {
199
- for pat in pat . iter_fields ( ) {
208
+ for pat in fields {
200
209
write ! ( f, "{}{:?}" , start_or_continue( " | " ) , pat) ?;
201
210
}
202
211
Ok ( ( ) )
@@ -254,9 +263,10 @@ impl<'p, Cx: TypeCx> PatOrWild<'p, Cx> {
254
263
/// Expand this (possibly-nested) or-pattern into its alternatives.
255
264
pub ( crate ) fn flatten_or_pat ( self ) -> SmallVec < [ Self ; 1 ] > {
256
265
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 ( ) ,
260
270
_ => smallvec ! [ self ] ,
261
271
}
262
272
}
0 commit comments