Skip to content

Commit fa36a7d

Browse files
committed
support revealing-uses in closures
1 parent abf6e65 commit fa36a7d

File tree

11 files changed

+394
-90
lines changed

11 files changed

+394
-90
lines changed

compiler/rustc_borrowck/src/consumers.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ pub use super::polonius::legacy::{
1515
RichLocation, RustcFacts,
1616
};
1717
pub use super::region_infer::RegionInferenceContext;
18-
use crate::{BorrowCheckRootCtxt, do_mir_borrowck};
18+
use crate::BorrowCheckRootCtxt;
1919

2020
/// Options determining the output behavior of [`get_body_with_borrowck_facts`].
2121
///
@@ -101,6 +101,6 @@ pub fn get_body_with_borrowck_facts(
101101
def_id: LocalDefId,
102102
options: ConsumerOptions,
103103
) -> BodyWithBorrowckFacts<'_> {
104-
let mut root_cx = BorrowCheckRootCtxt::new(tcx, def_id);
105-
*do_mir_borrowck(&mut root_cx, def_id, Some(options)).1.unwrap()
104+
let root_cx = BorrowCheckRootCtxt::new(tcx, def_id);
105+
*root_cx.borrowck_root(Some(options)).1.unwrap()
106106
}

compiler/rustc_borrowck/src/lib.rs

+60-12
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ use std::ops::{ControlFlow, Deref};
2424

2525
use borrow_set::LocalsStateAtExit;
2626
use diagnostics::RegionErrors;
27+
use nll::YieldComputeRegions;
2728
use root_cx::BorrowCheckRootCtxt;
2829
use rustc_abi::FieldIdx;
2930
use rustc_data_structures::fx::{FxIndexMap, FxIndexSet};
@@ -54,6 +55,7 @@ use rustc_session::lint::builtin::{TAIL_EXPR_DROP_ORDER, UNUSED_MUT};
5455
use rustc_span::{ErrorGuaranteed, Span, Symbol};
5556
use smallvec::SmallVec;
5657
use tracing::{debug, instrument};
58+
use type_check::Locations;
5759

5860
use crate::borrow_set::{BorrowData, BorrowSet};
5961
use crate::consumers::{BodyWithBorrowckFacts, ConsumerOptions};
@@ -127,12 +129,8 @@ fn mir_borrowck(
127129
let opaque_types = ConcreteOpaqueTypes(Default::default());
128130
Ok(tcx.arena.alloc(opaque_types))
129131
} else {
130-
let mut root_cx = BorrowCheckRootCtxt::new(tcx, def);
131-
let PropagatedBorrowCheckResults { closure_requirements, used_mut_upvars } =
132-
do_mir_borrowck(&mut root_cx, def, None).0;
133-
debug_assert!(closure_requirements.is_none());
134-
debug_assert!(used_mut_upvars.is_empty());
135-
root_cx.finalize()
132+
let root_cx = BorrowCheckRootCtxt::new(tcx, def);
133+
root_cx.borrowck_root(None).0
136134
}
137135
}
138136

@@ -144,6 +142,8 @@ struct PropagatedBorrowCheckResults<'tcx> {
144142
used_mut_upvars: SmallVec<[FieldIdx; 8]>,
145143
}
146144

145+
type DeferredClosureRequirements<'tcx> = Vec<(LocalDefId, ty::GenericArgsRef<'tcx>, Locations)>;
146+
147147
/// After we borrow check a closure, we are left with various
148148
/// requirements that we have inferred between the free regions that
149149
/// appear in the closure's signature or on its field types. These
@@ -282,6 +282,16 @@ impl<'tcx> ClosureOutlivesSubjectTy<'tcx> {
282282
}
283283
}
284284

