]>
Commit | Line | Data |
---|---|---|
60c5eb7d XL |
1 | //! The entry point of the NLL borrow checker. |
2 | ||
17df50a5 | 3 | use rustc_data_structures::vec_map::VecMap; |
8faf50e0 | 4 | use rustc_errors::Diagnostic; |
dfeec247 | 5 | use rustc_index::vec::IndexVec; |
74b04a01 | 6 | use rustc_infer::infer::InferCtxt; |
c295e0f8 | 7 | use rustc_middle::mir::{create_dump_file, dump_enabled, dump_mir, PassWhere}; |
ba9703b0 | 8 | use rustc_middle::mir::{ |
f9f354fc XL |
9 | BasicBlock, Body, ClosureOutlivesSubject, ClosureRegionRequirements, LocalKind, Location, |
10 | Promoted, | |
ba9703b0 | 11 | }; |
17df50a5 | 12 | use rustc_middle::ty::{self, OpaqueTypeKey, RegionKind, RegionVid, Ty}; |
dfeec247 | 13 | use rustc_span::symbol::sym; |
94b46f34 | 14 | use std::env; |
dfeec247 | 15 | use std::fmt::Debug; |
ff7c6d11 | 16 | use std::io; |
83c7162d | 17 | use std::path::PathBuf; |
94b46f34 XL |
18 | use std::rc::Rc; |
19 | use std::str::FromStr; | |
ff7c6d11 | 20 | |
94b46f34 | 21 | use polonius_engine::{Algorithm, Output}; |
60c5eb7d | 22 | |
c295e0f8 XL |
23 | use rustc_mir_dataflow::impls::MaybeInitializedPlaces; |
24 | use rustc_mir_dataflow::move_paths::{InitKind, InitLocation, MoveData}; | |
25 | use rustc_mir_dataflow::ResultsCursor; | |
ff7c6d11 | 26 | |
c295e0f8 | 27 | use crate::{ |
60c5eb7d | 28 | borrow_set::BorrowSet, |
dfeec247 XL |
29 | constraint_generation, |
30 | diagnostics::RegionErrors, | |
60c5eb7d | 31 | facts::{AllFacts, AllFactsExt, RustcFacts}, |
dfeec247 XL |
32 | invalidation, |
33 | location::LocationTable, | |
34 | region_infer::{values::RegionValueElements, RegionInferenceContext}, | |
35 | renumber, | |
36 | type_check::{self, MirTypeckRegionConstraints, MirTypeckResults}, | |
60c5eb7d | 37 | universal_regions::UniversalRegions, |
f035d41b | 38 | Upvar, |
60c5eb7d | 39 | }; |
ff7c6d11 | 40 | |
94222f64 | 41 | pub type PoloniusOutput = Output<RustcFacts>; |
ff7c6d11 | 42 | |
dfeec247 XL |
43 | /// The output of `nll::compute_regions`. This includes the computed `RegionInferenceContext`, any |
44 | /// closure requirements to propagate, and any generated errors. | |
45 | crate struct NllOutput<'tcx> { | |
46 | pub regioncx: RegionInferenceContext<'tcx>, | |
17df50a5 | 47 | pub opaque_type_values: VecMap<OpaqueTypeKey<'tcx>, Ty<'tcx>>, |
94222f64 | 48 | pub polonius_input: Option<Box<AllFacts>>, |
dfeec247 XL |
49 | pub polonius_output: Option<Rc<PoloniusOutput>>, |
50 | pub opt_closure_req: Option<ClosureRegionRequirements<'tcx>>, | |
51 | pub nll_errors: RegionErrors<'tcx>, | |
52 | } | |
53 | ||
54 | /// Rewrites the regions in the MIR to use NLL variables, also scraping out the set of universal | |
55 | /// regions (e.g., region parameters) declared on the function. That set will need to be given to | |
ff7c6d11 | 56 | /// `compute_regions`. |
c295e0f8 XL |
57 | #[instrument(skip(infcx, param_env, body, promoted), level = "debug")] |
58 | pub(crate) fn replace_regions_in_mir<'cx, 'tcx>( | |
dc9dc135 | 59 | infcx: &InferCtxt<'cx, 'tcx>, |
ff7c6d11 | 60 | param_env: ty::ParamEnv<'tcx>, |
f9f354fc XL |
61 | body: &mut Body<'tcx>, |
62 | promoted: &mut IndexVec<Promoted, Body<'tcx>>, | |
ff7c6d11 | 63 | ) -> UniversalRegions<'tcx> { |
29967ef6 XL |
64 | let def = body.source.with_opt_param().as_local().unwrap(); |
65 | ||
c295e0f8 | 66 | debug!(?def); |
ff7c6d11 XL |
67 | |
68 | // Compute named region information. This also renumbers the inputs/outputs. | |
3dfed10e | 69 | let universal_regions = UniversalRegions::new(infcx, def, param_env); |
ff7c6d11 XL |
70 | |
71 | // Replace all remaining regions with fresh inference variables. | |
e1599b0c | 72 | renumber::renumber_mir(infcx, body, promoted); |
ff7c6d11 | 73 | |
c295e0f8 | 74 | dump_mir(infcx.tcx, None, "renumber", &0, body, |_, _| Ok(())); |
ff7c6d11 XL |
75 | |
76 | universal_regions | |
77 | } | |
78 | ||
e1599b0c XL |
79 | // This function populates an AllFacts instance with base facts related to |
80 | // MovePaths and needed for the move analysis. | |
81 | fn populate_polonius_move_facts( | |
82 | all_facts: &mut AllFacts, | |
83 | move_data: &MoveData<'_>, | |
84 | location_table: &LocationTable, | |
dfeec247 XL |
85 | body: &Body<'_>, |
86 | ) { | |
e1599b0c | 87 | all_facts |
74b04a01 | 88 | .path_is_var |
dfeec247 | 89 | .extend(move_data.rev_lookup.iter_locals_enumerated().map(|(v, &m)| (m, v))); |
e1599b0c XL |
90 | |
91 | for (child, move_path) in move_data.move_paths.iter_enumerated() { | |
74b04a01 XL |
92 | if let Some(parent) = move_path.parent { |
93 | all_facts.child_path.push((child, parent)); | |
94 | } | |
e1599b0c XL |
95 | } |
96 | ||
74b04a01 XL |
97 | let fn_entry_start = location_table |
98 | .start_index(Location { block: BasicBlock::from_u32(0u32), statement_index: 0 }); | |
99 | ||
e1599b0c XL |
100 | // initialized_at |
101 | for init in move_data.inits.iter() { | |
e1599b0c XL |
102 | match init.location { |
103 | InitLocation::Statement(location) => { | |
104 | let block_data = &body[location.block]; | |
105 | let is_terminator = location.statement_index == block_data.statements.len(); | |
106 | ||
107 | if is_terminator && init.kind == InitKind::NonPanicPathOnly { | |
108 | // We are at the terminator of an init that has a panic path, | |
109 | // and where the init should not happen on panic | |
110 | ||
111 | for &successor in block_data.terminator().successors() { | |
112 | if body[successor].is_cleanup { | |
113 | continue; | |
114 | } | |
115 | ||
116 | // The initialization happened in (or rather, when arriving at) | |
117 | // the successors, but not in the unwind block. | |
dfeec247 | 118 | let first_statement = Location { block: successor, statement_index: 0 }; |
e1599b0c | 119 | all_facts |
74b04a01 | 120 | .path_assigned_at_base |
e1599b0c XL |
121 | .push((init.path, location_table.start_index(first_statement))); |
122 | } | |
e1599b0c XL |
123 | } else { |
124 | // In all other cases, the initialization just happens at the | |
125 | // midpoint, like any other effect. | |
74b04a01 XL |
126 | all_facts |
127 | .path_assigned_at_base | |
128 | .push((init.path, location_table.mid_index(location))); | |
e1599b0c | 129 | } |
dfeec247 | 130 | } |
e1599b0c XL |
131 | // Arguments are initialized on function entry |
132 | InitLocation::Argument(local) => { | |
133 | assert!(body.local_kind(local) == LocalKind::Arg); | |
74b04a01 | 134 | all_facts.path_assigned_at_base.push((init.path, fn_entry_start)); |
e1599b0c XL |
135 | } |
136 | } | |
137 | } | |
138 | ||
74b04a01 XL |
139 | for (local, &path) in move_data.rev_lookup.iter_locals_enumerated() { |
140 | if body.local_kind(local) != LocalKind::Arg { | |
141 | // Non-arguments start out deinitialised; we simulate this with an | |
142 | // initial move: | |
143 | all_facts.path_moved_at_base.push((path, fn_entry_start)); | |
144 | } | |
145 | } | |
146 | ||
e1599b0c XL |
147 | // moved_out_at |
148 | // deinitialisation is assumed to always happen! | |
149 | all_facts | |
74b04a01 | 150 | .path_moved_at_base |
dfeec247 | 151 | .extend(move_data.moves.iter().map(|mo| (mo.path, location_table.mid_index(mo.source)))); |
e1599b0c XL |
152 | } |
153 | ||
ff7c6d11 XL |
154 | /// Computes the (non-lexical) regions from the input MIR. |
155 | /// | |
156 | /// This may result in errors being reported. | |
c295e0f8 | 157 | pub(crate) fn compute_regions<'cx, 'tcx>( |
dc9dc135 | 158 | infcx: &InferCtxt<'cx, 'tcx>, |
ff7c6d11 | 159 | universal_regions: UniversalRegions<'tcx>, |
f9f354fc XL |
160 | body: &Body<'tcx>, |
161 | promoted: &IndexVec<Promoted, Body<'tcx>>, | |
83c7162d | 162 | location_table: &LocationTable, |
dc9dc135 | 163 | param_env: ty::ParamEnv<'tcx>, |
74b04a01 | 164 | flow_inits: &mut ResultsCursor<'cx, 'tcx, MaybeInitializedPlaces<'cx, 'tcx>>, |
ff7c6d11 | 165 | move_data: &MoveData<'tcx>, |
83c7162d | 166 | borrow_set: &BorrowSet<'tcx>, |
5869c6ff | 167 | upvars: &[Upvar<'tcx>], |
c295e0f8 | 168 | use_polonius: bool, |
dfeec247 | 169 | ) -> NllOutput<'tcx> { |
c295e0f8 XL |
170 | let mut all_facts = |
171 | (use_polonius || AllFacts::enabled(infcx.tcx)).then_some(AllFacts::default()); | |
94b46f34 | 172 | |
8faf50e0 XL |
173 | let universal_regions = Rc::new(universal_regions); |
174 | ||
dfeec247 | 175 | let elements = &Rc::new(RegionValueElements::new(&body)); |
8faf50e0 | 176 | |
ff7c6d11 | 177 | // Run the MIR type-checker. |
74b04a01 XL |
178 | let MirTypeckResults { constraints, universal_region_relations, opaque_type_values } = |
179 | type_check::type_check( | |
180 | infcx, | |
181 | param_env, | |
182 | body, | |
183 | promoted, | |
74b04a01 XL |
184 | &universal_regions, |
185 | location_table, | |
186 | borrow_set, | |
187 | &mut all_facts, | |
188 | flow_inits, | |
189 | move_data, | |
190 | elements, | |
f035d41b | 191 | upvars, |
74b04a01 | 192 | ); |
ff7c6d11 | 193 | |
83c7162d | 194 | if let Some(all_facts) = &mut all_facts { |
60c5eb7d | 195 | let _prof_timer = infcx.tcx.prof.generic_activity("polonius_fact_generation"); |
dfeec247 | 196 | all_facts.universal_region.extend(universal_regions.universal_regions()); |
60c5eb7d XL |
197 | populate_polonius_move_facts(all_facts, move_data, location_table, &body); |
198 | ||
199 | // Emit universal regions facts, and their relations, for Polonius. | |
200 | // | |
201 | // 1: universal regions are modeled in Polonius as a pair: | |
202 | // - the universal region vid itself. | |
203 | // - a "placeholder loan" associated to this universal region. Since they don't exist in | |
204 | // the `borrow_set`, their `BorrowIndex` are synthesized as the universal region index | |
205 | // added to the existing number of loans, as if they succeeded them in the set. | |
206 | // | |
3dfed10e | 207 | let borrow_count = borrow_set.len(); |
60c5eb7d XL |
208 | debug!( |
209 | "compute_regions: polonius placeholders, num_universals={}, borrow_count={}", | |
210 | universal_regions.len(), | |
211 | borrow_count | |
212 | ); | |
213 | ||
214 | for universal_region in universal_regions.universal_regions() { | |
215 | let universal_region_idx = universal_region.index(); | |
216 | let placeholder_loan_idx = borrow_count + universal_region_idx; | |
217 | all_facts.placeholder.push((universal_region, placeholder_loan_idx.into())); | |
218 | } | |
219 | ||
220 | // 2: the universal region relations `outlives` constraints are emitted as | |
94222f64 | 221 | // `known_placeholder_subset` facts. |
60c5eb7d XL |
222 | for (fr1, fr2) in universal_region_relations.known_outlives() { |
223 | if fr1 != fr2 { | |
224 | debug!( | |
94222f64 XL |
225 | "compute_regions: emitting polonius `known_placeholder_subset` \ |
226 | fr1={:?}, fr2={:?}", | |
60c5eb7d XL |
227 | fr1, fr2 |
228 | ); | |
94222f64 | 229 | all_facts.known_placeholder_subset.push((*fr1, *fr2)); |
60c5eb7d XL |
230 | } |
231 | } | |
83c7162d XL |
232 | } |
233 | ||
94b46f34 XL |
234 | // Create the region inference context, taking ownership of the |
235 | // region inference data that was contained in `infcx`, and the | |
236 | // base constraints generated by the type-check. | |
ff7c6d11 | 237 | let var_origins = infcx.take_region_var_origins(); |
94b46f34 | 238 | let MirTypeckRegionConstraints { |
a1dfa0c6 XL |
239 | placeholder_indices, |
240 | placeholder_index_to_region: _, | |
8faf50e0 | 241 | mut liveness_constraints, |
94b46f34 | 242 | outlives_constraints, |
dc9dc135 | 243 | member_constraints, |
0bf4aa26 | 244 | closure_bounds_mapping, |
94222f64 | 245 | universe_causes, |
94b46f34 | 246 | type_tests, |
b7449926 | 247 | } = constraints; |
a1dfa0c6 | 248 | let placeholder_indices = Rc::new(placeholder_indices); |
8faf50e0 XL |
249 | |
250 | constraint_generation::generate_constraints( | |
251 | infcx, | |
252 | &mut liveness_constraints, | |
253 | &mut all_facts, | |
254 | location_table, | |
dc9dc135 | 255 | &body, |
8faf50e0 XL |
256 | borrow_set, |
257 | ); | |
258 | ||
94b46f34 XL |
259 | let mut regioncx = RegionInferenceContext::new( |
260 | var_origins, | |
261 | universal_regions, | |
0bf4aa26 | 262 | placeholder_indices, |
8faf50e0 | 263 | universal_region_relations, |
94b46f34 | 264 | outlives_constraints, |
dc9dc135 | 265 | member_constraints, |
0bf4aa26 | 266 | closure_bounds_mapping, |
94222f64 | 267 | universe_causes, |
94b46f34 | 268 | type_tests, |
8faf50e0 XL |
269 | liveness_constraints, |
270 | elements, | |
94b46f34 | 271 | ); |
ff7c6d11 | 272 | |
94b46f34 | 273 | // Generate various additional constraints. |
dfeec247 | 274 | invalidation::generate_invalidates(infcx.tcx, &mut all_facts, location_table, body, borrow_set); |
ff7c6d11 | 275 | |
29967ef6 XL |
276 | let def_id = body.source.def_id(); |
277 | ||
83c7162d | 278 | // Dump facts if requested. |
94222f64 | 279 | let polonius_output = all_facts.as_ref().and_then(|all_facts| { |
94b46f34 | 280 | if infcx.tcx.sess.opts.debugging_opts.nll_facts { |
29967ef6 XL |
281 | let def_path = infcx.tcx.def_path(def_id); |
282 | let dir_path = PathBuf::from(&infcx.tcx.sess.opts.debugging_opts.nll_facts_dir) | |
283 | .join(def_path.to_filename_friendly_no_crate()); | |
94b46f34 XL |
284 | all_facts.write_to_dir(dir_path, location_table).unwrap(); |
285 | } | |
286 | ||
c295e0f8 | 287 | if use_polonius { |
dfeec247 | 288 | let algorithm = |
94222f64 | 289 | env::var("POLONIUS_ALGORITHM").unwrap_or_else(|_| String::from("Hybrid")); |
94b46f34 XL |
290 | let algorithm = Algorithm::from_str(&algorithm).unwrap(); |
291 | debug!("compute_regions: using polonius algorithm {:?}", algorithm); | |
60c5eb7d | 292 | let _prof_timer = infcx.tcx.prof.generic_activity("polonius_analysis"); |
dfeec247 | 293 | Some(Rc::new(Output::compute(&all_facts, algorithm, false))) |
94b46f34 XL |
294 | } else { |
295 | None | |
296 | } | |
297 | }); | |
ff7c6d11 XL |
298 | |
299 | // Solve the region constraints. | |
dfeec247 | 300 | let (closure_region_requirements, nll_errors) = |
29967ef6 | 301 | regioncx.solve(infcx, &body, polonius_output.clone()); |
dfeec247 | 302 | |
74b04a01 XL |
303 | if !nll_errors.is_empty() { |
304 | // Suppress unhelpful extra errors in `infer_opaque_types`. | |
305 | infcx.set_tainted_by_errors(); | |
306 | } | |
307 | ||
308 | let remapped_opaque_tys = regioncx.infer_opaque_types(&infcx, opaque_type_values, body.span); | |
309 | ||
dfeec247 XL |
310 | NllOutput { |
311 | regioncx, | |
74b04a01 | 312 | opaque_type_values: remapped_opaque_tys, |
94222f64 | 313 | polonius_input: all_facts.map(Box::new), |
dfeec247 XL |
314 | polonius_output, |
315 | opt_closure_req: closure_region_requirements, | |
316 | nll_errors, | |
317 | } | |
ff7c6d11 XL |
318 | } |
319 | ||
dfeec247 | 320 | pub(super) fn dump_mir_results<'a, 'tcx>( |
dc9dc135 | 321 | infcx: &InferCtxt<'a, 'tcx>, |
dc9dc135 | 322 | body: &Body<'tcx>, |
f035d41b | 323 | regioncx: &RegionInferenceContext<'tcx>, |
9fa01778 | 324 | closure_region_requirements: &Option<ClosureRegionRequirements<'_>>, |
ff7c6d11 | 325 | ) { |
c295e0f8 | 326 | if !dump_enabled(infcx.tcx, "nll", body.source.def_id()) { |
ff7c6d11 XL |
327 | return; |
328 | } | |
329 | ||
c295e0f8 | 330 | dump_mir(infcx.tcx, None, "nll", &0, body, |pass_where, out| { |
dfeec247 XL |
331 | match pass_where { |
332 | // Before the CFG, dump out the values for each region variable. | |
333 | PassWhere::BeforeCFG => { | |
f035d41b | 334 | regioncx.dump_mir(infcx.tcx, out)?; |
dfeec247 XL |
335 | writeln!(out, "|")?; |
336 | ||
337 | if let Some(closure_region_requirements) = closure_region_requirements { | |
338 | writeln!(out, "| Free Region Constraints")?; | |
339 | for_each_region_constraint(closure_region_requirements, &mut |msg| { | |
340 | writeln!(out, "| {}", msg) | |
341 | })?; | |
0731742a | 342 | writeln!(out, "|")?; |
ff7c6d11 | 343 | } |
dfeec247 | 344 | } |
ff7c6d11 | 345 | |
dfeec247 | 346 | PassWhere::BeforeLocation(_) => {} |
ff7c6d11 | 347 | |
dfeec247 | 348 | PassWhere::AfterTerminator(_) => {} |
8faf50e0 | 349 | |
dfeec247 XL |
350 | PassWhere::BeforeBlock(_) | PassWhere::AfterLocation(_) | PassWhere::AfterCFG => {} |
351 | } | |
352 | Ok(()) | |
353 | }); | |
ff7c6d11 XL |
354 | |
355 | // Also dump the inference graph constraints as a graphviz file. | |
9fa01778 | 356 | let _: io::Result<()> = try { |
ff7c6d11 | 357 | let mut file = |
c295e0f8 | 358 | create_dump_file(infcx.tcx, "regioncx.all.dot", None, "nll", &0, body.source)?; |
8faf50e0 XL |
359 | regioncx.dump_graphviz_raw_constraints(&mut file)?; |
360 | }; | |
361 | ||
362 | // Also dump the inference graph constraints as a graphviz file. | |
9fa01778 | 363 | let _: io::Result<()> = try { |
8faf50e0 | 364 | let mut file = |
c295e0f8 | 365 | create_dump_file(infcx.tcx, "regioncx.scc.dot", None, "nll", &0, body.source)?; |
8faf50e0 | 366 | regioncx.dump_graphviz_scc_constraints(&mut file)?; |
94b46f34 | 367 | }; |
ff7c6d11 XL |
368 | } |
369 | ||
dfeec247 | 370 | pub(super) fn dump_annotation<'a, 'tcx>( |
dc9dc135 XL |
371 | infcx: &InferCtxt<'a, 'tcx>, |
372 | body: &Body<'tcx>, | |
b7449926 | 373 | regioncx: &RegionInferenceContext<'tcx>, |
9fa01778 | 374 | closure_region_requirements: &Option<ClosureRegionRequirements<'_>>, |
17df50a5 | 375 | opaque_type_values: &VecMap<OpaqueTypeKey<'tcx>, Ty<'tcx>>, |
8faf50e0 | 376 | errors_buffer: &mut Vec<Diagnostic>, |
ff7c6d11 XL |
377 | ) { |
378 | let tcx = infcx.tcx; | |
3c0e092e | 379 | let base_def_id = tcx.typeck_root_def_id(body.source.def_id()); |
48663c56 | 380 | if !tcx.has_attr(base_def_id, sym::rustc_regions) { |
ff7c6d11 XL |
381 | return; |
382 | } | |
383 | ||
384 | // When the enclosing function is tagged with `#[rustc_regions]`, | |
385 | // we dump out various bits of state as warnings. This is useful | |
386 | // for verifying that the compiler is behaving as expected. These | |
387 | // warnings focus on the closure region requirements -- for | |
388 | // viewing the intraprocedural state, the -Zdump-mir output is | |
389 | // better. | |
390 | ||
74b04a01 | 391 | let mut err = if let Some(closure_region_requirements) = closure_region_requirements { |
dfeec247 | 392 | let mut err = tcx.sess.diagnostic().span_note_diag(body.span, "external requirements"); |
ff7c6d11 | 393 | |
b7449926 | 394 | regioncx.annotate(tcx, &mut err); |
ff7c6d11 XL |
395 | |
396 | err.note(&format!( | |
397 | "number of external vids: {}", | |
398 | closure_region_requirements.num_external_vids | |
399 | )); | |
400 | ||
401 | // Dump the region constraints we are imposing *between* those | |
402 | // newly created variables. | |
403 | for_each_region_constraint(closure_region_requirements, &mut |msg| { | |
404 | err.note(msg); | |
405 | Ok(()) | |
dfeec247 XL |
406 | }) |
407 | .unwrap(); | |
ff7c6d11 | 408 | |
74b04a01 | 409 | err |
ff7c6d11 | 410 | } else { |
dfeec247 | 411 | let mut err = tcx.sess.diagnostic().span_note_diag(body.span, "no external requirements"); |
b7449926 | 412 | regioncx.annotate(tcx, &mut err); |
8faf50e0 | 413 | |
74b04a01 XL |
414 | err |
415 | }; | |
416 | ||
417 | if !opaque_type_values.is_empty() { | |
418 | err.note(&format!("Inferred opaque type values:\n{:#?}", opaque_type_values)); | |
ff7c6d11 | 419 | } |
74b04a01 XL |
420 | |
421 | err.buffer(errors_buffer); | |
ff7c6d11 XL |
422 | } |
423 | ||
424 | fn for_each_region_constraint( | |
9fa01778 | 425 | closure_region_requirements: &ClosureRegionRequirements<'_>, |
0531ce1d | 426 | with_msg: &mut dyn FnMut(&str) -> io::Result<()>, |
ff7c6d11 XL |
427 | ) -> io::Result<()> { |
428 | for req in &closure_region_requirements.outlives_requirements { | |
0531ce1d | 429 | let subject: &dyn Debug = match &req.subject { |
ff7c6d11 XL |
430 | ClosureOutlivesSubject::Region(subject) => subject, |
431 | ClosureOutlivesSubject::Ty(ty) => ty, | |
432 | }; | |
dfeec247 | 433 | with_msg(&format!("where {:?}: {:?}", subject, req.outlived_free_region,))?; |
ff7c6d11 XL |
434 | } |
435 | Ok(()) | |
436 | } | |
437 | ||
438 | /// Right now, we piggy back on the `ReVar` to store our NLL inference | |
439 | /// regions. These are indexed with `RegionVid`. This method will | |
0531ce1d | 440 | /// assert that the region is a `ReVar` and extract its internal index. |
ff7c6d11 XL |
441 | /// This is reasonable because in our MIR we replace all universal regions |
442 | /// with inference variables. | |
443 | pub trait ToRegionVid { | |
444 | fn to_region_vid(self) -> RegionVid; | |
445 | } | |
446 | ||
447 | impl<'tcx> ToRegionVid for &'tcx RegionKind { | |
448 | fn to_region_vid(self) -> RegionVid { | |
dfeec247 | 449 | if let ty::ReVar(vid) = self { *vid } else { bug!("region is not an ReVar: {:?}", self) } |
ff7c6d11 XL |
450 | } |
451 | } | |
452 | ||
453 | impl ToRegionVid for RegionVid { | |
454 | fn to_region_vid(self) -> RegionVid { | |
455 | self | |
456 | } | |
457 | } | |
0bf4aa26 XL |
458 | |
459 | crate trait ConstraintDescription { | |
460 | fn description(&self) -> &'static str; | |
461 | } |