7
7
//! but we still need to do bounds checking and adjust the layout. To not duplicate that with MPlaceTy, we actually
8
8
//! implement the logic on OpTy, and MPlaceTy calls that.
9
9
10
+ use std:: marker:: PhantomData ;
11
+ use std:: ops:: Range ;
12
+
10
13
use rustc_middle:: mir;
11
14
use rustc_middle:: ty;
12
15
use rustc_middle:: ty:: layout:: { LayoutOf , TyAndLayout } ;
13
16
use rustc_middle:: ty:: Ty ;
14
- use rustc_middle:: ty:: TyCtxt ;
15
- use rustc_target:: abi:: HasDataLayout ;
16
17
use rustc_target:: abi:: Size ;
17
18
use rustc_target:: abi:: { self , VariantIdx } ;
18
19
@@ -24,44 +25,42 @@ pub trait Projectable<'tcx, Prov: Provenance>: Sized + std::fmt::Debug {
24
25
fn layout ( & self ) -> TyAndLayout < ' tcx > ;
25
26
26
27
/// Get the metadata of a wide value.
27
- fn meta < ' mir , M : Machine < ' mir , ' tcx , Provenance = Prov > > (
28
- & self ,
29
- ecx : & InterpCx < ' mir , ' tcx , M > ,
30
- ) -> InterpResult < ' tcx , MemPlaceMeta < M :: Provenance > > ;
28
+ fn meta ( & self ) -> InterpResult < ' tcx , MemPlaceMeta < Prov > > ;
31
29
32
30
fn len < ' mir , M : Machine < ' mir , ' tcx , Provenance = Prov > > (
33
31
& self ,
34
32
ecx : & InterpCx < ' mir , ' tcx , M > ,
35
33
) -> InterpResult < ' tcx , u64 > {
36
- self . meta ( ecx ) ?. len ( self . layout ( ) , ecx)
34
+ self . meta ( ) ?. len ( self . layout ( ) , ecx)
37
35
}
38
36
39
37
/// Offset the value by the given amount, replacing the layout and metadata.
40
- fn offset_with_meta (
38
+ fn offset_with_meta < ' mir , M : Machine < ' mir , ' tcx , Provenance = Prov > > (
41
39
& self ,
42
40
offset : Size ,
43
41
meta : MemPlaceMeta < Prov > ,
44
42
layout : TyAndLayout < ' tcx > ,
45
- cx : & impl HasDataLayout ,
43
+ ecx : & InterpCx < ' mir , ' tcx , M > ,
46
44
) -> InterpResult < ' tcx , Self > ;
47
45
48
- fn offset (
46
+ fn offset < ' mir , M : Machine < ' mir , ' tcx , Provenance = Prov > > (
49
47
& self ,
50
48
offset : Size ,
51
49
layout : TyAndLayout < ' tcx > ,
52
- cx : & impl HasDataLayout ,
50
+ ecx : & InterpCx < ' mir , ' tcx , M > ,
53
51
) -> InterpResult < ' tcx , Self > {
54
52
assert ! ( layout. is_sized( ) ) ;
55
- self . offset_with_meta ( offset, MemPlaceMeta :: None , layout, cx )
53
+ self . offset_with_meta ( offset, MemPlaceMeta :: None , layout, ecx )
56
54
}
57
55
58
- fn transmute (
56
+ fn transmute < ' mir , M : Machine < ' mir , ' tcx , Provenance = Prov > > (
59
57
& self ,
60
58
layout : TyAndLayout < ' tcx > ,
61
- cx : & impl HasDataLayout ,
59
+ ecx : & InterpCx < ' mir , ' tcx , M > ,
62
60
) -> InterpResult < ' tcx , Self > {
61
+ assert ! ( self . layout( ) . is_sized( ) && layout. is_sized( ) ) ;
63
62
assert_eq ! ( self . layout( ) . size, layout. size) ;
64
- self . offset_with_meta ( Size :: ZERO , MemPlaceMeta :: None , layout, cx )
63
+ self . offset_with_meta ( Size :: ZERO , MemPlaceMeta :: None , layout, ecx )
65
64
}
66
65
67
66
/// Convert this to an `OpTy`. This might be an irreversible transformation, but is useful for
@@ -72,6 +71,28 @@ pub trait Projectable<'tcx, Prov: Provenance>: Sized + std::fmt::Debug {
72
71
) -> InterpResult < ' tcx , OpTy < ' tcx , M :: Provenance > > ;
73
72
}
74
73
74
+ /// A type representing iteration over the elements of an array.
75
+ pub struct ArrayIterator < ' tcx , ' a , Prov : Provenance + ' static , P : Projectable < ' tcx , Prov > > {
76
+ base : & ' a P ,
77
+ range : Range < u64 > ,
78
+ stride : Size ,
79
+ field_layout : TyAndLayout < ' tcx > ,
80
+ _phantom : PhantomData < Prov > , // otherwise it says `Prov` is never used...
81
+ }
82
+
83
+ impl < ' tcx , ' a , Prov : Provenance + ' static , P : Projectable < ' tcx , Prov > >
84
+ ArrayIterator < ' tcx , ' a , Prov , P >
85
+ {
86
+ /// Should be the same `ecx` on each call, and match the one used to create the iterator.
87
+ pub fn next < ' mir , M : Machine < ' mir , ' tcx , Provenance = Prov > > (
88
+ & mut self ,
89
+ ecx : & InterpCx < ' mir , ' tcx , M > ,
90
+ ) -> InterpResult < ' tcx , Option < ( u64 , P ) > > {
91
+ let Some ( idx) = self . range . next ( ) else { return Ok ( None ) } ;
92
+ Ok ( Some ( ( idx, self . base . offset ( self . stride * idx, self . field_layout , ecx) ?) ) )
93
+ }
94
+ }
95
+
75
96
// FIXME: Working around https://github.com/rust-lang/rust/issues/54385
76
97
impl < ' mir , ' tcx : ' mir , Prov , M > InterpCx < ' mir , ' tcx , M >
77
98
where
@@ -104,7 +125,7 @@ where
104
125
// But const-prop actually feeds us such nonsense MIR! (see test `const_prop/issue-86351.rs`)
105
126
throw_inval ! ( ConstPropNonsense ) ;
106
127
}
107
- let base_meta = base. meta ( self ) ?;
128
+ let base_meta = base. meta ( ) ?;
108
129
// Re-use parent metadata to determine dynamic field layout.
109
130
// With custom DSTS, this *will* execute user-defined code, but the same
110
131
// happens at run-time so that's okay.
@@ -132,7 +153,7 @@ where
132
153
base : & P ,
133
154
variant : VariantIdx ,
134
155
) -> InterpResult < ' tcx , P > {
135
- assert ! ( !base. meta( self ) ?. has_meta( ) ) ;
156
+ assert ! ( !base. meta( ) ?. has_meta( ) ) ;
136
157
// Downcasts only change the layout.
137
158
// (In particular, no check about whether this is even the active variant -- that's by design,
138
159
// see https://github.com/rust-lang/rust/issues/93688#issuecomment-1032929496.)
@@ -206,20 +227,13 @@ where
206
227
pub fn project_array_fields < ' a , P : Projectable < ' tcx , M :: Provenance > > (
207
228
& self ,
208
229
base : & ' a P ,
209
- ) -> InterpResult < ' tcx , impl Iterator < Item = InterpResult < ' tcx , P > > + ' a >
210
- where
211
- ' tcx : ' a ,
212
- {
230
+ ) -> InterpResult < ' tcx , ArrayIterator < ' tcx , ' a , M :: Provenance , P > > {
213
231
let abi:: FieldsShape :: Array { stride, .. } = base. layout ( ) . fields else {
214
232
span_bug ! ( self . cur_span( ) , "operand_array_fields: expected an array layout" ) ;
215
233
} ;
216
234
let len = base. len ( self ) ?;
217
235
let field_layout = base. layout ( ) . field ( self , 0 ) ;
218
- let tcx: TyCtxt < ' tcx > = * self . tcx ;
219
- // `Size` multiplication
220
- Ok ( ( 0 ..len) . map ( move |i| {
221
- base. offset_with_meta ( stride * i, MemPlaceMeta :: None , field_layout, & tcx)
222
- } ) )
236
+ Ok ( ArrayIterator { base, range : 0 ..len, stride, field_layout, _phantom : PhantomData } )
223
237
}
224
238
225
239
/// Subslicing
0 commit comments