1 // Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
11 //! The code to do lexical region resolution.
13 use infer::region_constraints::Constraint;
14 use infer::region_constraints::GenericKind;
15 use infer::region_constraints::RegionConstraintData;
16 use infer::region_constraints::VarInfos;
17 use infer::region_constraints::VerifyBound;
18 use infer::RegionVariableOrigin;
19 use infer::SubregionOrigin;
20 use middle::free_region::RegionRelations;
21 use rustc_data_structures::fx::FxHashSet;
22 use rustc_data_structures::graph::implementation::{
23 Direction, Graph, NodeIndex, INCOMING, OUTGOING,
25 use rustc_data_structures::indexed_vec::{Idx, IndexVec};
28 use ty::fold::TypeFoldable;
29 use ty::{self, Ty, TyCtxt};
30 use ty::{ReEarlyBound, ReEmpty, ReErased, ReFree, ReStatic};
31 use ty::{ReLateBound, ReScope, RePlaceholder, ReVar};
32 use ty::{Region, RegionVid};
36 /// This function performs lexical region resolution given a complete
37 /// set of constraints and variable origins. It performs a fixed-point
38 /// iteration to find region values which satisfy all constraints,
39 /// assuming such values can be found. It returns the final values of
40 /// all the variables as well as a set of errors that must be reported.
42 region_rels: &RegionRelations<'_, '_, 'tcx>,
44 data: RegionConstraintData<'tcx>,
46 LexicalRegionResolutions<'tcx>,
47 Vec<RegionResolutionError<'tcx>>,
49 debug!("RegionConstraintData: resolve_regions()");
50 let mut errors = vec![];
51 let mut resolver = LexicalResolver {
56 let values = resolver.infer_variable_values(&mut errors);
60 /// Contains the result of lexical region resolution. Offers methods
61 /// to lookup up the final value of a region variable.
62 pub struct LexicalRegionResolutions<'tcx> {
63 values: IndexVec<RegionVid, VarValue<'tcx>>,
64 error_region: ty::Region<'tcx>,
67 #[derive(Copy, Clone, Debug)]
73 #[derive(Clone, Debug)]
74 pub enum RegionResolutionError<'tcx> {
75 /// `ConcreteFailure(o, a, b)`:
77 /// `o` requires that `a <= b`, but this does not hold
78 ConcreteFailure(SubregionOrigin<'tcx>, Region<'tcx>, Region<'tcx>),
80 /// `GenericBoundFailure(p, s, a)
82 /// The parameter/associated-type `p` must be known to outlive the lifetime
83 /// `a` (but none of the known bounds are sufficient).
84 GenericBoundFailure(SubregionOrigin<'tcx>, GenericKind<'tcx>, Region<'tcx>),
86 /// `SubSupConflict(v, sub_origin, sub_r, sup_origin, sup_r)`:
88 /// Could not infer a value for `v` because `sub_r <= v` (due to
89 /// `sub_origin`) but `v <= sup_r` (due to `sup_origin`) and
90 /// `sub_r <= sup_r` does not hold.
93 SubregionOrigin<'tcx>,
95 SubregionOrigin<'tcx>,
100 struct RegionAndOrigin<'tcx> {
101 region: Region<'tcx>,
102 origin: SubregionOrigin<'tcx>,
105 type RegionGraph<'tcx> = Graph<(), Constraint<'tcx>>;
107 struct LexicalResolver<'cx, 'gcx: 'tcx, 'tcx: 'cx> {
108 region_rels: &'cx RegionRelations<'cx, 'gcx, 'tcx>,
110 data: RegionConstraintData<'tcx>,
113 impl<'cx, 'gcx, 'tcx> LexicalResolver<'cx, 'gcx, 'tcx> {
114 fn tcx(&self) -> TyCtxt<'cx, 'gcx, 'tcx> {
118 fn infer_variable_values(
120 errors: &mut Vec<RegionResolutionError<'tcx>>,
121 ) -> LexicalRegionResolutions<'tcx> {
122 let mut var_data = self.construct_var_data(self.tcx());
124 // Dorky hack to cause `dump_constraints` to only get called
125 // if debug mode is enabled:
127 "----() End constraint listing (context={:?}) {:?}---",
128 self.region_rels.context,
129 self.dump_constraints(self.region_rels)
131 graphviz::maybe_print_constraints_for(&self.data, self.region_rels);
133 let graph = self.construct_graph();
134 self.expand_givens(&graph);
135 self.expansion(&mut var_data);
136 self.collect_errors(&mut var_data, errors);
137 self.collect_var_errors(&var_data, &graph, errors);
141 fn num_vars(&self) -> usize {
145 /// Initially, the value for all variables is set to `'empty`, the
146 /// empty region. The `expansion` phase will grow this larger.
147 fn construct_var_data(&self, tcx: TyCtxt<'_, '_, 'tcx>) -> LexicalRegionResolutions<'tcx> {
148 LexicalRegionResolutions {
149 error_region: tcx.types.re_static,
150 values: IndexVec::from_elem_n(VarValue::Value(tcx.types.re_empty), self.num_vars())
154 fn dump_constraints(&self, free_regions: &RegionRelations<'_, '_, 'tcx>) {
156 "----() Start constraint listing (context={:?}) ()----",
159 for (idx, (constraint, _)) in self.data.constraints.iter().enumerate() {
160 debug!("Constraint {} => {:?}", idx, constraint);
164 fn expand_givens(&mut self, graph: &RegionGraph<'_>) {
165 // Givens are a kind of horrible hack to account for
166 // constraints like 'c <= '0 that are known to hold due to
167 // closure signatures (see the comment above on the `givens`
168 // field). They should go away. But until they do, the role
169 // of this fn is to account for the transitive nature:
175 let seeds: Vec<_> = self.data.givens.iter().cloned().collect();
176 for (r, vid) in seeds {
177 // While all things transitively reachable in the graph
178 // from the variable (`'0` in the example above).
179 let seed_index = NodeIndex(vid.index() as usize);
180 for succ_index in graph.depth_traverse(seed_index, OUTGOING) {
181 let succ_index = succ_index.0;
183 // The first N nodes correspond to the region
184 // variables. Other nodes correspond to constant
186 if succ_index < self.num_vars() {
187 let succ_vid = RegionVid::new(succ_index);
190 self.data.givens.insert((r, succ_vid));
196 fn expansion(&self, var_values: &mut LexicalRegionResolutions<'tcx>) {
197 self.iterate_until_fixed_point("Expansion", |constraint, origin| {
198 debug!("expansion: constraint={:?} origin={:?}", constraint, origin);
200 Constraint::RegSubVar(a_region, b_vid) => {
201 let b_data = var_values.value_mut(b_vid);
202 self.expand_node(a_region, b_vid, b_data)
204 Constraint::VarSubVar(a_vid, b_vid) => match *var_values.value(a_vid) {
205 VarValue::ErrorValue => false,
206 VarValue::Value(a_region) => {
207 let b_node = var_values.value_mut(b_vid);
208 self.expand_node(a_region, b_vid, b_node)
211 Constraint::RegSubReg(..) | Constraint::VarSubReg(..) => {
212 // These constraints are checked after expansion
213 // is done, in `collect_errors`.
222 a_region: Region<'tcx>,
224 b_data: &mut VarValue<'tcx>,
226 debug!("expand_node({:?}, {:?} == {:?})", a_region, b_vid, b_data);
228 // Check if this relationship is implied by a given.
230 ty::ReEarlyBound(_) | ty::ReFree(_) => if self.data.givens.contains(&(a_region, b_vid))
239 VarValue::Value(cur_region) => {
240 let lub = self.lub_concrete_regions(a_region, cur_region);
241 if lub == cur_region {
246 "Expanding value of {:?} from {:?} to {:?}",
247 b_vid, cur_region, lub
250 *b_data = VarValue::Value(lub);
254 VarValue::ErrorValue => {
260 fn lub_concrete_regions(&self, a: Region<'tcx>, b: Region<'tcx>) -> Region<'tcx> {
261 let tcx = self.tcx();
263 (&ty::ReClosureBound(..), _)
264 | (_, &ty::ReClosureBound(..))
265 | (&ReLateBound(..), _)
266 | (_, &ReLateBound(..))
268 | (_, &ReErased) => {
269 bug!("cannot relate region: LUB({:?}, {:?})", a, b);
272 (r @ &ReStatic, _) | (_, r @ &ReStatic) => {
273 r // nothing lives longer than static
276 (&ReEmpty, r) | (r, &ReEmpty) => {
277 r // everything lives longer than empty
280 (&ReVar(v_id), _) | (_, &ReVar(v_id)) => {
282 self.var_infos[v_id].origin.span(),
283 "lub_concrete_regions invoked with non-concrete \
284 regions: {:?}, {:?}",
290 (&ReEarlyBound(_), &ReScope(s_id))
291 | (&ReScope(s_id), &ReEarlyBound(_))
292 | (&ReFree(_), &ReScope(s_id))
293 | (&ReScope(s_id), &ReFree(_)) => {
294 // A "free" region can be interpreted as "some region
295 // at least as big as fr.scope". So, we can
296 // reasonably compare free regions and scopes:
297 let fr_scope = match (a, b) {
298 (&ReEarlyBound(ref br), _) | (_, &ReEarlyBound(ref br)) => self.region_rels
300 .early_free_scope(self.tcx(), br),
301 (&ReFree(ref fr), _) | (_, &ReFree(ref fr)) => self.region_rels
303 .free_scope(self.tcx(), fr),
306 let r_id = self.region_rels
308 .nearest_common_ancestor(fr_scope, s_id);
309 if r_id == fr_scope {
310 // if the free region's scope `fr.scope` is bigger than
311 // the scope region `s_id`, then the LUB is the free
314 (_, &ReScope(_)) => return a,
315 (&ReScope(_), _) => return b,
320 // otherwise, we don't know what the free region is,
321 // so we must conservatively say the LUB is static:
325 (&ReScope(a_id), &ReScope(b_id)) => {
326 // The region corresponding to an outer block is a
327 // subtype of the region corresponding to an inner
329 let lub = self.region_rels
331 .nearest_common_ancestor(a_id, b_id);
332 tcx.mk_region(ReScope(lub))
335 (&ReEarlyBound(_), &ReEarlyBound(_))
336 | (&ReFree(_), &ReEarlyBound(_))
337 | (&ReEarlyBound(_), &ReFree(_))
338 | (&ReFree(_), &ReFree(_)) => self.region_rels.lub_free_regions(a, b),
340 // For these types, we cannot define any additional
342 (&RePlaceholder(..), _) | (_, &RePlaceholder(..)) => if a == b {
350 /// After expansion is complete, go and check upper bounds (i.e.,
351 /// cases where the region cannot grow larger than a fixed point)
352 /// and check that they are satisfied.
355 var_data: &mut LexicalRegionResolutions<'tcx>,
356 errors: &mut Vec<RegionResolutionError<'tcx>>,
358 for (constraint, origin) in &self.data.constraints {
360 "collect_errors: constraint={:?} origin={:?}",
364 Constraint::RegSubVar(..) | Constraint::VarSubVar(..) => {
365 // Expansion will ensure that these constraints hold. Ignore.
368 Constraint::RegSubReg(sub, sup) => {
369 if self.region_rels.is_subregion_of(sub, sup) {
374 "collect_errors: region error at {:?}: \
375 cannot verify that {:?} <= {:?}",
379 errors.push(RegionResolutionError::ConcreteFailure(
386 Constraint::VarSubReg(a_vid, b_region) => {
387 let a_data = var_data.value_mut(a_vid);
388 debug!("contraction: {:?} == {:?}, {:?}", a_vid, a_data, b_region);
390 let a_region = match *a_data {
391 VarValue::ErrorValue => continue,
392 VarValue::Value(a_region) => a_region,
395 // Do not report these errors immediately:
396 // instead, set the variable value to error and
397 // collect them later.
398 if !self.region_rels.is_subregion_of(a_region, b_region) {
400 "collect_errors: region error at {:?}: \
401 cannot verify that {:?}={:?} <= {:?}",
402 origin, a_vid, a_region, b_region
404 *a_data = VarValue::ErrorValue;
410 for verify in &self.data.verifys {
411 debug!("collect_errors: verify={:?}", verify);
412 let sub = var_data.normalize(self.tcx(), verify.region);
414 // This was an inference variable which didn't get
415 // constrained, therefore it can be assume to hold.
416 if let ty::ReEmpty = *sub {
420 let verify_kind_ty = verify.kind.to_ty(self.tcx());
421 if self.bound_is_met(&verify.bound, var_data, verify_kind_ty, sub) {
426 "collect_errors: region error at {:?}: \
427 cannot verify that {:?} <= {:?}",
428 verify.origin, verify.region, verify.bound
431 errors.push(RegionResolutionError::GenericBoundFailure(
432 verify.origin.clone(),
439 /// Go over the variables that were declared to be error variables
440 /// and create a `RegionResolutionError` for each of them.
441 fn collect_var_errors(
443 var_data: &LexicalRegionResolutions<'tcx>,
444 graph: &RegionGraph<'tcx>,
445 errors: &mut Vec<RegionResolutionError<'tcx>>,
447 debug!("collect_var_errors");
449 // This is the best way that I have found to suppress
450 // duplicate and related errors. Basically we keep a set of
451 // flags for every node. Whenever an error occurs, we will
452 // walk some portion of the graph looking to find pairs of
453 // conflicting regions to report to the user. As we walk, we
454 // trip the flags from false to true, and if we find that
455 // we've already reported an error involving any particular
456 // node we just stop and don't report the current error. The
457 // idea is to report errors that derive from independent
458 // regions of the graph, but not those that derive from
459 // overlapping locations.
460 let mut dup_vec = vec![u32::MAX; self.num_vars()];
462 for (node_vid, value) in var_data.values.iter_enumerated() {
464 VarValue::Value(_) => { /* Inference successful */ }
465 VarValue::ErrorValue => {
466 /* Inference impossible, this value contains
467 inconsistent constraints.
469 I think that in this case we should report an
470 error now---unlike the case above, we can't
471 wait to see whether the user needs the result
472 of this variable. The reason is that the mere
473 existence of this variable implies that the
474 region graph is inconsistent, whether or not it
477 For example, we may have created a region
478 variable that is the GLB of two other regions
479 which do not have a GLB. Even if that variable
480 is not used, it implies that those two regions
483 At least I think this is true. It may be that
484 the mere existence of a conflict in a region variable
485 that is not used is not a problem, so if this rule
486 starts to create problems we'll have to revisit
487 this portion of the code and think hard about it. =) */
488 self.collect_error_for_expanding_node(graph, &mut dup_vec, node_vid, errors);
494 fn construct_graph(&self) -> RegionGraph<'tcx> {
495 let num_vars = self.num_vars();
497 let mut graph = Graph::new();
499 for _ in 0..num_vars {
503 // Issue #30438: two distinct dummy nodes, one for incoming
504 // edges (dummy_source) and another for outgoing edges
505 // (dummy_sink). In `dummy -> a -> b -> dummy`, using one
506 // dummy node leads one to think (erroneously) there exists a
507 // path from `b` to `a`. Two dummy nodes sidesteps the issue.
508 let dummy_source = graph.add_node(());
509 let dummy_sink = graph.add_node(());
511 for (constraint, _) in &self.data.constraints {
513 Constraint::VarSubVar(a_id, b_id) => {
515 NodeIndex(a_id.index() as usize),
516 NodeIndex(b_id.index() as usize),
520 Constraint::RegSubVar(_, b_id) => {
521 graph.add_edge(dummy_source, NodeIndex(b_id.index() as usize), *constraint);
523 Constraint::VarSubReg(a_id, _) => {
524 graph.add_edge(NodeIndex(a_id.index() as usize), dummy_sink, *constraint);
526 Constraint::RegSubReg(..) => {
527 // this would be an edge from `dummy_source` to
528 // `dummy_sink`; just ignore it.
536 fn collect_error_for_expanding_node(
538 graph: &RegionGraph<'tcx>,
541 errors: &mut Vec<RegionResolutionError<'tcx>>,
543 // Errors in expanding nodes result from a lower-bound that is
544 // not contained by an upper-bound.
545 let (mut lower_bounds, lower_dup) =
546 self.collect_concrete_regions(graph, node_idx, INCOMING, dup_vec);
547 let (mut upper_bounds, upper_dup) =
548 self.collect_concrete_regions(graph, node_idx, OUTGOING, dup_vec);
550 if lower_dup || upper_dup {
554 // We place free regions first because we are special casing
555 // SubSupConflict(ReFree, ReFree) when reporting error, and so
556 // the user will more likely get a specific suggestion.
557 fn region_order_key(x: &RegionAndOrigin<'_>) -> u8 {
559 ReEarlyBound(_) => 0,
564 lower_bounds.sort_by_key(region_order_key);
565 upper_bounds.sort_by_key(region_order_key);
567 for lower_bound in &lower_bounds {
568 for upper_bound in &upper_bounds {
570 .is_subregion_of(lower_bound.region, upper_bound.region)
572 let origin = self.var_infos[node_idx].origin.clone();
574 "region inference error at {:?} for {:?}: SubSupConflict sub: {:?} \
576 origin, node_idx, lower_bound.region, upper_bound.region
578 errors.push(RegionResolutionError::SubSupConflict(
580 lower_bound.origin.clone(),
582 upper_bound.origin.clone(),
591 self.var_infos[node_idx].origin.span(),
592 "collect_error_for_expanding_node() could not find \
593 error for var {:?}, lower_bounds={:?}, \
601 fn collect_concrete_regions(
603 graph: &RegionGraph<'tcx>,
604 orig_node_idx: RegionVid,
607 ) -> (Vec<RegionAndOrigin<'tcx>>, bool) {
608 struct WalkState<'tcx> {
609 set: FxHashSet<RegionVid>,
610 stack: Vec<RegionVid>,
611 result: Vec<RegionAndOrigin<'tcx>>,
614 let mut state = WalkState {
615 set: Default::default(),
616 stack: vec![orig_node_idx],
620 state.set.insert(orig_node_idx);
622 // to start off the process, walk the source node in the
623 // direction specified
624 process_edges(&self.data, &mut state, graph, orig_node_idx, dir);
626 while !state.stack.is_empty() {
627 let node_idx = state.stack.pop().unwrap();
629 // check whether we've visited this node on some previous walk
630 if dup_vec[node_idx.index() as usize] == u32::MAX {
631 dup_vec[node_idx.index() as usize] = orig_node_idx.index() as u32;
632 } else if dup_vec[node_idx.index() as usize] != orig_node_idx.index() as u32 {
633 state.dup_found = true;
637 "collect_concrete_regions(orig_node_idx={:?}, node_idx={:?})",
638 orig_node_idx, node_idx
641 process_edges(&self.data, &mut state, graph, node_idx, dir);
645 result, dup_found, ..
647 return (result, dup_found);
649 fn process_edges<'tcx>(
650 this: &RegionConstraintData<'tcx>,
651 state: &mut WalkState<'tcx>,
652 graph: &RegionGraph<'tcx>,
653 source_vid: RegionVid,
656 debug!("process_edges(source_vid={:?}, dir={:?})", source_vid, dir);
658 let source_node_index = NodeIndex(source_vid.index() as usize);
659 for (_, edge) in graph.adjacent_edges(source_node_index, dir) {
661 Constraint::VarSubVar(from_vid, to_vid) => {
662 let opp_vid = if from_vid == source_vid {
667 if state.set.insert(opp_vid) {
668 state.stack.push(opp_vid);
672 Constraint::RegSubVar(region, _) | Constraint::VarSubReg(_, region) => {
673 state.result.push(RegionAndOrigin {
675 origin: this.constraints.get(&edge.data).unwrap().clone(),
679 Constraint::RegSubReg(..) => panic!(
680 "cannot reach reg-sub-reg edge in region inference \
688 fn iterate_until_fixed_point<F>(&self, tag: &str, mut body: F)
690 F: FnMut(&Constraint<'tcx>, &SubregionOrigin<'tcx>) -> bool,
692 let mut iteration = 0;
693 let mut changed = true;
697 debug!("---- {} Iteration {}{}", "#", tag, iteration);
698 for (constraint, origin) in &self.data.constraints {
699 let edge_changed = body(constraint, origin);
701 debug!("Updated due to constraint {:?}", constraint);
706 debug!("---- {} Complete after {} iteration(s)", tag, iteration);
711 bound: &VerifyBound<'tcx>,
712 var_values: &LexicalRegionResolutions<'tcx>,
713 generic_ty: Ty<'tcx>,
714 min: ty::Region<'tcx>,
717 VerifyBound::IfEq(k, b) => {
718 (var_values.normalize(self.region_rels.tcx, *k) == generic_ty)
719 && self.bound_is_met(b, var_values, generic_ty, min)
722 VerifyBound::OutlivedBy(r) =>
723 self.region_rels.is_subregion_of(
725 var_values.normalize(self.tcx(), r),
728 VerifyBound::AnyBound(bs) => bs.iter()
729 .any(|b| self.bound_is_met(b, var_values, generic_ty, min)),
731 VerifyBound::AllBounds(bs) => bs.iter()
732 .all(|b| self.bound_is_met(b, var_values, generic_ty, min)),
737 impl<'tcx> fmt::Debug for RegionAndOrigin<'tcx> {
738 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
739 write!(f, "RegionAndOrigin({:?},{:?})", self.region, self.origin)
743 impl<'tcx> LexicalRegionResolutions<'tcx> {
744 fn normalize<T>(&self, tcx: TyCtxt<'_, '_, 'tcx>, value: T) -> T
746 T: TypeFoldable<'tcx>,
748 tcx.fold_regions(&value, &mut false, |r, _db| match r {
749 ty::ReVar(rid) => self.resolve_var(*rid),
754 fn value(&self, rid: RegionVid) -> &VarValue<'tcx> {
758 fn value_mut(&mut self, rid: RegionVid) -> &mut VarValue<'tcx> {
759 &mut self.values[rid]
762 pub fn resolve_var(&self, rid: RegionVid) -> ty::Region<'tcx> {
763 let result = match self.values[rid] {
764 VarValue::Value(r) => r,
765 VarValue::ErrorValue => self.error_region,
767 debug!("resolve_var({:?}) = {:?}", rid, result);