@@ -20,32 +20,42 @@ 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 > > ,
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 ,
29
39
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 ,
33
42
/// Globally-unique id used to track usefulness at the level of subpatterns.
34
43
pub ( crate ) uid : PatId ,
35
44
}
36
45
37
46
impl < 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
-
42
47
pub fn new (
43
48
ctor : Constructor < Cx > ,
44
- fields : Vec < DeconstructedPat < Cx > > ,
49
+ fields : Vec < IndexedPat < Cx > > ,
50
+ arity : usize ,
45
51
ty : Cx :: Ty ,
46
52
data : Cx :: PatData ,
47
53
) -> 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 }
49
59
}
50
60
51
61
pub ( crate ) fn is_or_pat ( & self ) -> bool {
@@ -58,13 +68,15 @@ impl<Cx: TypeCx> DeconstructedPat<Cx> {
58
68
pub fn ty ( & self ) -> & Cx :: Ty {
59
69
& self . ty
60
70
}
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
65
77
}
66
78
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 > > {
68
80
self . fields . iter ( )
69
81
}
70
82
@@ -73,36 +85,40 @@ impl<Cx: TypeCx> DeconstructedPat<Cx> {
73
85
pub ( crate ) fn specialize < ' a > (
74
86
& ' a self ,
75
87
other_ctor : & Constructor < Cx > ,
76
- ctor_arity : usize ,
88
+ other_ctor_arity : usize ,
77
89
) -> 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 ) {
82
91
// 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 ) ;
97
113
}
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 ) ;
101
118
}
102
- fields
103
119
}
104
- _ => self . fields . iter ( ) . map ( PatOrWild :: Pat ) . collect ( ) ,
105
120
}
121
+ fields
106
122
}
107
123
108
124
/// Walk top-down and call `it` in each place where a pattern occurs
@@ -114,7 +130,7 @@ impl<Cx: TypeCx> DeconstructedPat<Cx> {
114
130
}
115
131
116
132
for p in self . iter_fields ( ) {
117
- p. walk ( it)
133
+ p. pat . walk ( it)
118
134
}
119
135
}
120
136
}
@@ -134,14 +150,19 @@ impl<Cx: TypeCx> fmt::Debug for DeconstructedPat<Cx> {
134
150
} ;
135
151
let mut start_or_comma = || start_or_continue ( ", " ) ;
136
152
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
+
137
158
match pat. ctor ( ) {
138
159
Struct | Variant ( _) | UnionField => {
139
160
Cx :: write_variant_name ( f, pat) ?;
140
161
// Without `cx`, we can't know which field corresponds to which, so we can't
141
162
// get the names of the fields. Instead we just display everything as a tuple
142
163
// struct, which should be good enough.
143
164
write ! ( f, "(" ) ?;
144
- for p in pat . iter_fields ( ) {
165
+ for p in fields {
145
166
write ! ( f, "{}" , start_or_comma( ) ) ?;
146
167
write ! ( f, "{p:?}" ) ?;
147
168
}
@@ -151,25 +172,23 @@ impl<Cx: TypeCx> fmt::Debug for DeconstructedPat<Cx> {
151
172
// be careful to detect strings here. However a string literal pattern will never
152
173
// be reported as a non-exhaustiveness witness, so we can ignore this issue.
153
174
Ref => {
154
- let subpattern = pat. iter_fields ( ) . next ( ) . unwrap ( ) ;
155
- write ! ( f, "&{:?}" , subpattern)
175
+ write ! ( f, "&{:?}" , & fields[ 0 ] )
156
176
}
157
177
Slice ( slice) => {
158
- let mut subpatterns = pat. iter_fields ( ) ;
159
178
write ! ( f, "[" ) ?;
160
179
match slice. kind {
161
180
SliceKind :: FixedLen ( _) => {
162
- for p in subpatterns {
181
+ for p in fields {
163
182
write ! ( f, "{}{:?}" , start_or_comma( ) , p) ?;
164
183
}
165
184
}
166
185
SliceKind :: VarLen ( prefix_len, _) => {
167
- for p in subpatterns . by_ref ( ) . take ( prefix_len) {
186
+ for p in & fields [ .. prefix_len] {
168
187
write ! ( f, "{}{:?}" , start_or_comma( ) , p) ?;
169
188
}
170
189
write ! ( f, "{}" , start_or_comma( ) ) ?;
171
190
write ! ( f, ".." ) ?;
172
- for p in subpatterns {
191
+ for p in & fields [ prefix_len.. ] {
173
192
write ! ( f, "{}{:?}" , start_or_comma( ) , p) ?;
174
193
}
175
194
}
@@ -184,7 +203,7 @@ impl<Cx: TypeCx> fmt::Debug for DeconstructedPat<Cx> {
184
203
Str ( value) => write ! ( f, "{value:?}" ) ,
185
204
Opaque ( ..) => write ! ( f, "<constant pattern>" ) ,
186
205
Or => {
187
- for pat in pat . iter_fields ( ) {
206
+ for pat in fields {
188
207
write ! ( f, "{}{:?}" , start_or_continue( " | " ) , pat) ?;
189
208
}
190
209
Ok ( ( ) )
@@ -242,9 +261,10 @@ impl<'p, Cx: TypeCx> PatOrWild<'p, Cx> {
242
261
/// Expand this (possibly-nested) or-pattern into its alternatives.
243
262
pub ( crate ) fn flatten_or_pat ( self ) -> SmallVec < [ Self ; 1 ] > {
244
263
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 ( ) ,
248
268
_ => smallvec ! [ self ] ,
249
269
}
250
270
}
0 commit comments