285+
struct YieldDoMirBorrowck<'tcx> {
286+
infcx: BorrowckInferCtxt<'tcx>,
287+
body_owned: Body<'tcx>,
288+
promoted: IndexVec<Promoted, Body<'tcx>>,
289+
move_data: MoveData<'tcx>,
290+
borrow_set: BorrowSet<'tcx>,
291+
location_table: PoloniusLocationTable,
292+
yield_compute_regions: YieldComputeRegions<'tcx>,
293+
}
294+
285295
/// Perform the actual borrow checking.
286296
///
287297
/// Use `consumer_options: None` for the default behavior of returning
@@ -290,11 +300,11 @@ impl<'tcx> ClosureOutlivesSubjectTy<'tcx> {
290300
///
291301
/// For nested bodies this should only be called through `root_cx.get_or_insert_nested`.
292302
#[instrument(skip(root_cx), level = "debug")]
293-
fn do_mir_borrowck<'tcx>(
303+
fn start_do_mir_borrowck<'tcx>(
294304
root_cx: &mut BorrowCheckRootCtxt<'tcx>,
295305
def: LocalDefId,
296306
consumer_options: Option<ConsumerOptions>,
297-
) -> (PropagatedBorrowCheckResults<'tcx>, Option<Box<BodyWithBorrowckFacts<'tcx>>>) {
307+
) -> YieldDoMirBorrowck<'tcx> {
298308
let tcx = root_cx.tcx;
299309
let infcx = BorrowckInferCtxt::new(tcx, def);
300310
let (input_body, promoted) = tcx.mir_promoted(def);
@@ -325,6 +335,46 @@ fn do_mir_borrowck<'tcx>(
325335
let locals_are_invalidated_at_exit = tcx.hir_body_owner_kind(def).is_fn_or_closure();
326336
let borrow_set = BorrowSet::build(tcx, body, locals_are_invalidated_at_exit, &move_data);
327337

338+
let yield_compute_regions = nll::compute_regions(
339+
root_cx,
340+
&infcx,
341+
universal_regions,
342+
body,
343+
&promoted,
344+
&location_table,
345+
flow_inits,
346+
&move_data,
347+
&borrow_set,
348+
consumer_options,
349+
);
350+
351+
YieldDoMirBorrowck {
352+
infcx,
353+
body_owned,
354+
promoted,
355+
move_data,
356+
borrow_set,
357+
location_table,
358+
yield_compute_regions,
359+
}
360+
}
361+
362+
fn resume_do_mir_borrowck<'tcx>(
363+
root_cx: &mut BorrowCheckRootCtxt<'tcx>,
364+
consumer_options: Option<ConsumerOptions>,
365+
YieldDoMirBorrowck {
366+
infcx,
367+
body_owned,
368+
promoted,
369+
move_data,
370+
borrow_set,
371+
location_table,
372+
yield_compute_regions,
373+
}: YieldDoMirBorrowck<'tcx>,
374+
) -> (PropagatedBorrowCheckResults<'tcx>, Option<Box<BodyWithBorrowckFacts<'tcx>>>) {
375+
assert!(!infcx.has_opaque_types_in_storage());
376+
let body = &body_owned;
377+
328378
// Compute non-lexical lifetimes.
329379
let nll::NllOutput {
330380
regioncx,
@@ -333,17 +383,15 @@ fn do_mir_borrowck<'tcx>(
333383
opt_closure_req,
334384
nll_errors,
335385
polonius_diagnostics,
336-
} = nll::compute_regions(
386+
} = nll::resume_compute_regions(
337387
root_cx,
338388
&infcx,
339-
universal_regions,
340389
body,
341-
&promoted,
342390
&location_table,
343-
flow_inits,
344391
&move_data,
345392
&borrow_set,
346393
consumer_options,
394+
yield_compute_regions,
347395
);
348396

349397
// Dump MIR results into a file, if that is enabled. This lets us

compiler/rustc_borrowck/src/nll.rs

+96-27
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,10 @@ use std::path::PathBuf;
55
use std::rc::Rc;
66
use std::str::FromStr;
77

8-
use polonius_engine::{Algorithm, Output};
8+
use polonius_engine::{Algorithm, AllFacts, Output};
9+
use rustc_data_structures::frozen::Frozen;
910
use rustc_index::IndexSlice;
11+
use rustc_infer::infer::outlives::env::RegionBoundPairs;
1012
use rustc_middle::mir::pretty::{PrettyPrintMirOptions, dump_mir_with_options};
1113
use rustc_middle::mir::{Body, PassWhere, Promoted, create_dump_file, dump_enabled, dump_mir};
1214
use rustc_middle::ty::print::with_no_trimmed_paths;
@@ -20,19 +22,20 @@ use rustc_span::sym;
2022
use tracing::{debug, instrument};
2123

2224
use crate::borrow_set::BorrowSet;
23-
use crate::consumers::ConsumerOptions;
25+
use crate::consumers::{ConsumerOptions, RustcFacts};
2426
use crate::diagnostics::RegionErrors;
25-
use crate::polonius::PoloniusDiagnosticsContext;
2627
use crate::polonius::legacy::{
2728
PoloniusFacts, PoloniusFactsExt, PoloniusLocationTable, PoloniusOutput,
2829
};
30+
use crate::polonius::{PoloniusContext, PoloniusDiagnosticsContext};
2931
use crate::region_infer::RegionInferenceContext;
30-
use crate::region_infer::opaque_types::handle_opaque_type_uses;
31-
use crate::type_check::{self, MirTypeckResults};
32+
use crate::region_infer::opaque_types::DeferredOpaqueTypeError;
33+
use crate::type_check::free_region_relations::UniversalRegionRelations;
34+
use crate::type_check::{self, MirTypeckRegionConstraints, MirTypeckResults};
3235
use crate::universal_regions::UniversalRegions;
3336
use crate::{
3437
BorrowCheckRootCtxt, BorrowckInferCtxt, ClosureOutlivesSubject, ClosureRegionRequirements,
35-
polonius, renumber,
38+
DeferredClosureRequirements, YieldDoMirBorrowck, polonius, renumber,
3639
};
3740

3841
/// The output of `nll::compute_regions`. This includes the computed `RegionInferenceContext`, any
@@ -73,6 +76,18 @@ pub(crate) fn replace_regions_in_mir<'tcx>(
7376
universal_regions
7477
}
7578

