@@ -21,6 +21,7 @@ use std::cell::RefCell;
2121use std:: marker:: PhantomData ;
2222use std:: ops:: { ControlFlow , Deref } ;
2323
24+ use root_cx:: BorrowCheckRootCtxt ;
2425use rustc_abi:: FieldIdx ;
2526use rustc_data_structures:: fx:: { FxIndexMap , FxIndexSet } ;
2627use rustc_data_structures:: graph:: dominators:: Dominators ;
@@ -35,7 +36,7 @@ use rustc_infer::infer::{
3536} ;
3637use rustc_middle:: mir:: * ;
3738use rustc_middle:: query:: Providers ;
38- use rustc_middle:: ty:: { self , ParamEnv , RegionVid , TyCtxt , TypingMode , fold_regions} ;
39+ use rustc_middle:: ty:: { self , ParamEnv , RegionVid , Ty , TyCtxt , TypingMode , fold_regions} ;
3940use rustc_middle:: { bug, span_bug} ;
4041use rustc_mir_dataflow:: impls:: {
4142 EverInitializedPlaces , MaybeInitializedPlaces , MaybeUninitializedPlaces ,
@@ -45,7 +46,7 @@ use rustc_mir_dataflow::move_paths::{
4546} ;
4647use rustc_mir_dataflow:: { Analysis , EntryStates , Results , ResultsVisitor , visit_results} ;
4748use rustc_session:: lint:: builtin:: { TAIL_EXPR_DROP_ORDER , UNUSED_MUT } ;
48- use rustc_span:: { Span , Symbol } ;
49+ use rustc_span:: { ErrorGuaranteed , Span , Symbol } ;
4950use smallvec:: SmallVec ;
5051use tracing:: { debug, instrument} ;
5152
@@ -73,14 +74,14 @@ mod def_use;
7374mod diagnostics;
7475mod member_constraints;
7576mod nll;
76- mod opaque_types;
7777mod path_utils;
7878mod place_ext;
7979mod places_conflict;
8080mod polonius;
8181mod prefixes;
8282mod region_infer;
8383mod renumber;
84+ mod root_cx;
8485mod session_diagnostics;
8586mod type_check;
8687mod universal_regions;
@@ -102,44 +103,194 @@ pub fn provide(providers: &mut Providers) {
102103 * providers = Providers { mir_borrowck, ..* providers } ;
103104}
104105
105- fn mir_borrowck ( tcx : TyCtxt < ' _ > , def : LocalDefId ) -> & BorrowCheckResult < ' _ > {
106+ fn mir_borrowck (
107+ tcx : TyCtxt < ' _ > ,
108+ def : LocalDefId ,
109+ ) -> Result < & ConcreteOpaqueTypes < ' _ > , ErrorGuaranteed > {
110+ assert ! ( !tcx. is_typeck_child( def. to_def_id( ) ) ) ;
106111 let ( input_body, _) = tcx. mir_promoted ( def) ;
112+ debug ! ( "run query mir_borrowck: {}" , tcx. def_path_str( def) ) ;
113+
107114 let input_body: & Body < ' _ > = & input_body. borrow ( ) ;
108- if input_body. should_skip ( ) || input_body. tainted_by_errors . is_some ( ) {
109- debug ! ( "Skipping borrowck because of injected body or tainted body" ) ;
110- // Let's make up a borrowck result! Fun times!
111- let result = BorrowCheckResult {
112- concrete_opaque_types : FxIndexMap :: default ( ) ,
113- closure_requirements : None ,
114- used_mut_upvars : SmallVec :: new ( ) ,
115- tainted_by_errors : input_body. tainted_by_errors ,
116- } ;
117- return tcx. arena . alloc ( result) ;
115+ if let Some ( guar) = input_body. tainted_by_errors {
116+ debug ! ( "Skipping borrowck because of tainted body" ) ;
117+ Err ( guar)
118+ } else if input_body. should_skip ( ) {
119+ debug ! ( "Skipping borrowck because of injected body" ) ;
120+ let opaque_types = ConcreteOpaqueTypes ( Default :: default ( ) ) ;
121+ Ok ( tcx. arena . alloc ( opaque_types) )
122+ } else {
123+ let mut root_cx = BorrowCheckRootCtxt :: new ( tcx, def) ;
124+ let BorrowCheckResult { closure_requirements, used_mut_upvars } =
125+ do_mir_borrowck ( & mut root_cx, def, None ) . 0 ;
126+ debug_assert ! ( closure_requirements. is_none( ) ) ;
127+ debug_assert ! ( used_mut_upvars. is_empty( ) ) ;
128+ root_cx. finalize ( )
118129 }
130+ }
131+
132+ #[ derive( Debug ) ]
133+ struct BorrowCheckResult < ' tcx > {
134+ closure_requirements : Option < ClosureRegionRequirements < ' tcx > > ,
135+ used_mut_upvars : SmallVec < [ FieldIdx ; 8 ] > ,
136+ }
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 > ,
119200
120- let borrowck_result = do_mir_borrowck ( tcx , def , None ) . 0 ;
121- debug ! ( "mir_borrowck done" ) ;
201+ // ... must outlive this one.
202+ pub outlived_free_region : ty :: RegionVid ,
122203
123- tcx. arena . alloc ( borrowck_result)
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+ }
124273}
125274
126275/// Perform the actual borrow checking.
127276///
128277/// Use `consumer_options: None` for the default behavior of returning
129278/// [`BorrowCheckResult`] only. Otherwise, return [`BodyWithBorrowckFacts`] according
130279/// to the given [`ConsumerOptions`].
131- #[ instrument( skip( tcx ) , level = "debug" ) ]
280+ #[ instrument( skip( root_cx ) , level = "debug" ) ]
132281fn do_mir_borrowck < ' tcx > (
133- tcx : TyCtxt < ' tcx > ,
282+ root_cx : & mut BorrowCheckRootCtxt < ' tcx > ,
134283 def : LocalDefId ,
135284 consumer_options : Option < ConsumerOptions > ,
136285) -> ( BorrowCheckResult < ' tcx > , Option < Box < BodyWithBorrowckFacts < ' tcx > > > ) {
286+ let tcx = root_cx. tcx ;
137287 let infcx = BorrowckInferCtxt :: new ( tcx, def) ;
138288 let ( input_body, promoted) = tcx. mir_promoted ( def) ;
139289 let input_body: & Body < ' _ > = & input_body. borrow ( ) ;
140290 let input_promoted: & IndexSlice < _ , _ > = & promoted. borrow ( ) ;
141291 if let Some ( e) = input_body. tainted_by_errors {
142292 infcx. set_tainted_by_errors ( e) ;
293+ root_cx. set_tainted_by_errors ( e) ;
143294 }
144295
145296 let mut local_names = IndexVec :: from_elem ( None , & input_body. local_decls ) ;
@@ -191,13 +342,13 @@ fn do_mir_borrowck<'tcx>(
191342 // Compute non-lexical lifetimes.
192343 let nll:: NllOutput {
193344 regioncx,
194- concrete_opaque_types,
195345 polonius_input,
196346 polonius_output,
197347 opt_closure_req,
198348 nll_errors,
199349 polonius_diagnostics,
200350 } = nll:: compute_regions (
351+ root_cx,
201352 & infcx,
202353 free_regions,
203354 body,
@@ -216,26 +367,19 @@ fn do_mir_borrowck<'tcx>(
216367 // We also have a `#[rustc_regions]` annotation that causes us to dump
217368 // information.
218369 let diags_buffer = & mut BorrowckDiagnosticsBuffer :: default ( ) ;
219- nll:: dump_annotation (
220- & infcx,
221- body,
222- & regioncx,
223- & opt_closure_req,
224- & concrete_opaque_types,
225- diags_buffer,
226- ) ;
370+ nll:: dump_annotation ( & infcx, body, & regioncx, & opt_closure_req, diags_buffer) ;
227371
228372 let movable_coroutine =
229- // The first argument is the coroutine type passed by value
230- if let Some ( local) = body. local_decls . raw . get ( 1 )
231- // Get the interior types and args which typeck computed
232- && let ty:: Coroutine ( def_id, _) = * local. ty . kind ( )
233- && tcx. coroutine_movability ( def_id) == hir:: Movability :: Movable
234- {
235- true
236- } else {
237- false
238- } ;
373+ // The first argument is the coroutine type passed by value
374+ if let Some ( local) = body. local_decls . raw . get ( 1 )
375+ // Get the interior types and args which typeck computed
376+ && let ty:: Coroutine ( def_id, _) = * local. ty . kind ( )
377+ && tcx. coroutine_movability ( def_id) == hir:: Movability :: Movable
378+ {
379+ true
380+ } else {
381+ false
382+ } ;
239383
240384 // While promoteds should mostly be correct by construction, we need to check them for
241385 // invalid moves to detect moving out of arrays:`struct S; fn main() { &([S][0]); }`.
@@ -246,6 +390,7 @@ fn do_mir_borrowck<'tcx>(
246390 // this check out of `MirBorrowckCtxt`, actually doing so is far from trivial.
247391 let move_data = MoveData :: gather_moves ( promoted_body, tcx, |_| true ) ;
248392 let mut promoted_mbcx = MirBorrowckCtxt {
393+ root_cx,
249394 infcx : & infcx,
250395 body : promoted_body,
251396 move_data : & move_data,
@@ -286,6 +431,7 @@ fn do_mir_borrowck<'tcx>(
286431 }
287432
288433 let mut mbcx = MirBorrowckCtxt {
434+ root_cx,
289435 infcx : & infcx,
290436 body,
291437 move_data : & move_data,
@@ -353,13 +499,13 @@ fn do_mir_borrowck<'tcx>(
353499
354500 debug ! ( "mbcx.used_mut: {:?}" , mbcx. used_mut) ;
355501 mbcx. lint_unused_mut ( ) ;
356- let tainted_by_errors = mbcx. emit_errors ( ) ;
502+ if let Some ( guar) = mbcx. emit_errors ( ) {
503+ mbcx. root_cx . set_tainted_by_errors ( guar) ;
504+ }
357505
358506 let result = BorrowCheckResult {
359- concrete_opaque_types : concrete_opaque_types. into_inner ( ) ,
360507 closure_requirements : opt_closure_req,
361508 used_mut_upvars : mbcx. used_mut_upvars ,
362- tainted_by_errors,
363509 } ;
364510
365511 let body_with_facts = if consumer_options. is_some ( ) {
@@ -512,6 +658,7 @@ impl<'tcx> Deref for BorrowckInferCtxt<'tcx> {
512658}
513659
514660struct MirBorrowckCtxt < ' a , ' infcx , ' tcx > {
661+ root_cx : & ' a mut BorrowCheckRootCtxt < ' tcx > ,
515662 infcx : & ' infcx BorrowckInferCtxt < ' tcx > ,
516663 body : & ' a Body < ' tcx > ,
517664 move_data : & ' a MoveData < ' tcx > ,
@@ -1385,11 +1532,13 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> {
13851532 | AggregateKind :: CoroutineClosure ( def_id, _)
13861533 | AggregateKind :: Coroutine ( def_id, _) => {
13871534 let def_id = def_id. expect_local ( ) ;
1388- let BorrowCheckResult { used_mut_upvars, .. } =
1389- self . infcx . tcx . mir_borrowck ( def_id) ;
1535+ let used_mut_upvars = self . root_cx . used_mut_upvars ( def_id) ;
13901536 debug ! ( "{:?} used_mut_upvars={:?}" , def_id, used_mut_upvars) ;
1391- for field in used_mut_upvars {
1392- self . propagate_closure_used_mut_upvar ( & operands[ * field] ) ;
1537+ // FIXME: We're cloning the `SmallVec` here to avoid borrowing `root_cx`
1538+ // when calling `propagate_closure_used_mut_upvar`. This should ideally
1539+ // be unnecessary.
1540+ for field in used_mut_upvars. clone ( ) {
1541+ self . propagate_closure_used_mut_upvar ( & operands[ field] ) ;
13931542 }
13941543 }
13951544 AggregateKind :: Adt ( ..)
0 commit comments