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.
15 use middle::ty::{BoundRegion, FreeRegion, Region, RegionVid, Vid};
16 use middle::ty::{ReEmpty, ReStatic, ReInfer, ReFree, ReEarlyBound,
18 use middle::ty::{ReScope, ReVar, ReSkolemized, BrFresh};
19 use middle::typeck::infer::cres;
20 use middle::typeck::infer::{RegionVariableOrigin, SubregionOrigin, TypeTrace};
21 use middle::typeck::infer;
23 use middle::graph::{Direction, NodeIndex};
24 use util::common::indenter;
25 use util::ppaux::{Repr};
27 use std::cell::{Cell, RefCell};
29 use collections::{HashMap, HashSet};
34 #[deriving(Eq, TotalEq, Hash)]
36 ConstrainVarSubVar(RegionVid, RegionVid),
37 ConstrainRegSubVar(Region, RegionVid),
38 ConstrainVarSubReg(RegionVid, Region),
39 ConstrainRegSubReg(Region, Region),
42 #[deriving(Eq, TotalEq, Hash)]
43 pub struct TwoRegions {
48 pub enum UndoLogEntry {
51 AddConstraint(Constraint),
52 AddCombination(CombineMapType, TwoRegions)
55 pub enum CombineMapType {
60 pub enum RegionResolutionError {
61 /// `ConcreteFailure(o, a, b)`:
63 /// `o` requires that `a <= b`, but this does not hold
64 ConcreteFailure(SubregionOrigin, Region, Region),
66 /// `SubSupConflict(v, sub_origin, sub_r, sup_origin, sup_r)`:
68 /// Could not infer a value for `v` because `sub_r <= v` (due to
69 /// `sub_origin`) but `v <= sup_r` (due to `sup_origin`) and
70 /// `sub_r <= sup_r` does not hold.
71 SubSupConflict(RegionVariableOrigin,
72 SubregionOrigin, Region,
73 SubregionOrigin, Region),
75 /// `SupSupConflict(v, origin1, r1, origin2, r2)`:
77 /// Could not infer a value for `v` because `v <= r1` (due to
78 /// `origin1`) and `v <= r2` (due to `origin2`) and
79 /// `r1` and `r2` have no intersection.
80 SupSupConflict(RegionVariableOrigin,
81 SubregionOrigin, Region,
82 SubregionOrigin, Region),
84 /// For subsets of `ConcreteFailure` and `SubSupConflict`, we can derive
85 /// more specific errors message by suggesting to the user where they
86 /// should put a lifetime. In those cases we process and put those errors
87 /// into `ProcessedErrors` before we do any reporting.
88 ProcessedErrors(Vec<RegionVariableOrigin>,
89 Vec<(TypeTrace, ty::type_err)>,
93 /// SameRegions is used to group regions that we think are the same and would
94 /// like to indicate so to the user.
95 /// For example, the following function
97 /// struct Foo { bar: int }
98 /// fn foo2<'a, 'b>(x: &'a Foo) -> &'b int {
102 /// would report an error because we expect 'a and 'b to match, and so we group
103 /// 'a and 'b together inside a SameRegions struct
105 pub struct SameRegions {
106 pub scope_id: ast::NodeId,
107 pub regions: Vec<BoundRegion>
111 pub fn contains(&self, other: &BoundRegion) -> bool {
112 self.regions.contains(other)
115 pub fn push(&mut self, other: BoundRegion) {
116 self.regions.push(other);
120 pub type CombineMap = HashMap<TwoRegions, RegionVid>;
122 pub struct RegionVarBindings<'a> {
124 var_origins: RefCell<Vec<RegionVariableOrigin>>,
125 constraints: RefCell<HashMap<Constraint, SubregionOrigin>>,
126 lubs: RefCell<CombineMap>,
127 glbs: RefCell<CombineMap>,
128 skolemization_count: Cell<uint>,
129 bound_count: Cell<uint>,
131 // The undo log records actions that might later be undone.
133 // Note: when the undo_log is empty, we are not actively
134 // snapshotting. When the `start_snapshot()` method is called, we
135 // push a Snapshot entry onto the list to indicate that we are now
136 // actively snapshotting. The reason for this is that otherwise
137 // we end up adding entries for things like the lower bound on
138 // a variable and so forth, which can never be rolled back.
139 undo_log: RefCell<Vec<UndoLogEntry> >,
141 // This contains the results of inference. It begins as an empty
142 // option and only acquires a value after inference is complete.
143 values: RefCell<Option<Vec<VarValue> >>,
146 pub fn RegionVarBindings<'a>(tcx: &'a ty::ctxt) -> RegionVarBindings<'a> {
149 var_origins: RefCell::new(Vec::new()),
150 values: RefCell::new(None),
151 constraints: RefCell::new(HashMap::new()),
152 lubs: RefCell::new(HashMap::new()),
153 glbs: RefCell::new(HashMap::new()),
154 skolemization_count: Cell::new(0),
155 bound_count: Cell::new(0),
156 undo_log: RefCell::new(Vec::new())
160 impl<'a> RegionVarBindings<'a> {
161 pub fn in_snapshot(&self) -> bool {
162 self.undo_log.borrow().len() > 0
165 pub fn start_snapshot(&self) -> uint {
166 debug!("RegionVarBindings: start_snapshot()");
167 if self.in_snapshot() {
168 self.undo_log.borrow().len()
170 self.undo_log.borrow_mut().push(Snapshot);
175 pub fn commit(&self) {
176 debug!("RegionVarBindings: commit()");
177 let mut undo_log = self.undo_log.borrow_mut();
178 while undo_log.len() > 0 {
179 undo_log.pop().unwrap();
183 pub fn rollback_to(&self, snapshot: uint) {
184 debug!("RegionVarBindings: rollback_to({})", snapshot);
185 let mut undo_log = self.undo_log.borrow_mut();
186 while undo_log.len() > snapshot {
187 let undo_item = undo_log.pop().unwrap();
188 debug!("undo_item={:?}", undo_item);
192 let mut var_origins = self.var_origins.borrow_mut();
193 assert_eq!(var_origins.len(), vid.to_uint() + 1);
194 var_origins.pop().unwrap();
196 AddConstraint(ref constraint) => {
197 self.constraints.borrow_mut().remove(constraint);
199 AddCombination(Glb, ref regions) => {
200 self.glbs.borrow_mut().remove(regions);
202 AddCombination(Lub, ref regions) => {
203 self.lubs.borrow_mut().remove(regions);
209 pub fn num_vars(&self) -> uint {
210 self.var_origins.borrow().len()
213 pub fn new_region_var(&self, origin: RegionVariableOrigin) -> RegionVid {
214 let id = self.num_vars();
215 self.var_origins.borrow_mut().push(origin.clone());
216 let vid = RegionVid { id: id };
217 if self.in_snapshot() {
218 self.undo_log.borrow_mut().push(AddVar(vid));
220 debug!("created new region variable {:?} with origin {:?}",
221 vid, origin.repr(self.tcx));
225 pub fn new_skolemized(&self, br: ty::BoundRegion) -> Region {
226 let sc = self.skolemization_count.get();
227 self.skolemization_count.set(sc + 1);
228 ReInfer(ReSkolemized(sc, br))
231 pub fn new_bound(&self, binder_id: ast::NodeId) -> Region {
232 // Creates a fresh bound variable for use in GLB computations.
233 // See discussion of GLB computation in the large comment at
234 // the top of this file for more details.
236 // This computation is potentially wrong in the face of
237 // rollover. It's conceivable, if unlikely, that one might
238 // wind up with accidental capture for nested functions in
239 // that case, if the outer function had bound regions created
240 // a very long time before and the inner function somehow
241 // wound up rolling over such that supposedly fresh
242 // identifiers were in fact shadowed. For now, we just assert
243 // that there is no rollover -- eventually we should try to be
244 // robust against this possibility, either by checking the set
245 // of bound identifiers that appear in a given expression and
246 // ensure that we generate one that is distinct, or by
247 // changing the representation of bound regions in a fn
250 let sc = self.bound_count.get();
251 self.bound_count.set(sc + 1);
253 if sc >= self.bound_count.get() {
254 self.tcx.sess.bug("rollover in RegionInference new_bound()");
257 ReLateBound(binder_id, BrFresh(sc))
260 fn values_are_none(&self) -> bool {
261 self.values.borrow().is_none()
264 pub fn add_constraint(&self,
265 constraint: Constraint,
266 origin: SubregionOrigin) {
267 // cannot add constraints once regions are resolved
268 assert!(self.values_are_none());
270 debug!("RegionVarBindings: add_constraint({:?})", constraint);
272 if self.constraints.borrow_mut().insert(constraint, origin) {
273 if self.in_snapshot() {
274 self.undo_log.borrow_mut().push(AddConstraint(constraint));
279 pub fn make_subregion(&self,
280 origin: SubregionOrigin,
283 // cannot add constraints once regions are resolved
284 assert!(self.values_are_none());
286 debug!("RegionVarBindings: make_subregion({}, {}) due to {}",
289 origin.repr(self.tcx));
292 (ReEarlyBound(..), _) |
293 (ReLateBound(..), _) |
294 (_, ReEarlyBound(..)) |
295 (_, ReLateBound(..)) => {
296 self.tcx.sess.span_bug(
298 format!("cannot relate bound region: {} <= {}",
300 sup.repr(self.tcx)).as_slice());
303 // all regions are subregions of static, so we can ignore this
305 (ReInfer(ReVar(sub_id)), ReInfer(ReVar(sup_id))) => {
306 self.add_constraint(ConstrainVarSubVar(sub_id, sup_id), origin);
308 (r, ReInfer(ReVar(sup_id))) => {
309 self.add_constraint(ConstrainRegSubVar(r, sup_id), origin);
311 (ReInfer(ReVar(sub_id)), r) => {
312 self.add_constraint(ConstrainVarSubReg(sub_id, r), origin);
315 self.add_constraint(ConstrainRegSubReg(sub, sup), origin);
320 pub fn lub_regions(&self,
321 origin: SubregionOrigin,
325 // cannot add constraints once regions are resolved
326 assert!(self.values_are_none());
328 debug!("RegionVarBindings: lub_regions({:?}, {:?})", a, b);
330 (ReStatic, _) | (_, ReStatic) => {
331 ReStatic // nothing lives longer than static
336 Lub, a, b, origin.clone(),
338 this.make_subregion(origin.clone(), old_r, new_r))
343 pub fn glb_regions(&self,
344 origin: SubregionOrigin,
348 // cannot add constraints once regions are resolved
349 assert!(self.values_are_none());
351 debug!("RegionVarBindings: glb_regions({:?}, {:?})", a, b);
353 (ReStatic, r) | (r, ReStatic) => {
354 // static lives longer than everything else
360 Glb, a, b, origin.clone(),
362 this.make_subregion(origin.clone(), new_r, old_r))
367 pub fn resolve_var(&self, rid: RegionVid) -> ty::Region {
368 let v = match *self.values.borrow() {
370 self.tcx.sess.span_bug(
371 self.var_origins.borrow().get(rid.to_uint()).span(),
372 "attempt to resolve region variable before values have \
375 Some(ref values) => *values.get(rid.to_uint())
378 debug!("RegionVarBindings: resolve_var({:?}={})={:?}",
379 rid, rid.to_uint(), v);
384 // No constraints, return ty::ReEmpty
389 // An error that has previously been reported.
395 fn combine_map<'a>(&'a self, t: CombineMapType)
396 -> &'a RefCell<CombineMap> {
403 pub fn combine_vars(&self,
407 origin: SubregionOrigin,
408 relate: |this: &RegionVarBindings,
412 let vars = TwoRegions { a: a, b: b };
413 match self.combine_map(t).borrow().find(&vars) {
415 return ReInfer(ReVar(c));
419 let c = self.new_region_var(infer::MiscVariable(origin.span()));
420 self.combine_map(t).borrow_mut().insert(vars, c);
421 if self.in_snapshot() {
422 self.undo_log.borrow_mut().push(AddCombination(t, vars));
424 relate(self, a, ReInfer(ReVar(c)));
425 relate(self, b, ReInfer(ReVar(c)));
426 debug!("combine_vars() c={:?}", c);
430 pub fn vars_created_since_snapshot(&self, snapshot: uint)
432 self.undo_log.borrow().slice_from(snapshot).iter()
433 .filter_map(|&elt| match elt {
434 AddVar(vid) => Some(vid),
440 pub fn tainted(&self, snapshot: uint, r0: Region) -> Vec<Region> {
442 * Computes all regions that have been related to `r0` in any
443 * way since the snapshot `snapshot` was taken---`r0` itself
444 * will be the first entry. This is used when checking whether
445 * skolemized regions are being improperly related to other
449 debug!("tainted(snapshot={}, r0={:?})", snapshot, r0);
450 let _indenter = indenter();
452 let undo_len = self.undo_log.borrow().len();
454 // `result_set` acts as a worklist: we explore all outgoing
455 // edges and add any new regions we find to result_set. This
456 // is not a terribly efficient implementation.
457 let mut result_set = vec!(r0);
458 let mut result_index = 0;
459 while result_index < result_set.len() {
460 // nb: can't use uint::range() here because result_set grows
461 let r = *result_set.get(result_index);
463 debug!("result_index={}, r={:?}", result_index, r);
465 let mut undo_index = snapshot;
466 while undo_index < undo_len {
467 // nb: can't use uint::range() here as we move result_set
468 let regs = match self.undo_log.borrow().get(undo_index) {
469 &AddConstraint(ConstrainVarSubVar(ref a, ref b)) => {
470 Some((ReInfer(ReVar(*a)),
473 &AddConstraint(ConstrainRegSubVar(ref a, ref b)) => {
474 Some((*a, ReInfer(ReVar(*b))))
476 &AddConstraint(ConstrainVarSubReg(ref a, ref b)) => {
477 Some((ReInfer(ReVar(*a)), *b))
479 &AddConstraint(ConstrainRegSubReg(a, b)) => {
491 consider_adding_edge(result_set, r, r1, r2);
493 consider_adding_edge(result_set, r, r2, r1);
505 fn consider_adding_edge(result_set: Vec<Region> ,
508 r2: Region) -> Vec<Region> {
509 let mut result_set = result_set;
510 if r == r1 { // Clearly, this is potentially inefficient.
511 if !result_set.iter().any(|x| *x == r2) {
520 This function performs the actual region resolution. It must be
521 called after all constraints have been added. It performs a
522 fixed-point iteration to find region values which satisfy all
523 constraints, assuming such values can be found; if they cannot,
526 pub fn resolve_regions(&self) -> Vec<RegionResolutionError> {
527 debug!("RegionVarBindings: resolve_regions()");
528 let mut errors = vec!();
529 let v = self.infer_variable_values(&mut errors);
530 *self.values.borrow_mut() = Some(v);
535 impl<'a> RegionVarBindings<'a> {
536 fn is_subregion_of(&self, sub: Region, sup: Region) -> bool {
537 self.tcx.region_maps.is_subregion_of(sub, sup)
540 fn lub_concrete_regions(&self, a: Region, b: Region) -> Region {
542 (ReLateBound(..), _) |
543 (_, ReLateBound(..)) |
544 (ReEarlyBound(..), _) |
545 (_, ReEarlyBound(..)) => {
547 format!("cannot relate bound region: LUB({}, {})",
549 b.repr(self.tcx)).as_slice());
552 (ReStatic, _) | (_, ReStatic) => {
553 ReStatic // nothing lives longer than static
556 (ReEmpty, r) | (r, ReEmpty) => {
557 r // everything lives longer than empty
560 (ReInfer(ReVar(v_id)), _) | (_, ReInfer(ReVar(v_id))) => {
561 self.tcx.sess.span_bug(
562 self.var_origins.borrow().get(v_id.to_uint()).span(),
563 format!("lub_concrete_regions invoked with \
564 non-concrete regions: {:?}, {:?}",
569 (f @ ReFree(ref fr), ReScope(s_id)) |
570 (ReScope(s_id), f @ ReFree(ref fr)) => {
571 // A "free" region can be interpreted as "some region
572 // at least as big as the block fr.scope_id". So, we can
573 // reasonably compare free regions and scopes:
574 match self.tcx.region_maps.nearest_common_ancestor(fr.scope_id, s_id) {
575 // if the free region's scope `fr.scope_id` is bigger than
576 // the scope region `s_id`, then the LUB is the free
578 Some(r_id) if r_id == fr.scope_id => f,
580 // otherwise, we don't know what the free region is,
581 // so we must conservatively say the LUB is static:
586 (ReScope(a_id), ReScope(b_id)) => {
587 // The region corresponding to an outer block is a
588 // subtype of the region corresponding to an inner
590 match self.tcx.region_maps.nearest_common_ancestor(a_id, b_id) {
591 Some(r_id) => ReScope(r_id),
596 (ReFree(ref a_fr), ReFree(ref b_fr)) => {
597 self.lub_free_regions(a_fr, b_fr)
600 // For these types, we cannot define any additional
602 (ReInfer(ReSkolemized(..)), _) |
603 (_, ReInfer(ReSkolemized(..))) => {
604 if a == b {a} else {ReStatic}
609 fn lub_free_regions(&self,
611 b: &FreeRegion) -> ty::Region
614 * Computes a region that encloses both free region arguments.
615 * Guarantee that if the same two regions are given as argument,
616 * in any order, a consistent result is returned.
619 return match a.cmp(b) {
620 Less => helper(self, a, b),
621 Greater => helper(self, b, a),
622 Equal => ty::ReFree(*a)
625 fn helper(this: &RegionVarBindings,
627 b: &FreeRegion) -> ty::Region
629 if this.tcx.region_maps.sub_free_region(*a, *b) {
631 } else if this.tcx.region_maps.sub_free_region(*b, *a) {
639 fn glb_concrete_regions(&self,
643 debug!("glb_concrete_regions({:?}, {:?})", a, b);
645 (ReLateBound(..), _) |
646 (_, ReLateBound(..)) |
647 (ReEarlyBound(..), _) |
648 (_, ReEarlyBound(..)) => {
650 format!("cannot relate bound region: GLB({}, {})",
652 b.repr(self.tcx)).as_slice());
655 (ReStatic, r) | (r, ReStatic) => {
656 // static lives longer than everything else
660 (ReEmpty, _) | (_, ReEmpty) => {
661 // nothing lives shorter than everything else
665 (ReInfer(ReVar(v_id)), _) |
666 (_, ReInfer(ReVar(v_id))) => {
667 self.tcx.sess.span_bug(
668 self.var_origins.borrow().get(v_id.to_uint()).span(),
669 format!("glb_concrete_regions invoked with \
670 non-concrete regions: {:?}, {:?}",
675 (ReFree(ref fr), s @ ReScope(s_id)) |
676 (s @ ReScope(s_id), ReFree(ref fr)) => {
677 // Free region is something "at least as big as
678 // `fr.scope_id`." If we find that the scope `fr.scope_id` is bigger
679 // than the scope `s_id`, then we can say that the GLB
680 // is the scope `s_id`. Otherwise, as we do not know
681 // big the free region is precisely, the GLB is undefined.
682 match self.tcx.region_maps.nearest_common_ancestor(fr.scope_id, s_id) {
683 Some(r_id) if r_id == fr.scope_id => Ok(s),
684 _ => Err(ty::terr_regions_no_overlap(b, a))
688 (ReScope(a_id), ReScope(b_id)) => {
689 self.intersect_scopes(a, b, a_id, b_id)
692 (ReFree(ref a_fr), ReFree(ref b_fr)) => {
693 self.glb_free_regions(a_fr, b_fr)
696 // For these types, we cannot define any additional
698 (ReInfer(ReSkolemized(..)), _) |
699 (_, ReInfer(ReSkolemized(..))) => {
703 Err(ty::terr_regions_no_overlap(b, a))
709 fn glb_free_regions(&self,
711 b: &FreeRegion) -> cres<ty::Region>
714 * Computes a region that is enclosed by both free region arguments,
715 * if any. Guarantees that if the same two regions are given as argument,
716 * in any order, a consistent result is returned.
719 return match a.cmp(b) {
720 Less => helper(self, a, b),
721 Greater => helper(self, b, a),
722 Equal => Ok(ty::ReFree(*a))
725 fn helper(this: &RegionVarBindings,
727 b: &FreeRegion) -> cres<ty::Region>
729 if this.tcx.region_maps.sub_free_region(*a, *b) {
731 } else if this.tcx.region_maps.sub_free_region(*b, *a) {
734 this.intersect_scopes(ty::ReFree(*a), ty::ReFree(*b),
735 a.scope_id, b.scope_id)
740 fn intersect_scopes(&self,
741 region_a: ty::Region,
742 region_b: ty::Region,
743 scope_a: ast::NodeId,
744 scope_b: ast::NodeId) -> cres<Region>
746 // We want to generate the intersection of two
747 // scopes or two free regions. So, if one of
748 // these scopes is a subscope of the other, return
749 // it. Otherwise fail.
750 debug!("intersect_scopes(scope_a={:?}, scope_b={:?}, region_a={:?}, region_b={:?})",
751 scope_a, scope_b, region_a, region_b);
752 match self.tcx.region_maps.nearest_common_ancestor(scope_a, scope_b) {
753 Some(r_id) if scope_a == r_id => Ok(ReScope(scope_b)),
754 Some(r_id) if scope_b == r_id => Ok(ReScope(scope_a)),
755 _ => Err(ty::terr_regions_no_overlap(region_a, region_b))
760 // ______________________________________________________________________
762 #[deriving(Eq, Show)]
763 enum Classification { Expanding, Contracting }
765 pub enum VarValue { NoValue, Value(Region), ErrorValue }
768 classification: Classification,
772 struct RegionAndOrigin {
774 origin: SubregionOrigin,
777 type RegionGraph = graph::Graph<(), Constraint>;
779 impl<'a> RegionVarBindings<'a> {
780 fn infer_variable_values(&self,
781 errors: &mut Vec<RegionResolutionError>)
783 let mut var_data = self.construct_var_data();
784 self.expansion(var_data.as_mut_slice());
785 self.contraction(var_data.as_mut_slice());
786 self.collect_concrete_region_errors(&mut *errors);
787 self.extract_values_and_collect_conflicts(var_data.as_slice(), errors)
790 fn construct_var_data(&self) -> Vec<VarData> {
791 Vec::from_fn(self.num_vars(), |_| {
793 // All nodes are initially classified as contracting; during
794 // the expansion phase, we will shift the classification for
795 // those nodes that have a concrete region predecessor to
797 classification: Contracting,
803 fn expansion(&self, var_data: &mut [VarData]) {
804 self.iterate_until_fixed_point("Expansion", |constraint| {
806 ConstrainRegSubVar(a_region, b_vid) => {
807 let b_data = &mut var_data[b_vid.to_uint()];
808 self.expand_node(a_region, b_vid, b_data)
810 ConstrainVarSubVar(a_vid, b_vid) => {
811 match var_data[a_vid.to_uint()].value {
812 NoValue | ErrorValue => false,
814 let b_node = &mut var_data[b_vid.to_uint()];
815 self.expand_node(a_region, b_vid, b_node)
819 ConstrainVarSubReg(..) => {
820 // This is a contraction constraint. Ignore it.
823 ConstrainRegSubReg(..) => {
824 // No region variables involved. Ignore.
831 fn expand_node(&self,
834 b_data: &mut VarData)
836 debug!("expand_node({:?}, {:?} == {:?})",
837 a_region, b_vid, b_data.value);
839 b_data.classification = Expanding;
842 debug!("Setting initial value of {:?} to {:?}", b_vid, a_region);
844 b_data.value = Value(a_region);
848 Value(cur_region) => {
849 let lub = self.lub_concrete_regions(a_region, cur_region);
850 if lub == cur_region {
854 debug!("Expanding value of {:?} from {:?} to {:?}",
855 b_vid, cur_region, lub);
857 b_data.value = Value(lub);
867 fn contraction(&self,
868 var_data: &mut [VarData]) {
869 self.iterate_until_fixed_point("Contraction", |constraint| {
871 ConstrainRegSubVar(..) => {
872 // This is an expansion constraint. Ignore.
875 ConstrainVarSubVar(a_vid, b_vid) => {
876 match var_data[b_vid.to_uint()].value {
877 NoValue | ErrorValue => false,
879 let a_data = &mut var_data[a_vid.to_uint()];
880 self.contract_node(a_vid, a_data, b_region)
884 ConstrainVarSubReg(a_vid, b_region) => {
885 let a_data = &mut var_data[a_vid.to_uint()];
886 self.contract_node(a_vid, a_data, b_region)
888 ConstrainRegSubReg(..) => {
889 // No region variables involved. Ignore.
896 fn contract_node(&self,
898 a_data: &mut VarData,
901 debug!("contract_node({:?} == {:?}/{:?}, {:?})",
902 a_vid, a_data.value, a_data.classification, b_region);
904 return match a_data.value {
906 assert_eq!(a_data.classification, Contracting);
907 a_data.value = Value(b_region);
916 match a_data.classification {
918 check_node(self, a_vid, a_data, a_region, b_region)
921 adjust_node(self, a_vid, a_data, a_region, b_region)
927 fn check_node(this: &RegionVarBindings,
929 a_data: &mut VarData,
933 if !this.is_subregion_of(a_region, b_region) {
934 debug!("Setting {:?} to ErrorValue: {:?} not subregion of {:?}",
935 a_vid, a_region, b_region);
936 a_data.value = ErrorValue;
941 fn adjust_node(this: &RegionVarBindings,
943 a_data: &mut VarData,
947 match this.glb_concrete_regions(a_region, b_region) {
952 debug!("Contracting value of {:?} from {:?} to {:?}",
953 a_vid, a_region, glb);
954 a_data.value = Value(glb);
959 debug!("Setting {:?} to ErrorValue: no glb of {:?}, {:?}",
960 a_vid, a_region, b_region);
961 a_data.value = ErrorValue;
968 fn collect_concrete_region_errors(
970 errors: &mut Vec<RegionResolutionError>)
972 for (constraint, _) in self.constraints.borrow().iter() {
973 let (sub, sup) = match *constraint {
974 ConstrainVarSubVar(..) |
975 ConstrainRegSubVar(..) |
976 ConstrainVarSubReg(..) => {
979 ConstrainRegSubReg(sub, sup) => {
984 if self.is_subregion_of(sub, sup) {
988 debug!("ConcreteFailure: !(sub <= sup): sub={:?}, sup={:?}",
990 let origin = self.constraints.borrow().get_copy(constraint);
991 errors.push(ConcreteFailure(origin, sub, sup));
995 fn extract_values_and_collect_conflicts(
997 var_data: &[VarData],
998 errors: &mut Vec<RegionResolutionError>)
1000 debug!("extract_values_and_collect_conflicts()");
1002 // This is the best way that I have found to suppress
1003 // duplicate and related errors. Basically we keep a set of
1004 // flags for every node. Whenever an error occurs, we will
1005 // walk some portion of the graph looking to find pairs of
1006 // conflicting regions to report to the user. As we walk, we
1007 // trip the flags from false to true, and if we find that
1008 // we've already reported an error involving any particular
1009 // node we just stop and don't report the current error. The
1010 // idea is to report errors that derive from independent
1011 // regions of the graph, but not those that derive from
1012 // overlapping locations.
1013 let mut dup_vec = Vec::from_elem(self.num_vars(), uint::MAX);
1015 let mut opt_graph = None;
1017 for idx in range(0u, self.num_vars()) {
1018 match var_data[idx].value {
1020 /* Inference successful */
1023 /* Unconstrained inference: do not report an error
1024 until the value of this variable is requested.
1025 After all, sometimes we make region variables but never
1026 really use their values. */
1029 /* Inference impossible, this value contains
1030 inconsistent constraints.
1032 I think that in this case we should report an
1033 error now---unlike the case above, we can't
1034 wait to see whether the user needs the result
1035 of this variable. The reason is that the mere
1036 existence of this variable implies that the
1037 region graph is inconsistent, whether or not it
1040 For example, we may have created a region
1041 variable that is the GLB of two other regions
1042 which do not have a GLB. Even if that variable
1043 is not used, it implies that those two regions
1044 *should* have a GLB.
1046 At least I think this is true. It may be that
1047 the mere existence of a conflict in a region variable
1048 that is not used is not a problem, so if this rule
1049 starts to create problems we'll have to revisit
1050 this portion of the code and think hard about it. =) */
1052 if opt_graph.is_none() {
1053 opt_graph = Some(self.construct_graph());
1055 let graph = opt_graph.get_ref();
1057 let node_vid = RegionVid { id: idx };
1058 match var_data[idx].classification {
1060 self.collect_error_for_expanding_node(
1061 graph, var_data, dup_vec.as_mut_slice(),
1065 self.collect_error_for_contracting_node(
1066 graph, var_data, dup_vec.as_mut_slice(),
1074 Vec::from_fn(self.num_vars(), |idx| var_data[idx].value)
1077 fn construct_graph(&self) -> RegionGraph {
1078 let num_vars = self.num_vars();
1080 let constraints = self.constraints.borrow();
1081 let num_edges = constraints.len();
1083 let mut graph = graph::Graph::with_capacity(num_vars + 1,
1086 for _ in range(0u, num_vars) {
1089 let dummy_idx = graph.add_node(());
1091 for (constraint, _) in constraints.iter() {
1093 ConstrainVarSubVar(a_id, b_id) => {
1094 graph.add_edge(NodeIndex(a_id.to_uint()),
1095 NodeIndex(b_id.to_uint()),
1098 ConstrainRegSubVar(_, b_id) => {
1099 graph.add_edge(dummy_idx,
1100 NodeIndex(b_id.to_uint()),
1103 ConstrainVarSubReg(a_id, _) => {
1104 graph.add_edge(NodeIndex(a_id.to_uint()),
1108 ConstrainRegSubReg(..) => {
1109 // Relations between two concrete regions do not
1110 // require an edge in the graph.
1118 fn collect_error_for_expanding_node(
1120 graph: &RegionGraph,
1121 var_data: &[VarData],
1122 dup_vec: &mut [uint],
1123 node_idx: RegionVid,
1124 errors: &mut Vec<RegionResolutionError>)
1126 // Errors in expanding nodes result from a lower-bound that is
1127 // not contained by an upper-bound.
1128 let (mut lower_bounds, lower_dup) =
1129 self.collect_concrete_regions(graph, var_data, node_idx,
1130 graph::Incoming, dup_vec);
1131 let (mut upper_bounds, upper_dup) =
1132 self.collect_concrete_regions(graph, var_data, node_idx,
1133 graph::Outgoing, dup_vec);
1135 if lower_dup || upper_dup {
1139 // We place free regions first because we are special casing
1140 // SubSupConflict(ReFree, ReFree) when reporting error, and so
1141 // the user will more likely get a specific suggestion.
1142 fn free_regions_first(a: &RegionAndOrigin,
1143 b: &RegionAndOrigin)
1145 match (a.region, b.region) {
1146 (ReFree(..), ReFree(..)) => Equal,
1147 (ReFree(..), _) => Less,
1148 (_, ReFree(..)) => Greater,
1152 lower_bounds.sort_by(|a, b| { free_regions_first(a, b) });
1153 upper_bounds.sort_by(|a, b| { free_regions_first(a, b) });
1155 for lower_bound in lower_bounds.iter() {
1156 for upper_bound in upper_bounds.iter() {
1157 if !self.is_subregion_of(lower_bound.region,
1158 upper_bound.region) {
1159 errors.push(SubSupConflict(
1160 self.var_origins.borrow().get(node_idx.to_uint()).clone(),
1161 lower_bound.origin.clone(),
1163 upper_bound.origin.clone(),
1164 upper_bound.region));
1170 self.tcx.sess.span_bug(
1171 self.var_origins.borrow().get(node_idx.to_uint()).span(),
1172 format!("collect_error_for_expanding_node() could not find error \
1173 for var {:?}, lower_bounds={}, upper_bounds={}",
1177 .collect::<Vec<ty::Region>>()
1181 .collect::<Vec<ty::Region>>()
1182 .repr(self.tcx)).as_slice());
1185 fn collect_error_for_contracting_node(
1187 graph: &RegionGraph,
1188 var_data: &[VarData],
1189 dup_vec: &mut [uint],
1190 node_idx: RegionVid,
1191 errors: &mut Vec<RegionResolutionError>)
1193 // Errors in contracting nodes result from two upper-bounds
1194 // that have no intersection.
1195 let (upper_bounds, dup_found) =
1196 self.collect_concrete_regions(graph, var_data, node_idx,
1197 graph::Outgoing, dup_vec);
1203 for upper_bound_1 in upper_bounds.iter() {
1204 for upper_bound_2 in upper_bounds.iter() {
1205 match self.glb_concrete_regions(upper_bound_1.region,
1206 upper_bound_2.region) {
1209 errors.push(SupSupConflict(
1210 self.var_origins.borrow().get(node_idx.to_uint()).clone(),
1211 upper_bound_1.origin.clone(),
1212 upper_bound_1.region,
1213 upper_bound_2.origin.clone(),
1214 upper_bound_2.region));
1221 self.tcx.sess.span_bug(
1222 self.var_origins.borrow().get(node_idx.to_uint()).span(),
1223 format!("collect_error_for_contracting_node() could not find error \
1224 for var {:?}, upper_bounds={}",
1228 .collect::<Vec<ty::Region>>()
1229 .repr(self.tcx)).as_slice());
1232 fn collect_concrete_regions(&self,
1233 graph: &RegionGraph,
1234 var_data: &[VarData],
1235 orig_node_idx: RegionVid,
1237 dup_vec: &mut [uint])
1238 -> (Vec<RegionAndOrigin> , bool) {
1240 set: HashSet<RegionVid>,
1241 stack: Vec<RegionVid> ,
1242 result: Vec<RegionAndOrigin> ,
1245 let mut state = WalkState {
1246 set: HashSet::new(),
1247 stack: vec!(orig_node_idx),
1251 state.set.insert(orig_node_idx);
1253 // to start off the process, walk the source node in the
1254 // direction specified
1255 process_edges(self, &mut state, graph, orig_node_idx, dir);
1257 while !state.stack.is_empty() {
1258 let node_idx = state.stack.pop().unwrap();
1259 let classification = var_data[node_idx.to_uint()].classification;
1261 // check whether we've visited this node on some previous walk
1262 if dup_vec[node_idx.to_uint()] == uint::MAX {
1263 dup_vec[node_idx.to_uint()] = orig_node_idx.to_uint();
1264 } else if dup_vec[node_idx.to_uint()] != orig_node_idx.to_uint() {
1265 state.dup_found = true;
1268 debug!("collect_concrete_regions(orig_node_idx={:?}, node_idx={:?}, \
1269 classification={:?})",
1270 orig_node_idx, node_idx, classification);
1272 // figure out the direction from which this node takes its
1273 // values, and search for concrete regions etc in that direction
1274 let dir = match classification {
1275 Expanding => graph::Incoming,
1276 Contracting => graph::Outgoing,
1279 process_edges(self, &mut state, graph, node_idx, dir);
1282 let WalkState {result, dup_found, ..} = state;
1283 return (result, dup_found);
1285 fn process_edges(this: &RegionVarBindings,
1286 state: &mut WalkState,
1287 graph: &RegionGraph,
1288 source_vid: RegionVid,
1290 debug!("process_edges(source_vid={:?}, dir={:?})", source_vid, dir);
1292 let source_node_index = NodeIndex(source_vid.to_uint());
1293 graph.each_adjacent_edge(source_node_index, dir, |_, edge| {
1295 ConstrainVarSubVar(from_vid, to_vid) => {
1297 if from_vid == source_vid {to_vid} else {from_vid};
1298 if state.set.insert(opp_vid) {
1299 state.stack.push(opp_vid);
1303 ConstrainRegSubVar(region, _) |
1304 ConstrainVarSubReg(_, region) => {
1305 state.result.push(RegionAndOrigin {
1307 origin: this.constraints.borrow().get_copy(&edge.data)
1311 ConstrainRegSubReg(..) => {}
1318 fn iterate_until_fixed_point(&self,
1320 body: |constraint: &Constraint| -> bool) {
1321 let mut iteration = 0;
1322 let mut changed = true;
1326 debug!("---- {} Iteration \\#{}", tag, iteration);
1327 for (constraint, _) in self.constraints.borrow().iter() {
1328 let edge_changed = body(constraint);
1330 debug!("Updated due to constraint {}",
1331 constraint.repr(self.tcx));
1336 debug!("---- {} Complete after {} iteration(s)", tag, iteration);
1341 impl Repr for Constraint {
1342 fn repr(&self, tcx: &ty::ctxt) -> String {
1344 ConstrainVarSubVar(a, b) => {
1345 format!("ConstrainVarSubVar({}, {})", a.repr(tcx), b.repr(tcx))
1347 ConstrainRegSubVar(a, b) => {
1348 format!("ConstrainRegSubVar({}, {})", a.repr(tcx), b.repr(tcx))
1350 ConstrainVarSubReg(a, b) => {
1351 format!("ConstrainVarSubReg({}, {})", a.repr(tcx), b.repr(tcx))
1353 ConstrainRegSubReg(a, b) => {
1354 format!("ConstrainRegSubReg({}, {})", a.repr(tcx), b.repr(tcx))