about summary refs log tree commit diff
path: root/src/librustc/middle
diff options
context:
space:
mode:
authorTaylor Cramer <cramertaylorj@gmail.com>2017-04-10 00:00:08 -0700
committerNiko Matsakis <niko@alum.mit.edu>2017-04-30 17:03:30 -0400
commit73cd9bde373cc134aa2ebb6a8064d532621ca0a6 (patch)
treec27699bff217136b907b85b1cd76d6eba7089f18 /src/librustc/middle
parentc7dc39dbf095f04839b57a1e34afc6ab29d905d3 (diff)
downloadrust-73cd9bde373cc134aa2ebb6a8064d532621ca0a6.tar.gz
rust-73cd9bde373cc134aa2ebb6a8064d532621ca0a6.zip
introduce per-fn RegionMaps
Instead of requesting the region maps for the entire crate, request for
a given item etc. Several bits of code were modified to take
`&RegionMaps` as input (e.g., the `resolve_regions_and_report_errors()`
function). I am not totally happy with this setup -- I *think* I'd
rather have the region maps be part of typeck tables -- but at least the
`RegionMaps` works in a "parallel" way to `FreeRegionMap`, so it's not
too bad. Given that I expect a lot of this code to go away with NLL, I
didn't want to invest *too* much energy tweaking it.
Diffstat (limited to 'src/librustc/middle')
-rw-r--r--src/librustc/middle/expr_use_visitor.rs9
-rw-r--r--src/librustc/middle/free_region.rs153
-rw-r--r--src/librustc/middle/mem_categorization.rs19
-rw-r--r--src/librustc/middle/region.rs80
4 files changed, 168 insertions, 93 deletions
diff --git a/src/librustc/middle/expr_use_visitor.rs b/src/librustc/middle/expr_use_visitor.rs
index 9be05313439..a49f3d3b7a7 100644
--- a/src/librustc/middle/expr_use_visitor.rs
+++ b/src/librustc/middle/expr_use_visitor.rs
@@ -270,19 +270,24 @@ enum PassArgs {
 
 impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> {
     pub fn new(delegate: &'a mut (Delegate<'tcx>+'a),
+               context: DefId,
                infcx: &'a InferCtxt<'a, 'gcx, 'tcx>)
                -> Self
     {
-        ExprUseVisitor::with_options(delegate, infcx, mc::MemCategorizationOptions::default())
+        ExprUseVisitor::with_options(delegate,
+                                     infcx,
+                                     context,
+                                     mc::MemCategorizationOptions::default())
     }
 
     pub fn with_options(delegate: &'a mut (Delegate<'tcx>+'a),
                         infcx: &'a InferCtxt<'a, 'gcx, 'tcx>,
+                        context: DefId,
                         options: mc::MemCategorizationOptions)
                -> Self
     {
         ExprUseVisitor {
-            mc: mc::MemCategorizationContext::with_options(infcx, options),
+            mc: mc::MemCategorizationContext::with_options(infcx, context, options),
             delegate: delegate
         }
     }
diff --git a/src/librustc/middle/free_region.rs b/src/librustc/middle/free_region.rs
index 1dc633c6d00..2dc7aac04ae 100644
--- a/src/librustc/middle/free_region.rs
+++ b/src/librustc/middle/free_region.rs
@@ -15,10 +15,108 @@
 //! `TransitiveRelation` type and use that to decide when one free
 //! region outlives another and so forth.
 
+use hir::def_id::DefId;
+use middle::region::RegionMaps;
 use ty::{self, Lift, TyCtxt, Region};
 use ty::wf::ImpliedBound;
 use rustc_data_structures::transitive_relation::TransitiveRelation;
 
+/// Combines a `RegionMaps` (which governs relationships between
+/// scopes) and a `FreeRegionMap` (which governs relationships between
+/// free regions) to yield a complete relation between concrete
+/// regions.
+///
+/// This stuff is a bit convoluted and should be refactored, but as we
+/// move to NLL it'll all go away anyhow.
+pub struct RegionRelations<'a, 'gcx: 'tcx, 'tcx: 'a> {
+    pub tcx: TyCtxt<'a, 'gcx, 'tcx>,
+
+    /// context used to fetch the region maps
+    pub context: DefId,
+
+    /// region maps for the given context
+    pub region_maps: &'a RegionMaps<'tcx>,
+
+    /// free-region relationships
+    pub free_regions: &'a FreeRegionMap<'tcx>,
+}
+
+impl<'a, 'gcx, 'tcx> RegionRelations<'a, 'gcx, 'tcx> {
+    pub fn new(
+        tcx: TyCtxt<'a, 'gcx, 'tcx>,
+        context: DefId,
+        region_maps: &'a RegionMaps<'tcx>,
+        free_regions: &'a FreeRegionMap<'tcx>,
+    ) -> Self {
+        Self {
+            tcx,
+            context,
+            region_maps,
+            free_regions,
+        }
+    }
+
+    /// Determines whether one region is a subregion of another.  This is intended to run *after
+    /// inference* and sadly the logic is somewhat duplicated with the code in infer.rs.
+    pub fn is_subregion_of(&self,
+                           sub_region: ty::Region<'tcx>,
+                           super_region: ty::Region<'tcx>)
+                           -> bool {
+        let result = sub_region == super_region || {
+            match (sub_region, super_region) {
+                (&ty::ReEmpty, _) |
+                (_, &ty::ReStatic) =>
+                    true,
+
+                (&ty::ReScope(sub_scope), &ty::ReScope(super_scope)) =>
+                    self.region_maps.is_subscope_of(sub_scope, super_scope),
+
+                (&ty::ReScope(sub_scope), &ty::ReFree(fr)) => {
+                    // 1. It is safe to unwrap `fr.scope` because we
+                    // should only ever wind up comparing against
+                    // `ReScope` in the context of a method or
+                    // body, where `fr.scope` should be `Some`.
+                    self.region_maps.is_subscope_of(sub_scope, fr.scope.unwrap() /*1*/) ||
+                        self.is_static(super_region)
+                }
+
+                (&ty::ReFree(_), &ty::ReFree(_)) =>
+                    self.free_regions.relation.contains(&sub_region, &super_region) ||
+                        self.is_static(super_region),
+
+                (&ty::ReStatic, &ty::ReFree(_)) =>
+                    self.is_static(super_region),
+
+                _ =>
+                    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
+    fn is_static(&self, super_region: ty::Region<'tcx>) -> bool {
+        debug!("is_static(super_region={:?})", super_region);
+        match *super_region {
+            ty::ReStatic => true,
+            ty::ReFree(_) => {
+                let re_static = self.tcx.mk_region(ty::ReStatic);
+                self.free_regions.relation.contains(&re_static, &super_region)
+            }
+            _ => bug!("only free regions should be given to `is_static`")
+        }
+    }
+
+    pub fn lub_free_regions(&self,
+                            r_a: Region<'tcx>,
+                            r_b: Region<'tcx>)
+                            -> Region<'tcx> {
+        self.free_regions.lub_free_regions(self.tcx, r_a, r_b)
+    }
+}
+
 #[derive(Clone, RustcEncodable, RustcDecodable)]
 pub struct FreeRegionMap<'tcx> {
     // Stores the relation `a < b`, where `a` and `b` are regions.
@@ -116,61 +214,6 @@ impl<'tcx> FreeRegionMap<'tcx> {
         debug!("lub_free_regions(r_a={:?}, r_b={:?}) = {:?}", r_a, r_b, result);
         result
     }
-
-    /// Determines whether one region is a subregion of another.  This is intended to run *after
-    /// inference* and sadly the logic is somewhat duplicated with the code in infer.rs.
-    pub fn is_subregion_of<'a, 'gcx>(&self,
-                                     tcx: TyCtxt<'a, 'gcx, 'tcx>,
-                                     sub_region: ty::Region<'tcx>,
-                                     super_region: ty::Region<'tcx>)
-                                     -> bool {
-        let result = sub_region == super_region || {
-            match (sub_region, super_region) {
-                (&ty::ReEmpty, _) |
-                (_, &ty::ReStatic) =>
-                    true,
-
-                (&ty::ReScope(sub_scope), &ty::ReScope(super_scope)) =>
-                    tcx.region_maps().is_subscope_of(sub_scope, super_scope),
-
-                (&ty::ReScope(sub_scope), &ty::ReFree(fr)) => {
-                    // 1. It is safe to unwrap `fr.scope` because we
-                    // should only ever wind up comparing against
-                    // `ReScope` in the context of a method or
-                    // body, where `fr.scope` should be `Some`.
-                    tcx.region_maps().is_subscope_of(sub_scope, fr.scope.unwrap() /*1*/) ||
-                        self.is_static(tcx, super_region)
-                }
-
-                (&ty::ReFree(_), &ty::ReFree(_)) =>
-                    self.relation.contains(&sub_region, &super_region) ||
-                        self.is_static(tcx, super_region),
-
-                (&ty::ReStatic, &ty::ReFree(_)) =>
-                    self.is_static(tcx, super_region),
-
-                _ =>
-                    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
-    fn is_static<'a, 'gcx>(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>, super_region: ty::Region<'tcx>)
-                           -> bool {
-        debug!("is_static(super_region={:?})", super_region);
-        match *super_region {
-            ty::ReStatic => true,
-            ty::ReFree(_) => {
-                let re_static = tcx.mk_region(ty::ReStatic);
-                self.relation.contains(&re_static, &super_region)
-            }
-            _ => bug!("only free regions should be given to `is_static`")
-        }
-    }
 }
 
 impl_stable_hash_for!(struct FreeRegionMap<'tcx> {
diff --git a/src/librustc/middle/mem_categorization.rs b/src/librustc/middle/mem_categorization.rs
index 3b1a9552ece..0e2db746e45 100644
--- a/src/librustc/middle/mem_categorization.rs
+++ b/src/librustc/middle/mem_categorization.rs
@@ -70,6 +70,7 @@ pub use self::Note::*;
 
 use self::Aliasability::*;
 
+use middle::region::RegionMaps;
 use hir::def_id::DefId;
 use hir::map as hir_map;
 use infer::InferCtxt;
@@ -286,9 +287,10 @@ impl ast_node for hir::Pat {
     fn span(&self) -> Span { self.span }
 }
 
-#[derive(Copy, Clone)]
+#[derive(Clone)]
 pub struct MemCategorizationContext<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
     pub infcx: &'a InferCtxt<'a, 'gcx, 'tcx>,
+    pub region_maps: Rc<RegionMaps<'tcx>>,
     options: MemCategorizationOptions,
 }
 
@@ -402,16 +404,21 @@ impl MutabilityCategory {
 }
 
 impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> {
-    pub fn new(infcx: &'a InferCtxt<'a, 'gcx, 'tcx>)
+    /// Context should be the `DefId` we use to fetch region-maps.
+    pub fn new(infcx: &'a InferCtxt<'a, 'gcx, 'tcx>,
+               context: DefId)
                -> MemCategorizationContext<'a, 'gcx, 'tcx> {
-        MemCategorizationContext::with_options(infcx, MemCategorizationOptions::default())
+        MemCategorizationContext::with_options(infcx, context, MemCategorizationOptions::default())
     }
 
     pub fn with_options(infcx: &'a InferCtxt<'a, 'gcx, 'tcx>,
+                        context: DefId,
                         options: MemCategorizationOptions)
                         -> MemCategorizationContext<'a, 'gcx, 'tcx> {
+        let region_maps = infcx.tcx.region_maps(context);
         MemCategorizationContext {
             infcx: infcx,
+            region_maps: region_maps,
             options: options,
         }
     }
@@ -786,7 +793,7 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> {
             };
 
             match fn_expr.node {
-                hir::ExprClosure(.., body_id, _) => body_id.node_id,
+                hir::ExprClosure(.., body_id, _) => body_id,
                 _ => bug!()
             }
         };
@@ -796,7 +803,7 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> {
             // The environment of a closure is guaranteed to
             // outlive any bindings introduced in the body of the
             // closure itself.
-            scope: Some(self.tcx().item_extent(fn_body_id)),
+            scope: Some(self.tcx().item_extent(fn_body_id.node_id)),
             bound_region: ty::BrEnv
         }));
 
@@ -845,7 +852,7 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> {
     pub fn temporary_scope(&self, id: ast::NodeId) -> (ty::Region<'tcx>, ty::Region<'tcx>)
     {
         let (scope, old_scope) =
-            self.tcx().region_maps().old_and_new_temporary_scope(self.tcx(), id);
+            self.region_maps.old_and_new_temporary_scope(self.tcx(), id);
         (self.tcx().mk_region(match scope {
             Some(scope) => ty::ReScope(scope),
             None => ty::ReStatic
diff --git a/src/librustc/middle/region.rs b/src/librustc/middle/region.rs
index 062432e27e5..fb0c3a29def 100644
--- a/src/librustc/middle/region.rs
+++ b/src/librustc/middle/region.rs
@@ -29,8 +29,7 @@ use syntax_pos::Span;
 use ty::TyCtxt;
 use ty::maps::Providers;
 
-use hir;
-use hir::def_id::{CrateNum, LOCAL_CRATE};
+use hir; use hir::def_id::DefId;
 use hir::intravisit::{self, Visitor, FnKind, NestedVisitorMap};
 use hir::{Block, Item, FnDecl, Arm, Pat, PatKind, Stmt, Expr, Local};
 
@@ -226,6 +225,9 @@ pub struct RegionMaps<'tcx> {
     /// which that variable is declared.
     var_map: NodeMap<CodeExtent<'tcx>>,
 
+    /// maps from a node-id to the associated destruction scope (if any)
+    destruction_scopes: NodeMap<CodeExtent<'tcx>>,
+
     /// `rvalue_scopes` includes entries for those expressions whose cleanup scope is
     /// larger than the default. The map goes from the expression id
     /// to the cleanup scope id. For rvalues not present in this
@@ -301,11 +303,22 @@ struct RegionResolutionVisitor<'a, 'tcx: 'a> {
     /// arbitrary amounts of stack space. Terminating scopes end
     /// up being contained in a DestructionScope that contains the
     /// destructor's execution.
-    terminating_scopes: NodeSet
+    terminating_scopes: NodeSet,
 }
 
 
 impl<'tcx> RegionMaps<'tcx> {
+    pub fn new() -> Self {
+        RegionMaps {
+            scope_map: FxHashMap(),
+            destruction_scopes: FxHashMap(),
+            var_map: NodeMap(),
+            rvalue_scopes: NodeMap(),
+            shrunk_rvalue_scopes: NodeMap(),
+            fn_tree: NodeMap(),
+        }
+    }
+
     pub fn each_encl_scope<E>(&self, mut e:E) where E: FnMut(CodeExtent<'tcx>, CodeExtent<'tcx>) {
         for (&child, &parent) in &self.scope_map {
             e(child, parent)
@@ -317,6 +330,10 @@ impl<'tcx> RegionMaps<'tcx> {
         }
     }
 
+    pub fn opt_destruction_extent(&self, n: ast::NodeId) -> Option<CodeExtent<'tcx>> {
+        self.destruction_scopes.get(&n).cloned()
+    }
+
     /// Records that `sub_fn` is defined within `sup_fn`. These ids
     /// should be the id of the block that is the fn body, which is
     /// also the root of the region hierarchy for that fn.
@@ -1029,18 +1046,18 @@ fn resolve_fn<'a, 'tcx>(visitor: &mut RegionResolutionVisitor<'a, 'tcx>,
                         body_id: hir::BodyId,
                         sp: Span,
                         id: ast::NodeId) {
+    visitor.cx.parent = Some(visitor.new_code_extent(
+        CodeExtentData::CallSiteScope { fn_id: id, body_id: body_id.node_id }));
+
     debug!("region::resolve_fn(id={:?}, \
-                               span={:?}, \
-                               body.id={:?}, \
-                               cx.parent={:?})",
+            span={:?}, \
+            body.id={:?}, \
+            cx.parent={:?})",
            id,
            visitor.tcx.sess.codemap().span_to_string(sp),
            body_id,
            visitor.cx.parent);
 
-    visitor.cx.parent = Some(visitor.new_code_extent(
-        CodeExtentData::CallSiteScope { fn_id: id, body_id: body_id.node_id }));
-
     let fn_decl_scope = visitor.new_code_extent(
         CodeExtentData::ParameterScope { fn_id: id, body_id: body_id.node_id });
 
@@ -1086,6 +1103,12 @@ impl<'a, 'tcx> RegionResolutionVisitor<'a, 'tcx> {
             let prev = self.region_maps.scope_map.insert(code_extent, p);
             assert!(prev.is_none());
         }
+
+        // record the destruction scopes for later so we can query them
+        if let &CodeExtentData::DestructionScope(n) = code_extent {
+            self.region_maps.destruction_scopes.insert(n, code_extent);
+        }
+
         code_extent
     }
 
@@ -1162,47 +1185,44 @@ impl<'a, 'tcx> Visitor<'tcx> for RegionResolutionVisitor<'a, 'tcx> {
     }
 }
 
-pub fn resolve_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) -> Rc<RegionMaps<'tcx>> {
-    tcx.region_resolve_crate(LOCAL_CRATE)
-}
-
-fn region_resolve_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, crate_num: CrateNum)
+fn region_maps<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, fn_id: DefId)
     -> Rc<RegionMaps<'tcx>>
 {
-    debug_assert!(crate_num == LOCAL_CRATE);
-
-    let hir_map = &tcx.hir;
+    let fn_node_id = tcx.hir.as_local_node_id(fn_id)
+                            .expect("fn DefId should be for LOCAL_CRATE");
+    let node = tcx.hir.get(fn_node_id);
+    match node {
+        hir_map::NodeItem(_) | hir_map::NodeTraitItem(_) | hir_map::NodeImplItem(_) => { }
+        _ => {
+            let parent_id = tcx.hir.get_parent(fn_node_id);
+            let parent_def_id = tcx.hir.local_def_id(parent_id);
+            return tcx.region_maps(parent_def_id);
+        }
+    }
 
-    let krate = hir_map.krate();
-
-    let mut maps = RegionMaps {
-        scope_map: FxHashMap(),
-        var_map: NodeMap(),
-        rvalue_scopes: NodeMap(),
-        shrunk_rvalue_scopes: NodeMap(),
-        fn_tree: NodeMap(),
-    };
+    let mut maps = RegionMaps::new();
 
     {
         let mut visitor = RegionResolutionVisitor {
             tcx: tcx,
             region_maps: &mut maps,
-            map: hir_map,
+            map: &tcx.hir,
             cx: Context {
                 root_id: None,
                 parent: None,
                 var_parent: None,
             },
-            terminating_scopes: NodeSet()
+            terminating_scopes: NodeSet(),
         };
-        krate.visit_all_item_likes(&mut visitor.as_deep_visitor());
+        visitor.visit_hir_map_node(node);
     }
+
     Rc::new(maps)
 }
 
 pub fn provide(providers: &mut Providers) {
     *providers = Providers {
-        region_resolve_crate,
+        region_maps,
         ..*providers
     };
 }