about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorNiko Matsakis <niko@alum.mit.edu>2018-09-12 15:11:53 -0400
committerNiko Matsakis <niko@alum.mit.edu>2018-09-26 09:30:54 -0400
commit84563dac88f1bda275ccbc8bb66067fd6cbbdcfe (patch)
tree73dd04fe2bd507861e71f9a8237046e9f5bb1de1 /src
parent1fb4ea91f2844b3a2b0efbfd3cefe16bdb946d23 (diff)
downloadrust-84563dac88f1bda275ccbc8bb66067fd6cbbdcfe.tar.gz
rust-84563dac88f1bda275ccbc8bb66067fd6cbbdcfe.zip
build up a map of the region-bound pairs for each body-id
Presently unused.
Diffstat (limited to 'src')
-rw-r--r--src/librustc/infer/outlives/env.rs65
-rw-r--r--src/librustc_typeck/check/regionck.rs9
2 files changed, 63 insertions, 11 deletions
diff --git a/src/librustc/infer/outlives/env.rs b/src/librustc/infer/outlives/env.rs
index 568e4412fdb..6808e9dc9e3 100644
--- a/src/librustc/infer/outlives/env.rs
+++ b/src/librustc/infer/outlives/env.rs
@@ -10,11 +10,11 @@
 
 use infer::outlives::free_region_map::FreeRegionMap;
 use infer::{GenericKind, InferCtxt};
-use traits::query::outlives_bounds::{self, OutlivesBound};
-use ty::{self, Ty};
-
+use rustc_data_structures::fx::FxHashMap;
 use syntax::ast;
 use syntax_pos::Span;
+use traits::query::outlives_bounds::{self, OutlivesBound};
+use ty::{self, Ty};
 
 /// The `OutlivesEnvironment` collects information about what outlives
 /// what in a given type-checking setting. For example, if we have a
@@ -39,15 +39,51 @@ use syntax_pos::Span;
 pub struct OutlivesEnvironment<'tcx> {
     param_env: ty::ParamEnv<'tcx>,
     free_region_map: FreeRegionMap<'tcx>,
-    region_bound_pairs: Vec<(ty::Region<'tcx>, GenericKind<'tcx>)>,
+
+    // Contains, for each body B that we are checking (that is, the fn
+    // item, but also any nested closures), the set of implied region
+    // bounds that are in scope in that particular body.
+    //
+    // Example:
+    //
+    // ```
+    // fn foo<'a, 'b, T>(x: &'a T, y: &'b ()) {
+    //   bar(x, y, |y: &'b T| { .. } // body B1)
+    // } // body B0
+    // ```
+    //
+    // Here, for body B0, the list would be `[T: 'a]`, because we
+    // infer that `T` must outlive `'a` from the implied bounds on the
+    // fn declaration.
+    //
+    // For the body B1, the list would be `[T: 'a, T: 'b]`, because we
+    // also can see that -- within the closure body! -- `T` must
+    // outlive `'b`. This is not necessarily true outside the closure
+    // body, since the closure may never be called.
+    //
+    // We collect this map as we descend the tree. We then use the
+    // results when proving outlives obligations like `T: 'x` later
+    // (e.g., if `T: 'x` must be proven within the body B1, then we
+    // know it is true if either `'a: 'x` or `'b: 'x`).
+    region_bound_pairs_map: FxHashMap<ast::NodeId, RegionBoundPairs<'tcx>>,
+
+    // Used to compute `region_bound_pairs_map`: contains the set of
+    // in-scope region-bound pairs thus far.
+    region_bound_pairs_accum: RegionBoundPairs<'tcx>,
 }
 