79+
pub(crate) struct YieldComputeRegions<'tcx> {
80+
pub(crate) constraints: MirTypeckRegionConstraints<'tcx>,
81+
pub(crate) universal_region_relations: Frozen<UniversalRegionRelations<'tcx>>,
82+
pub(crate) region_bound_pairs: Frozen<RegionBoundPairs<'tcx>>,
83+
pub(crate) known_type_outlives_obligations: Frozen<Vec<ty::PolyTypeOutlivesPredicate<'tcx>>>,
84+
pub(crate) location_map: Rc<DenseLocationMap>,
85+
pub(crate) deferred_closure_requirements: DeferredClosureRequirements<'tcx>,
86+
pub(crate) deferred_opaque_type_errors: Vec<DeferredOpaqueTypeError<'tcx>>,
87+
polonius_facts: Option<AllFacts<RustcFacts>>,
88+
polonius_context: Option<PoloniusContext>,
89+
}
90+
7691
/// Computes the (non-lexical) regions from the input MIR.
7792
///
7893
/// This may result in errors being reported.
@@ -87,41 +102,95 @@ pub(crate) fn compute_regions<'a, 'tcx>(
87102
move_data: &MoveData<'tcx>,
88103
borrow_set: &BorrowSet<'tcx>,
89104
consumer_options: Option<ConsumerOptions>,
90-
) -> NllOutput<'tcx> {
105+
) -> YieldComputeRegions<'tcx> {
91106
let is_polonius_legacy_enabled = infcx.tcx.sess.opts.unstable_opts.polonius.is_legacy_enabled();
92107
let polonius_input = consumer_options.map(|c| c.polonius_input()).unwrap_or_default()
93108
|| is_polonius_legacy_enabled;
94-
let polonius_output = consumer_options.map(|c| c.polonius_output()).unwrap_or_default()
95-
|| is_polonius_legacy_enabled;
96109
let mut polonius_facts =
97110
(polonius_input || PoloniusFacts::enabled(infcx.tcx)).then_some(PoloniusFacts::default());
98111

