]> git.lizzy.rs Git - rust.git/commitdiff
rewrite `free_region`/`region_inference` to use newly minted
authorNiko Matsakis <niko@alum.mit.edu>
Tue, 18 Aug 2015 21:41:20 +0000 (17:41 -0400)
committerNiko Matsakis <niko@alum.mit.edu>
Tue, 18 Aug 2015 21:41:20 +0000 (17:41 -0400)
`TransitiveRelation`

src/librustc/middle/free_region.rs
src/librustc/middle/infer/region_inference/mod.rs

index 5af37e9530ccea22ba6475fcdc81da8a5f6155bd..787303231b039a31e53716d43f96c3c3b16ab8b6 100644 (file)
 
 //! This file defines
 
+use middle::ty::{self, FreeRegion, Region};
 use middle::wf::ImpliedBound;
-use middle::ty::{self, FreeRegion};
-use util::common::can_reach;
-use util::nodemap::{FnvHashMap, FnvHashSet};
+use rustc_data_structures::transitive_relation::TransitiveRelation;
 
 #[derive(Clone)]
 pub struct FreeRegionMap {
-    /// `map` maps from a free region `a` to a list of
-    /// free regions `bs` such that `a <= b for all b in bs`
-    map: FnvHashMap<FreeRegion, Vec<FreeRegion>>,
-    /// regions that are required to outlive (and therefore be
-    /// equal to) 'static.
-    statics: FnvHashSet<FreeRegion>
+    relation: TransitiveRelation<Region>
 }
 
 impl FreeRegionMap {
     pub fn new() -> FreeRegionMap {
-        FreeRegionMap { map: FnvHashMap(), statics: FnvHashSet() }
+        FreeRegionMap { relation: TransitiveRelation::new() }
     }
 
     pub fn relate_free_regions_from_implied_bounds<'tcx>(&mut self,
@@ -84,14 +78,11 @@ pub fn relate_free_regions_from_predicates<'tcx>(&mut self,
     }
 
     fn relate_to_static(&mut self, sup: FreeRegion) {
-        self.statics.insert(sup);
+        self.relation.add(ty::ReStatic, ty::ReFree(sup));
     }
 
     fn relate_free_regions(&mut self, sub: FreeRegion, sup: FreeRegion) {
-       let mut sups = self.map.entry(sub).or_insert(Vec::new());
-        if !sups.contains(&sup) {
-            sups.push(sup);
-        }
+        self.relation.add(ty::ReFree(sub), ty::ReFree(sup))
     }
 
     /// Determines whether two free regions have a subregion relationship