+/// "Region-bound pairs" tracks outlives relations that are known to
+/// be true, either because of explicit where clauses like `T: 'a` or
+/// because of implied bounds.
+pub type RegionBoundPairs<'tcx> = Vec<(ty::Region<'tcx>, GenericKind<'tcx>)>;
+
 impl<'a, 'gcx: 'tcx, 'tcx: 'a> OutlivesEnvironment<'tcx> {
     pub fn new(param_env: ty::ParamEnv<'tcx>) -> Self {
         let mut env = OutlivesEnvironment {
             param_env,
             free_region_map: FreeRegionMap::new(),
-            region_bound_pairs: vec![],
+            region_bound_pairs_map: FxHashMap::default(),
+            region_bound_pairs_accum: vec![],
         };
 
         env.add_outlives_bounds(None, outlives_bounds::explicit_outlives_bounds(param_env));
@@ -62,7 +98,7 @@ impl<'a, 'gcx: 'tcx, 'tcx: 'a> OutlivesEnvironment<'tcx> {
 
     /// Borrows current value of the `region_bound_pairs`.
     pub fn region_bound_pairs(&self) -> &[(ty::Region<'tcx>, GenericKind<'tcx>)] {
-        &self.region_bound_pairs
+        &self.region_bound_pairs_accum
     }
 
     /// Returns ownership of the `free_region_map`.
@@ -108,12 +144,12 @@ impl<'a, 'gcx: 'tcx, 'tcx: 'a> OutlivesEnvironment<'tcx> {
     /// similar leaks around givens that seem equally suspicious, to
     /// be honest. --nmatsakis
     pub fn push_snapshot_pre_closure(&self) -> usize {
-        self.region_bound_pairs.len()
+        self.region_bound_pairs_accum.len()
     }
 
     /// See `push_snapshot_pre_closure`.
     pub fn pop_snapshot_post_closure(&mut self, len: usize) {
-        self.region_bound_pairs.truncate(len);
+        self.region_bound_pairs_accum.truncate(len);
     }
 
     /// This method adds "implied bounds" into the outlives environment.
@@ -149,6 +185,15 @@ impl<'a, 'gcx: 'tcx, 'tcx: 'a> OutlivesEnvironment<'tcx> {
         }
     }
 
+    /// Save the current set of region-bound pairs under the given `body_id`.
+    pub fn save_implied_bounds(&mut self, body_id: ast::NodeId) {
+        let old = self.region_bound_pairs_map.insert(
+            body_id,
+            self.region_bound_pairs_accum.clone(),
+        );
+        assert!(old.is_none());
+    }
+
     /// Processes outlives bounds that are known to hold, whether from implied or other sources.
     ///
     /// The `infcx` parameter is optional; if the implied bounds may
@@ -174,11 +219,11 @@ impl<'a, 'gcx: 'tcx, 'tcx: 'a> OutlivesEnvironment<'tcx> {
                         .add_given(r_a, vid_b);
                 }
                 OutlivesBound::RegionSubParam(r_a, param_b) => {
-                    self.region_bound_pairs
+                    self.region_bound_pairs_accum
                         .push((r_a, GenericKind::Param(param_b)));
                 }
                 OutlivesBound::RegionSubProjection(r_a, projection_b) => {
-                    self.region_bound_pairs
+                    self.region_bound_pairs_accum
                         .push((r_a, GenericKind::Projection(projection_b)));
                 }
                 OutlivesBound::RegionSubRegion(r_a, r_b) => {
diff --git a/src/librustc_typeck/check/regionck.rs b/src/librustc_typeck/check/regionck.rs
index e3f9d6cd97c..aad474d0a88 100644
--- a/src/librustc_typeck/check/regionck.rs
+++ b/src/librustc_typeck/check/regionck.rs
@@ -130,6 +130,11 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
             Subject(subject),
             self.param_env,
         );
+
+        // There are no add'l implied bounds when checking a
+        // standalone expr (e.g., the `E` in a type like `[u32; E]`).
+        rcx.outlives_environment.save_implied_bounds(id);
+
         if self.err_count_since_creation() == 0 {
             // regionck assumes typeck succeeded
             rcx.visit_body(body);
@@ -155,6 +160,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
         );
         rcx.outlives_environment
             .add_implied_bounds(self, wf_tys, item_id, span);
+        rcx.outlives_environment.save_implied_bounds(item_id);
         rcx.visit_region_obligations(item_id);
         rcx.resolve_regions_and_report_errors();
     }
@@ -308,7 +314,7 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> {
         id: ast::NodeId, // the id of the fn itself
         body: &'gcx hir::Body,
         span: Span,
-    ) {
+   ) {
         // When we enter a function, we can derive
         debug!("visit_fn_body(id={})", id);
 
@@ -349,6 +355,7 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> {
             body_id.node_id,
             span,
         );
+        self.outlives_environment.save_implied_bounds(body_id.node_id);
         self.link_fn_args(
             region::Scope {
                 id: body.value.hir_id.local_id,