1 //! Lexical region resolution.
3 use crate::hir::def_id::DefId;
4 use crate::infer::region_constraints::Constraint;
5 use crate::infer::region_constraints::GenericKind;
6 use crate::infer::region_constraints::MemberConstraint;
7 use crate::infer::region_constraints::RegionConstraintData;
8 use crate::infer::region_constraints::VarInfos;
9 use crate::infer::region_constraints::VerifyBound;
10 use crate::infer::RegionVariableOrigin;
11 use crate::infer::SubregionOrigin;
12 use crate::middle::free_region::RegionRelations;
13 use crate::ty::fold::TypeFoldable;
14 use crate::ty::{self, Ty, TyCtxt};
15 use crate::ty::{ReEarlyBound, ReEmpty, ReErased, ReFree, ReStatic};
16 use crate::ty::{ReLateBound, RePlaceholder, ReScope, ReVar};
17 use crate::ty::{Region, RegionVid};
18 use rustc_data_structures::fx::FxHashSet;
19 use rustc_data_structures::graph::implementation::{
20 Direction, Graph, NodeIndex, INCOMING, OUTGOING,
22 use rustc_index::vec::{Idx, IndexVec};
23 use smallvec::SmallVec;
29 /// This function performs lexical region resolution given a complete
30 /// set of constraints and variable origins. It performs a fixed-point
31 /// iteration to find region values which satisfy all constraints,
32 /// assuming such values can be found. It returns the final values of
33 /// all the variables as well as a set of errors that must be reported.
35 region_rels: &RegionRelations<'_, 'tcx>,
37 data: RegionConstraintData<'tcx>,
38 ) -> (LexicalRegionResolutions<'tcx>, Vec<RegionResolutionError<'tcx>>) {
39 debug!("RegionConstraintData: resolve_regions()");
40 let mut errors = vec![];
41 let mut resolver = LexicalResolver { region_rels, var_infos, data };
42 let values = resolver.infer_variable_values(&mut errors);
46 /// Contains the result of lexical region resolution. Offers methods
47 /// to lookup up the final value of a region variable.
48 pub struct LexicalRegionResolutions<'tcx> {
49 values: IndexVec<RegionVid, VarValue<'tcx>>,
50 error_region: ty::Region<'tcx>,
53 #[derive(Copy, Clone, Debug)]
59 #[derive(Clone, Debug)]
60 pub enum RegionResolutionError<'tcx> {
61 /// `ConcreteFailure(o, a, b)`:
63 /// `o` requires that `a <= b`, but this does not hold
64 ConcreteFailure(SubregionOrigin<'tcx>, Region<'tcx>, Region<'tcx>),
66 /// `GenericBoundFailure(p, s, a)
68 /// The parameter/associated-type `p` must be known to outlive the lifetime
69 /// `a` (but none of the known bounds are sufficient).
70 GenericBoundFailure(SubregionOrigin<'tcx>, GenericKind<'tcx>, Region<'tcx>),
72 /// `SubSupConflict(v, v_origin, sub_origin, sub_r, sup_origin, sup_r)`:
74 /// Could not infer a value for `v` (which has origin `v_origin`)
75 /// because `sub_r <= v` (due to `sub_origin`) but `v <= sup_r` (due to `sup_origin`) and
76 /// `sub_r <= sup_r` does not hold.
80 SubregionOrigin<'tcx>,
82 SubregionOrigin<'tcx>,
86 /// Indicates a failure of a `MemberConstraint`. These arise during
87 /// impl trait processing explicitly -- basically, the impl trait's hidden type
88 /// included some region that it was not supposed to.
89 MemberConstraintFailure {
91 opaque_type_def_id: DefId,
93 member_region: Region<'tcx>,
94 choice_regions: Vec<Region<'tcx>>,
98 struct RegionAndOrigin<'tcx> {
100 origin: SubregionOrigin<'tcx>,
103 type RegionGraph<'tcx> = Graph<(), Constraint<'tcx>>;
105 struct LexicalResolver<'cx, 'tcx> {
106 region_rels: &'cx RegionRelations<'cx, 'tcx>,
108 data: RegionConstraintData<'tcx>,
111 impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> {
112 fn tcx(&self) -> TyCtxt<'tcx> {
116 fn infer_variable_values(
118 errors: &mut Vec<RegionResolutionError<'tcx>>,
119 ) -> LexicalRegionResolutions<'tcx> {
120 let mut var_data = self.construct_var_data(self.tcx());
122 // Dorky hack to cause `dump_constraints` to only get called
123 // if debug mode is enabled:
125 "----() End constraint listing (context={:?}) {:?}---",
126 self.region_rels.context,
127 self.dump_constraints(self.region_rels)
129 graphviz::maybe_print_constraints_for(&self.data, self.region_rels);
131 let graph = self.construct_graph();
132 self.expand_givens(&graph);
134 self.expansion(&mut var_data);
135 if !self.enforce_member_constraints(&graph, &mut var_data) {
139 self.collect_errors(&mut var_data, errors);
140 self.collect_var_errors(&var_data, &graph, errors);
144 fn num_vars(&self) -> usize {
148 /// Initially, the value for all variables is set to `'empty`, the
149 /// empty region. The `expansion` phase will grow this larger.
150 fn construct_var_data(&self, tcx: TyCtxt<'tcx>) -> LexicalRegionResolutions<'tcx> {
151 LexicalRegionResolutions {
152 error_region: tcx.lifetimes.re_static,
153 values: IndexVec::from_elem_n(VarValue::Value(tcx.lifetimes.re_empty), self.num_vars()),
157 fn dump_constraints(&self, free_regions: &RegionRelations<'_, 'tcx>) {
159 "----() Start constraint listing (context={:?}) ()----",
162 for (idx, (constraint, _)) in self.data.constraints.iter().enumerate() {
163 debug!("Constraint {} => {:?}", idx, constraint);
167 fn expand_givens(&mut self, graph: &RegionGraph<'_>) {
168 // Givens are a kind of horrible hack to account for
169 // constraints like 'c <= '0 that are known to hold due to
170 // closure signatures (see the comment above on the `givens`
171 // field). They should go away. But until they do, the role
172 // of this fn is to account for the transitive nature:
178 let seeds: Vec<_> = self.data.givens.iter().cloned().collect();
179 for (r, vid) in seeds {
180 // While all things transitively reachable in the graph
181 // from the variable (`'0` in the example above).
182 let seed_index = NodeIndex(vid.index() as usize);
183 for succ_index in graph.depth_traverse(seed_index, OUTGOING) {
184 let succ_index = succ_index.0;
186 // The first N nodes correspond to the region
187 // variables. Other nodes correspond to constant
189 if succ_index < self.num_vars() {
190 let succ_vid = RegionVid::new(succ_index);
193 self.data.givens.insert((r, succ_vid));
199 /// Enforce all member constraints and return true if anything
200 /// changed. See `enforce_member_constraint` for more details.
201 fn enforce_member_constraints(
203 graph: &RegionGraph<'tcx>,
204 var_values: &mut LexicalRegionResolutions<'tcx>,
206 // Note: we don't use the `any` combinator because we don't
207 // want to stop at the first constraint that makes a change.
208 let mut any_changed = false;
209 for member_constraint in &self.data.member_constraints {
210 if self.enforce_member_constraint(graph, member_constraint, var_values) {
217 /// Enforce a constraint like
220 /// 'r member of ['c...]
223 /// We look for all choice regions from the list `'c...` that:
225 /// (a) are greater than the current value of `'r` (which is a lower bound)
229 /// (b) are compatible with the upper bounds of `'r` that we can
230 /// find by traversing the graph.
232 /// From that list, we look for a *minimal* option `'c_min`. If we
233 /// find one, then we can enforce that `'r: 'c_min`.
234 fn enforce_member_constraint(
236 graph: &RegionGraph<'tcx>,
237 member_constraint: &MemberConstraint<'tcx>,
238 var_values: &mut LexicalRegionResolutions<'tcx>,
240 debug!("enforce_member_constraint(member_constraint={:#?})", member_constraint);
242 // The constraint is some inference variable (`vid`) which
243 // must be equal to one of the options.
244 let member_vid = match member_constraint.member_region {
245 ty::ReVar(vid) => *vid,
249 // The current value of `vid` is a lower bound LB -- i.e., we
250 // know that `LB <= vid` must be true.
251 let member_lower_bound: ty::Region<'tcx> = match var_values.value(member_vid) {
252 VarValue::ErrorValue => return false,
253 VarValue::Value(r) => r,
256 // Find all the "upper bounds" -- that is, each region `b` such that
257 // `r0 <= b` must hold.
258 let (member_upper_bounds, _) = self.collect_concrete_regions(
265 // Get an iterator over the *available choice* -- that is,
266 // each choice region `c` where `lb <= c` and `c <= ub` for all the
267 // upper bounds `ub`.
268 debug!("enforce_member_constraint: upper_bounds={:#?}", member_upper_bounds);
269 let mut options = member_constraint.choice_regions.iter().filter(|option| {
270 self.sub_concrete_regions(member_lower_bound, option)
271 && member_upper_bounds
273 .all(|upper_bound| self.sub_concrete_regions(option, upper_bound.region))
276 // If there is more than one option, we only make a choice if
277 // there is a single *least* choice -- i.e., some available
278 // region that is `<=` all the others.
279 let mut least_choice: ty::Region<'tcx> = match options.next() {
281 None => return false,
283 debug!("enforce_member_constraint: least_choice={:?}", least_choice);
284 for &option in options {
285 debug!("enforce_member_constraint: option={:?}", option);
286 if !self.sub_concrete_regions(least_choice, option) {
287 if self.sub_concrete_regions(option, least_choice) {
288 debug!("enforce_member_constraint: new least choice");
289 least_choice = option;
291 debug!("enforce_member_constraint: no least choice");
297 debug!("enforce_member_constraint: final least choice = {:?}", least_choice);
298 if least_choice != member_lower_bound {
299 *var_values.value_mut(member_vid) = VarValue::Value(least_choice);
306 fn expansion(&self, var_values: &mut LexicalRegionResolutions<'tcx>) {
307 self.iterate_until_fixed_point("Expansion", |constraint| {
308 debug!("expansion: constraint={:?}", constraint);
309 let (a_region, b_vid, b_data, retain) = match *constraint {
310 Constraint::RegSubVar(a_region, b_vid) => {
311 let b_data = var_values.value_mut(b_vid);
312 (a_region, b_vid, b_data, false)
314 Constraint::VarSubVar(a_vid, b_vid) => match *var_values.value(a_vid) {
315 VarValue::ErrorValue => return (false, false),
316 VarValue::Value(a_region) => {
317 let b_data = var_values.value_mut(b_vid);
318 let retain = match *b_data {
319 VarValue::Value(ReStatic) | VarValue::ErrorValue => false,
322 (a_region, b_vid, b_data, retain)
325 Constraint::RegSubReg(..) | Constraint::VarSubReg(..) => {
326 // These constraints are checked after expansion
327 // is done, in `collect_errors`.
328 return (false, false);
332 let changed = self.expand_node(a_region, b_vid, b_data);
337 // This function is very hot in some workloads. There's a single callsite
338 // so always inlining is ok even though it's large.
342 a_region: Region<'tcx>,
344 b_data: &mut VarValue<'tcx>,
346 debug!("expand_node({:?}, {:?} == {:?})", a_region, b_vid, b_data);
349 // Check if this relationship is implied by a given.
350 ty::ReEarlyBound(_) | ty::ReFree(_) => {
351 if self.data.givens.contains(&(a_region, b_vid)) {
361 VarValue::Value(cur_region) => {
362 // Identical scopes can show up quite often, if the fixed point
363 // iteration converges slowly, skip them
364 if let (ReScope(a_scope), ReScope(cur_scope)) = (a_region, cur_region) {
365 if a_scope == cur_scope {
370 let mut lub = self.lub_concrete_regions(a_region, cur_region);
371 if lub == cur_region {
375 // Watch out for `'b: !1` relationships, where the
376 // universe of `'b` can't name the placeholder `!1`. In
377 // that case, we have to grow `'b` to be `'static` for the
378 // relationship to hold. This is obviously a kind of sub-optimal
379 // choice -- in the future, when we incorporate a knowledge
380 // of the parameter environment, we might be able to find a
381 // tighter bound than `'static`.
383 // (This might e.g. arise from being asked to prove `for<'a> { 'b: 'a }`.)
384 let b_universe = self.var_infos[b_vid].universe;
385 if let ty::RePlaceholder(p) = lub {
386 if b_universe.cannot_name(p.universe) {
387 lub = self.tcx().lifetimes.re_static;
391 debug!("Expanding value of {:?} from {:?} to {:?}", b_vid, cur_region, lub);
393 *b_data = VarValue::Value(lub);
397 VarValue::ErrorValue => {
403 /// True if `a <= b`, but not defined over inference variables.
404 fn sub_concrete_regions(&self, a: Region<'tcx>, b: Region<'tcx>) -> bool {
405 self.lub_concrete_regions(a, b) == b
408 /// Returns the smallest region `c` such that `a <= c` and `b <= c`.
409 fn lub_concrete_regions(&self, a: Region<'tcx>, b: Region<'tcx>) -> Region<'tcx> {
410 let tcx = self.tcx();
413 (&ty::ReClosureBound(..), _)
414 | (_, &ty::ReClosureBound(..))
415 | (&ReLateBound(..), _)
416 | (_, &ReLateBound(..))
418 | (_, &ReErased) => {
419 bug!("cannot relate region: LUB({:?}, {:?})", a, b);
422 (r @ &ReStatic, _) | (_, r @ &ReStatic) => {
423 r // nothing lives longer than static
426 (&ReEmpty, r) | (r, &ReEmpty) => {
427 r // everything lives longer than empty
430 (&ReVar(v_id), _) | (_, &ReVar(v_id)) => {
432 self.var_infos[v_id].origin.span(),
433 "lub_concrete_regions invoked with non-concrete \
434 regions: {:?}, {:?}",
440 (&ReEarlyBound(_), &ReScope(s_id))
441 | (&ReScope(s_id), &ReEarlyBound(_))
442 | (&ReFree(_), &ReScope(s_id))
443 | (&ReScope(s_id), &ReFree(_)) => {
444 // A "free" region can be interpreted as "some region
445 // at least as big as fr.scope". So, we can
446 // reasonably compare free regions and scopes:
447 let fr_scope = match (a, b) {
448 (&ReEarlyBound(ref br), _) | (_, &ReEarlyBound(ref br)) => {
449 self.region_rels.region_scope_tree.early_free_scope(self.tcx(), br)
451 (&ReFree(ref fr), _) | (_, &ReFree(ref fr)) => {
452 self.region_rels.region_scope_tree.free_scope(self.tcx(), fr)
457 self.region_rels.region_scope_tree.nearest_common_ancestor(fr_scope, s_id);
458 if r_id == fr_scope {
459 // if the free region's scope `fr.scope` is bigger than
460 // the scope region `s_id`, then the LUB is the free
463 (_, &ReScope(_)) => return a,
464 (&ReScope(_), _) => return b,
469 // otherwise, we don't know what the free region is,
470 // so we must conservatively say the LUB is static:
471 tcx.lifetimes.re_static
474 (&ReScope(a_id), &ReScope(b_id)) => {
475 // The region corresponding to an outer block is a
476 // subtype of the region corresponding to an inner
478 let lub = self.region_rels.region_scope_tree.nearest_common_ancestor(a_id, b_id);
479 tcx.mk_region(ReScope(lub))
482 (&ReEarlyBound(_), &ReEarlyBound(_))
483 | (&ReFree(_), &ReEarlyBound(_))
484 | (&ReEarlyBound(_), &ReFree(_))
485 | (&ReFree(_), &ReFree(_)) => self.region_rels.lub_free_regions(a, b),
487 // For these types, we cannot define any additional
489 (&RePlaceholder(..), _) | (_, &RePlaceholder(..)) => {
493 tcx.lifetimes.re_static
499 /// After expansion is complete, go and check upper bounds (i.e.,
500 /// cases where the region cannot grow larger than a fixed point)
501 /// and check that they are satisfied.
504 var_data: &mut LexicalRegionResolutions<'tcx>,
505 errors: &mut Vec<RegionResolutionError<'tcx>>,
507 for (constraint, origin) in &self.data.constraints {
508 debug!("collect_errors: constraint={:?} origin={:?}", constraint, origin);
510 Constraint::RegSubVar(..) | Constraint::VarSubVar(..) => {
511 // Expansion will ensure that these constraints hold. Ignore.
514 Constraint::RegSubReg(sub, sup) => {
515 if self.region_rels.is_subregion_of(sub, sup) {
520 "collect_errors: region error at {:?}: \
521 cannot verify that {:?} <= {:?}",
525 errors.push(RegionResolutionError::ConcreteFailure(
532 Constraint::VarSubReg(a_vid, b_region) => {
533 let a_data = var_data.value_mut(a_vid);
534 debug!("contraction: {:?} == {:?}, {:?}", a_vid, a_data, b_region);
536 let a_region = match *a_data {
537 VarValue::ErrorValue => continue,
538 VarValue::Value(a_region) => a_region,
541 // Do not report these errors immediately:
542 // instead, set the variable value to error and
543 // collect them later.
544 if !self.region_rels.is_subregion_of(a_region, b_region) {
546 "collect_errors: region error at {:?}: \
547 cannot verify that {:?}={:?} <= {:?}",
548 origin, a_vid, a_region, b_region
550 *a_data = VarValue::ErrorValue;
556 // Check that all member constraints are satisfied.
557 for member_constraint in &self.data.member_constraints {
558 let member_region = var_data.normalize(self.tcx(), member_constraint.member_region);
559 let choice_regions = member_constraint
562 .map(|&choice_region| var_data.normalize(self.tcx(), choice_region));
563 if !choice_regions.clone().any(|choice_region| member_region == choice_region) {
564 let span = self.tcx().def_span(member_constraint.opaque_type_def_id);
565 errors.push(RegionResolutionError::MemberConstraintFailure {
567 opaque_type_def_id: member_constraint.opaque_type_def_id,
568 hidden_ty: member_constraint.hidden_ty,
570 choice_regions: choice_regions.collect(),
575 for verify in &self.data.verifys {
576 debug!("collect_errors: verify={:?}", verify);
577 let sub = var_data.normalize(self.tcx(), verify.region);
579 // This was an inference variable which didn't get
580 // constrained, therefore it can be assume to hold.
581 if let ty::ReEmpty = *sub {
585 let verify_kind_ty = verify.kind.to_ty(self.tcx());
586 if self.bound_is_met(&verify.bound, var_data, verify_kind_ty, sub) {
591 "collect_errors: region error at {:?}: \
592 cannot verify that {:?} <= {:?}",
593 verify.origin, verify.region, verify.bound
596 errors.push(RegionResolutionError::GenericBoundFailure(
597 verify.origin.clone(),
604 /// Go over the variables that were declared to be error variables
605 /// and create a `RegionResolutionError` for each of them.
606 fn collect_var_errors(
608 var_data: &LexicalRegionResolutions<'tcx>,
609 graph: &RegionGraph<'tcx>,
610 errors: &mut Vec<RegionResolutionError<'tcx>>,
612 debug!("collect_var_errors");
614 // This is the best way that I have found to suppress
615 // duplicate and related errors. Basically we keep a set of
616 // flags for every node. Whenever an error occurs, we will
617 // walk some portion of the graph looking to find pairs of
618 // conflicting regions to report to the user. As we walk, we
619 // trip the flags from false to true, and if we find that
620 // we've already reported an error involving any particular
621 // node we just stop and don't report the current error. The
622 // idea is to report errors that derive from independent
623 // regions of the graph, but not those that derive from
624 // overlapping locations.
625 let mut dup_vec = IndexVec::from_elem_n(None, self.num_vars());
627 for (node_vid, value) in var_data.values.iter_enumerated() {
629 VarValue::Value(_) => { /* Inference successful */ }
630 VarValue::ErrorValue => {
631 // Inference impossible: this value contains
632 // inconsistent constraints.
634 // I think that in this case we should report an
635 // error now -- unlike the case above, we can't
636 // wait to see whether the user needs the result
637 // of this variable. The reason is that the mere
638 // existence of this variable implies that the
639 // region graph is inconsistent, whether or not it
642 // For example, we may have created a region
643 // variable that is the GLB of two other regions
644 // which do not have a GLB. Even if that variable
645 // is not used, it implies that those two regions
646 // *should* have a GLB.
648 // At least I think this is true. It may be that
649 // the mere existence of a conflict in a region
650 // variable that is not used is not a problem, so
651 // if this rule starts to create problems we'll
652 // have to revisit this portion of the code and
653 // think hard about it. =) -- nikomatsakis
654 self.collect_error_for_expanding_node(graph, &mut dup_vec, node_vid, errors);
660 fn construct_graph(&self) -> RegionGraph<'tcx> {
661 let num_vars = self.num_vars();
663 let mut graph = Graph::new();
665 for _ in 0..num_vars {
669 // Issue #30438: two distinct dummy nodes, one for incoming
670 // edges (dummy_source) and another for outgoing edges
671 // (dummy_sink). In `dummy -> a -> b -> dummy`, using one
672 // dummy node leads one to think (erroneously) there exists a
673 // path from `b` to `a`. Two dummy nodes sidesteps the issue.
674 let dummy_source = graph.add_node(());
675 let dummy_sink = graph.add_node(());
677 for (constraint, _) in &self.data.constraints {
679 Constraint::VarSubVar(a_id, b_id) => {
681 NodeIndex(a_id.index() as usize),
682 NodeIndex(b_id.index() as usize),
686 Constraint::RegSubVar(_, b_id) => {
687 graph.add_edge(dummy_source, NodeIndex(b_id.index() as usize), *constraint);
689 Constraint::VarSubReg(a_id, _) => {
690 graph.add_edge(NodeIndex(a_id.index() as usize), dummy_sink, *constraint);
692 Constraint::RegSubReg(..) => {
693 // this would be an edge from `dummy_source` to
694 // `dummy_sink`; just ignore it.
702 fn collect_error_for_expanding_node(
704 graph: &RegionGraph<'tcx>,
705 dup_vec: &mut IndexVec<RegionVid, Option<RegionVid>>,
707 errors: &mut Vec<RegionResolutionError<'tcx>>,
709 // Errors in expanding nodes result from a lower-bound that is
710 // not contained by an upper-bound.
711 let (mut lower_bounds, lower_dup) =
712 self.collect_concrete_regions(graph, node_idx, INCOMING, Some(dup_vec));
713 let (mut upper_bounds, upper_dup) =
714 self.collect_concrete_regions(graph, node_idx, OUTGOING, Some(dup_vec));
716 if lower_dup || upper_dup {
720 // We place free regions first because we are special casing
721 // SubSupConflict(ReFree, ReFree) when reporting error, and so
722 // the user will more likely get a specific suggestion.
723 fn region_order_key(x: &RegionAndOrigin<'_>) -> u8 {
725 ReEarlyBound(_) => 0,
730 lower_bounds.sort_by_key(region_order_key);
731 upper_bounds.sort_by_key(region_order_key);
733 let node_universe = self.var_infos[node_idx].universe;
735 for lower_bound in &lower_bounds {
736 let effective_lower_bound = if let ty::RePlaceholder(p) = lower_bound.region {
737 if node_universe.cannot_name(p.universe) {
738 self.tcx().lifetimes.re_static
746 for upper_bound in &upper_bounds {
747 if !self.region_rels.is_subregion_of(effective_lower_bound, upper_bound.region) {
748 let origin = self.var_infos[node_idx].origin.clone();
750 "region inference error at {:?} for {:?}: SubSupConflict sub: {:?} \
752 origin, node_idx, lower_bound.region, upper_bound.region
754 errors.push(RegionResolutionError::SubSupConflict(
757 lower_bound.origin.clone(),
759 upper_bound.origin.clone(),
767 // Errors in earlier passes can yield error variables without
768 // resolution errors here; delay ICE in favor of those errors.
769 self.tcx().sess.delay_span_bug(
770 self.var_infos[node_idx].origin.span(),
771 &format!("collect_error_for_expanding_node() could not find \
772 error for var {:?} in universe {:?}, lower_bounds={:#?}, \
780 fn collect_concrete_regions(
782 graph: &RegionGraph<'tcx>,
783 orig_node_idx: RegionVid,
785 mut dup_vec: Option<&mut IndexVec<RegionVid, Option<RegionVid>>>,
786 ) -> (Vec<RegionAndOrigin<'tcx>>, bool) {
787 struct WalkState<'tcx> {
788 set: FxHashSet<RegionVid>,
789 stack: Vec<RegionVid>,
790 result: Vec<RegionAndOrigin<'tcx>>,
793 let mut state = WalkState {
794 set: Default::default(),
795 stack: vec![orig_node_idx],
799 state.set.insert(orig_node_idx);
801 // to start off the process, walk the source node in the
802 // direction specified
803 process_edges(&self.data, &mut state, graph, orig_node_idx, dir);
805 while !state.stack.is_empty() {
806 let node_idx = state.stack.pop().unwrap();
808 // check whether we've visited this node on some previous walk
809 if let Some(dup_vec) = &mut dup_vec {
810 if dup_vec[node_idx].is_none() {
811 dup_vec[node_idx] = Some(orig_node_idx);
812 } else if dup_vec[node_idx] != Some(orig_node_idx) {
813 state.dup_found = true;
817 "collect_concrete_regions(orig_node_idx={:?}, node_idx={:?})",
818 orig_node_idx, node_idx
822 process_edges(&self.data, &mut state, graph, node_idx, dir);
825 let WalkState { result, dup_found, .. } = state;
826 return (result, dup_found);
828 fn process_edges<'tcx>(
829 this: &RegionConstraintData<'tcx>,
830 state: &mut WalkState<'tcx>,
831 graph: &RegionGraph<'tcx>,
832 source_vid: RegionVid,
835 debug!("process_edges(source_vid={:?}, dir={:?})", source_vid, dir);
837 let source_node_index = NodeIndex(source_vid.index() as usize);
838 for (_, edge) in graph.adjacent_edges(source_node_index, dir) {
840 Constraint::VarSubVar(from_vid, to_vid) => {
841 let opp_vid = if from_vid == source_vid { to_vid } else { from_vid };
842 if state.set.insert(opp_vid) {
843 state.stack.push(opp_vid);
847 Constraint::RegSubVar(region, _) | Constraint::VarSubReg(_, region) => {
848 state.result.push(RegionAndOrigin {
850 origin: this.constraints.get(&edge.data).unwrap().clone(),
854 Constraint::RegSubReg(..) => panic!(
855 "cannot reach reg-sub-reg edge in region inference \
863 fn iterate_until_fixed_point<F>(&self, tag: &str, mut body: F)
865 F: FnMut(&Constraint<'tcx>) -> (bool, bool),
867 let mut constraints: SmallVec<[_; 16]> = self.data.constraints.keys().collect();
868 let mut iteration = 0;
869 let mut changed = true;
873 debug!("---- {} Iteration {}{}", "#", tag, iteration);
874 constraints.retain(|constraint| {
875 let (edge_changed, retain) = body(constraint);
877 debug!("updated due to constraint {:?}", constraint);
883 debug!("---- {} Complete after {} iteration(s)", tag, iteration);
888 bound: &VerifyBound<'tcx>,
889 var_values: &LexicalRegionResolutions<'tcx>,
890 generic_ty: Ty<'tcx>,
891 min: ty::Region<'tcx>,
894 VerifyBound::IfEq(k, b) => {
895 (var_values.normalize(self.region_rels.tcx, *k) == generic_ty)
896 && self.bound_is_met(b, var_values, generic_ty, min)
899 VerifyBound::OutlivedBy(r) => {
900 self.region_rels.is_subregion_of(min, var_values.normalize(self.tcx(), r))
903 VerifyBound::AnyBound(bs) => {
904 bs.iter().any(|b| self.bound_is_met(b, var_values, generic_ty, min))
907 VerifyBound::AllBounds(bs) => {
908 bs.iter().all(|b| self.bound_is_met(b, var_values, generic_ty, min))
914 impl<'tcx> fmt::Debug for RegionAndOrigin<'tcx> {
915 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
916 write!(f, "RegionAndOrigin({:?},{:?})", self.region, self.origin)
920 impl<'tcx> LexicalRegionResolutions<'tcx> {
921 fn normalize<T>(&self, tcx: TyCtxt<'tcx>, value: T) -> T
923 T: TypeFoldable<'tcx>,
925 tcx.fold_regions(&value, &mut false, |r, _db| match r {
926 ty::ReVar(rid) => self.resolve_var(*rid),
931 fn value(&self, rid: RegionVid) -> &VarValue<'tcx> {
935 fn value_mut(&mut self, rid: RegionVid) -> &mut VarValue<'tcx> {
936 &mut self.values[rid]
939 pub fn resolve_var(&self, rid: RegionVid) -> ty::Region<'tcx> {
940 let result = match self.values[rid] {
941 VarValue::Value(r) => r,
942 VarValue::ErrorValue => self.error_region,
944 debug!("resolve_var({:?}) = {:?}", rid, result);