@@ -99,7 +90,26 @@ fn relate_free_regions(&mut self, sub: FreeRegion, sup: FreeRegion) {
     /// it is possible that `sub != sup` and `sub <= sup` and `sup <= sub`
     /// (that is, the user can give two different names to the same lifetime).
     pub fn sub_free_region(&self, sub: FreeRegion, sup: FreeRegion) -> bool {
-        can_reach(&self.map, sub, sup) || self.is_static(&sup)
+        let result = sub == sup || {
+            let sub = ty::ReFree(sub);
+            let sup = ty::ReFree(sup);
+            self.relation.contains(&sub, &sup) || self.relation.contains(&sup, &ty::ReStatic)
+        };
+        debug!("sub_free_region(sub={:?}, sup={:?}) = {:?}", sub, sup, result);
+        result
+    }
+
+    pub fn lub_free_regions(&self, fr_a: FreeRegion, fr_b: FreeRegion) -> Region {
+        let r_a = ty::ReFree(fr_a);
+        let r_b = ty::ReFree(fr_b);
+        let result = if fr_a == fr_b { r_a } else {
+            match self.relation.best_upper_bound(&r_a, &r_b) {
+                None => ty::ReStatic,
+                Some(r) => *r,
+            }
+        };
+        debug!("lub_free_regions(fr_a={:?}, fr_b={:?}) = {:?}", fr_a, fr_b, result);
+        result
     }
 
     /// Determines whether one region is a subregion of another.  This is intended to run *after
@@ -109,10 +119,7 @@ pub fn is_subregion_of(&self,
                            sub_region: ty::Region,
                            super_region: ty::Region)
                            -> bool {
-        debug!("is_subregion_of(sub_region={:?}, super_region={:?})",
-               sub_region, super_region);
-
-        sub_region == super_region || {
+        let result = sub_region == super_region || {
             match (sub_region, super_region) {
                 (ty::ReEmpty, _) |
                 (_, ty::ReStatic) =>
@@ -121,23 +128,47 @@ pub fn is_subregion_of(&self,
                 (ty::ReScope(sub_scope), ty::ReScope(super_scope)) =>
                     tcx.region_maps.is_subscope_of(sub_scope, super_scope),
 
-                (ty::ReScope(sub_scope), ty::ReFree(ref fr)) =>
-                    tcx.region_maps.is_subscope_of(sub_scope, fr.scope.to_code_extent()),
+                (ty::ReScope(sub_scope), ty::ReFree(fr)) =>
+                    tcx.region_maps.is_subscope_of(sub_scope, fr.scope.to_code_extent()) ||
+                    self.is_static(fr),
 
                 (ty::ReFree(sub_fr), ty::ReFree(super_fr)) =>
                     self.sub_free_region(sub_fr, super_fr),
 
-                (ty::ReStatic, ty::ReFree(ref sup_fr)) => self.is_static(sup_fr),
+                (ty::ReStatic, ty::ReFree(sup_fr)) =>
+                    self.is_static(sup_fr),
 
                 _ =>
                     false,
             }
-        }
+        };
+        debug!("is_subregion_of(sub_region={:?}, super_region={:?}) = {:?}",
+               sub_region, super_region, result);
+        result
     }
 
     /// Determines whether this free-region is required to be 'static
-    pub fn is_static(&self, super_region: &ty::FreeRegion) -> bool {
+    pub fn is_static(&self, super_region: ty::FreeRegion) -> bool {
         debug!("is_static(super_region={:?})", super_region);
-        self.statics.iter().any(|s| can_reach(&self.map, *s, *super_region))
+        self.relation.contains(&ty::ReStatic, &ty::ReFree(super_region))
     }
 }
+
+#[cfg(test)]
+fn free_region(index: u32) -> FreeRegion {
+    use middle::region::DestructionScopeData;
+    FreeRegion { scope: DestructionScopeData::new(0),
+                 bound_region: ty::BoundRegion::BrAnon(index) }
+}
+
+#[test]
+fn lub() {
+    // a very VERY basic test, but see the tests in
+    // TransitiveRelation, which are much more thorough.
+    let frs: Vec<_> = (0..3).map(|i| free_region(i)).collect();
+    let mut map = FreeRegionMap::new();
+    map.relate_free_regions(frs[0], frs[2]);
+    map.relate_free_regions(frs[1], frs[2]);
+    assert_eq!(map.lub_free_regions(frs[0], frs[1]), ty::ReFree(frs[2]));
+}
+
index e8f8dbfbb0e638cf5123abac14d1abd831354599..e04f2955ddc18a2b348e22a4ec07644b0c1f4480 100644 (file)
@@ -812,8 +812,8 @@ fn lub_concrete_regions(&self, free_regions: &FreeRegionMap, a: Region, b: Regio
             ReScope(self.tcx.region_maps.nearest_common_ancestor(a_id, b_id))
           }
 
-          (ReFree(ref a_fr), ReFree(ref b_fr)) => {
-             self.lub_free_regions(free_regions, a_fr, b_fr)
+          (ReFree(a_fr), ReFree(b_fr)) => {
+            free_regions.lub_free_regions(a_fr, b_fr)
           }
 
           // For these types, we cannot define any additional
@@ -825,35 +825,6 @@ fn lub_concrete_regions(&self, free_regions: &FreeRegionMap, a: Region, b: Regio
         }
     }
 
-    /// Computes a region that encloses both free region arguments. Guarantee that if the same two
-    /// regions are given as argument, in any order, a consistent result is returned.
-    fn lub_free_regions(&self,
-                        free_regions: &FreeRegionMap,
-                        a: &FreeRegion,
-                        b: &FreeRegion)
-                        -> ty::Region
-    {
-        return match a.cmp(b) {
-            Less => helper(self, free_regions, a, b),
-            Greater => helper(self, free_regions, b, a),
-            Equal => ty::ReFree(*a)
-        };
-
-        fn helper(_this: &RegionVarBindings,
-                  free_regions: &FreeRegionMap,
-                  a: &FreeRegion,
-                  b: &FreeRegion) -> ty::Region
-        {
-            if free_regions.sub_free_region(*a, *b) {
-                ty::ReFree(*b)
-            } else if free_regions.sub_free_region(*b, *a) {
-                ty::ReFree(*a)
-            } else {
-                ty::ReStatic
-            }
-        }
-    }
-
     fn glb_concrete_regions(&self,
                             free_regions: &FreeRegionMap,
                             a: Region,
@@ -892,8 +863,8 @@ fn glb_concrete_regions(&self,
                             b));
             }
 
-            (ReFree(ref fr), ReScope(s_id)) |
-            (ReScope(s_id), ReFree(ref fr)) => {
+            (ReFree(fr), ReScope(s_id)) |
+            (ReScope(s_id), ReFree(fr)) => {
                 let s = ReScope(s_id);
                 // Free region is something "at least as big as
                 // `fr.scope_id`."  If we find that the scope `fr.scope_id` is bigger