1 //! Lexical region resolution.
3 use crate::infer::region_constraints::Constraint;
4 use crate::infer::region_constraints::GenericKind;
5 use crate::infer::region_constraints::RegionConstraintData;
6 use crate::infer::region_constraints::VarInfos;
7 use crate::infer::region_constraints::VerifyBound;
8 use crate::infer::RegionVariableOrigin;
9 use crate::infer::SubregionOrigin;
10 use crate::middle::free_region::RegionRelations;
11 use rustc_data_structures::fx::FxHashSet;
12 use rustc_data_structures::graph::implementation::{
13 Direction, Graph, NodeIndex, INCOMING, OUTGOING,
15 use rustc_data_structures::indexed_vec::{Idx, IndexVec};
16 use smallvec::SmallVec;
19 use crate::ty::fold::TypeFoldable;
20 use crate::ty::{self, Ty, TyCtxt};
21 use crate::ty::{ReEarlyBound, ReEmpty, ReErased, ReFree, ReStatic};
22 use crate::ty::{ReLateBound, ReScope, RePlaceholder, ReVar};
23 use crate::ty::{Region, RegionVid};
27 /// This function performs lexical region resolution given a complete
28 /// set of constraints and variable origins. It performs a fixed-point
29 /// iteration to find region values which satisfy all constraints,
30 /// assuming such values can be found. It returns the final values of
31 /// all the variables as well as a set of errors that must be reported.
33 region_rels: &RegionRelations<'_, '_, 'tcx>,
35 data: RegionConstraintData<'tcx>,
37 LexicalRegionResolutions<'tcx>,
38 Vec<RegionResolutionError<'tcx>>,
40 debug!("RegionConstraintData: resolve_regions()");
41 let mut errors = vec![];
42 let mut resolver = LexicalResolver {
47 let values = resolver.infer_variable_values(&mut errors);
51 /// Contains the result of lexical region resolution. Offers methods
52 /// to lookup up the final value of a region variable.
53 pub struct LexicalRegionResolutions<'tcx> {
54 values: IndexVec<RegionVid, VarValue<'tcx>>,
55 error_region: ty::Region<'tcx>,
58 #[derive(Copy, Clone, Debug)]
64 #[derive(Clone, Debug)]
65 pub enum RegionResolutionError<'tcx> {
66 /// `ConcreteFailure(o, a, b)`:
68 /// `o` requires that `a <= b`, but this does not hold
69 ConcreteFailure(SubregionOrigin<'tcx>, Region<'tcx>, Region<'tcx>),
71 /// `GenericBoundFailure(p, s, a)
73 /// The parameter/associated-type `p` must be known to outlive the lifetime
74 /// `a` (but none of the known bounds are sufficient).
75 GenericBoundFailure(SubregionOrigin<'tcx>, GenericKind<'tcx>, Region<'tcx>),
77 /// `SubSupConflict(v, v_origin, sub_origin, sub_r, sup_origin, sup_r)`:
79 /// Could not infer a value for `v` (which has origin `v_origin`)
80 /// because `sub_r <= v` (due to `sub_origin`) but `v <= sup_r` (due to `sup_origin`) and
81 /// `sub_r <= sup_r` does not hold.
85 SubregionOrigin<'tcx>,
87 SubregionOrigin<'tcx>,
92 struct RegionAndOrigin<'tcx> {
94 origin: SubregionOrigin<'tcx>,
97 type RegionGraph<'tcx> = Graph<(), Constraint<'tcx>>;
99 struct LexicalResolver<'cx, 'gcx: 'tcx, 'tcx: 'cx> {
100 region_rels: &'cx RegionRelations<'cx, 'gcx, 'tcx>,
102 data: RegionConstraintData<'tcx>,
105 impl<'cx, 'gcx, 'tcx> LexicalResolver<'cx, 'gcx, 'tcx> {
106 fn tcx(&self) -> TyCtxt<'cx, 'gcx, 'tcx> {
110 fn infer_variable_values(
112 errors: &mut Vec<RegionResolutionError<'tcx>>,
113 ) -> LexicalRegionResolutions<'tcx> {
114 let mut var_data = self.construct_var_data(self.tcx());
116 // Dorky hack to cause `dump_constraints` to only get called
117 // if debug mode is enabled:
119 "----() End constraint listing (context={:?}) {:?}---",
120 self.region_rels.context,
121 self.dump_constraints(self.region_rels)
123 graphviz::maybe_print_constraints_for(&self.data, self.region_rels);
125 let graph = self.construct_graph();
126 self.expand_givens(&graph);
127 self.expansion(&mut var_data);
128 self.collect_errors(&mut var_data, errors);
129 self.collect_var_errors(&var_data, &graph, errors);
133 fn num_vars(&self) -> usize {
137 /// Initially, the value for all variables is set to `'empty`, the
138 /// empty region. The `expansion` phase will grow this larger.
139 fn construct_var_data(&self, tcx: TyCtxt<'_, '_, 'tcx>) -> LexicalRegionResolutions<'tcx> {
140 LexicalRegionResolutions {
141 error_region: tcx.lifetimes.re_static,
142 values: IndexVec::from_elem_n(VarValue::Value(tcx.lifetimes.re_empty), self.num_vars())
146 fn dump_constraints(&self, free_regions: &RegionRelations<'_, '_, 'tcx>) {
148 "----() Start constraint listing (context={:?}) ()----",
151 for (idx, (constraint, _)) in self.data.constraints.iter().enumerate() {
152 debug!("Constraint {} => {:?}", idx, constraint);
156 fn expand_givens(&mut self, graph: &RegionGraph<'_>) {
157 // Givens are a kind of horrible hack to account for
158 // constraints like 'c <= '0 that are known to hold due to
159 // closure signatures (see the comment above on the `givens`
160 // field). They should go away. But until they do, the role
161 // of this fn is to account for the transitive nature:
167 let seeds: Vec<_> = self.data.givens.iter().cloned().collect();
168 for (r, vid) in seeds {
169 // While all things transitively reachable in the graph
170 // from the variable (`'0` in the example above).
171 let seed_index = NodeIndex(vid.index() as usize);
172 for succ_index in graph.depth_traverse(seed_index, OUTGOING) {
173 let succ_index = succ_index.0;
175 // The first N nodes correspond to the region
176 // variables. Other nodes correspond to constant
178 if succ_index < self.num_vars() {
179 let succ_vid = RegionVid::new(succ_index);
182 self.data.givens.insert((r, succ_vid));
188 fn expansion(&self, var_values: &mut LexicalRegionResolutions<'tcx>) {
189 self.iterate_until_fixed_point("Expansion", |constraint| {
190 debug!("expansion: constraint={:?}", constraint);
191 let (a_region, b_vid, b_data, retain) = match *constraint {
192 Constraint::RegSubVar(a_region, b_vid) => {
193 let b_data = var_values.value_mut(b_vid);
194 (a_region, b_vid, b_data, false)
196 Constraint::VarSubVar(a_vid, b_vid) => match *var_values.value(a_vid) {
197 VarValue::ErrorValue => return (false, false),
198 VarValue::Value(a_region) => {
199 let b_data = var_values.value_mut(b_vid);
200 let retain = match *b_data {
201 VarValue::Value(ReStatic) | VarValue::ErrorValue => false,
204 (a_region, b_vid, b_data, retain)
207 Constraint::RegSubReg(..) | Constraint::VarSubReg(..) => {
208 // These constraints are checked after expansion
209 // is done, in `collect_errors`.
210 return (false, false)
214 let changed = self.expand_node(a_region, b_vid, b_data);
219 // This function is very hot in some workloads. There's a single callsite
220 // so always inlining is ok even though it's large.
224 a_region: Region<'tcx>,
226 b_data: &mut VarValue<'tcx>,
228 debug!("expand_node({:?}, {:?} == {:?})", a_region, b_vid, b_data);
231 // Check if this relationship is implied by a given.
232 ty::ReEarlyBound(_) | ty::ReFree(_) => if self.data.givens.contains(&(a_region, b_vid))
243 VarValue::Value(cur_region) => {
244 // Identical scopes can show up quite often, if the fixed point
245 // iteration converges slowly, skip them
246 if let (ReScope(a_scope), ReScope(cur_scope)) = (a_region, cur_region) {
247 if a_scope == cur_scope {
252 let mut lub = self.lub_concrete_regions(a_region, cur_region);
253 if lub == cur_region {
257 // Watch out for `'b: !1` relationships, where the
258 // universe of `'b` can't name the placeholder `!1`. In
259 // that case, we have to grow `'b` to be `'static` for the
260 // relationship to hold. This is obviously a kind of sub-optimal
261 // choice -- in the future, when we incorporate a knowledge
262 // of the parameter environment, we might be able to find a
263 // tighter bound than `'static`.
265 // (This might e.g. arise from being asked to prove `for<'a> { 'b: 'a }`.)
266 let b_universe = self.var_infos[b_vid].universe;
267 if let ty::RePlaceholder(p) = lub {
268 if b_universe.cannot_name(p.universe) {
269 lub = self.tcx().lifetimes.re_static;
274 "Expanding value of {:?} from {:?} to {:?}",
275 b_vid, cur_region, lub
278 *b_data = VarValue::Value(lub);
282 VarValue::ErrorValue => {
288 fn lub_concrete_regions(&self, a: Region<'tcx>, b: Region<'tcx>) -> Region<'tcx> {
289 let tcx = self.tcx();
292 (&ty::ReClosureBound(..), _)
293 | (_, &ty::ReClosureBound(..))
294 | (&ReLateBound(..), _)
295 | (_, &ReLateBound(..))
297 | (_, &ReErased) => {
298 bug!("cannot relate region: LUB({:?}, {:?})", a, b);
301 (r @ &ReStatic, _) | (_, r @ &ReStatic) => {
302 r // nothing lives longer than static
305 (&ReEmpty, r) | (r, &ReEmpty) => {
306 r // everything lives longer than empty
309 (&ReVar(v_id), _) | (_, &ReVar(v_id)) => {
311 self.var_infos[v_id].origin.span(),
312 "lub_concrete_regions invoked with non-concrete \
313 regions: {:?}, {:?}",
319 (&ReEarlyBound(_), &ReScope(s_id))
320 | (&ReScope(s_id), &ReEarlyBound(_))
321 | (&ReFree(_), &ReScope(s_id))
322 | (&ReScope(s_id), &ReFree(_)) => {
323 // A "free" region can be interpreted as "some region
324 // at least as big as fr.scope". So, we can
325 // reasonably compare free regions and scopes:
326 let fr_scope = match (a, b) {
327 (&ReEarlyBound(ref br), _) | (_, &ReEarlyBound(ref br)) => self.region_rels
329 .early_free_scope(self.tcx(), br),
330 (&ReFree(ref fr), _) | (_, &ReFree(ref fr)) => self.region_rels
332 .free_scope(self.tcx(), fr),
335 let r_id = self.region_rels
337 .nearest_common_ancestor(fr_scope, s_id);
338 if r_id == fr_scope {
339 // if the free region's scope `fr.scope` is bigger than
340 // the scope region `s_id`, then the LUB is the free
343 (_, &ReScope(_)) => return a,
344 (&ReScope(_), _) => return b,
349 // otherwise, we don't know what the free region is,
350 // so we must conservatively say the LUB is static:
351 tcx.lifetimes.re_static
354 (&ReScope(a_id), &ReScope(b_id)) => {
355 // The region corresponding to an outer block is a
356 // subtype of the region corresponding to an inner
358 let lub = self.region_rels
360 .nearest_common_ancestor(a_id, b_id);
361 tcx.mk_region(ReScope(lub))
364 (&ReEarlyBound(_), &ReEarlyBound(_))
365 | (&ReFree(_), &ReEarlyBound(_))
366 | (&ReEarlyBound(_), &ReFree(_))
367 | (&ReFree(_), &ReFree(_)) => self.region_rels.lub_free_regions(a, b),
369 // For these types, we cannot define any additional
371 (&RePlaceholder(..), _) | (_, &RePlaceholder(..)) => if a == b {
374 tcx.lifetimes.re_static
379 /// After expansion is complete, go and check upper bounds (i.e.,
380 /// cases where the region cannot grow larger than a fixed point)
381 /// and check that they are satisfied.
384 var_data: &mut LexicalRegionResolutions<'tcx>,
385 errors: &mut Vec<RegionResolutionError<'tcx>>,
387 for (constraint, origin) in &self.data.constraints {
389 "collect_errors: constraint={:?} origin={:?}",
393 Constraint::RegSubVar(..) | Constraint::VarSubVar(..) => {
394 // Expansion will ensure that these constraints hold. Ignore.
397 Constraint::RegSubReg(sub, sup) => {
398 if self.region_rels.is_subregion_of(sub, sup) {
403 "collect_errors: region error at {:?}: \
404 cannot verify that {:?} <= {:?}",
408 errors.push(RegionResolutionError::ConcreteFailure(
415 Constraint::VarSubReg(a_vid, b_region) => {
416 let a_data = var_data.value_mut(a_vid);
417 debug!("contraction: {:?} == {:?}, {:?}", a_vid, a_data, b_region);
419 let a_region = match *a_data {
420 VarValue::ErrorValue => continue,
421 VarValue::Value(a_region) => a_region,
424 // Do not report these errors immediately:
425 // instead, set the variable value to error and
426 // collect them later.
427 if !self.region_rels.is_subregion_of(a_region, b_region) {
429 "collect_errors: region error at {:?}: \
430 cannot verify that {:?}={:?} <= {:?}",
431 origin, a_vid, a_region, b_region
433 *a_data = VarValue::ErrorValue;
439 for verify in &self.data.verifys {
440 debug!("collect_errors: verify={:?}", verify);
441 let sub = var_data.normalize(self.tcx(), verify.region);
443 // This was an inference variable which didn't get
444 // constrained, therefore it can be assume to hold.
445 if let ty::ReEmpty = *sub {
449 let verify_kind_ty = verify.kind.to_ty(self.tcx());
450 if self.bound_is_met(&verify.bound, var_data, verify_kind_ty, sub) {
455 "collect_errors: region error at {:?}: \
456 cannot verify that {:?} <= {:?}",
457 verify.origin, verify.region, verify.bound
460 errors.push(RegionResolutionError::GenericBoundFailure(
461 verify.origin.clone(),
468 /// Go over the variables that were declared to be error variables
469 /// and create a `RegionResolutionError` for each of them.
470 fn collect_var_errors(
472 var_data: &LexicalRegionResolutions<'tcx>,
473 graph: &RegionGraph<'tcx>,
474 errors: &mut Vec<RegionResolutionError<'tcx>>,
476 debug!("collect_var_errors");
478 // This is the best way that I have found to suppress
479 // duplicate and related errors. Basically we keep a set of
480 // flags for every node. Whenever an error occurs, we will
481 // walk some portion of the graph looking to find pairs of
482 // conflicting regions to report to the user. As we walk, we
483 // trip the flags from false to true, and if we find that
484 // we've already reported an error involving any particular
485 // node we just stop and don't report the current error. The
486 // idea is to report errors that derive from independent
487 // regions of the graph, but not those that derive from
488 // overlapping locations.
489 let mut dup_vec = vec![u32::MAX; self.num_vars()];
491 for (node_vid, value) in var_data.values.iter_enumerated() {
493 VarValue::Value(_) => { /* Inference successful */ }
494 VarValue::ErrorValue => {
495 /* Inference impossible: this value contains
496 inconsistent constraints.
498 I think that in this case we should report an
499 error now -- unlike the case above, we can't
500 wait to see whether the user needs the result
501 of this variable. The reason is that the mere
502 existence of this variable implies that the
503 region graph is inconsistent, whether or not it
506 For example, we may have created a region
507 variable that is the GLB of two other regions
508 which do not have a GLB. Even if that variable
509 is not used, it implies that those two regions
512 At least I think this is true. It may be that
513 the mere existence of a conflict in a region variable
514 that is not used is not a problem, so if this rule
515 starts to create problems we'll have to revisit
516 this portion of the code and think hard about it. =) */
517 self.collect_error_for_expanding_node(graph, &mut dup_vec, node_vid, errors);
523 fn construct_graph(&self) -> RegionGraph<'tcx> {
524 let num_vars = self.num_vars();
526 let mut graph = Graph::new();
528 for _ in 0..num_vars {
532 // Issue #30438: two distinct dummy nodes, one for incoming
533 // edges (dummy_source) and another for outgoing edges
534 // (dummy_sink). In `dummy -> a -> b -> dummy`, using one
535 // dummy node leads one to think (erroneously) there exists a
536 // path from `b` to `a`. Two dummy nodes sidesteps the issue.
537 let dummy_source = graph.add_node(());
538 let dummy_sink = graph.add_node(());
540 for (constraint, _) in &self.data.constraints {
542 Constraint::VarSubVar(a_id, b_id) => {
544 NodeIndex(a_id.index() as usize),
545 NodeIndex(b_id.index() as usize),
549 Constraint::RegSubVar(_, b_id) => {
550 graph.add_edge(dummy_source, NodeIndex(b_id.index() as usize), *constraint);
552 Constraint::VarSubReg(a_id, _) => {
553 graph.add_edge(NodeIndex(a_id.index() as usize), dummy_sink, *constraint);
555 Constraint::RegSubReg(..) => {
556 // this would be an edge from `dummy_source` to
557 // `dummy_sink`; just ignore it.
565 fn collect_error_for_expanding_node(
567 graph: &RegionGraph<'tcx>,
570 errors: &mut Vec<RegionResolutionError<'tcx>>,
572 // Errors in expanding nodes result from a lower-bound that is
573 // not contained by an upper-bound.
574 let (mut lower_bounds, lower_dup) =
575 self.collect_concrete_regions(graph, node_idx, INCOMING, dup_vec);
576 let (mut upper_bounds, upper_dup) =
577 self.collect_concrete_regions(graph, node_idx, OUTGOING, dup_vec);
579 if lower_dup || upper_dup {
583 // We place free regions first because we are special casing
584 // SubSupConflict(ReFree, ReFree) when reporting error, and so
585 // the user will more likely get a specific suggestion.
586 fn region_order_key(x: &RegionAndOrigin<'_>) -> u8 {
588 ReEarlyBound(_) => 0,
593 lower_bounds.sort_by_key(region_order_key);
594 upper_bounds.sort_by_key(region_order_key);
596 let node_universe = self.var_infos[node_idx].universe;
598 for lower_bound in &lower_bounds {
599 let effective_lower_bound = if let ty::RePlaceholder(p) = lower_bound.region {
600 if node_universe.cannot_name(p.universe) {
601 self.tcx().lifetimes.re_static
609 for upper_bound in &upper_bounds {
611 .is_subregion_of(effective_lower_bound, upper_bound.region)
613 let origin = self.var_infos[node_idx].origin.clone();
615 "region inference error at {:?} for {:?}: SubSupConflict sub: {:?} \
617 origin, node_idx, lower_bound.region, upper_bound.region
619 errors.push(RegionResolutionError::SubSupConflict(
622 lower_bound.origin.clone(),
624 upper_bound.origin.clone(),
633 self.var_infos[node_idx].origin.span(),
634 "collect_error_for_expanding_node() could not find \
635 error for var {:?} in universe {:?}, lower_bounds={:#?}, \
644 fn collect_concrete_regions(
646 graph: &RegionGraph<'tcx>,
647 orig_node_idx: RegionVid,
650 ) -> (Vec<RegionAndOrigin<'tcx>>, bool) {
651 struct WalkState<'tcx> {
652 set: FxHashSet<RegionVid>,
653 stack: Vec<RegionVid>,
654 result: Vec<RegionAndOrigin<'tcx>>,
657 let mut state = WalkState {
658 set: Default::default(),
659 stack: vec![orig_node_idx],
663 state.set.insert(orig_node_idx);
665 // to start off the process, walk the source node in the
666 // direction specified
667 process_edges(&self.data, &mut state, graph, orig_node_idx, dir);
669 while !state.stack.is_empty() {
670 let node_idx = state.stack.pop().unwrap();
672 // check whether we've visited this node on some previous walk
673 if dup_vec[node_idx.index() as usize] == u32::MAX {
674 dup_vec[node_idx.index() as usize] = orig_node_idx.index() as u32;
675 } else if dup_vec[node_idx.index() as usize] != orig_node_idx.index() as u32 {
676 state.dup_found = true;
680 "collect_concrete_regions(orig_node_idx={:?}, node_idx={:?})",
681 orig_node_idx, node_idx
684 process_edges(&self.data, &mut state, graph, node_idx, dir);
688 result, dup_found, ..
690 return (result, dup_found);
692 fn process_edges<'tcx>(
693 this: &RegionConstraintData<'tcx>,
694 state: &mut WalkState<'tcx>,
695 graph: &RegionGraph<'tcx>,
696 source_vid: RegionVid,
699 debug!("process_edges(source_vid={:?}, dir={:?})", source_vid, dir);
701 let source_node_index = NodeIndex(source_vid.index() as usize);
702 for (_, edge) in graph.adjacent_edges(source_node_index, dir) {
704 Constraint::VarSubVar(from_vid, to_vid) => {
705 let opp_vid = if from_vid == source_vid {
710 if state.set.insert(opp_vid) {
711 state.stack.push(opp_vid);
715 Constraint::RegSubVar(region, _) | Constraint::VarSubReg(_, region) => {
716 state.result.push(RegionAndOrigin {
718 origin: this.constraints.get(&edge.data).unwrap().clone(),
722 Constraint::RegSubReg(..) => panic!(
723 "cannot reach reg-sub-reg edge in region inference \
731 fn iterate_until_fixed_point<F>(&self, tag: &str, mut body: F)
732 where F: FnMut(&Constraint<'tcx>) -> (bool, bool),
734 let mut constraints: SmallVec<[_; 16]> = self.data.constraints.keys().collect();
735 let mut iteration = 0;
736 let mut changed = true;
740 debug!("---- {} Iteration {}{}", "#", tag, iteration);
741 constraints.retain(|constraint| {
742 let (edge_changed, retain) = body(constraint);
744 debug!("Updated due to constraint {:?}", constraint);
750 debug!("---- {} Complete after {} iteration(s)", tag, iteration);
755 bound: &VerifyBound<'tcx>,
756 var_values: &LexicalRegionResolutions<'tcx>,
757 generic_ty: Ty<'tcx>,
758 min: ty::Region<'tcx>,
761 VerifyBound::IfEq(k, b) => {
762 (var_values.normalize(self.region_rels.tcx, *k) == generic_ty)
763 && self.bound_is_met(b, var_values, generic_ty, min)
766 VerifyBound::OutlivedBy(r) =>
767 self.region_rels.is_subregion_of(
769 var_values.normalize(self.tcx(), r),
772 VerifyBound::AnyBound(bs) => bs.iter()
773 .any(|b| self.bound_is_met(b, var_values, generic_ty, min)),
775 VerifyBound::AllBounds(bs) => bs.iter()
776 .all(|b| self.bound_is_met(b, var_values, generic_ty, min)),
781 impl<'tcx> fmt::Debug for RegionAndOrigin<'tcx> {
782 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
783 write!(f, "RegionAndOrigin({:?},{:?})", self.region, self.origin)
787 impl<'tcx> LexicalRegionResolutions<'tcx> {
788 fn normalize<T>(&self, tcx: TyCtxt<'_, '_, 'tcx>, value: T) -> T
790 T: TypeFoldable<'tcx>,
792 tcx.fold_regions(&value, &mut false, |r, _db| match r {
793 ty::ReVar(rid) => self.resolve_var(*rid),
798 fn value(&self, rid: RegionVid) -> &VarValue<'tcx> {
802 fn value_mut(&mut self, rid: RegionVid) -> &mut VarValue<'tcx> {
803 &mut self.values[rid]
806 pub fn resolve_var(&self, rid: RegionVid) -> ty::Region<'tcx> {
807 let result = match self.values[rid] {
808 VarValue::Value(r) => r,
809 VarValue::ErrorValue => self.error_region,
811 debug!("resolve_var({:?}) = {:?}", rid, result);