@@ -36,7 +36,7 @@ use rustc_infer::infer::{
36
36
} ;
37
37
use rustc_middle:: mir:: * ;
38
38
use rustc_middle:: query:: Providers ;
39
- use rustc_middle:: ty:: { self , ParamEnv , RegionVid , TyCtxt , TypingMode , fold_regions} ;
39
+ use rustc_middle:: ty:: { self , ParamEnv , RegionVid , Ty , TyCtxt , TypingMode , fold_regions} ;
40
40
use rustc_middle:: { bug, span_bug} ;
41
41
use rustc_mir_dataflow:: impls:: {
42
42
EverInitializedPlaces , MaybeInitializedPlaces , MaybeUninitializedPlaces ,
@@ -135,6 +135,143 @@ struct BorrowCheckResult<'tcx> {
135
135
used_mut_upvars : SmallVec < [ FieldIdx ; 8 ] > ,
136
136
}
137
137
138
+ /// After we borrow check a closure, we are left with various
139
+ /// requirements that we have inferred between the free regions that
140
+ /// appear in the closure's signature or on its field types. These
141
+ /// requirements are then verified and proved by the closure's
142
+ /// creating function. This struct encodes those requirements.
143
+ ///
144
+ /// The requirements are listed as being between various `RegionVid`. The 0th
145
+ /// region refers to `'static`; subsequent region vids refer to the free
146
+ /// regions that appear in the closure (or coroutine's) type, in order of
147
+ /// appearance. (This numbering is actually defined by the `UniversalRegions`
148
+ /// struct in the NLL region checker. See for example
149
+ /// `UniversalRegions::closure_mapping`.) Note the free regions in the
150
+ /// closure's signature and captures are erased.
151
+ ///
152
+ /// Example: If type check produces a closure with the closure args:
153
+ ///
154
+ /// ```text
155
+ /// ClosureArgs = [
156
+ /// 'a, // From the parent.
157
+ /// 'b,
158
+ /// i8, // the "closure kind"
159
+ /// for<'x> fn(&'<erased> &'x u32) -> &'x u32, // the "closure signature"
160
+ /// &'<erased> String, // some upvar
161
+ /// ]
162
+ /// ```
163
+ ///
164
+ /// We would "renumber" each free region to a unique vid, as follows:
165
+ ///
166
+ /// ```text
167
+ /// ClosureArgs = [
168
+ /// '1, // From the parent.
169
+ /// '2,
170
+ /// i8, // the "closure kind"
171
+ /// for<'x> fn(&'3 &'x u32) -> &'x u32, // the "closure signature"
172
+ /// &'4 String, // some upvar
173
+ /// ]
174
+ /// ```
175
+ ///
176
+ /// Now the code might impose a requirement like `'1: '2`. When an
177
+ /// instance of the closure is created, the corresponding free regions
178
+ /// can be extracted from its type and constrained to have the given
179
+ /// outlives relationship.
180
+ #[ derive( Clone , Debug ) ]
181
+ pub struct ClosureRegionRequirements < ' tcx > {
182
+ /// The number of external regions defined on the closure. In our
183
+ /// example above, it would be 3 -- one for `'static`, then `'1`
184
+ /// and `'2`. This is just used for a sanity check later on, to
185
+ /// make sure that the number of regions we see at the callsite
186
+ /// matches.
187
+ pub num_external_vids : usize ,
188
+
189
+ /// Requirements between the various free regions defined in
190
+ /// indices.
191
+ pub outlives_requirements : Vec < ClosureOutlivesRequirement < ' tcx > > ,
192
+ }
193
+
194
+ /// Indicates an outlives-constraint between a type or between two
195
+ /// free regions declared on the closure.
196
+ #[ derive( Copy , Clone , Debug ) ]
197
+ pub struct ClosureOutlivesRequirement < ' tcx > {
198
+ // This region or type ...
199
+ pub subject : ClosureOutlivesSubject < ' tcx > ,
200
+
201
+ // ... must outlive this one.
202
+ pub outlived_free_region : ty:: RegionVid ,
203
+
204
+ // If not, report an error here ...
205
+ pub blame_span : Span ,
206
+
207
+ // ... due to this reason.
208
+ pub category : ConstraintCategory < ' tcx > ,
209
+ }
210
+
211
+ // Make sure this enum doesn't unintentionally grow
212
+ #[ cfg( target_pointer_width = "64" ) ]
213
+ rustc_data_structures:: static_assert_size!( ConstraintCategory <' _>, 16 ) ;
214
+
215
+ /// The subject of a `ClosureOutlivesRequirement` -- that is, the thing
216
+ /// that must outlive some region.
217
+ #[ derive( Copy , Clone , Debug ) ]
218
+ pub enum ClosureOutlivesSubject < ' tcx > {
219
+ /// Subject is a type, typically a type parameter, but could also
220
+ /// be a projection. Indicates a requirement like `T: 'a` being
221
+ /// passed to the caller, where the type here is `T`.
222
+ Ty ( ClosureOutlivesSubjectTy < ' tcx > ) ,
223
+
224
+ /// Subject is a free region from the closure. Indicates a requirement
225
+ /// like `'a: 'b` being passed to the caller; the region here is `'a`.
226
+ Region ( ty:: RegionVid ) ,
227
+ }
228
+
229
+ /// Represents a `ty::Ty` for use in [`ClosureOutlivesSubject`].
230
+ ///
231
+ /// This abstraction is necessary because the type may include `ReVar` regions,
232
+ /// which is what we use internally within NLL code, and they can't be used in
233
+ /// a query response.
234
+ ///
235
+ /// DO NOT implement `TypeVisitable` or `TypeFoldable` traits, because this
236
+ /// type is not recognized as a binder for late-bound region.
237
+ #[ derive( Copy , Clone , Debug ) ]
238
+ pub struct ClosureOutlivesSubjectTy < ' tcx > {
239
+ inner : Ty < ' tcx > ,
240
+ }
241
+
242
+ impl < ' tcx > ClosureOutlivesSubjectTy < ' tcx > {
243
+ /// All regions of `ty` must be of kind `ReVar` and must represent
244
+ /// universal regions *external* to the closure.
245
+ pub fn bind ( tcx : TyCtxt < ' tcx > , ty : Ty < ' tcx > ) -> Self {
246
+ let inner = fold_regions ( tcx, ty, |r, depth| match r. kind ( ) {
247
+ ty:: ReVar ( vid) => {
248
+ let br = ty:: BoundRegion {
249
+ var : ty:: BoundVar :: from_usize ( vid. index ( ) ) ,
250
+ kind : ty:: BoundRegionKind :: Anon ,
251
+ } ;
252
+ ty:: Region :: new_bound ( tcx, depth, br)
253
+ }
254
+ _ => bug ! ( "unexpected region in ClosureOutlivesSubjectTy: {r:?}" ) ,
255
+ } ) ;
256
+
257
+ Self { inner }
258
+ }
259
+
260
+ pub fn instantiate (
261
+ self ,
262
+ tcx : TyCtxt < ' tcx > ,
263
+ mut map : impl FnMut ( ty:: RegionVid ) -> ty:: Region < ' tcx > ,
264
+ ) -> Ty < ' tcx > {
265
+ fold_regions ( tcx, self . inner , |r, depth| match r. kind ( ) {
266
+ ty:: ReBound ( debruijn, br) => {
267
+ debug_assert_eq ! ( debruijn, depth) ;
268
+ map ( ty:: RegionVid :: from_usize ( br. var . index ( ) ) )
269
+ }
270
+ _ => bug ! ( "unexpected region {r:?}" ) ,
271
+ } )
272
+ }
273
+ }
274
+
138
275
/// Perform the actual borrow checking.
139
276
///
140
277
/// Use `consumer_options: None` for the default behavior of returning
0 commit comments