1 use crate::borrow_check::borrow_set::BorrowSet;
2 use crate::borrow_check::location::{LocationIndex, LocationTable};
3 use crate::borrow_check::nll::facts::AllFactsExt;
4 use crate::borrow_check::nll::type_check::{MirTypeckResults, MirTypeckRegionConstraints};
5 use crate::borrow_check::nll::region_infer::values::RegionValueElements;
6 use crate::dataflow::indexes::BorrowIndex;
7 use crate::dataflow::move_paths::MoveData;
8 use crate::dataflow::FlowAtLocation;
9 use crate::dataflow::MaybeInitializedPlaces;
10 use crate::transform::MirSource;
11 use crate::borrow_check::Upvar;
12 use rustc::hir::def_id::DefId;
13 use rustc::infer::InferCtxt;
14 use rustc::mir::{ClosureOutlivesSubject, ClosureRegionRequirements, Local, Body};
15 use rustc::ty::{self, RegionKind, RegionVid};
16 use rustc_errors::Diagnostic;
20 use std::path::PathBuf;
22 use std::str::FromStr;
23 use syntax::symbol::sym;
25 use self::mir_util::PassWhere;
26 use polonius_engine::{Algorithm, Output};
27 use crate::util as mir_util;
28 use crate::util::pretty;
30 mod constraint_generation;
31 pub mod explain_borrow;
34 crate mod region_infer;
37 mod universal_regions;
40 mod member_constraints;
42 use self::facts::AllFacts;
43 use self::region_infer::RegionInferenceContext;
44 use self::universal_regions::UniversalRegions;
46 /// Rewrites the regions in the MIR to use NLL variables, also
47 /// scraping out the set of universal regions (e.g., region parameters)
48 /// declared on the function. That set will need to be given to
49 /// `compute_regions`.
50 pub(in crate::borrow_check) fn replace_regions_in_mir<'cx, 'tcx>(
51 infcx: &InferCtxt<'cx, 'tcx>,
53 param_env: ty::ParamEnv<'tcx>,
54 body: &mut Body<'tcx>,
55 ) -> UniversalRegions<'tcx> {
56 debug!("replace_regions_in_mir(def_id={:?})", def_id);
58 // Compute named region information. This also renumbers the inputs/outputs.
59 let universal_regions = UniversalRegions::new(infcx, def_id, param_env);
61 // Replace all remaining regions with fresh inference variables.
62 renumber::renumber_mir(infcx, body);
64 let source = MirSource::item(def_id);
65 mir_util::dump_mir(infcx.tcx, None, "renumber", &0, source, body, |_, _| Ok(()));
70 /// Computes the (non-lexical) regions from the input MIR.
72 /// This may result in errors being reported.
73 pub(in crate::borrow_check) fn compute_regions<'cx, 'tcx>(
74 infcx: &InferCtxt<'cx, 'tcx>,
76 universal_regions: UniversalRegions<'tcx>,
79 location_table: &LocationTable,
80 param_env: ty::ParamEnv<'tcx>,
81 flow_inits: &mut FlowAtLocation<'tcx, MaybeInitializedPlaces<'cx, 'tcx>>,
82 move_data: &MoveData<'tcx>,
83 borrow_set: &BorrowSet<'tcx>,
84 errors_buffer: &mut Vec<Diagnostic>,
86 RegionInferenceContext<'tcx>,
87 Option<Rc<Output<RegionVid, BorrowIndex, LocationIndex, Local>>>,
88 Option<ClosureRegionRequirements<'tcx>>,
90 let mut all_facts = if AllFacts::enabled(infcx.tcx) {
91 Some(AllFacts::default())
96 let universal_regions = Rc::new(universal_regions);
98 let elements = &Rc::new(RegionValueElements::new(body));
100 // Run the MIR type-checker.
101 let MirTypeckResults {
103 universal_region_relations,
104 } = type_check::type_check(
118 if let Some(all_facts) = &mut all_facts {
121 .extend(universal_regions.universal_regions());
124 // Create the region inference context, taking ownership of the
125 // region inference data that was contained in `infcx`, and the
126 // base constraints generated by the type-check.
127 let var_origins = infcx.take_region_var_origins();
128 let MirTypeckRegionConstraints {
130 placeholder_index_to_region: _,
131 mut liveness_constraints,
132 outlives_constraints,
134 closure_bounds_mapping,
137 let placeholder_indices = Rc::new(placeholder_indices);
139 constraint_generation::generate_constraints(
141 &mut liveness_constraints,
148 let mut regioncx = RegionInferenceContext::new(
152 universal_region_relations,
154 outlives_constraints,
156 closure_bounds_mapping,
158 liveness_constraints,
162 // Generate various additional constraints.
163 invalidation::generate_invalidates(
171 // Dump facts if requested.
172 let polonius_output = all_facts.and_then(|all_facts| {
173 if infcx.tcx.sess.opts.debugging_opts.nll_facts {
174 let def_path = infcx.tcx.hir().def_path(def_id);
176 PathBuf::from("nll-facts").join(def_path.to_filename_friendly_no_crate());
177 all_facts.write_to_dir(dir_path, location_table).unwrap();
180 if infcx.tcx.sess.opts.debugging_opts.polonius {
181 let algorithm = env::var("POLONIUS_ALGORITHM")
182 .unwrap_or_else(|_| String::from("Hybrid"));
183 let algorithm = Algorithm::from_str(&algorithm).unwrap();
184 debug!("compute_regions: using polonius algorithm {:?}", algorithm);
185 Some(Rc::new(Output::compute(
195 // Solve the region constraints.
196 let closure_region_requirements =
197 regioncx.solve(infcx, &body, upvars, def_id, errors_buffer);
199 // Dump MIR results into a file, if that is enabled. This let us
200 // write unit-tests, as well as helping with debugging.
203 MirSource::item(def_id),
206 &closure_region_requirements,
209 // We also have a `#[rustc_nll]` annotation that causes us to dump
211 dump_annotation(infcx, &body, def_id, ®ioncx, &closure_region_requirements, errors_buffer);
213 (regioncx, polonius_output, closure_region_requirements)
216 fn dump_mir_results<'a, 'tcx>(
217 infcx: &InferCtxt<'a, 'tcx>,
218 source: MirSource<'tcx>,
220 regioncx: &RegionInferenceContext<'_>,
221 closure_region_requirements: &Option<ClosureRegionRequirements<'_>>,
223 if !mir_util::dump_enabled(infcx.tcx, "nll", source) {
236 // Before the CFG, dump out the values for each region variable.
237 PassWhere::BeforeCFG => {
238 regioncx.dump_mir(out)?;
241 if let Some(closure_region_requirements) = closure_region_requirements {
242 writeln!(out, "| Free Region Constraints")?;
243 for_each_region_constraint(closure_region_requirements, &mut |msg| {
244 writeln!(out, "| {}", msg)
250 PassWhere::BeforeLocation(_) => {
253 PassWhere::AfterTerminator(_) => {
256 PassWhere::BeforeBlock(_) | PassWhere::AfterLocation(_) | PassWhere::AfterCFG => {}
262 // Also dump the inference graph constraints as a graphviz file.
263 let _: io::Result<()> = try {
265 pretty::create_dump_file(infcx.tcx, "regioncx.all.dot", None, "nll", &0, source)?;
266 regioncx.dump_graphviz_raw_constraints(&mut file)?;
269 // Also dump the inference graph constraints as a graphviz file.
270 let _: io::Result<()> = try {
272 pretty::create_dump_file(infcx.tcx, "regioncx.scc.dot", None, "nll", &0, source)?;
273 regioncx.dump_graphviz_scc_constraints(&mut file)?;
277 fn dump_annotation<'a, 'tcx>(
278 infcx: &InferCtxt<'a, 'tcx>,
281 regioncx: &RegionInferenceContext<'tcx>,
282 closure_region_requirements: &Option<ClosureRegionRequirements<'_>>,
283 errors_buffer: &mut Vec<Diagnostic>,
286 let base_def_id = tcx.closure_base_def_id(mir_def_id);
287 if !tcx.has_attr(base_def_id, sym::rustc_regions) {
291 // When the enclosing function is tagged with `#[rustc_regions]`,
292 // we dump out various bits of state as warnings. This is useful
293 // for verifying that the compiler is behaving as expected. These
294 // warnings focus on the closure region requirements -- for
295 // viewing the intraprocedural state, the -Zdump-mir output is
298 if let Some(closure_region_requirements) = closure_region_requirements {
302 .span_note_diag(body.span, "External requirements");
304 regioncx.annotate(tcx, &mut err);
307 "number of external vids: {}",
308 closure_region_requirements.num_external_vids
311 // Dump the region constraints we are imposing *between* those
312 // newly created variables.
313 for_each_region_constraint(closure_region_requirements, &mut |msg| {
318 err.buffer(errors_buffer);
323 .span_note_diag(body.span, "No external requirements");
324 regioncx.annotate(tcx, &mut err);
326 err.buffer(errors_buffer);
330 fn for_each_region_constraint(
331 closure_region_requirements: &ClosureRegionRequirements<'_>,
332 with_msg: &mut dyn FnMut(&str) -> io::Result<()>,
333 ) -> io::Result<()> {
334 for req in &closure_region_requirements.outlives_requirements {
335 let subject: &dyn Debug = match &req.subject {
336 ClosureOutlivesSubject::Region(subject) => subject,
337 ClosureOutlivesSubject::Ty(ty) => ty,
341 subject, req.outlived_free_region,
347 /// Right now, we piggy back on the `ReVar` to store our NLL inference
348 /// regions. These are indexed with `RegionVid`. This method will
349 /// assert that the region is a `ReVar` and extract its internal index.
350 /// This is reasonable because in our MIR we replace all universal regions
351 /// with inference variables.
352 pub trait ToRegionVid {
353 fn to_region_vid(self) -> RegionVid;
356 impl<'tcx> ToRegionVid for &'tcx RegionKind {
357 fn to_region_vid(self) -> RegionVid {
358 if let ty::ReVar(vid) = self {
361 bug!("region is not an ReVar: {:?}", self)
366 impl ToRegionVid for RegionVid {
367 fn to_region_vid(self) -> RegionVid {
372 crate trait ConstraintDescription {
373 fn description(&self) -> &'static str;