@@ -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 ,
@@ -140,6 +140,143 @@ struct PropagatedBorrowCheckResults<'tcx> {
140140 used_mut_upvars : SmallVec < [ FieldIdx ; 8 ] > ,
141141}
142142
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+
143280/// Perform the actual borrow checking.
144281///
145282/// Use `consumer_options: None` for the default behavior of returning
0 commit comments