1 // Copyright 2012 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::{FreeRegion, Region, RegionVid};
16 use middle::ty::{re_empty, re_static, re_infer, re_free, re_bound};
17 use middle::ty::{re_scope, ReVar, ReSkolemized, br_fresh};
18 use middle::typeck::infer::cres;
19 use middle::typeck::infer::{RegionVariableOrigin, SubregionOrigin};
20 use middle::typeck::infer;
22 use middle::graph::{Direction, NodeIndex};
23 use util::common::indenter;
24 use util::ppaux::{Repr};
27 use std::hashmap::{HashMap, HashSet};
32 use syntax::opt_vec::OptVec;
36 #[deriving(Eq, IterBytes)]
38 ConstrainVarSubVar(RegionVid, RegionVid),
39 ConstrainRegSubVar(Region, RegionVid),
40 ConstrainVarSubReg(RegionVid, Region),
41 ConstrainRegSubReg(Region, Region),
44 #[deriving(Eq, IterBytes)]
53 AddConstraint(Constraint),
54 AddCombination(CombineMapType, TwoRegions)
61 pub enum RegionResolutionError {
62 /// `ConcreteFailure(o, a, b)`:
64 /// `o` requires that `a <= b`, but this does not hold
65 ConcreteFailure(SubregionOrigin, Region, Region),
67 /// `SubSupConflict(v, sub_origin, sub_r, sup_origin, sup_r)`:
69 /// Could not infer a value for `v` because `sub_r <= v` (due to
70 /// `sub_origin`) but `v <= sup_r` (due to `sup_origin`) and
71 /// `sub_r <= sup_r` does not hold.
72 SubSupConflict(RegionVariableOrigin,
73 SubregionOrigin, Region,
74 SubregionOrigin, Region),
76 /// `SupSupConflict(v, origin1, r1, origin2, r2)`:
78 /// Could not infer a value for `v` because `v <= r1` (due to
79 /// `origin1`) and `v <= r2` (due to `origin2`) and
80 /// `r1` and `r2` have no intersection.
81 SupSupConflict(RegionVariableOrigin,
82 SubregionOrigin, Region,
83 SubregionOrigin, Region),
86 type CombineMap = HashMap<TwoRegions, RegionVid>;
88 pub struct RegionVarBindings {
90 var_origins: ~[RegionVariableOrigin],
91 constraints: HashMap<Constraint, SubregionOrigin>,
94 skolemization_count: uint,
97 // The undo log records actions that might later be undone.
99 // Note: when the undo_log is empty, we are not actively
100 // snapshotting. When the `start_snapshot()` method is called, we
101 // push a Snapshot entry onto the list to indicate that we are now
102 // actively snapshotting. The reason for this is that otherwise
103 // we end up adding entries for things like the lower bound on
104 // a variable and so forth, which can never be rolled back.
105 undo_log: ~[UndoLogEntry],
107 // This contains the results of inference. It begins as an empty
108 // cell and only acquires a value after inference is complete.
109 // We use a cell vs a mutable option to circumvent borrowck errors.
110 values: Cell<~[VarValue]>,
113 pub fn RegionVarBindings(tcx: ty::ctxt) -> RegionVarBindings {
117 values: Cell::new_empty(),
118 constraints: HashMap::new(),
119 lubs: HashMap::new(),
120 glbs: HashMap::new(),
121 skolemization_count: 0,
127 impl RegionVarBindings {
128 pub fn in_snapshot(&self) -> bool {
129 self.undo_log.len() > 0
132 pub fn start_snapshot(&mut self) -> uint {
133 debug!("RegionVarBindings: snapshot()=%u", self.undo_log.len());
134 if self.in_snapshot() {
137 self.undo_log.push(Snapshot);
142 pub fn commit(&mut self) {
143 debug!("RegionVarBindings: commit()");
144 while self.undo_log.len() > 0 {
149 pub fn rollback_to(&mut self, snapshot: uint) {
150 debug!("RegionVarBindings: rollback_to(%u)", snapshot);
151 while self.undo_log.len() > snapshot {
152 let undo_item = self.undo_log.pop();
153 debug!("undo_item=%?", undo_item);
157 assert_eq!(self.var_origins.len(), vid.to_uint() + 1);
158 self.var_origins.pop();
160 AddConstraint(ref constraint) => {
161 self.constraints.remove(constraint);
163 AddCombination(Glb, ref regions) => {
164 self.glbs.remove(regions);
166 AddCombination(Lub, ref regions) => {
167 self.lubs.remove(regions);
173 pub fn num_vars(&self) -> uint {
174 self.var_origins.len()
177 pub fn new_region_var(&mut self, origin: RegionVariableOrigin) -> RegionVid {
178 let id = self.num_vars();
179 self.var_origins.push(origin);
180 let vid = RegionVid { id: id };
181 if self.in_snapshot() {
182 self.undo_log.push(AddVar(vid));
184 debug!("created new region variable %? with origin %?",
185 vid, origin.repr(self.tcx));
189 pub fn new_skolemized(&mut self, br: ty::bound_region) -> Region {
190 let sc = self.skolemization_count;
191 self.skolemization_count += 1;
192 re_infer(ReSkolemized(sc, br))
195 pub fn new_bound(&mut self) -> Region {
196 // Creates a fresh bound variable for use in GLB computations.
197 // See discussion of GLB computation in the large comment at
198 // the top of this file for more details.
200 // This computation is mildly wrong in the face of rollover.
201 // It's conceivable, if unlikely, that one might wind up with
202 // accidental capture for nested functions in that case, if
203 // the outer function had bound regions created a very long
204 // time before and the inner function somehow wound up rolling
205 // over such that supposedly fresh identifiers were in fact
206 // shadowed. We should convert our bound_region
207 // representation to use deBruijn indices or something like
208 // that to eliminate that possibility.
210 let sc = self.bound_count;
211 self.bound_count += 1;
212 re_bound(br_fresh(sc))
215 pub fn add_constraint(&mut self,
216 constraint: Constraint,
217 origin: SubregionOrigin) {
218 // cannot add constraints once regions are resolved
219 assert!(self.values.is_empty());
221 debug!("RegionVarBindings: add_constraint(%?)", constraint);
223 if self.constraints.insert(constraint, origin) {
224 if self.in_snapshot() {
225 self.undo_log.push(AddConstraint(constraint));
230 pub fn make_subregion(&mut self,
231 origin: SubregionOrigin,
234 // cannot add constraints once regions are resolved
235 assert!(self.values.is_empty());
237 debug!("RegionVarBindings: make_subregion(%?, %?)", sub, sup);
239 (re_infer(ReVar(sub_id)), re_infer(ReVar(sup_id))) => {
240 self.add_constraint(ConstrainVarSubVar(sub_id, sup_id), origin);
242 (r, re_infer(ReVar(sup_id))) => {
243 self.add_constraint(ConstrainRegSubVar(r, sup_id), origin);
245 (re_infer(ReVar(sub_id)), r) => {
246 self.add_constraint(ConstrainVarSubReg(sub_id, r), origin);
248 (re_bound(br), _) => {
249 self.tcx.sess.span_bug(
251 fmt!("Cannot relate bound region as subregion: %?", br));
253 (_, re_bound(br)) => {
254 self.tcx.sess.span_bug(
256 fmt!("Cannot relate bound region as superregion: %?", br));
259 self.add_constraint(ConstrainRegSubReg(sub, sup), origin);
264 pub fn lub_regions(&mut self,
265 origin: SubregionOrigin,
269 // cannot add constraints once regions are resolved
270 assert!(self.values.is_empty());
272 debug!("RegionVarBindings: lub_regions(%?, %?)", a, b);
274 (re_static, _) | (_, re_static) => {
275 re_static // nothing lives longer than static
282 this.make_subregion(origin, old_r, new_r))
287 pub fn glb_regions(&mut self,
288 origin: SubregionOrigin,
292 // cannot add constraints once regions are resolved
293 assert!(self.values.is_empty());
295 debug!("RegionVarBindings: glb_regions(%?, %?)", a, b);
297 (re_static, r) | (r, re_static) => {
298 // static lives longer than everything else
306 this.make_subregion(origin, new_r, old_r))
311 pub fn resolve_var(&mut self, rid: RegionVid) -> ty::Region {
312 if self.values.is_empty() {
313 self.tcx.sess.span_bug(
314 self.var_origins[rid.to_uint()].span(),
315 fmt!("Attempt to resolve region variable before values have \
319 let v = self.values.with_ref(|values| values[rid.to_uint()]);
320 debug!("RegionVarBindings: resolve_var(%?=%u)=%?",
321 rid, rid.to_uint(), v);
326 // No constraints, return ty::re_empty
331 // An error that has previously been reported.
337 fn combine_map<'a>(&'a mut self,
339 -> &'a mut CombineMap
342 Glb => &mut self.glbs,
343 Lub => &mut self.lubs,
347 pub fn combine_vars(&mut self,
351 origin: SubregionOrigin,
352 relate: &fn(this: &mut RegionVarBindings,
356 let vars = TwoRegions { a: a, b: b };
357 match self.combine_map(t).find(&vars) {
359 return re_infer(ReVar(c));
363 let c = self.new_region_var(infer::MiscVariable(origin.span()));
364 self.combine_map(t).insert(vars, c);
365 if self.in_snapshot() {
366 self.undo_log.push(AddCombination(t, vars));
368 relate(self, a, re_infer(ReVar(c)));
369 relate(self, b, re_infer(ReVar(c)));
370 debug!("combine_vars() c=%?", c);
374 pub fn vars_created_since_snapshot(&mut self, snapshot: uint)
376 do vec::build |push| {
377 for &elt in self.undo_log.slice_from(snapshot).iter() {
379 AddVar(vid) => push(vid),
386 pub fn tainted(&mut self, snapshot: uint, r0: Region) -> ~[Region] {
388 * Computes all regions that have been related to `r0` in any
389 * way since the snapshot `snapshot` was taken---`r0` itself
390 * will be the first entry. This is used when checking whether
391 * skolemized regions are being improperly related to other
395 debug!("tainted(snapshot=%u, r0=%?)", snapshot, r0);
396 let _indenter = indenter();
398 let undo_len = self.undo_log.len();
400 // `result_set` acts as a worklist: we explore all outgoing
401 // edges and add any new regions we find to result_set. This
402 // is not a terribly efficient implementation.
403 let mut result_set = ~[r0];
404 let mut result_index = 0;
405 while result_index < result_set.len() {
406 // nb: can't use uint::range() here because result_set grows
407 let r = result_set[result_index];
409 debug!("result_index=%u, r=%?", result_index, r);
411 let mut undo_index = snapshot;
412 while undo_index < undo_len {
413 // nb: can't use uint::range() here as we move result_set
414 let regs = match self.undo_log[undo_index] {
415 AddConstraint(ConstrainVarSubVar(ref a, ref b)) => {
416 Some((re_infer(ReVar(*a)),
417 re_infer(ReVar(*b))))
419 AddConstraint(ConstrainRegSubVar(ref a, ref b)) => {
420 Some((*a, re_infer(ReVar(*b))))
422 AddConstraint(ConstrainVarSubReg(ref a, ref b)) => {
423 Some((re_infer(ReVar(*a)), *b))
425 AddConstraint(ConstrainRegSubReg(a, b)) => {
437 consider_adding_edge(result_set, r, r1, r2);
439 consider_adding_edge(result_set, r, r2, r1);
451 fn consider_adding_edge(result_set: ~[Region],
454 r2: Region) -> ~[Region]
456 let mut result_set = result_set;
457 if r == r1 { // Clearly, this is potentially inefficient.
458 if !result_set.iter().any(|x| *x == r2) {
467 This function performs the actual region resolution. It must be
468 called after all constraints have been added. It performs a
469 fixed-point iteration to find region values which satisfy all
470 constraints, assuming such values can be found; if they cannot,
473 pub fn resolve_regions(&mut self) -> OptVec<RegionResolutionError> {
474 debug!("RegionVarBindings: resolve_regions()");
475 let mut errors = opt_vec::Empty;
476 let v = self.infer_variable_values(&mut errors);
477 self.values.put_back(v);
482 impl RegionVarBindings {
483 fn is_subregion_of(&self, sub: Region, sup: Region) -> bool {
484 let rm = self.tcx.region_maps;
485 rm.is_subregion_of(sub, sup)
488 fn lub_concrete_regions(&self, a: Region, b: Region) -> Region {
490 (re_static, _) | (_, re_static) => {
491 re_static // nothing lives longer than static
494 (re_empty, r) | (r, re_empty) => {
495 r // everything lives longer than empty
498 (re_infer(ReVar(v_id)), _) | (_, re_infer(ReVar(v_id))) => {
499 self.tcx.sess.span_bug(
500 self.var_origins[v_id.to_uint()].span(),
501 fmt!("lub_concrete_regions invoked with \
502 non-concrete regions: %?, %?", a, b));
505 (f @ re_free(ref fr), re_scope(s_id)) |
506 (re_scope(s_id), f @ re_free(ref fr)) => {
507 // A "free" region can be interpreted as "some region
508 // at least as big as the block fr.scope_id". So, we can
509 // reasonably compare free regions and scopes:
510 let rm = self.tcx.region_maps;
511 match rm.nearest_common_ancestor(fr.scope_id, s_id) {
512 // if the free region's scope `fr.scope_id` is bigger than
513 // the scope region `s_id`, then the LUB is the free
515 Some(r_id) if r_id == fr.scope_id => f,
517 // otherwise, we don't know what the free region is,
518 // so we must conservatively say the LUB is static:
523 (re_scope(a_id), re_scope(b_id)) => {
524 // The region corresponding to an outer block is a
525 // subtype of the region corresponding to an inner
527 let rm = self.tcx.region_maps;
528 match rm.nearest_common_ancestor(a_id, b_id) {
529 Some(r_id) => re_scope(r_id),
534 (re_free(ref a_fr), re_free(ref b_fr)) => {
535 self.lub_free_regions(a_fr, b_fr)
538 // For these types, we cannot define any additional
540 (re_infer(ReSkolemized(*)), _) |
541 (_, re_infer(ReSkolemized(*))) |
542 (re_bound(_), re_bound(_)) |
543 (re_bound(_), re_free(_)) |
544 (re_bound(_), re_scope(_)) |
545 (re_free(_), re_bound(_)) |
546 (re_scope(_), re_bound(_)) => {
547 if a == b {a} else {re_static}
552 fn lub_free_regions(&self,
554 b: &FreeRegion) -> ty::Region
557 * Computes a region that encloses both free region arguments.
558 * Guarantee that if the same two regions are given as argument,
559 * in any order, a consistent result is returned.
562 return match a.cmp(b) {
563 Less => helper(self, a, b),
564 Greater => helper(self, b, a),
565 Equal => ty::re_free(*a)
568 fn helper(this: &RegionVarBindings,
570 b: &FreeRegion) -> ty::Region
572 let rm = this.tcx.region_maps;
573 if rm.sub_free_region(*a, *b) {
575 } else if rm.sub_free_region(*b, *a) {
583 fn glb_concrete_regions(&self,
587 debug!("glb_concrete_regions(%?, %?)", a, b);
589 (re_static, r) | (r, re_static) => {
590 // static lives longer than everything else
594 (re_empty, _) | (_, re_empty) => {
595 // nothing lives shorter than everything else
599 (re_infer(ReVar(v_id)), _) |
600 (_, re_infer(ReVar(v_id))) => {
601 self.tcx.sess.span_bug(
602 self.var_origins[v_id.to_uint()].span(),
603 fmt!("glb_concrete_regions invoked with \
604 non-concrete regions: %?, %?", a, b));
607 (re_free(ref fr), s @ re_scope(s_id)) |
608 (s @ re_scope(s_id), re_free(ref fr)) => {
609 // Free region is something "at least as big as
610 // `fr.scope_id`." If we find that the scope `fr.scope_id` is bigger
611 // than the scope `s_id`, then we can say that the GLB
612 // is the scope `s_id`. Otherwise, as we do not know
613 // big the free region is precisely, the GLB is undefined.
614 let rm = self.tcx.region_maps;
615 match rm.nearest_common_ancestor(fr.scope_id, s_id) {
616 Some(r_id) if r_id == fr.scope_id => Ok(s),
617 _ => Err(ty::terr_regions_no_overlap(b, a))
621 (re_scope(a_id), re_scope(b_id)) => {
622 self.intersect_scopes(a, b, a_id, b_id)
625 (re_free(ref a_fr), re_free(ref b_fr)) => {
626 self.glb_free_regions(a_fr, b_fr)
629 // For these types, we cannot define any additional
631 (re_infer(ReSkolemized(*)), _) |
632 (_, re_infer(ReSkolemized(*))) |
633 (re_bound(_), re_bound(_)) |
634 (re_bound(_), re_free(_)) |
635 (re_bound(_), re_scope(_)) |
636 (re_free(_), re_bound(_)) |
637 (re_scope(_), re_bound(_)) => {
641 Err(ty::terr_regions_no_overlap(b, a))
647 fn glb_free_regions(&self,
649 b: &FreeRegion) -> cres<ty::Region>
652 * Computes a region that is enclosed by both free region arguments,
653 * if any. Guarantees that if the same two regions are given as argument,
654 * in any order, a consistent result is returned.
657 return match a.cmp(b) {
658 Less => helper(self, a, b),
659 Greater => helper(self, b, a),
660 Equal => Ok(ty::re_free(*a))
663 fn helper(this: &RegionVarBindings,
665 b: &FreeRegion) -> cres<ty::Region>
667 let rm = this.tcx.region_maps;
668 if rm.sub_free_region(*a, *b) {
670 } else if rm.sub_free_region(*b, *a) {
673 this.intersect_scopes(ty::re_free(*a), ty::re_free(*b),
674 a.scope_id, b.scope_id)
679 fn report_type_error(&mut self,
680 origin: SubregionOrigin,
681 terr: &ty::type_err) {
682 let terr_str = ty::type_err_to_str(self.tcx, terr);
683 self.tcx.sess.span_err(origin.span(), terr_str);
686 fn intersect_scopes(&self,
687 region_a: ty::Region,
688 region_b: ty::Region,
689 scope_a: ast::NodeId,
690 scope_b: ast::NodeId) -> cres<Region>
692 // We want to generate the intersection of two
693 // scopes or two free regions. So, if one of
694 // these scopes is a subscope of the other, return
695 // it. Otherwise fail.
696 debug!("intersect_scopes(scope_a=%?, scope_b=%?, region_a=%?, region_b=%?)",
697 scope_a, scope_b, region_a, region_b);
698 let rm = self.tcx.region_maps;
699 match rm.nearest_common_ancestor(scope_a, scope_b) {
700 Some(r_id) if scope_a == r_id => Ok(re_scope(scope_b)),
701 Some(r_id) if scope_b == r_id => Ok(re_scope(scope_a)),
702 _ => Err(ty::terr_regions_no_overlap(region_a, region_b))
707 // ______________________________________________________________________
710 enum Classification { Expanding, Contracting }
712 enum VarValue { NoValue, Value(Region), ErrorValue }
715 classification: Classification,
719 struct RegionAndOrigin {
721 origin: SubregionOrigin,
724 type RegionGraph = graph::Graph<(), Constraint>;
726 impl RegionVarBindings {
727 fn infer_variable_values(&self,
728 errors: &mut OptVec<RegionResolutionError>)
730 let mut var_data = self.construct_var_data();
731 self.expansion(var_data);
732 self.contraction(var_data);
733 self.collect_concrete_region_errors(errors);
734 self.extract_values_and_collect_conflicts(var_data, errors)
737 fn construct_var_data(&self) -> ~[VarData] {
738 vec::from_fn(self.num_vars(), |_| {
740 // All nodes are initially classified as contracting; during
741 // the expansion phase, we will shift the classification for
742 // those nodes that have a concrete region predecessor to
744 classification: Contracting,
750 fn expansion(&self, var_data: &mut [VarData]) {
751 do self.iterate_until_fixed_point("Expansion") |constraint| {
753 ConstrainRegSubVar(a_region, b_vid) => {
754 let b_data = &mut var_data[b_vid.to_uint()];
755 self.expand_node(a_region, b_vid, b_data)
757 ConstrainVarSubVar(a_vid, b_vid) => {
758 match var_data[a_vid.to_uint()].value {
759 NoValue | ErrorValue => false,
761 let b_node = &mut var_data[b_vid.to_uint()];
762 self.expand_node(a_region, b_vid, b_node)
766 ConstrainVarSubReg(*) => {
767 // This is a contraction constraint. Ignore it.
770 ConstrainRegSubReg(*) => {
771 // No region variables involved. Ignore.
778 fn expand_node(&self,
781 b_data: &mut VarData)
783 debug!("expand_node(%?, %? == %?)",
784 a_region, b_vid, b_data.value);
786 b_data.classification = Expanding;
789 debug!("Setting initial value of %? to %?", b_vid, a_region);
791 b_data.value = Value(a_region);
795 Value(cur_region) => {
796 let lub = self.lub_concrete_regions(a_region, cur_region);
797 if lub == cur_region {
801 debug!("Expanding value of %? from %? to %?",
802 b_vid, cur_region, lub);
804 b_data.value = Value(lub);
814 fn contraction(&self,
815 var_data: &mut [VarData]) {
816 do self.iterate_until_fixed_point("Contraction") |constraint| {
818 ConstrainRegSubVar(*) => {
819 // This is an expansion constraint. Ignore.
822 ConstrainVarSubVar(a_vid, b_vid) => {
823 match var_data[b_vid.to_uint()].value {
824 NoValue | ErrorValue => false,
826 let a_data = &mut var_data[a_vid.to_uint()];
827 self.contract_node(a_vid, a_data, b_region)
831 ConstrainVarSubReg(a_vid, b_region) => {
832 let a_data = &mut var_data[a_vid.to_uint()];
833 self.contract_node(a_vid, a_data, b_region)
835 ConstrainRegSubReg(*) => {
836 // No region variables involved. Ignore.
843 fn contract_node(&self,
845 a_data: &mut VarData,
848 debug!("contract_node(%? == %?/%?, %?)",
849 a_vid, a_data.value, a_data.classification, b_region);
851 return match a_data.value {
853 assert_eq!(a_data.classification, Contracting);
854 a_data.value = Value(b_region);
863 match a_data.classification {
865 check_node(self, a_vid, a_data, a_region, b_region)
868 adjust_node(self, a_vid, a_data, a_region, b_region)
874 fn check_node(this: &RegionVarBindings,
876 a_data: &mut VarData,
880 if !this.is_subregion_of(a_region, b_region) {
881 debug!("Setting %? to ErrorValue: %? not subregion of %?",
882 a_vid, a_region, b_region);
883 a_data.value = ErrorValue;
888 fn adjust_node(this: &RegionVarBindings,
890 a_data: &mut VarData,
894 match this.glb_concrete_regions(a_region, b_region) {
899 debug!("Contracting value of %? from %? to %?",
900 a_vid, a_region, glb);
901 a_data.value = Value(glb);
906 debug!("Setting %? to ErrorValue: no glb of %?, %?",
907 a_vid, a_region, b_region);
908 a_data.value = ErrorValue;
915 fn collect_concrete_region_errors(
917 errors: &mut OptVec<RegionResolutionError>)
919 for (constraint, _) in self.constraints.iter() {
920 let (sub, sup) = match *constraint {
921 ConstrainVarSubVar(*) |
922 ConstrainRegSubVar(*) |
923 ConstrainVarSubReg(*) => {
926 ConstrainRegSubReg(sub, sup) => {
931 if self.is_subregion_of(sub, sup) {
935 debug!("ConcreteFailure: !(sub <= sup): sub=%?, sup=%?",
937 let origin = self.constraints.get_copy(constraint);
938 errors.push(ConcreteFailure(origin, sub, sup));
942 fn extract_values_and_collect_conflicts(
944 var_data: &[VarData],
945 errors: &mut OptVec<RegionResolutionError>)
948 debug!("extract_values_and_collect_conflicts()");
950 // This is the best way that I have found to suppress
951 // duplicate and related errors. Basically we keep a set of
952 // flags for every node. Whenever an error occurs, we will
953 // walk some portion of the graph looking to find pairs of
954 // conflicting regions to report to the user. As we walk, we
955 // trip the flags from false to true, and if we find that
956 // we've already reported an error involving any particular
957 // node we just stop and don't report the current error. The
958 // idea is to report errors that derive from independent
959 // regions of the graph, but not those that derive from
960 // overlapping locations.
961 let mut dup_vec = vec::from_elem(self.num_vars(), uint::max_value);
963 let mut opt_graph = None;
965 for idx in range(0u, self.num_vars()) {
966 match var_data[idx].value {
968 /* Inference successful */
971 /* Unconstrained inference: do not report an error
972 until the value of this variable is requested.
973 After all, sometimes we make region variables but never
974 really use their values. */
977 /* Inference impossible, this value contains
978 inconsistent constraints.
980 I think that in this case we should report an
981 error now---unlike the case above, we can't
982 wait to see whether the user needs the result
983 of this variable. The reason is that the mere
984 existence of this variable implies that the
985 region graph is inconsistent, whether or not it
988 For example, we may have created a region
989 variable that is the GLB of two other regions
990 which do not have a GLB. Even if that variable
991 is not used, it implies that those two regions
994 At least I think this is true. It may be that
995 the mere existence of a conflict in a region variable
996 that is not used is not a problem, so if this rule
997 starts to create problems we'll have to revisit
998 this portion of the code and think hard about it. =) */
1000 if opt_graph.is_none() {
1001 opt_graph = Some(self.construct_graph());
1003 let graph = opt_graph.get_ref();
1005 let node_vid = RegionVid { id: idx };
1006 match var_data[idx].classification {
1008 self.collect_error_for_expanding_node(
1009 graph, var_data, dup_vec, node_vid, errors);
1012 self.collect_error_for_contracting_node(
1013 graph, var_data, dup_vec, node_vid, errors);
1020 vec::from_fn(self.num_vars(), |idx| var_data[idx].value)
1023 fn construct_graph(&self) -> RegionGraph {
1024 let num_vars = self.num_vars();
1025 let num_edges = self.constraints.len();
1027 let mut graph = graph::Graph::with_capacity(num_vars + 1,
1030 for _ in range(0u, num_vars) {
1033 let dummy_idx = graph.add_node(());
1035 for (constraint, _) in self.constraints.iter() {
1037 ConstrainVarSubVar(a_id, b_id) => {
1038 graph.add_edge(NodeIndex(a_id.to_uint()),
1039 NodeIndex(b_id.to_uint()),
1042 ConstrainRegSubVar(_, b_id) => {
1043 graph.add_edge(dummy_idx,
1044 NodeIndex(b_id.to_uint()),
1047 ConstrainVarSubReg(a_id, _) => {
1048 graph.add_edge(NodeIndex(a_id.to_uint()),
1052 ConstrainRegSubReg(*) => {
1053 // Relations between two concrete regions do not
1054 // require an edge in the graph.
1062 fn collect_error_for_expanding_node(
1064 graph: &RegionGraph,
1065 var_data: &[VarData],
1066 dup_vec: &mut [uint],
1067 node_idx: RegionVid,
1068 errors: &mut OptVec<RegionResolutionError>)
1070 // Errors in expanding nodes result from a lower-bound that is
1071 // not contained by an upper-bound.
1072 let (lower_bounds, lower_dup) =
1073 self.collect_concrete_regions(graph, var_data, node_idx,
1074 graph::Incoming, dup_vec);
1075 let (upper_bounds, upper_dup) =
1076 self.collect_concrete_regions(graph, var_data, node_idx,
1077 graph::Outgoing, dup_vec);
1079 if lower_dup || upper_dup {
1083 for lower_bound in lower_bounds.iter() {
1084 for upper_bound in upper_bounds.iter() {
1085 if !self.is_subregion_of(lower_bound.region,
1086 upper_bound.region) {
1087 errors.push(SubSupConflict(
1088 self.var_origins[node_idx.to_uint()],
1092 upper_bound.region));
1098 self.tcx.sess.span_bug(
1099 self.var_origins[node_idx.to_uint()].span(),
1100 fmt!("collect_error_for_expanding_node() could not find error \
1101 for var %?, lower_bounds=%s, upper_bounds=%s",
1103 lower_bounds.map(|x| x.region).repr(self.tcx),
1104 upper_bounds.map(|x| x.region).repr(self.tcx)));
1107 fn collect_error_for_contracting_node(
1109 graph: &RegionGraph,
1110 var_data: &[VarData],
1111 dup_vec: &mut [uint],
1112 node_idx: RegionVid,
1113 errors: &mut OptVec<RegionResolutionError>)
1115 // Errors in contracting nodes result from two upper-bounds
1116 // that have no intersection.
1117 let (upper_bounds, dup_found) =
1118 self.collect_concrete_regions(graph, var_data, node_idx,
1119 graph::Outgoing, dup_vec);
1125 for upper_bound_1 in upper_bounds.iter() {
1126 for upper_bound_2 in upper_bounds.iter() {
1127 match self.glb_concrete_regions(upper_bound_1.region,
1128 upper_bound_2.region) {
1131 errors.push(SupSupConflict(
1132 self.var_origins[node_idx.to_uint()],
1133 upper_bound_1.origin,
1134 upper_bound_1.region,
1135 upper_bound_2.origin,
1136 upper_bound_2.region));
1143 self.tcx.sess.span_bug(
1144 self.var_origins[node_idx.to_uint()].span(),
1145 fmt!("collect_error_for_contracting_node() could not find error \
1146 for var %?, upper_bounds=%s",
1148 upper_bounds.map(|x| x.region).repr(self.tcx)));
1151 fn collect_concrete_regions(&self,
1152 graph: &RegionGraph,
1153 var_data: &[VarData],
1154 orig_node_idx: RegionVid,
1156 dup_vec: &mut [uint])
1157 -> (~[RegionAndOrigin], bool) {
1159 set: HashSet<RegionVid>,
1160 stack: ~[RegionVid],
1161 result: ~[RegionAndOrigin],
1164 let mut state = WalkState {
1165 set: HashSet::new(),
1166 stack: ~[orig_node_idx],
1170 state.set.insert(orig_node_idx);
1172 // to start off the process, walk the source node in the
1173 // direction specified
1174 process_edges(self, &mut state, graph, orig_node_idx, dir);
1176 while !state.stack.is_empty() {
1177 let node_idx = state.stack.pop();
1178 let classification = var_data[node_idx.to_uint()].classification;
1180 // check whether we've visited this node on some previous walk
1181 if dup_vec[node_idx.to_uint()] == uint::max_value {
1182 dup_vec[node_idx.to_uint()] = orig_node_idx.to_uint();
1183 } else if dup_vec[node_idx.to_uint()] != orig_node_idx.to_uint() {
1184 state.dup_found = true;
1187 debug!("collect_concrete_regions(orig_node_idx=%?, node_idx=%?, \
1188 classification=%?)",
1189 orig_node_idx, node_idx, classification);
1191 // figure out the direction from which this node takes its
1192 // values, and search for concrete regions etc in that direction
1193 let dir = match classification {
1194 Expanding => graph::Incoming,
1195 Contracting => graph::Outgoing,
1198 process_edges(self, &mut state, graph, node_idx, dir);
1201 let WalkState {result, dup_found, _} = state;
1202 return (result, dup_found);
1204 fn process_edges(this: &RegionVarBindings,
1205 state: &mut WalkState,
1206 graph: &RegionGraph,
1207 source_vid: RegionVid,
1209 debug!("process_edges(source_vid=%?, dir=%?)", source_vid, dir);
1211 let source_node_index = NodeIndex(source_vid.to_uint());
1212 do graph.each_adjacent_edge(source_node_index, dir) |_, edge| {
1214 ConstrainVarSubVar(from_vid, to_vid) => {
1216 if from_vid == source_vid {to_vid} else {from_vid};
1217 if state.set.insert(opp_vid) {
1218 state.stack.push(opp_vid);
1222 ConstrainRegSubVar(region, _) |
1223 ConstrainVarSubReg(_, region) => {
1224 state.result.push(RegionAndOrigin {
1226 origin: this.constraints.get_copy(&edge.data)
1230 ConstrainRegSubReg(*) => {}
1237 fn iterate_until_fixed_point(&self,
1239 body: &fn(constraint: &Constraint) -> bool) {
1240 let mut iteration = 0;
1241 let mut changed = true;
1245 debug!("---- %s Iteration #%u", tag, iteration);
1246 for (constraint, _) in self.constraints.iter() {
1247 let edge_changed = body(constraint);
1249 debug!("Updated due to constraint %s",
1250 constraint.repr(self.tcx));
1255 debug!("---- %s Complete after %u iteration(s)", tag, iteration);
1260 impl Repr for Constraint {
1261 fn repr(&self, tcx: ty::ctxt) -> ~str {
1263 ConstrainVarSubVar(a, b) => fmt!("ConstrainVarSubVar(%s, %s)",
1264 a.repr(tcx), b.repr(tcx)),
1265 ConstrainRegSubVar(a, b) => fmt!("ConstrainRegSubVar(%s, %s)",
1266 a.repr(tcx), b.repr(tcx)),
1267 ConstrainVarSubReg(a, b) => fmt!("ConstrainVarSubReg(%s, %s)",
1268 a.repr(tcx), b.repr(tcx)),
1269 ConstrainRegSubReg(a, b) => fmt!("ConstrainRegSubReg(%s, %s)",
1270 a.repr(tcx), b.repr(tcx)),