99112
let location_map = Rc::new(DenseLocationMap::new(body));
100113

101114
// Run the MIR type-checker.
102-
let MirTypeckResults { constraints, universal_region_relations, polonius_context } =
103-
type_check::type_check(
104-
root_cx,
105-
infcx,
106-
body,
107-
promoted,
108-
universal_regions,
109-
location_table,
110-
borrow_set,
111-
&mut polonius_facts,
112-
flow_inits,
113-
move_data,
114-
Rc::clone(&location_map),
115-
);
116-
117-
let (constraints, deferred_opaque_type_errors) = handle_opaque_type_uses(
115+
let MirTypeckResults {
116+
constraints,
117+
universal_region_relations,
118+
region_bound_pairs,
119+
known_type_outlives_obligations,
120+
deferred_closure_requirements,
121+
polonius_context,
122+
} = type_check::type_check(
118123
root_cx,
119124
infcx,
120-
constraints,
121-
&universal_region_relations,
125+
body,
126+
promoted,
127+
universal_regions,
128+
location_table,
129+
borrow_set,
130+
&mut polonius_facts,
131+
flow_inits,
132+
move_data,
122133
Rc::clone(&location_map),
123134
);
124135

136+
YieldComputeRegions {
137+
constraints,
138+
universal_region_relations,
139+
region_bound_pairs,
140+
known_type_outlives_obligations,
141+
location_map,
142+
deferred_closure_requirements,
143+
deferred_opaque_type_errors: Default::default(),
144+
polonius_facts,
145+
polonius_context,
146+
}
147+
}
148+
149+
pub(crate) fn compute_closure_requirements_modulo_opaques<'tcx>(
150+
partial_result: &YieldDoMirBorrowck<'tcx>,
151+
) -> Option<ClosureRegionRequirements<'tcx>> {
152+
let YieldDoMirBorrowck {
153+
infcx,
154+
body_owned,
155+
yield_compute_regions:
156+
YieldComputeRegions { constraints, universal_region_relations, location_map, .. },
157+
..
158+
} = partial_result;
159+
160+
let mut regioncx = RegionInferenceContext::new(
161+
&infcx,
162+
constraints.clone(),
163+
universal_region_relations.clone(),
164+
location_map.clone(),
165+
);
166+
let (closure_region_requirements, _nll_errors) = regioncx.solve(infcx, &body_owned, None);
167+
closure_region_requirements
168+
}
169+
170+
pub(crate) fn resume_compute_regions<'tcx>(
171+
root_cx: &mut BorrowCheckRootCtxt<'tcx>,
172+
infcx: &BorrowckInferCtxt<'tcx>,
173+
body: &Body<'tcx>,
174+
location_table: &PoloniusLocationTable,
175+
move_data: &MoveData<'tcx>,
176+
borrow_set: &BorrowSet<'tcx>,
177+
consumer_options: Option<ConsumerOptions>,
178+
YieldComputeRegions {
179+
constraints,
180+
universal_region_relations,
181+
region_bound_pairs: _,
182+
known_type_outlives_obligations: _,
183+
location_map,
184+
deferred_closure_requirements,
185+
deferred_opaque_type_errors,
186+
mut polonius_facts,
187+
polonius_context,
188+
}: YieldComputeRegions<'tcx>,
189+
) -> NllOutput<'tcx> {
190+
assert!(deferred_closure_requirements.is_empty());
191+
let is_polonius_legacy_enabled = infcx.tcx.sess.opts.unstable_opts.polonius.is_legacy_enabled();
192+
let polonius_output = consumer_options.map(|c| c.polonius_output()).unwrap_or_default()
193+
|| is_polonius_legacy_enabled;
125194
// If requested, emit legacy polonius facts.
126195
polonius::legacy::emit_facts(
127196
&mut polonius_facts,

0 commit comments

Comments
 (0)