@@ -13,29 +13,29 @@ use super::{
13
13
14
14
// A thing that we can project into, and that has a layout.
15
15
// This wouldn't have to depend on `Machine` but with the current type inference,
16
- // that's just more convenient to work with (avoids repeading all the `Machine` bounds).
16
+ // that's just more convenient to work with (avoids repeating all the `Machine` bounds).
17
17
pub trait Value < ' a , ' mir , ' tcx , M : Machine < ' a , ' mir , ' tcx > > : Copy
18
18
{
19
- // Get this value's layout.
19
+ /// Get this value's layout.
20
20
fn layout ( & self ) -> TyLayout < ' tcx > ;
21
21
22
- // Make this into an `OpTy`.
22
+ /// Make this into an `OpTy`.
23
23
fn to_op (
24
24
self ,
25
25
ecx : & EvalContext < ' a , ' mir , ' tcx , M > ,
26
26
) -> EvalResult < ' tcx , OpTy < ' tcx , M :: PointerTag > > ;
27
27
28
- // Create this from an `MPlaceTy`.
28
+ /// Create this from an `MPlaceTy`.
29
29
fn from_mem_place ( MPlaceTy < ' tcx , M :: PointerTag > ) -> Self ;
30
30
31
- // Project to the given enum variant.
31
+ /// Project to the given enum variant.
32
32
fn project_downcast (
33
33
self ,
34
34
ecx : & EvalContext < ' a , ' mir , ' tcx , M > ,
35
35
variant : usize ,
36
36
) -> EvalResult < ' tcx , Self > ;
37
37
38
- // Project to the n-th field.
38
+ /// Project to the n-th field.
39
39
fn project_field (
40
40
self ,
41
41
ecx : & mut EvalContext < ' a , ' mir , ' tcx , M > ,
@@ -166,27 +166,32 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> Value<'a, 'mir, 'tcx, M>
166
166
pub trait ValueVisitor < ' a , ' mir , ' tcx : ' mir +' a , M : Machine < ' a , ' mir , ' tcx > > : Sized {
167
167
type V : Value < ' a , ' mir , ' tcx , M > ;
168
168
169
- // The visitor must have an `EvalContext` in it.
169
+ /// The visitor must have an `EvalContext` in it.
170
170
fn ecx ( & mut self ) -> & mut EvalContext < ' a , ' mir , ' tcx , M > ;
171
171
172
- // Recursie actions, ready to be overloaded.
173
- /// Visit the given value, dispatching as appropriate to more speicalized visitors.
172
+ // Recursive actions, ready to be overloaded.
173
+ /// Visit the given value, dispatching as appropriate to more specialized visitors.
174
174
#[ inline( always) ]
175
175
fn visit_value ( & mut self , v : Self :: V ) -> EvalResult < ' tcx >
176
176
{
177
177
self . walk_value ( v)
178
178
}
179
- /// Visit the given value as a union.
179
+ /// Visit the given value as a union. No automatic recursion can happen here.
180
180
#[ inline( always) ]
181
181
fn visit_union ( & mut self , _v : Self :: V ) -> EvalResult < ' tcx >
182
182
{
183
183
Ok ( ( ) )
184
184
}
185
- /// Visit the given value as an array.
185
+ /// Visit this vale as an aggregate, you are even getting an iterator yielding
186
+ /// all the fields (still in an `EvalResult`, you have to do error handling yourself).
187
+ /// Recurses into the fields.
186
188
#[ inline( always) ]
187
- fn visit_array ( & mut self , v : Self :: V ) -> EvalResult < ' tcx >
188
- {
189
- self . walk_array ( v)
189
+ fn visit_aggregate (
190
+ & mut self ,
191
+ v : Self :: V ,
192
+ fields : impl Iterator < Item =EvalResult < ' tcx , Self :: V > > ,
193
+ ) -> EvalResult < ' tcx > {
194
+ self . walk_aggregate ( v, fields)
190
195
}
191
196
/// Called each time we recurse down to a field, passing in old and new value.
192
197
/// This gives the visitor the chance to track the stack of nested fields that
@@ -201,39 +206,39 @@ pub trait ValueVisitor<'a, 'mir, 'tcx: 'mir+'a, M: Machine<'a, 'mir, 'tcx>>: Siz
201
206
self . visit_value ( new_val)
202
207
}
203
208
204
- // Actions on the leaves, ready to be overloaded.
205
209
/// Called whenever we reach a value with uninhabited layout.
206
- /// Recursing to fields will continue after this!
210
+ /// Recursing to fields will *always* continue after this! This is not meant to control
211
+ /// whether and how we descend recursively/ into the scalar's fields if there are any, it is
212
+ /// meant to provide the chance for additional checks when a value of uninhabited layout is
213
+ /// detected.
207
214
#[ inline( always) ]
208
215
fn visit_uninhabited ( & mut self ) -> EvalResult < ' tcx >
209
216
{ Ok ( ( ) ) }
210
217
/// Called whenever we reach a value with scalar layout.
211
- /// We do NOT provide a `ScalarMaybeUndef` here to avoid accessing memory
212
- /// if the visitor is not even interested in scalars.
213
- /// Recursing to fields will continue after this!
218
+ /// We do NOT provide a `ScalarMaybeUndef` here to avoid accessing memory if the visitor is not
219
+ /// even interested in scalars.
220
+ /// Recursing to fields will *always* continue after this! This is not meant to control
221
+ /// whether and how we descend recursively/ into the scalar's fields if there are any, it is
222
+ /// meant to provide the chance for additional checks when a value of scalar layout is detected.
214
223
#[ inline( always) ]
215
224
fn visit_scalar ( & mut self , _v : Self :: V , _layout : & layout:: Scalar ) -> EvalResult < ' tcx >
216
225
{ Ok ( ( ) ) }
226
+
217
227
/// Called whenever we reach a value of primitive type. There can be no recursion
218
- /// below such a value.
228
+ /// below such a value. This is the leave function.
219
229
#[ inline( always) ]
220
230
fn visit_primitive ( & mut self , _val : ValTy < ' tcx , M :: PointerTag > ) -> EvalResult < ' tcx >
221
231
{ Ok ( ( ) ) }
222
232
223
233
// Default recursors. Not meant to be overloaded.
224
- fn walk_array ( & mut self , v : Self :: V ) -> EvalResult < ' tcx >
225
- {
226
- // Let's get an mplace first.
227
- let mplace = if v. layout ( ) . is_zst ( ) {
228
- // it's a ZST, the memory content cannot matter
229
- MPlaceTy :: dangling ( v. layout ( ) , & self . ecx ( ) )
230
- } else {
231
- // non-ZST array/slice/str cannot be immediate
232
- v. to_op ( self . ecx ( ) ) ?. to_mem_place ( )
233
- } ;
234
+ fn walk_aggregate (
235
+ & mut self ,
236
+ v : Self :: V ,
237
+ fields : impl Iterator < Item =EvalResult < ' tcx , Self :: V > > ,
238
+ ) -> EvalResult < ' tcx > {
234
239
// Now iterate over it.
235
- for ( i , field ) in self . ecx ( ) . mplace_array_fields ( mplace ) ? . enumerate ( ) {
236
- self . visit_field ( v, i , Value :: from_mem_place ( field? ) ) ?;
240
+ for ( idx , field_val ) in fields . enumerate ( ) {
241
+ self . visit_field ( v, idx , field_val? ) ?;
237
242
}
238
243
Ok ( ( ) )
239
244
}
@@ -312,13 +317,30 @@ pub trait ValueVisitor<'a, 'mir, 'tcx: 'mir+'a, M: Machine<'a, 'mir, 'tcx>>: Siz
312
317
self . visit_union ( v) ?;
313
318
} ,
314
319
layout:: FieldPlacement :: Arbitrary { ref offsets, .. } => {
315
- for i in 0 ..offsets. len ( ) {
316
- let val = v. project_field ( self . ecx ( ) , i as u64 ) ?;
317
- self . visit_field ( v, i, val) ?;
318
- }
320
+ // We collect in a vec because otherwise there are lifetime errors:
321
+ // Projecting to a field needs (mutable!) access to `ecx`.
322
+ let fields: Vec < EvalResult < ' tcx , Self :: V > > =
323
+ ( 0 ..offsets. len ( ) ) . map ( |i| {
324
+ v. project_field ( self . ecx ( ) , i as u64 )
325
+ } )
326
+ . collect ( ) ;
327
+ self . visit_aggregate ( v, fields. into_iter ( ) ) ?;
319
328
} ,
320
329
layout:: FieldPlacement :: Array { .. } => {
321
- self . visit_array ( v) ?;
330
+ // Let's get an mplace first.
331
+ let mplace = if v. layout ( ) . is_zst ( ) {
332
+ // it's a ZST, the memory content cannot matter
333
+ MPlaceTy :: dangling ( v. layout ( ) , & self . ecx ( ) )
334
+ } else {
335
+ // non-ZST array/slice/str cannot be immediate
336
+ v. to_op ( self . ecx ( ) ) ?. to_mem_place ( )
337
+ } ;
338
+ // Now we can go over all the fields.
339
+ let iter = self . ecx ( ) . mplace_array_fields ( mplace) ?
340
+ . map ( |f| f. and_then ( |f| {
341
+ Ok ( Value :: from_mem_place ( f) )
342
+ } ) ) ;
343
+ self . visit_aggregate ( v, iter) ?;
322
344
}
323
345
}
324
346
Ok ( ( ) )
0 commit comments