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