1 //! The code to do lexical region resolution.
3 use infer::region_constraints::Constraint;
4 use infer::region_constraints::GenericKind;
5 use infer::region_constraints::RegionConstraintData;
6 use infer::region_constraints::VarInfos;
7 use infer::region_constraints::VerifyBound;
8 use infer::RegionVariableOrigin;
9 use infer::SubregionOrigin;
10 use 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 ty::fold::TypeFoldable;
20 use ty::{self, Ty, TyCtxt};
21 use ty::{ReEarlyBound, ReEmpty, ReErased, ReFree, ReStatic};
22 use ty::{ReLateBound, ReScope, RePlaceholder, ReVar};
23 use 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.types.re_static,
142 values: IndexVec::from_elem_n(VarValue::Value(tcx.types.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, origin| {
190 debug!("expansion: constraint={:?} origin={:?}", constraint, origin);
192 Constraint::RegSubVar(a_region, b_vid) => {
193 let b_data = var_values.value_mut(b_vid);
194 (self.expand_node(a_region, b_vid, b_data), false)
196 Constraint::VarSubVar(a_vid, b_vid) => match *var_values.value(a_vid) {
197 VarValue::ErrorValue => (false, false),
198 VarValue::Value(a_region) => {
199 let b_node = var_values.value_mut(b_vid);
200 let changed = self.expand_node(a_region, b_vid, b_node);
201 let retain = match *b_node {
202 VarValue::Value(ReStatic) | VarValue::ErrorValue => false,
208 Constraint::RegSubReg(..) | Constraint::VarSubReg(..) => {
209 // These constraints are checked after expansion
210 // is done, in `collect_errors`.
219 a_region: Region<'tcx>,
221 b_data: &mut VarValue<'tcx>,
223 debug!("expand_node({:?}, {:?} == {:?})", a_region, b_vid, b_data);
226 // Check if this relationship is implied by a given.
227 ty::ReEarlyBound(_) | ty::ReFree(_) => if self.data.givens.contains(&(a_region, b_vid))
238 VarValue::Value(cur_region) => {
239 let mut lub = self.lub_concrete_regions(a_region, cur_region);
240 if lub == cur_region {
244 // Watch out for `'b: !1` relationships, where the
245 // universe of `'b` can't name the placeholder `!1`. In
246 // that case, we have to grow `'b` to be `'static` for the
247 // relationship to hold. This is obviously a kind of sub-optimal
248 // choice -- in the future, when we incorporate a knowledge
249 // of the parameter environment, we might be able to find a
250 // tighter bound than `'static`.
252 // (This might e.g. arise from being asked to prove `for<'a> { 'b: 'a }`.)
253 let b_universe = self.var_infos[b_vid].universe;
254 if let ty::RePlaceholder(p) = lub {
255 if b_universe.cannot_name(p.universe) {
256 lub = self.tcx().types.re_static;
261 "Expanding value of {:?} from {:?} to {:?}",
262 b_vid, cur_region, lub
265 *b_data = VarValue::Value(lub);
269 VarValue::ErrorValue => {
275 fn lub_concrete_regions(&self, a: Region<'tcx>, b: Region<'tcx>) -> Region<'tcx> {
276 let tcx = self.tcx();
278 // Equal scopes can show up quite often, if the fixed point
279 // iteration converges slowly, skip them
285 (&ty::ReClosureBound(..), _)
286 | (_, &ty::ReClosureBound(..))
287 | (&ReLateBound(..), _)
288 | (_, &ReLateBound(..))
290 | (_, &ReErased) => {
291 bug!("cannot relate region: LUB({:?}, {:?})", a, b);
294 (r @ &ReStatic, _) | (_, r @ &ReStatic) => {
295 r // nothing lives longer than static
298 (&ReEmpty, r) | (r, &ReEmpty) => {
299 r // everything lives longer than empty
302 (&ReVar(v_id), _) | (_, &ReVar(v_id)) => {
304 self.var_infos[v_id].origin.span(),
305 "lub_concrete_regions invoked with non-concrete \
306 regions: {:?}, {:?}",
312 (&ReEarlyBound(_), &ReScope(s_id))
313 | (&ReScope(s_id), &ReEarlyBound(_))
314 | (&ReFree(_), &ReScope(s_id))
315 | (&ReScope(s_id), &ReFree(_)) => {
316 // A "free" region can be interpreted as "some region
317 // at least as big as fr.scope". So, we can
318 // reasonably compare free regions and scopes:
319 let fr_scope = match (a, b) {
320 (&ReEarlyBound(ref br), _) | (_, &ReEarlyBound(ref br)) => self.region_rels
322 .early_free_scope(self.tcx(), br),
323 (&ReFree(ref fr), _) | (_, &ReFree(ref fr)) => self.region_rels
325 .free_scope(self.tcx(), fr),
328 let r_id = self.region_rels
330 .nearest_common_ancestor(fr_scope, s_id);
331 if r_id == fr_scope {
332 // if the free region's scope `fr.scope` is bigger than
333 // the scope region `s_id`, then the LUB is the free
336 (_, &ReScope(_)) => return a,
337 (&ReScope(_), _) => return b,
342 // otherwise, we don't know what the free region is,
343 // so we must conservatively say the LUB is static:
347 (&ReScope(a_id), &ReScope(b_id)) => {
348 // The region corresponding to an outer block is a
349 // subtype of the region corresponding to an inner
351 let lub = self.region_rels
353 .nearest_common_ancestor(a_id, b_id);
354 tcx.mk_region(ReScope(lub))
357 (&ReEarlyBound(_), &ReEarlyBound(_))
358 | (&ReFree(_), &ReEarlyBound(_))
359 | (&ReEarlyBound(_), &ReFree(_))
360 | (&ReFree(_), &ReFree(_)) => self.region_rels.lub_free_regions(a, b),
362 // For these types, we cannot define any additional
364 (&RePlaceholder(..), _) | (_, &RePlaceholder(..)) => if a == b {
372 /// After expansion is complete, go and check upper bounds (i.e.,
373 /// cases where the region cannot grow larger than a fixed point)
374 /// and check that they are satisfied.
377 var_data: &mut LexicalRegionResolutions<'tcx>,
378 errors: &mut Vec<RegionResolutionError<'tcx>>,
380 for (constraint, origin) in &self.data.constraints {
382 "collect_errors: constraint={:?} origin={:?}",
386 Constraint::RegSubVar(..) | Constraint::VarSubVar(..) => {
387 // Expansion will ensure that these constraints hold. Ignore.
390 Constraint::RegSubReg(sub, sup) => {
391 if self.region_rels.is_subregion_of(sub, sup) {
396 "collect_errors: region error at {:?}: \
397 cannot verify that {:?} <= {:?}",
401 errors.push(RegionResolutionError::ConcreteFailure(
408 Constraint::VarSubReg(a_vid, b_region) => {
409 let a_data = var_data.value_mut(a_vid);
410 debug!("contraction: {:?} == {:?}, {:?}", a_vid, a_data, b_region);
412 let a_region = match *a_data {
413 VarValue::ErrorValue => continue,
414 VarValue::Value(a_region) => a_region,
417 // Do not report these errors immediately:
418 // instead, set the variable value to error and
419 // collect them later.
420 if !self.region_rels.is_subregion_of(a_region, b_region) {
422 "collect_errors: region error at {:?}: \
423 cannot verify that {:?}={:?} <= {:?}",
424 origin, a_vid, a_region, b_region
426 *a_data = VarValue::ErrorValue;
432 for verify in &self.data.verifys {
433 debug!("collect_errors: verify={:?}", verify);
434 let sub = var_data.normalize(self.tcx(), verify.region);
436 // This was an inference variable which didn't get
437 // constrained, therefore it can be assume to hold.
438 if let ty::ReEmpty = *sub {
442 let verify_kind_ty = verify.kind.to_ty(self.tcx());
443 if self.bound_is_met(&verify.bound, var_data, verify_kind_ty, sub) {
448 "collect_errors: region error at {:?}: \
449 cannot verify that {:?} <= {:?}",
450 verify.origin, verify.region, verify.bound
453 errors.push(RegionResolutionError::GenericBoundFailure(
454 verify.origin.clone(),
461 /// Go over the variables that were declared to be error variables
462 /// and create a `RegionResolutionError` for each of them.
463 fn collect_var_errors(
465 var_data: &LexicalRegionResolutions<'tcx>,
466 graph: &RegionGraph<'tcx>,
467 errors: &mut Vec<RegionResolutionError<'tcx>>,
469 debug!("collect_var_errors");
471 // This is the best way that I have found to suppress
472 // duplicate and related errors. Basically we keep a set of
473 // flags for every node. Whenever an error occurs, we will
474 // walk some portion of the graph looking to find pairs of
475 // conflicting regions to report to the user. As we walk, we
476 // trip the flags from false to true, and if we find that
477 // we've already reported an error involving any particular
478 // node we just stop and don't report the current error. The
479 // idea is to report errors that derive from independent
480 // regions of the graph, but not those that derive from
481 // overlapping locations.
482 let mut dup_vec = vec![u32::MAX; self.num_vars()];
484 for (node_vid, value) in var_data.values.iter_enumerated() {
486 VarValue::Value(_) => { /* Inference successful */ }
487 VarValue::ErrorValue => {
488 /* Inference impossible, this value contains
489 inconsistent constraints.
491 I think that in this case we should report an
492 error now---unlike the case above, we can't
493 wait to see whether the user needs the result
494 of this variable. The reason is that the mere
495 existence of this variable implies that the
496 region graph is inconsistent, whether or not it
499 For example, we may have created a region
500 variable that is the GLB of two other regions
501 which do not have a GLB. Even if that variable
502 is not used, it implies that those two regions
505 At least I think this is true. It may be that
506 the mere existence of a conflict in a region variable
507 that is not used is not a problem, so if this rule
508 starts to create problems we'll have to revisit
509 this portion of the code and think hard about it. =) */
510 self.collect_error_for_expanding_node(graph, &mut dup_vec, node_vid, errors);
516 fn construct_graph(&self) -> RegionGraph<'tcx> {
517 let num_vars = self.num_vars();
519 let mut graph = Graph::new();
521 for _ in 0..num_vars {
525 // Issue #30438: two distinct dummy nodes, one for incoming
526 // edges (dummy_source) and another for outgoing edges
527 // (dummy_sink). In `dummy -> a -> b -> dummy`, using one
528 // dummy node leads one to think (erroneously) there exists a
529 // path from `b` to `a`. Two dummy nodes sidesteps the issue.
530 let dummy_source = graph.add_node(());
531 let dummy_sink = graph.add_node(());
533 for (constraint, _) in &self.data.constraints {
535 Constraint::VarSubVar(a_id, b_id) => {
537 NodeIndex(a_id.index() as usize),
538 NodeIndex(b_id.index() as usize),
542 Constraint::RegSubVar(_, b_id) => {
543 graph.add_edge(dummy_source, NodeIndex(b_id.index() as usize), *constraint);
545 Constraint::VarSubReg(a_id, _) => {
546 graph.add_edge(NodeIndex(a_id.index() as usize), dummy_sink, *constraint);
548 Constraint::RegSubReg(..) => {
549 // this would be an edge from `dummy_source` to
550 // `dummy_sink`; just ignore it.
558 fn collect_error_for_expanding_node(
560 graph: &RegionGraph<'tcx>,
563 errors: &mut Vec<RegionResolutionError<'tcx>>,
565 // Errors in expanding nodes result from a lower-bound that is
566 // not contained by an upper-bound.
567 let (mut lower_bounds, lower_dup) =
568 self.collect_concrete_regions(graph, node_idx, INCOMING, dup_vec);
569 let (mut upper_bounds, upper_dup) =
570 self.collect_concrete_regions(graph, node_idx, OUTGOING, dup_vec);
572 if lower_dup || upper_dup {
576 // We place free regions first because we are special casing
577 // SubSupConflict(ReFree, ReFree) when reporting error, and so
578 // the user will more likely get a specific suggestion.
579 fn region_order_key(x: &RegionAndOrigin<'_>) -> u8 {
581 ReEarlyBound(_) => 0,
586 lower_bounds.sort_by_key(region_order_key);
587 upper_bounds.sort_by_key(region_order_key);
589 let node_universe = self.var_infos[node_idx].universe;
591 for lower_bound in &lower_bounds {
592 let effective_lower_bound = if let ty::RePlaceholder(p) = lower_bound.region {
593 if node_universe.cannot_name(p.universe) {
594 self.tcx().types.re_static
602 for upper_bound in &upper_bounds {
604 .is_subregion_of(effective_lower_bound, upper_bound.region)
606 let origin = self.var_infos[node_idx].origin.clone();
608 "region inference error at {:?} for {:?}: SubSupConflict sub: {:?} \
610 origin, node_idx, lower_bound.region, upper_bound.region
612 errors.push(RegionResolutionError::SubSupConflict(
615 lower_bound.origin.clone(),
617 upper_bound.origin.clone(),
626 self.var_infos[node_idx].origin.span(),
627 "collect_error_for_expanding_node() could not find \
628 error for var {:?} in universe {:?}, lower_bounds={:#?}, \
637 fn collect_concrete_regions(
639 graph: &RegionGraph<'tcx>,
640 orig_node_idx: RegionVid,
643 ) -> (Vec<RegionAndOrigin<'tcx>>, bool) {
644 struct WalkState<'tcx> {
645 set: FxHashSet<RegionVid>,
646 stack: Vec<RegionVid>,
647 result: Vec<RegionAndOrigin<'tcx>>,
650 let mut state = WalkState {
651 set: Default::default(),
652 stack: vec![orig_node_idx],
656 state.set.insert(orig_node_idx);
658 // to start off the process, walk the source node in the
659 // direction specified
660 process_edges(&self.data, &mut state, graph, orig_node_idx, dir);
662 while !state.stack.is_empty() {
663 let node_idx = state.stack.pop().unwrap();
665 // check whether we've visited this node on some previous walk
666 if dup_vec[node_idx.index() as usize] == u32::MAX {
667 dup_vec[node_idx.index() as usize] = orig_node_idx.index() as u32;
668 } else if dup_vec[node_idx.index() as usize] != orig_node_idx.index() as u32 {
669 state.dup_found = true;
673 "collect_concrete_regions(orig_node_idx={:?}, node_idx={:?})",
674 orig_node_idx, node_idx
677 process_edges(&self.data, &mut state, graph, node_idx, dir);
681 result, dup_found, ..
683 return (result, dup_found);
685 fn process_edges<'tcx>(
686 this: &RegionConstraintData<'tcx>,
687 state: &mut WalkState<'tcx>,
688 graph: &RegionGraph<'tcx>,
689 source_vid: RegionVid,
692 debug!("process_edges(source_vid={:?}, dir={:?})", source_vid, dir);
694 let source_node_index = NodeIndex(source_vid.index() as usize);
695 for (_, edge) in graph.adjacent_edges(source_node_index, dir) {
697 Constraint::VarSubVar(from_vid, to_vid) => {
698 let opp_vid = if from_vid == source_vid {
703 if state.set.insert(opp_vid) {
704 state.stack.push(opp_vid);
708 Constraint::RegSubVar(region, _) | Constraint::VarSubReg(_, region) => {
709 state.result.push(RegionAndOrigin {
711 origin: this.constraints.get(&edge.data).unwrap().clone(),
715 Constraint::RegSubReg(..) => panic!(
716 "cannot reach reg-sub-reg edge in region inference \
724 fn iterate_until_fixed_point<F>(&self, tag: &str, mut body: F)
726 F: FnMut(&Constraint<'tcx>, &SubregionOrigin<'tcx>) -> (bool, bool),
728 let mut constraints: SmallVec<[_; 16]> = self.data.constraints.iter().collect();
729 let mut iteration = 0;
730 let mut changed = true;
734 debug!("---- {} Iteration {}{}", "#", tag, iteration);
735 constraints.retain(|(constraint, origin)| {
736 let (edge_changed, retain) = body(constraint, origin);
738 debug!("Updated due to constraint {:?}", constraint);
744 debug!("---- {} Complete after {} iteration(s)", tag, iteration);
749 bound: &VerifyBound<'tcx>,
750 var_values: &LexicalRegionResolutions<'tcx>,
751 generic_ty: Ty<'tcx>,
752 min: ty::Region<'tcx>,
755 VerifyBound::IfEq(k, b) => {
756 (var_values.normalize(self.region_rels.tcx, *k) == generic_ty)
757 && self.bound_is_met(b, var_values, generic_ty, min)
760 VerifyBound::OutlivedBy(r) =>
761 self.region_rels.is_subregion_of(
763 var_values.normalize(self.tcx(), r),
766 VerifyBound::AnyBound(bs) => bs.iter()
767 .any(|b| self.bound_is_met(b, var_values, generic_ty, min)),
769 VerifyBound::AllBounds(bs) => bs.iter()
770 .all(|b| self.bound_is_met(b, var_values, generic_ty, min)),
775 impl<'tcx> fmt::Debug for RegionAndOrigin<'tcx> {
776 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
777 write!(f, "RegionAndOrigin({:?},{:?})", self.region, self.origin)
781 impl<'tcx> LexicalRegionResolutions<'tcx> {
782 fn normalize<T>(&self, tcx: TyCtxt<'_, '_, 'tcx>, value: T) -> T
784 T: TypeFoldable<'tcx>,
786 tcx.fold_regions(&value, &mut false, |r, _db| match r {
787 ty::ReVar(rid) => self.resolve_var(*rid),
792 fn value(&self, rid: RegionVid) -> &VarValue<'tcx> {
796 fn value_mut(&mut self, rid: RegionVid) -> &mut VarValue<'tcx> {
797 &mut self.values[rid]
800 pub fn resolve_var(&self, rid: RegionVid) -> ty::Region<'tcx> {
801 let result = match self.values[rid] {
802 VarValue::Value(r) => r,
803 VarValue::ErrorValue => self.error_region,
805 debug!("resolve_var({:?}) = {:?}", rid, result);