@@ -178,77 +178,91 @@ pub trait ValueVisitor<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>>: fmt::Debug +
178
178
self . value ( ) . layout ( )
179
179
}
180
180
181
- // Replace the value by `val`, which must be the `field`th field of `self`, then call
182
- // `visit_value` and then un-do everything that might have happened to the visitor state.
183
- // The point of this is that some visitors keep a stack of fields that we projected below,
184
- // and this lets us avoid copying that stack; instead they will pop the stack after
185
- // executing `visit_value`.
186
- fn visit_field (
187
- & mut self ,
188
- ectx : & mut EvalContext < ' a , ' mir , ' tcx , M > ,
189
- val : Self :: V ,
190
- field : usize ,
191
- ) -> EvalResult < ' tcx > ;
192
-
193
- // A chance for the visitor to do special (different or more efficient) handling for some
194
- // array types. Return `true` if the value was handled and we should return.
181
+ // Recursie actions, ready to be overloaded.
182
+ /// Visit the current value, dispatching as appropriate to more speicalized visitors.
195
183
#[ inline]
196
- fn handle_array ( & mut self , _ectx : & EvalContext < ' a , ' mir , ' tcx , M > )
197
- -> EvalResult < ' tcx , bool >
184
+ fn visit_value ( & mut self , ectx : & mut EvalContext < ' a , ' mir , ' tcx , M > )
185
+ -> EvalResult < ' tcx >
198
186
{
199
- Ok ( false )
187
+ self . walk_value ( ectx )
200
188
}
201
-
202
- // Execute visitor on the current value. Used for recursing.
189
+ /// Visit the current value as an array.
203
190
#[ inline]
204
- fn visit ( & mut self , ectx : & mut EvalContext < ' a , ' mir , ' tcx , M > )
191
+ fn visit_array ( & mut self , ectx : & mut EvalContext < ' a , ' mir , ' tcx , M > )
205
192
-> EvalResult < ' tcx >
206
193
{
207
- ectx . walk_value ( self )
194
+ self . walk_array ( ectx )
208
195
}
196
+ /// Called each time we recurse down to a field of the value, to (a) let
197
+ /// the visitor change its internal state (recording the new current value),
198
+ /// and (b) let the visitor track the "stack" of fields that we descended below.
199
+ fn visit_field (
200
+ & mut self ,
201
+ ectx : & mut EvalContext < ' a , ' mir , ' tcx , M > ,
202
+ val : Self :: V ,
203
+ field : usize ,
204
+ ) -> EvalResult < ' tcx > ;
209
205
210
- // Actions on the leaves.
206
+ // Actions on the leaves, ready to be overloaded.
207
+ #[ inline]
211
208
fn visit_uninhabited ( & mut self , _ectx : & mut EvalContext < ' a , ' mir , ' tcx , M > )
212
209
-> EvalResult < ' tcx >
213
210
{ Ok ( ( ) ) }
211
+ #[ inline]
214
212
fn visit_scalar ( & mut self , _ectx : & mut EvalContext < ' a , ' mir , ' tcx , M > , _layout : & layout:: Scalar )
215
213
-> EvalResult < ' tcx >
216
214
{ Ok ( ( ) ) }
215
+ #[ inline]
217
216
fn visit_primitive ( & mut self , _ectx : & mut EvalContext < ' a , ' mir , ' tcx , M > )
218
217
-> EvalResult < ' tcx >
219
218
{ Ok ( ( ) ) }
220
- }
221
219
222
- impl < ' a , ' mir , ' tcx , M : Machine < ' a , ' mir , ' tcx > > EvalContext < ' a , ' mir , ' tcx , M > {
223
- pub fn walk_value < V : ValueVisitor < ' a , ' mir , ' tcx , M > > (
224
- & mut self ,
225
- v : & mut V ,
226
- ) -> EvalResult < ' tcx > {
227
- trace ! ( "walk_value: {:?}" , v) ;
220
+ // Default recursors. Not meant to be overloaded.
221
+ fn walk_array ( & mut self , ectx : & mut EvalContext < ' a , ' mir , ' tcx , M > )
222
+ -> EvalResult < ' tcx >
223
+ {
224
+ // Let's get an mplace first.
225
+ let mplace = if self . layout ( ) . is_zst ( ) {
226
+ // it's a ZST, the memory content cannot matter
227
+ MPlaceTy :: dangling ( self . layout ( ) , ectx)
228
+ } else {
229
+ // non-ZST array/slice/str cannot be immediate
230
+ self . value ( ) . to_mem_place ( ectx) ?
231
+ } ;
232
+ // Now iterate over it.
233
+ for ( i, field) in ectx. mplace_array_fields ( mplace) ?. enumerate ( ) {
234
+ self . visit_field ( ectx, Value :: from_mem_place ( field?) , i) ?;
235
+ }
236
+ Ok ( ( ) )
237
+ }
238
+ fn walk_value ( & mut self , ectx : & mut EvalContext < ' a , ' mir , ' tcx , M > )
239
+ -> EvalResult < ' tcx >
240
+ {
241
+ trace ! ( "walk_value: {:?}" , self ) ;
228
242
229
243
// If this is a multi-variant layout, we have find the right one and proceed with that.
230
244
// (No benefit from making this recursion, but it is equivalent to that.)
231
- match v . layout ( ) . variants {
245
+ match self . layout ( ) . variants {
232
246
layout:: Variants :: NicheFilling { .. } |
233
247
layout:: Variants :: Tagged { .. } => {
234
- let ( inner, idx) = v . value ( ) . project_downcast ( self ) ?;
248
+ let ( inner, idx) = self . value ( ) . project_downcast ( ectx ) ?;
235
249
trace ! ( "variant layout: {:#?}" , inner. layout( ) ) ;
236
250
// recurse with the inner type
237
- return v . visit_field ( self , inner, idx) ;
251
+ return self . visit_field ( ectx , inner, idx) ;
238
252
}
239
253
layout:: Variants :: Single { .. } => { }
240
254
}
241
255
242
256
// Even for single variants, we might be able to get a more refined type:
243
257
// If it is a trait object, switch to the actual type that was used to create it.
244
- match v . layout ( ) . ty . sty {
258
+ match self . layout ( ) . ty . sty {
245
259
ty:: Dynamic ( ..) => {
246
260
// immediate trait objects are not a thing
247
- let dest = v . value ( ) . to_mem_place ( self ) ?;
248
- let inner = self . unpack_dyn_trait ( dest) ?. 1 ;
261
+ let dest = self . value ( ) . to_mem_place ( ectx ) ?;
262
+ let inner = ectx . unpack_dyn_trait ( dest) ?. 1 ;
249
263
trace ! ( "dyn object layout: {:#?}" , inner. layout) ;
250
264
// recurse with the inner type
251
- return v . visit_field ( self , Value :: from_mem_place ( inner) , 0 ) ;
265
+ return self . visit_field ( ectx , Value :: from_mem_place ( inner) , 0 ) ;
252
266
} ,
253
267
_ => { } ,
254
268
} ;
@@ -260,12 +274,12 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M>
260
274
// FIXME: We could avoid some redundant checks here. For newtypes wrapping
261
275
// scalars, we do the same check on every "level" (e.g. first we check
262
276
// MyNewtype and then the scalar in there).
263
- match v . layout ( ) . abi {
277
+ match self . layout ( ) . abi {
264
278
layout:: Abi :: Uninhabited => {
265
- v . visit_uninhabited ( self ) ?;
279
+ self . visit_uninhabited ( ectx ) ?;
266
280
}
267
281
layout:: Abi :: Scalar ( ref layout) => {
268
- v . visit_scalar ( self , layout) ?;
282
+ self . visit_scalar ( ectx , layout) ?;
269
283
}
270
284
// FIXME: Should we do something for ScalarPair? Vector?
271
285
_ => { }
@@ -276,17 +290,17 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M>
276
290
// so we check them separately and before aggregate handling.
277
291
// It is CRITICAL that we get this check right, or we might be
278
292
// validating the wrong thing!
279
- let primitive = match v . layout ( ) . fields {
293
+ let primitive = match self . layout ( ) . fields {
280
294
// Primitives appear as Union with 0 fields -- except for Boxes and fat pointers.
281
295
layout:: FieldPlacement :: Union ( 0 ) => true ,
282
- _ => v . layout ( ) . ty . builtin_deref ( true ) . is_some ( ) ,
296
+ _ => self . layout ( ) . ty . builtin_deref ( true ) . is_some ( ) ,
283
297
} ;
284
298
if primitive {
285
- return v . visit_primitive ( self ) ;
299
+ return self . visit_primitive ( ectx ) ;
286
300
}
287
301
288
302
// Proceed into the fields.
289
- match v . layout ( ) . fields {
303
+ match self . layout ( ) . fields {
290
304
layout:: FieldPlacement :: Union ( fields) => {
291
305
// Empty unions are not accepted by rustc. That's great, it means we can
292
306
// use that as an unambiguous signal for detecting primitives. Make sure
@@ -298,26 +312,12 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M>
298
312
} ,
299
313
layout:: FieldPlacement :: Arbitrary { ref offsets, .. } => {
300
314
for i in 0 ..offsets. len ( ) {
301
- let val = v . value ( ) . project_field ( self , i as u64 ) ?;
302
- v . visit_field ( self , val, i) ?;
315
+ let val = self . value ( ) . project_field ( ectx , i as u64 ) ?;
316
+ self . visit_field ( ectx , val, i) ?;
303
317
}
304
318
} ,
305
319
layout:: FieldPlacement :: Array { .. } => {
306
- if !v. handle_array ( self ) ? {
307
- // We still have to work!
308
- // Let's get an mplace first.
309
- let mplace = if v. layout ( ) . is_zst ( ) {
310
- // it's a ZST, the memory content cannot matter
311
- MPlaceTy :: dangling ( v. layout ( ) , self )
312
- } else {
313
- // non-ZST array/slice/str cannot be immediate
314
- v. value ( ) . to_mem_place ( self ) ?
315
- } ;
316
- // Now iterate over it.
317
- for ( i, field) in self . mplace_array_fields ( mplace) ?. enumerate ( ) {
318
- v. visit_field ( self , Value :: from_mem_place ( field?) , i) ?;
319
- }
320
- }
320
+ self . visit_array ( ectx) ?;
321
321
}
322
322
}
323
323
Ok ( ( ) )
0 commit comments