@@ -36,7 +36,7 @@ use rustc_infer::infer::{
3636} ;
3737use rustc_middle:: mir:: * ;
3838use 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} ;
4040use rustc_middle:: { bug, span_bug} ;
4141use rustc_mir_dataflow:: impls:: {
4242 EverInitializedPlaces , MaybeInitializedPlaces , MaybeUninitializedPlaces ,
@@ -135,6 +135,143 @@ struct BorrowCheckResult<'tcx> {
135135 used_mut_upvars : SmallVec < [ FieldIdx ; 8 ] > ,
136136}
137137
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+
138275/// Perform the actual borrow checking.
139276///
140277/// Use `consumer_options: None` for the default behavior of returning
0 commit comments