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::SubregionOrigin;
14 use infer::RegionVariableOrigin;
15 use infer::region_constraints::Constraint;
16 use infer::region_constraints::GenericKind;
17 use infer::region_constraints::RegionConstraintData;
18 use infer::region_constraints::VarInfos;
19 use infer::region_constraints::VerifyBound;
20 use middle::free_region::RegionRelations;
21 use rustc_data_structures::indexed_vec::{Idx, IndexVec};
22 use rustc_data_structures::fx::FxHashSet;
23 use rustc_data_structures::control_flow_graph::implementation::{Graph, Direction, NodeIndex, INCOMING, OUTGOING};
26 use ty::{self, TyCtxt};
27 use ty::{Region, RegionVid};
28 use ty::{ReEarlyBound, ReEmpty, ReErased, ReFree, ReStatic};
29 use ty::{ReLateBound, ReScope, ReSkolemized, ReVar};
33 /// This function performs lexical region resolution given a complete
34 /// set of constraints and variable origins. It performs a fixed-point
35 /// iteration to find region values which satisfy all constraints,
36 /// assuming such values can be found. It returns the final values of
37 /// all the variables as well as a set of errors that must be reported.
39 region_rels: &RegionRelations<'_, '_, 'tcx>,
41 data: RegionConstraintData<'tcx>,
43 LexicalRegionResolutions<'tcx>,
44 Vec<RegionResolutionError<'tcx>>,
46 debug!("RegionConstraintData: resolve_regions()");
47 let mut errors = vec![];
48 let mut resolver = LexicalResolver {
53 let values = resolver.infer_variable_values(&mut errors);
57 /// Contains the result of lexical region resolution. Offers methods
58 /// to lookup up the final value of a region variable.
59 pub struct LexicalRegionResolutions<'tcx> {
60 values: IndexVec<RegionVid, VarValue<'tcx>>,
61 error_region: ty::Region<'tcx>,
64 #[derive(Copy, Clone, Debug)]
70 #[derive(Clone, Debug)]
71 pub enum RegionResolutionError<'tcx> {
72 /// `ConcreteFailure(o, a, b)`:
74 /// `o` requires that `a <= b`, but this does not hold
75 ConcreteFailure(SubregionOrigin<'tcx>, Region<'tcx>, Region<'tcx>),
77 /// `GenericBoundFailure(p, s, a)
79 /// The parameter/associated-type `p` must be known to outlive the lifetime
80 /// `a` (but none of the known bounds are sufficient).
81 GenericBoundFailure(SubregionOrigin<'tcx>, GenericKind<'tcx>, Region<'tcx>),
83 /// `SubSupConflict(v, sub_origin, sub_r, sup_origin, sup_r)`:
85 /// Could not infer a value for `v` because `sub_r <= v` (due to
86 /// `sub_origin`) but `v <= sup_r` (due to `sup_origin`) and
87 /// `sub_r <= sup_r` does not hold.
90 SubregionOrigin<'tcx>,
92 SubregionOrigin<'tcx>,
97 struct RegionAndOrigin<'tcx> {
99 origin: SubregionOrigin<'tcx>,
102 type RegionGraph<'tcx> = Graph<(), Constraint<'tcx>>;
104 struct LexicalResolver<'cx, 'gcx: 'tcx, 'tcx: 'cx> {
105 region_rels: &'cx RegionRelations<'cx, 'gcx, 'tcx>,
107 data: RegionConstraintData<'tcx>,
110 impl<'cx, 'gcx, 'tcx> LexicalResolver<'cx, 'gcx, 'tcx> {
111 fn infer_variable_values(
113 errors: &mut Vec<RegionResolutionError<'tcx>>,
114 ) -> LexicalRegionResolutions<'tcx> {
115 let mut var_data = self.construct_var_data(self.region_rels.tcx);
117 // Dorky hack to cause `dump_constraints` to only get called
118 // if debug mode is enabled:
120 "----() End constraint listing (context={:?}) {:?}---",
121 self.region_rels.context,
122 self.dump_constraints(self.region_rels)
124 graphviz::maybe_print_constraints_for(&self.data, self.region_rels);
126 let graph = self.construct_graph();
127 self.expand_givens(&graph);
128 self.expansion(&mut var_data);
129 self.collect_errors(&mut var_data, errors);
130 self.collect_var_errors(&var_data, &graph, errors);
134 fn num_vars(&self) -> usize {
138 /// Initially, the value for all variables is set to `'empty`, the
139 /// empty region. The `expansion` phase will grow this larger.
140 fn construct_var_data(&self, tcx: TyCtxt<'_, '_, 'tcx>) -> LexicalRegionResolutions<'tcx> {
141 LexicalRegionResolutions {
142 error_region: tcx.types.re_static,
143 values: (0..self.num_vars())
144 .map(|_| VarValue::Value(tcx.types.re_empty))
149 fn dump_constraints(&self, free_regions: &RegionRelations<'_, '_, 'tcx>) {
151 "----() Start constraint listing (context={:?}) ()----",
154 for (idx, (constraint, _)) in self.data.constraints.iter().enumerate() {
155 debug!("Constraint {} => {:?}", idx, constraint);
159 fn expand_givens(&mut self, graph: &RegionGraph) {
160 // Givens are a kind of horrible hack to account for
161 // constraints like 'c <= '0 that are known to hold due to
162 // closure signatures (see the comment above on the `givens`
163 // field). They should go away. But until they do, the role
164 // of this fn is to account for the transitive nature:
170 let seeds: Vec<_> = self.data.givens.iter().cloned().collect();
171 for (r, vid) in seeds {
172 // While all things transitively reachable in the graph
173 // from the variable (`'0` in the example above).
174 let seed_index = NodeIndex(vid.index() as usize);
175 for succ_index in graph.depth_traverse(seed_index, OUTGOING) {
176 let succ_index = succ_index.0;
178 // The first N nodes correspond to the region
179 // variables. Other nodes correspond to constant
181 if succ_index < self.num_vars() {
182 let succ_vid = RegionVid::new(succ_index);
185 self.data.givens.insert((r, succ_vid));
191 fn expansion(&self, var_values: &mut LexicalRegionResolutions<'tcx>) {
192 self.iterate_until_fixed_point("Expansion", |constraint, origin| {
193 debug!("expansion: constraint={:?} origin={:?}", constraint, origin);
195 Constraint::RegSubVar(a_region, b_vid) => {
196 let b_data = var_values.value_mut(b_vid);
197 self.expand_node(a_region, b_vid, b_data)
199 Constraint::VarSubVar(a_vid, b_vid) => match *var_values.value(a_vid) {
200 VarValue::ErrorValue => false,
201 VarValue::Value(a_region) => {
202 let b_node = var_values.value_mut(b_vid);
203 self.expand_node(a_region, b_vid, b_node)
206 Constraint::RegSubReg(..) | Constraint::VarSubReg(..) => {
207 // These constraints are checked after expansion
208 // is done, in `collect_errors`.
217 a_region: Region<'tcx>,
219 b_data: &mut VarValue<'tcx>,
221 debug!("expand_node({:?}, {:?} == {:?})", a_region, b_vid, b_data);
223 // Check if this relationship is implied by a given.
225 ty::ReEarlyBound(_) | ty::ReFree(_) => if self.data.givens.contains(&(a_region, b_vid))
234 VarValue::Value(cur_region) => {
235 let lub = self.lub_concrete_regions(a_region, cur_region);
236 if lub == cur_region {
241 "Expanding value of {:?} from {:?} to {:?}",
247 *b_data = VarValue::Value(lub);
251 VarValue::ErrorValue => {
258 fn lub_concrete_regions(&self, a: Region<'tcx>, b: Region<'tcx>) -> Region<'tcx> {
259 let tcx = self.region_rels.tcx;
261 (&ty::ReCanonical(..), _) |
262 (_, &ty::ReCanonical(..)) |
263 (&ty::ReClosureBound(..), _) |
264 (_, &ty::ReClosureBound(..)) |
265 (&ReLateBound(..), _) |
266 (_, &ReLateBound(..)) |
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.region_rels.tcx, br),
301 (&ReFree(ref fr), _) | (_, &ReFree(ref fr)) => self.region_rels
303 .free_scope(self.region_rels.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 (&ReSkolemized(..), _) | (_, &ReSkolemized(..)) => 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={:?}",
365 Constraint::RegSubVar(..) | Constraint::VarSubVar(..) => {
366 // Expansion will ensure that these constraints hold. Ignore.
369 Constraint::RegSubReg(sub, sup) => {
370 if self.region_rels.is_subregion_of(sub, sup) {
375 "collect_errors: region error at {:?}: \
376 cannot verify that {:?} <= {:?}",
382 errors.push(RegionResolutionError::ConcreteFailure(
389 Constraint::VarSubReg(a_vid, b_region) => {
390 let a_data = var_data.value_mut(a_vid);
391 debug!("contraction: {:?} == {:?}, {:?}", a_vid, a_data, b_region);
393 let a_region = match *a_data {
394 VarValue::ErrorValue => continue,
395 VarValue::Value(a_region) => a_region,
398 // Do not report these errors immediately:
399 // instead, set the variable value to error and
400 // collect them later.
401 if !self.region_rels.is_subregion_of(a_region, b_region) {
403 "collect_errors: region error at {:?}: \
404 cannot verify that {:?}={:?} <= {:?}",
410 *a_data = VarValue::ErrorValue;
416 for verify in &self.data.verifys {
417 debug!("collect_errors: verify={:?}", verify);
418 let sub = var_data.normalize(verify.region);
420 // This was an inference variable which didn't get
421 // constrained, therefore it can be assume to hold.
422 if let ty::ReEmpty = *sub {
426 if self.bound_is_met(&verify.bound, var_data, sub) {
431 "collect_errors: region error at {:?}: \
432 cannot verify that {:?} <= {:?}",
438 errors.push(RegionResolutionError::GenericBoundFailure(
439 verify.origin.clone(),
446 /// Go over the variables that were declared to be error variables
447 /// and create a `RegionResolutionError` for each of them.
448 fn collect_var_errors(
450 var_data: &LexicalRegionResolutions<'tcx>,
451 graph: &RegionGraph<'tcx>,
452 errors: &mut Vec<RegionResolutionError<'tcx>>,
454 debug!("collect_var_errors");
456 // This is the best way that I have found to suppress
457 // duplicate and related errors. Basically we keep a set of
458 // flags for every node. Whenever an error occurs, we will
459 // walk some portion of the graph looking to find pairs of
460 // conflicting regions to report to the user. As we walk, we
461 // trip the flags from false to true, and if we find that
462 // we've already reported an error involving any particular
463 // node we just stop and don't report the current error. The
464 // idea is to report errors that derive from independent
465 // regions of the graph, but not those that derive from
466 // overlapping locations.
467 let mut dup_vec = vec![u32::MAX; self.num_vars()];
469 for (node_vid, value) in var_data.values.iter_enumerated() {
471 VarValue::Value(_) => { /* Inference successful */ }
472 VarValue::ErrorValue => {
473 /* Inference impossible, this value contains
474 inconsistent constraints.
476 I think that in this case we should report an
477 error now---unlike the case above, we can't
478 wait to see whether the user needs the result
479 of this variable. The reason is that the mere
480 existence of this variable implies that the
481 region graph is inconsistent, whether or not it
484 For example, we may have created a region
485 variable that is the GLB of two other regions
486 which do not have a GLB. Even if that variable
487 is not used, it implies that those two regions
490 At least I think this is true. It may be that
491 the mere existence of a conflict in a region variable
492 that is not used is not a problem, so if this rule
493 starts to create problems we'll have to revisit
494 this portion of the code and think hard about it. =) */
495 self.collect_error_for_expanding_node(graph, &mut dup_vec, node_vid, errors);
501 fn construct_graph(&self) -> RegionGraph<'tcx> {
502 let num_vars = self.num_vars();
504 let mut graph = Graph::new();
506 for _ in 0..num_vars {
510 // Issue #30438: two distinct dummy nodes, one for incoming
511 // edges (dummy_source) and another for outgoing edges
512 // (dummy_sink). In `dummy -> a -> b -> dummy`, using one
513 // dummy node leads one to think (erroneously) there exists a
514 // path from `b` to `a`. Two dummy nodes sidesteps the issue.
515 let dummy_source = graph.add_node(());
516 let dummy_sink = graph.add_node(());
518 for (constraint, _) in &self.data.constraints {
520 Constraint::VarSubVar(a_id, b_id) => {
522 NodeIndex(a_id.index() as usize),
523 NodeIndex(b_id.index() as usize),
527 Constraint::RegSubVar(_, b_id) => {
528 graph.add_edge(dummy_source, NodeIndex(b_id.index() as usize), *constraint);
530 Constraint::VarSubReg(a_id, _) => {
531 graph.add_edge(NodeIndex(a_id.index() as usize), dummy_sink, *constraint);
533 Constraint::RegSubReg(..) => {
534 // this would be an edge from `dummy_source` to
535 // `dummy_sink`; just ignore it.
543 fn collect_error_for_expanding_node(
545 graph: &RegionGraph<'tcx>,
548 errors: &mut Vec<RegionResolutionError<'tcx>>,
550 // Errors in expanding nodes result from a lower-bound that is
551 // not contained by an upper-bound.
552 let (mut lower_bounds, lower_dup) =
553 self.collect_concrete_regions(graph, node_idx, INCOMING, dup_vec);
554 let (mut upper_bounds, upper_dup) =
555 self.collect_concrete_regions(graph, node_idx, OUTGOING, dup_vec);
557 if lower_dup || upper_dup {
561 // We place free regions first because we are special casing
562 // SubSupConflict(ReFree, ReFree) when reporting error, and so
563 // the user will more likely get a specific suggestion.
564 fn region_order_key(x: &RegionAndOrigin) -> u8 {
566 ReEarlyBound(_) => 0,
571 lower_bounds.sort_by_key(region_order_key);
572 upper_bounds.sort_by_key(region_order_key);
574 for lower_bound in &lower_bounds {
575 for upper_bound in &upper_bounds {
577 .is_subregion_of(lower_bound.region, upper_bound.region)
579 let origin = self.var_infos[node_idx].origin.clone();
581 "region inference error at {:?} for {:?}: SubSupConflict sub: {:?} \
588 errors.push(RegionResolutionError::SubSupConflict(
590 lower_bound.origin.clone(),
592 upper_bound.origin.clone(),
601 self.var_infos[node_idx].origin.span(),
602 "collect_error_for_expanding_node() could not find \
603 error for var {:?}, lower_bounds={:?}, \
611 fn collect_concrete_regions(
613 graph: &RegionGraph<'tcx>,
614 orig_node_idx: RegionVid,
617 ) -> (Vec<RegionAndOrigin<'tcx>>, bool) {
618 struct WalkState<'tcx> {
619 set: FxHashSet<RegionVid>,
620 stack: Vec<RegionVid>,
621 result: Vec<RegionAndOrigin<'tcx>>,
624 let mut state = WalkState {
626 stack: vec![orig_node_idx],
630 state.set.insert(orig_node_idx);
632 // to start off the process, walk the source node in the
633 // direction specified
634 process_edges(&self.data, &mut state, graph, orig_node_idx, dir);
636 while !state.stack.is_empty() {
637 let node_idx = state.stack.pop().unwrap();
639 // check whether we've visited this node on some previous walk
640 if dup_vec[node_idx.index() as usize] == u32::MAX {
641 dup_vec[node_idx.index() as usize] = orig_node_idx.index() as u32;
642 } else if dup_vec[node_idx.index() as usize] != orig_node_idx.index() as u32 {
643 state.dup_found = true;
647 "collect_concrete_regions(orig_node_idx={:?}, node_idx={:?})",
652 process_edges(&self.data, &mut state, graph, node_idx, dir);
656 result, dup_found, ..
658 return (result, dup_found);
660 fn process_edges<'tcx>(
661 this: &RegionConstraintData<'tcx>,
662 state: &mut WalkState<'tcx>,
663 graph: &RegionGraph<'tcx>,
664 source_vid: RegionVid,
667 debug!("process_edges(source_vid={:?}, dir={:?})", source_vid, dir);
669 let source_node_index = NodeIndex(source_vid.index() as usize);
670 for (_, edge) in graph.adjacent_edges(source_node_index, dir) {
672 Constraint::VarSubVar(from_vid, to_vid) => {
673 let opp_vid = if from_vid == source_vid {
678 if state.set.insert(opp_vid) {
679 state.stack.push(opp_vid);
683 Constraint::RegSubVar(region, _) | Constraint::VarSubReg(_, region) => {
684 state.result.push(RegionAndOrigin {
686 origin: this.constraints.get(&edge.data).unwrap().clone(),
690 Constraint::RegSubReg(..) => panic!(
691 "cannot reach reg-sub-reg edge in region inference \
699 fn iterate_until_fixed_point<F>(&self, tag: &str, mut body: F)
701 F: FnMut(&Constraint<'tcx>, &SubregionOrigin<'tcx>) -> bool,
703 let mut iteration = 0;
704 let mut changed = true;
708 debug!("---- {} Iteration {}{}", "#", tag, iteration);
709 for (constraint, origin) in &self.data.constraints {
710 let edge_changed = body(constraint, origin);
712 debug!("Updated due to constraint {:?}", constraint);
717 debug!("---- {} Complete after {} iteration(s)", tag, iteration);
722 bound: &VerifyBound<'tcx>,
723 var_values: &LexicalRegionResolutions<'tcx>,
724 min: ty::Region<'tcx>,
727 VerifyBound::AnyRegion(rs) => rs.iter()
728 .map(|&r| var_values.normalize(r))
729 .any(|r| self.region_rels.is_subregion_of(min, r)),
731 VerifyBound::AllRegions(rs) => rs.iter()
732 .map(|&r| var_values.normalize(r))
733 .all(|r| self.region_rels.is_subregion_of(min, r)),
735 VerifyBound::AnyBound(bs) => bs.iter().any(|b| self.bound_is_met(b, var_values, min)),
737 VerifyBound::AllBounds(bs) => bs.iter().all(|b| self.bound_is_met(b, var_values, min)),
742 impl<'tcx> fmt::Debug for RegionAndOrigin<'tcx> {
743 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
744 write!(f, "RegionAndOrigin({:?},{:?})", self.region, self.origin)
749 impl<'tcx> LexicalRegionResolutions<'tcx> {
750 fn normalize(&self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
752 ty::ReVar(rid) => self.resolve_var(rid),
757 fn value(&self, rid: RegionVid) -> &VarValue<'tcx> {
761 fn value_mut(&mut self, rid: RegionVid) -> &mut VarValue<'tcx> {
762 &mut self.values[rid]
765 pub fn resolve_var(&self, rid: RegionVid) -> ty::Region<'tcx> {
766 let result = match self.values[rid] {
767 VarValue::Value(r) => r,
768 VarValue::ErrorValue => self.error_region,
770 debug!("resolve_var({:?}) = {:?}", rid, result);