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};
18 use ty::fold::TypeFoldable;
19 use ty::{self, Ty, TyCtxt};
20 use ty::{ReEarlyBound, ReEmpty, ReErased, ReFree, ReStatic};
21 use ty::{ReLateBound, ReScope, RePlaceholder, ReVar};
22 use ty::{Region, RegionVid};
26 /// This function performs lexical region resolution given a complete
27 /// set of constraints and variable origins. It performs a fixed-point
28 /// iteration to find region values which satisfy all constraints,
29 /// assuming such values can be found. It returns the final values of
30 /// all the variables as well as a set of errors that must be reported.
32 region_rels: &RegionRelations<'_, '_, 'tcx>,
34 data: RegionConstraintData<'tcx>,
36 LexicalRegionResolutions<'tcx>,
37 Vec<RegionResolutionError<'tcx>>,
39 debug!("RegionConstraintData: resolve_regions()");
40 let mut errors = vec![];
41 let mut resolver = LexicalResolver {
46 let values = resolver.infer_variable_values(&mut errors);
50 /// Contains the result of lexical region resolution. Offers methods
51 /// to lookup up the final value of a region variable.
52 pub struct LexicalRegionResolutions<'tcx> {
53 values: IndexVec<RegionVid, VarValue<'tcx>>,
54 error_region: ty::Region<'tcx>,
57 #[derive(Copy, Clone, Debug)]
63 #[derive(Clone, Debug)]
64 pub enum RegionResolutionError<'tcx> {
65 /// `ConcreteFailure(o, a, b)`:
67 /// `o` requires that `a <= b`, but this does not hold
68 ConcreteFailure(SubregionOrigin<'tcx>, Region<'tcx>, Region<'tcx>),
70 /// `GenericBoundFailure(p, s, a)
72 /// The parameter/associated-type `p` must be known to outlive the lifetime
73 /// `a` (but none of the known bounds are sufficient).
74 GenericBoundFailure(SubregionOrigin<'tcx>, GenericKind<'tcx>, Region<'tcx>),
76 /// `SubSupConflict(v, v_origin, sub_origin, sub_r, sup_origin, sup_r)`:
78 /// Could not infer a value for `v` (which has origin `v_origin`)
79 /// because `sub_r <= v` (due to `sub_origin`) but `v <= sup_r` (due to `sup_origin`) and
80 /// `sub_r <= sup_r` does not hold.
84 SubregionOrigin<'tcx>,
86 SubregionOrigin<'tcx>,
91 struct RegionAndOrigin<'tcx> {
93 origin: SubregionOrigin<'tcx>,
96 type RegionGraph<'tcx> = Graph<(), Constraint<'tcx>>;
98 struct LexicalResolver<'cx, 'gcx: 'tcx, 'tcx: 'cx> {
99 region_rels: &'cx RegionRelations<'cx, 'gcx, 'tcx>,
101 data: RegionConstraintData<'tcx>,
104 impl<'cx, 'gcx, 'tcx> LexicalResolver<'cx, 'gcx, 'tcx> {
105 fn tcx(&self) -> TyCtxt<'cx, 'gcx, 'tcx> {
109 fn infer_variable_values(
111 errors: &mut Vec<RegionResolutionError<'tcx>>,
112 ) -> LexicalRegionResolutions<'tcx> {
113 let mut var_data = self.construct_var_data(self.tcx());
115 // Dorky hack to cause `dump_constraints` to only get called
116 // if debug mode is enabled:
118 "----() End constraint listing (context={:?}) {:?}---",
119 self.region_rels.context,
120 self.dump_constraints(self.region_rels)
122 graphviz::maybe_print_constraints_for(&self.data, self.region_rels);
124 let graph = self.construct_graph();
125 self.expand_givens(&graph);
126 self.expansion(&mut var_data);
127 self.collect_errors(&mut var_data, errors);
128 self.collect_var_errors(&var_data, &graph, errors);
132 fn num_vars(&self) -> usize {
136 /// Initially, the value for all variables is set to `'empty`, the
137 /// empty region. The `expansion` phase will grow this larger.
138 fn construct_var_data(&self, tcx: TyCtxt<'_, '_, 'tcx>) -> LexicalRegionResolutions<'tcx> {
139 LexicalRegionResolutions {
140 error_region: tcx.types.re_static,
141 values: IndexVec::from_elem_n(VarValue::Value(tcx.types.re_empty), self.num_vars())
145 fn dump_constraints(&self, free_regions: &RegionRelations<'_, '_, 'tcx>) {
147 "----() Start constraint listing (context={:?}) ()----",
150 for (idx, (constraint, _)) in self.data.constraints.iter().enumerate() {
151 debug!("Constraint {} => {:?}", idx, constraint);
155 fn expand_givens(&mut self, graph: &RegionGraph<'_>) {
156 // Givens are a kind of horrible hack to account for
157 // constraints like 'c <= '0 that are known to hold due to
158 // closure signatures (see the comment above on the `givens`
159 // field). They should go away. But until they do, the role
160 // of this fn is to account for the transitive nature:
166 let seeds: Vec<_> = self.data.givens.iter().cloned().collect();
167 for (r, vid) in seeds {
168 // While all things transitively reachable in the graph
169 // from the variable (`'0` in the example above).
170 let seed_index = NodeIndex(vid.index() as usize);
171 for succ_index in graph.depth_traverse(seed_index, OUTGOING) {
172 let succ_index = succ_index.0;
174 // The first N nodes correspond to the region
175 // variables. Other nodes correspond to constant
177 if succ_index < self.num_vars() {
178 let succ_vid = RegionVid::new(succ_index);
181 self.data.givens.insert((r, succ_vid));
187 fn expansion(&self, var_values: &mut LexicalRegionResolutions<'tcx>) {
188 self.iterate_until_fixed_point("Expansion", |constraint, origin| {
189 debug!("expansion: constraint={:?} origin={:?}", constraint, origin);
191 Constraint::RegSubVar(a_region, b_vid) => {
192 let b_data = var_values.value_mut(b_vid);
193 self.expand_node(a_region, b_vid, b_data)
195 Constraint::VarSubVar(a_vid, b_vid) => match *var_values.value(a_vid) {
196 VarValue::ErrorValue => false,
197 VarValue::Value(a_region) => {
198 let b_node = var_values.value_mut(b_vid);
199 self.expand_node(a_region, b_vid, b_node)
202 Constraint::RegSubReg(..) | Constraint::VarSubReg(..) => {
203 // These constraints are checked after expansion
204 // is done, in `collect_errors`.
213 a_region: Region<'tcx>,
215 b_data: &mut VarValue<'tcx>,
217 debug!("expand_node({:?}, {:?} == {:?})", a_region, b_vid, b_data);
220 // Check if this relationship is implied by a given.
221 ty::ReEarlyBound(_) | ty::ReFree(_) => if self.data.givens.contains(&(a_region, b_vid))
232 VarValue::Value(cur_region) => {
233 let mut lub = self.lub_concrete_regions(a_region, cur_region);
234 if lub == cur_region {
238 // Watch out for `'b: !1` relationships, where the
239 // universe of `'b` can't name the placeholder `!1`. In
240 // that case, we have to grow `'b` to be `'static` for the
241 // relationship to hold. This is obviously a kind of sub-optimal
242 // choice -- in the future, when we incorporate a knowledge
243 // of the parameter environment, we might be able to find a
244 // tighter bound than `'static`.
246 // (This might e.g. arise from being asked to prove `for<'a> { 'b: 'a }`.)
247 let b_universe = self.var_infos[b_vid].universe;
248 if let ty::RePlaceholder(p) = lub {
249 if b_universe.cannot_name(p.universe) {
250 lub = self.tcx().types.re_static;
255 "Expanding value of {:?} from {:?} to {:?}",
256 b_vid, cur_region, lub
259 *b_data = VarValue::Value(lub);
263 VarValue::ErrorValue => {
269 fn lub_concrete_regions(&self, a: Region<'tcx>, b: Region<'tcx>) -> Region<'tcx> {
270 let tcx = self.tcx();
272 (&ty::ReClosureBound(..), _)
273 | (_, &ty::ReClosureBound(..))
274 | (&ReLateBound(..), _)
275 | (_, &ReLateBound(..))
277 | (_, &ReErased) => {
278 bug!("cannot relate region: LUB({:?}, {:?})", a, b);
281 (r @ &ReStatic, _) | (_, r @ &ReStatic) => {
282 r // nothing lives longer than static
285 (&ReEmpty, r) | (r, &ReEmpty) => {
286 r // everything lives longer than empty
289 (&ReVar(v_id), _) | (_, &ReVar(v_id)) => {
291 self.var_infos[v_id].origin.span(),
292 "lub_concrete_regions invoked with non-concrete \
293 regions: {:?}, {:?}",
299 (&ReEarlyBound(_), &ReScope(s_id))
300 | (&ReScope(s_id), &ReEarlyBound(_))
301 | (&ReFree(_), &ReScope(s_id))
302 | (&ReScope(s_id), &ReFree(_)) => {
303 // A "free" region can be interpreted as "some region
304 // at least as big as fr.scope". So, we can
305 // reasonably compare free regions and scopes:
306 let fr_scope = match (a, b) {
307 (&ReEarlyBound(ref br), _) | (_, &ReEarlyBound(ref br)) => self.region_rels
309 .early_free_scope(self.tcx(), br),
310 (&ReFree(ref fr), _) | (_, &ReFree(ref fr)) => self.region_rels
312 .free_scope(self.tcx(), fr),
315 let r_id = self.region_rels
317 .nearest_common_ancestor(fr_scope, s_id);
318 if r_id == fr_scope {
319 // if the free region's scope `fr.scope` is bigger than
320 // the scope region `s_id`, then the LUB is the free
323 (_, &ReScope(_)) => return a,
324 (&ReScope(_), _) => return b,
329 // otherwise, we don't know what the free region is,
330 // so we must conservatively say the LUB is static:
334 (&ReScope(a_id), &ReScope(b_id)) => {
335 // The region corresponding to an outer block is a
336 // subtype of the region corresponding to an inner
338 let lub = self.region_rels
340 .nearest_common_ancestor(a_id, b_id);
341 tcx.mk_region(ReScope(lub))
344 (&ReEarlyBound(_), &ReEarlyBound(_))
345 | (&ReFree(_), &ReEarlyBound(_))
346 | (&ReEarlyBound(_), &ReFree(_))
347 | (&ReFree(_), &ReFree(_)) => self.region_rels.lub_free_regions(a, b),
349 // For these types, we cannot define any additional
351 (&RePlaceholder(..), _) | (_, &RePlaceholder(..)) => if a == b {
359 /// After expansion is complete, go and check upper bounds (i.e.,
360 /// cases where the region cannot grow larger than a fixed point)
361 /// and check that they are satisfied.
364 var_data: &mut LexicalRegionResolutions<'tcx>,
365 errors: &mut Vec<RegionResolutionError<'tcx>>,
367 for (constraint, origin) in &self.data.constraints {
369 "collect_errors: constraint={:?} origin={:?}",
373 Constraint::RegSubVar(..) | Constraint::VarSubVar(..) => {
374 // Expansion will ensure that these constraints hold. Ignore.
377 Constraint::RegSubReg(sub, sup) => {
378 if self.region_rels.is_subregion_of(sub, sup) {
383 "collect_errors: region error at {:?}: \
384 cannot verify that {:?} <= {:?}",
388 errors.push(RegionResolutionError::ConcreteFailure(
395 Constraint::VarSubReg(a_vid, b_region) => {
396 let a_data = var_data.value_mut(a_vid);
397 debug!("contraction: {:?} == {:?}, {:?}", a_vid, a_data, b_region);
399 let a_region = match *a_data {
400 VarValue::ErrorValue => continue,
401 VarValue::Value(a_region) => a_region,
404 // Do not report these errors immediately:
405 // instead, set the variable value to error and
406 // collect them later.
407 if !self.region_rels.is_subregion_of(a_region, b_region) {
409 "collect_errors: region error at {:?}: \
410 cannot verify that {:?}={:?} <= {:?}",
411 origin, a_vid, a_region, b_region
413 *a_data = VarValue::ErrorValue;
419 for verify in &self.data.verifys {
420 debug!("collect_errors: verify={:?}", verify);
421 let sub = var_data.normalize(self.tcx(), verify.region);
423 // This was an inference variable which didn't get
424 // constrained, therefore it can be assume to hold.
425 if let ty::ReEmpty = *sub {
429 let verify_kind_ty = verify.kind.to_ty(self.tcx());
430 if self.bound_is_met(&verify.bound, var_data, verify_kind_ty, sub) {
435 "collect_errors: region error at {:?}: \
436 cannot verify that {:?} <= {:?}",
437 verify.origin, verify.region, verify.bound
440 errors.push(RegionResolutionError::GenericBoundFailure(
441 verify.origin.clone(),
448 /// Go over the variables that were declared to be error variables
449 /// and create a `RegionResolutionError` for each of them.
450 fn collect_var_errors(
452 var_data: &LexicalRegionResolutions<'tcx>,
453 graph: &RegionGraph<'tcx>,
454 errors: &mut Vec<RegionResolutionError<'tcx>>,
456 debug!("collect_var_errors");
458 // This is the best way that I have found to suppress
459 // duplicate and related errors. Basically we keep a set of
460 // flags for every node. Whenever an error occurs, we will
461 // walk some portion of the graph looking to find pairs of
462 // conflicting regions to report to the user. As we walk, we
463 // trip the flags from false to true, and if we find that
464 // we've already reported an error involving any particular
465 // node we just stop and don't report the current error. The
466 // idea is to report errors that derive from independent
467 // regions of the graph, but not those that derive from
468 // overlapping locations.
469 let mut dup_vec = vec![u32::MAX; self.num_vars()];
471 for (node_vid, value) in var_data.values.iter_enumerated() {
473 VarValue::Value(_) => { /* Inference successful */ }
474 VarValue::ErrorValue => {
475 /* Inference impossible, this value contains
476 inconsistent constraints.
478 I think that in this case we should report an
479 error now---unlike the case above, we can't
480 wait to see whether the user needs the result
481 of this variable. The reason is that the mere
482 existence of this variable implies that the
483 region graph is inconsistent, whether or not it
486 For example, we may have created a region
487 variable that is the GLB of two other regions
488 which do not have a GLB. Even if that variable
489 is not used, it implies that those two regions
492 At least I think this is true. It may be that
493 the mere existence of a conflict in a region variable
494 that is not used is not a problem, so if this rule
495 starts to create problems we'll have to revisit
496 this portion of the code and think hard about it. =) */
497 self.collect_error_for_expanding_node(graph, &mut dup_vec, node_vid, errors);
503 fn construct_graph(&self) -> RegionGraph<'tcx> {
504 let num_vars = self.num_vars();
506 let mut graph = Graph::new();
508 for _ in 0..num_vars {
512 // Issue #30438: two distinct dummy nodes, one for incoming
513 // edges (dummy_source) and another for outgoing edges
514 // (dummy_sink). In `dummy -> a -> b -> dummy`, using one
515 // dummy node leads one to think (erroneously) there exists a
516 // path from `b` to `a`. Two dummy nodes sidesteps the issue.
517 let dummy_source = graph.add_node(());
518 let dummy_sink = graph.add_node(());
520 for (constraint, _) in &self.data.constraints {
522 Constraint::VarSubVar(a_id, b_id) => {
524 NodeIndex(a_id.index() as usize),
525 NodeIndex(b_id.index() as usize),
529 Constraint::RegSubVar(_, b_id) => {
530 graph.add_edge(dummy_source, NodeIndex(b_id.index() as usize), *constraint);
532 Constraint::VarSubReg(a_id, _) => {
533 graph.add_edge(NodeIndex(a_id.index() as usize), dummy_sink, *constraint);
535 Constraint::RegSubReg(..) => {
536 // this would be an edge from `dummy_source` to
537 // `dummy_sink`; just ignore it.
545 fn collect_error_for_expanding_node(
547 graph: &RegionGraph<'tcx>,
550 errors: &mut Vec<RegionResolutionError<'tcx>>,
552 // Errors in expanding nodes result from a lower-bound that is
553 // not contained by an upper-bound.
554 let (mut lower_bounds, lower_dup) =
555 self.collect_concrete_regions(graph, node_idx, INCOMING, dup_vec);
556 let (mut upper_bounds, upper_dup) =
557 self.collect_concrete_regions(graph, node_idx, OUTGOING, dup_vec);
559 if lower_dup || upper_dup {
563 // We place free regions first because we are special casing
564 // SubSupConflict(ReFree, ReFree) when reporting error, and so
565 // the user will more likely get a specific suggestion.
566 fn region_order_key(x: &RegionAndOrigin<'_>) -> u8 {
568 ReEarlyBound(_) => 0,
573 lower_bounds.sort_by_key(region_order_key);
574 upper_bounds.sort_by_key(region_order_key);
576 let node_universe = self.var_infos[node_idx].universe;
578 for lower_bound in &lower_bounds {
579 let effective_lower_bound = if let ty::RePlaceholder(p) = lower_bound.region {
580 if node_universe.cannot_name(p.universe) {
581 self.tcx().types.re_static
589 for upper_bound in &upper_bounds {
591 .is_subregion_of(effective_lower_bound, upper_bound.region)
593 let origin = self.var_infos[node_idx].origin.clone();
595 "region inference error at {:?} for {:?}: SubSupConflict sub: {:?} \
597 origin, node_idx, lower_bound.region, upper_bound.region
599 errors.push(RegionResolutionError::SubSupConflict(
602 lower_bound.origin.clone(),
604 upper_bound.origin.clone(),
613 self.var_infos[node_idx].origin.span(),
614 "collect_error_for_expanding_node() could not find \
615 error for var {:?} in universe {:?}, lower_bounds={:#?}, \
624 fn collect_concrete_regions(
626 graph: &RegionGraph<'tcx>,
627 orig_node_idx: RegionVid,
630 ) -> (Vec<RegionAndOrigin<'tcx>>, bool) {
631 struct WalkState<'tcx> {
632 set: FxHashSet<RegionVid>,
633 stack: Vec<RegionVid>,
634 result: Vec<RegionAndOrigin<'tcx>>,
637 let mut state = WalkState {
638 set: Default::default(),
639 stack: vec![orig_node_idx],
643 state.set.insert(orig_node_idx);
645 // to start off the process, walk the source node in the
646 // direction specified
647 process_edges(&self.data, &mut state, graph, orig_node_idx, dir);
649 while !state.stack.is_empty() {
650 let node_idx = state.stack.pop().unwrap();
652 // check whether we've visited this node on some previous walk
653 if dup_vec[node_idx.index() as usize] == u32::MAX {
654 dup_vec[node_idx.index() as usize] = orig_node_idx.index() as u32;
655 } else if dup_vec[node_idx.index() as usize] != orig_node_idx.index() as u32 {
656 state.dup_found = true;
660 "collect_concrete_regions(orig_node_idx={:?}, node_idx={:?})",
661 orig_node_idx, node_idx
664 process_edges(&self.data, &mut state, graph, node_idx, dir);
668 result, dup_found, ..
670 return (result, dup_found);
672 fn process_edges<'tcx>(
673 this: &RegionConstraintData<'tcx>,
674 state: &mut WalkState<'tcx>,
675 graph: &RegionGraph<'tcx>,
676 source_vid: RegionVid,
679 debug!("process_edges(source_vid={:?}, dir={:?})", source_vid, dir);
681 let source_node_index = NodeIndex(source_vid.index() as usize);
682 for (_, edge) in graph.adjacent_edges(source_node_index, dir) {
684 Constraint::VarSubVar(from_vid, to_vid) => {
685 let opp_vid = if from_vid == source_vid {
690 if state.set.insert(opp_vid) {
691 state.stack.push(opp_vid);
695 Constraint::RegSubVar(region, _) | Constraint::VarSubReg(_, region) => {
696 state.result.push(RegionAndOrigin {
698 origin: this.constraints.get(&edge.data).unwrap().clone(),
702 Constraint::RegSubReg(..) => panic!(
703 "cannot reach reg-sub-reg edge in region inference \
711 fn iterate_until_fixed_point<F>(&self, tag: &str, mut body: F)
713 F: FnMut(&Constraint<'tcx>, &SubregionOrigin<'tcx>) -> bool,
715 let mut iteration = 0;
716 let mut changed = true;
720 debug!("---- {} Iteration {}{}", "#", tag, iteration);
721 for (constraint, origin) in &self.data.constraints {
722 let edge_changed = body(constraint, origin);
724 debug!("Updated due to constraint {:?}", constraint);
729 debug!("---- {} Complete after {} iteration(s)", tag, iteration);
734 bound: &VerifyBound<'tcx>,
735 var_values: &LexicalRegionResolutions<'tcx>,
736 generic_ty: Ty<'tcx>,
737 min: ty::Region<'tcx>,
740 VerifyBound::IfEq(k, b) => {
741 (var_values.normalize(self.region_rels.tcx, *k) == generic_ty)
742 && self.bound_is_met(b, var_values, generic_ty, min)
745 VerifyBound::OutlivedBy(r) =>
746 self.region_rels.is_subregion_of(
748 var_values.normalize(self.tcx(), r),
751 VerifyBound::AnyBound(bs) => bs.iter()
752 .any(|b| self.bound_is_met(b, var_values, generic_ty, min)),
754 VerifyBound::AllBounds(bs) => bs.iter()
755 .all(|b| self.bound_is_met(b, var_values, generic_ty, min)),
760 impl<'tcx> fmt::Debug for RegionAndOrigin<'tcx> {
761 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
762 write!(f, "RegionAndOrigin({:?},{:?})", self.region, self.origin)
766 impl<'tcx> LexicalRegionResolutions<'tcx> {
767 fn normalize<T>(&self, tcx: TyCtxt<'_, '_, 'tcx>, value: T) -> T
769 T: TypeFoldable<'tcx>,
771 tcx.fold_regions(&value, &mut false, |r, _db| match r {
772 ty::ReVar(rid) => self.resolve_var(*rid),
777 fn value(&self, rid: RegionVid) -> &VarValue<'tcx> {
781 fn value_mut(&mut self, rid: RegionVid) -> &mut VarValue<'tcx> {
782 &mut self.values[rid]
785 pub fn resolve_var(&self, rid: RegionVid) -> ty::Region<'tcx> {
786 let result = match self.values[rid] {
787 VarValue::Value(r) => r,
788 VarValue::ErrorValue => self.error_region,
790 debug!("resolve_var({:?}) = {:?}", rid, result);