@@ -13,29 +13,29 @@ use super::{
1313
1414// A thing that we can project into, and that has a layout.
1515// 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).
1717pub trait Value < ' a , ' mir , ' tcx , M : Machine < ' a , ' mir , ' tcx > > : Copy
1818{
19- // Get this value's layout.
19+ /// Get this value's layout.
2020 fn layout ( & self ) -> TyLayout < ' tcx > ;
2121
22- // Make this into an `OpTy`.
22+ /// Make this into an `OpTy`.
2323 fn to_op (
2424 self ,
2525 ecx : & EvalContext < ' a , ' mir , ' tcx , M > ,
2626 ) -> EvalResult < ' tcx , OpTy < ' tcx , M :: PointerTag > > ;
2727
28- // Create this from an `MPlaceTy`.
28+ /// Create this from an `MPlaceTy`.
2929 fn from_mem_place ( MPlaceTy < ' tcx , M :: PointerTag > ) -> Self ;
3030
31- // Project to the given enum variant.
31+ /// Project to the given enum variant.
3232 fn project_downcast (
3333 self ,
3434 ecx : & EvalContext < ' a , ' mir , ' tcx , M > ,
3535 variant : usize ,
3636 ) -> EvalResult < ' tcx , Self > ;
3737
38- // Project to the n-th field.
38+ /// Project to the n-th field.
3939 fn project_field (
4040 self ,
4141 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>
166166pub trait ValueVisitor < ' a , ' mir , ' tcx : ' mir +' a , M : Machine < ' a , ' mir , ' tcx > > : Sized {
167167 type V : Value < ' a , ' mir , ' tcx , M > ;
168168
169- // The visitor must have an `EvalContext` in it.
169+ /// The visitor must have an `EvalContext` in it.
170170 fn ecx ( & mut self ) -> & mut EvalContext < ' a , ' mir , ' tcx , M > ;
171171
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.
174174 #[ inline( always) ]
175175 fn visit_value ( & mut self , v : Self :: V ) -> EvalResult < ' tcx >
176176 {
177177 self . walk_value ( v)
178178 }
179- /// Visit the given value as a union.
179+ /// Visit the given value as a union. No automatic recursion can happen here.
180180 #[ inline( always) ]
181181 fn visit_union ( & mut self , _v : Self :: V ) -> EvalResult < ' tcx >
182182 {
183183 Ok ( ( ) )
184184 }
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.
186188 #[ 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)
190195 }
191196 /// Called each time we recurse down to a field, passing in old and new value.
192197 /// 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
201206 self . visit_value ( new_val)
202207 }
203208
204- // Actions on the leaves, ready to be overloaded.
205209 /// 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.
207214 #[ inline( always) ]
208215 fn visit_uninhabited ( & mut self ) -> EvalResult < ' tcx >
209216 { Ok ( ( ) ) }
210217 /// 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.
214223 #[ inline( always) ]
215224 fn visit_scalar ( & mut self , _v : Self :: V , _layout : & layout:: Scalar ) -> EvalResult < ' tcx >
216225 { Ok ( ( ) ) }
226+
217227 /// 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.
219229 #[ inline( always) ]
220230 fn visit_primitive ( & mut self , _val : ValTy < ' tcx , M :: PointerTag > ) -> EvalResult < ' tcx >
221231 { Ok ( ( ) ) }
222232
223233 // 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 > {
234239 // 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? ) ?;
237242 }
238243 Ok ( ( ) )
239244 }
@@ -312,13 +317,30 @@ pub trait ValueVisitor<'a, 'mir, 'tcx: 'mir+'a, M: Machine<'a, 'mir, 'tcx>>: Siz
312317 self . visit_union ( v) ?;
313318 } ,
314319 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 ( ) ) ?;
319328 } ,
320329 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) ?;
322344 }
323345 }
324346 Ok ( ( ) )
0 commit comments