about summary refs log tree commit diff
diff options
context:
space:
mode:
authorNiko Matsakis <niko@alum.mit.edu>2017-12-04 11:37:34 -0500
committerNiko Matsakis <niko@alum.mit.edu>2017-12-15 10:27:51 -0500
commit5804637a81a8e5216fbbf2e3e7c0a7bdca9c99de (patch)
tree721b2b9e4e42cfa449b029ebf8ef8545f92971e1
parentc7cfa2367b0ad4aed16dff7ad3d8d3e9eea6540a (diff)
permit `ClosureOutlivesRequirement` to constrain regions or types
-rw-r--r--src/librustc/ich/impls_mir.rs21
-rw-r--r--src/librustc/mir/mod.rs33
-rw-r--r--src/librustc/ty/maps/mod.rs2
-rw-r--r--src/librustc_mir/borrow_check/mod.rs4
-rw-r--r--src/librustc_mir/borrow_check/nll/mod.rs11
-rw-r--r--src/librustc_mir/borrow_check/nll/region_infer/mod.rs63
6 files changed, 96 insertions, 38 deletions
diff --git a/src/librustc/ich/impls_mir.rs b/src/librustc/ich/impls_mir.rs
index 32577ac46f3..df67c3abbe8 100644
--- a/src/librustc/ich/impls_mir.rs
+++ b/src/librustc/ich/impls_mir.rs
@@ -536,14 +536,29 @@ impl<'gcx> HashStable<StableHashingContext<'gcx>> for mir::Literal<'gcx> {
 
 impl_stable_hash_for!(struct mir::Location { block, statement_index });
 
-impl_stable_hash_for!(struct mir::ClosureRegionRequirements {
+impl_stable_hash_for!(struct mir::ClosureRegionRequirements<'tcx> {
     num_external_vids,
     outlives_requirements
 });
 
-impl_stable_hash_for!(struct mir::ClosureOutlivesRequirement {
-    free_region,
+impl_stable_hash_for!(struct mir::ClosureOutlivesRequirement<'tcx> {
+    subject,
     outlived_free_region,
     blame_span
 });
 
+impl<'gcx> HashStable<StableHashingContext<'gcx>> for mir::ClosureOutlivesSubject<'gcx> {
+    fn hash_stable<W: StableHasherResult>(&self,
+                                          hcx: &mut StableHashingContext<'gcx>,
+                                          hasher: &mut StableHasher<W>) {
+        mem::discriminant(self).hash_stable(hcx, hasher);
+        match *self {
+            mir::ClosureOutlivesSubject::Ty(ref ty) => {
+                ty.hash_stable(hcx, hasher);
+            }
+            mir::ClosureOutlivesSubject::Region(ref region) => {
+                region.hash_stable(hcx, hasher);
+            }
+        }
+    }
+}
diff --git a/src/librustc/mir/mod.rs b/src/librustc/mir/mod.rs
index a83c3f29d25..d7afce7de46 100644
--- a/src/librustc/mir/mod.rs
+++ b/src/librustc/mir/mod.rs
@@ -1832,7 +1832,7 @@ pub struct GeneratorLayout<'tcx> {
 /// can be extracted from its type and constrained to have the given
 /// outlives relationship.
 #[derive(Clone, Debug, RustcEncodable, RustcDecodable)]
-pub struct ClosureRegionRequirements {
+pub struct ClosureRegionRequirements<'gcx> {
     /// The number of external regions defined on the closure.  In our
     /// example above, it would be 3 -- one for `'static`, then `'1`
     /// and `'2`. This is just used for a sanity check later on, to
@@ -1842,15 +1842,15 @@ pub struct ClosureRegionRequirements {
 
     /// Requirements between the various free regions defined in
     /// indices.
-    pub outlives_requirements: Vec<ClosureOutlivesRequirement>,
+    pub outlives_requirements: Vec<ClosureOutlivesRequirement<'gcx>>,
 }
 
-/// Indicates an outlives constraint between two free-regions declared
-/// on the closure.
-#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, RustcEncodable, RustcDecodable)]
-pub struct ClosureOutlivesRequirement {
-    // This region ...
-    pub free_region: ty::RegionVid,
+/// Indicates an outlives constraint between a type or between two
+/// free-regions declared on the closure.
+#[derive(Copy, Clone, Debug, RustcEncodable, RustcDecodable)]
+pub struct ClosureOutlivesRequirement<'tcx> {
+    // This region or type ...
+    pub subject: ClosureOutlivesSubject<'tcx>,
 
     // .. must outlive this one.
     pub outlived_free_region: ty::RegionVid,
@@ -1859,6 +1859,23 @@ pub struct ClosureOutlivesRequirement {
     pub blame_span: Span,
 }
 
+/// The subject of a ClosureOutlivesRequirement -- that is, the thing
+/// that must outlive some region.
+#[derive(Copy, Clone, Debug, RustcEncodable, RustcDecodable)]
+pub enum ClosureOutlivesSubject<'tcx> {
+    /// Subject is a type, typically a type parameter, but could also
+    /// be a projection. Indicates a requirement like `T: 'a` being
+    /// passed to the caller, where the type here is `T`.
+    ///
+    /// The type here is guaranteed not to contain any free regions at
+    /// present.
+    Ty(Ty<'tcx>),
+
+    /// Subject is a free region from the closure. Indicates a requirement
+    /// like `'a: 'b` being passed to the caller; the region here is `'a`.
+    Region(ty::RegionVid),
+}
+
 /*
  * TypeFoldable implementations for MIR types
  */
diff --git a/src/librustc/ty/maps/mod.rs b/src/librustc/ty/maps/mod.rs
index 7ba063adff4..319f63dd7c8 100644
--- a/src/librustc/ty/maps/mod.rs
+++ b/src/librustc/ty/maps/mod.rs
@@ -193,7 +193,7 @@ define_maps! { <'tcx>
 
     /// Borrow checks the function body. If this is a closure, returns
     /// additional requirements that the closure's creator must verify.
-    [] fn mir_borrowck: MirBorrowCheck(DefId) -> Option<mir::ClosureRegionRequirements>,
+    [] fn mir_borrowck: MirBorrowCheck(DefId) -> Option<mir::ClosureRegionRequirements<'tcx>>,
 
     /// Gets a complete map from all types to their inherent impls.
     /// Not meant to be used directly outside of coherence.
diff --git a/src/librustc_mir/borrow_check/mod.rs b/src/librustc_mir/borrow_check/mod.rs
index 576d5985798..e0b03aec69a 100644
--- a/src/librustc_mir/borrow_check/mod.rs
+++ b/src/librustc_mir/borrow_check/mod.rs
@@ -65,7 +65,7 @@ pub fn provide(providers: &mut Providers) {
 fn mir_borrowck<'a, 'tcx>(
     tcx: TyCtxt<'a, 'tcx, 'tcx>,
     def_id: DefId,
-) -> Option<ClosureRegionRequirements> {
+) -> Option<ClosureRegionRequirements<'tcx>> {
     let input_mir = tcx.mir_validated(def_id);
     debug!("run query mir_borrowck: {}", tcx.item_path_str(def_id));
 
@@ -89,7 +89,7 @@ fn do_mir_borrowck<'a, 'gcx, 'tcx>(
     infcx: &InferCtxt<'a, 'gcx, 'tcx>,
     input_mir: &Mir<'gcx>,
     def_id: DefId,
-) -> Option<ClosureRegionRequirements> {
+) -> Option<ClosureRegionRequirements<'gcx>> {
     let tcx = infcx.tcx;
     let attributes = tcx.get_attrs(def_id);
     let param_env = tcx.param_env(def_id);
diff --git a/src/librustc_mir/borrow_check/nll/mod.rs b/src/librustc_mir/borrow_check/nll/mod.rs
index 9e7c94cd7ff..23fa2689053 100644
--- a/src/librustc_mir/borrow_check/nll/mod.rs
+++ b/src/librustc_mir/borrow_check/nll/mod.rs
@@ -9,11 +9,12 @@
 // except according to those terms.
 
 use rustc::hir::def_id::DefId;
-use rustc::mir::{ClosureRegionRequirements, Mir};
+use rustc::mir::{ClosureRegionRequirements, ClosureOutlivesSubject, Mir};
 use rustc::infer::InferCtxt;
 use rustc::ty::{self, RegionKind, RegionVid};
 use rustc::util::nodemap::FxHashMap;
 use std::collections::BTreeSet;
+use std::fmt::Debug;
 use std::io;
 use transform::MirSource;
 use util::liveness::{LivenessResults, LocalSet};
@@ -73,7 +74,7 @@ pub(in borrow_check) fn compute_regions<'cx, 'gcx, 'tcx>(
     move_data: &MoveData<'tcx>,
 ) -> (
     RegionInferenceContext<'tcx>,
-    Option<ClosureRegionRequirements>,
+    Option<ClosureRegionRequirements<'gcx>>,
 ) {
     // Run the MIR type-checker.
     let mir_node_id = infcx.tcx.hir.as_local_node_id(def_id).unwrap();
@@ -263,9 +264,13 @@ fn for_each_region_constraint(
     with_msg: &mut FnMut(&str) -> io::Result<()>,
 ) -> io::Result<()> {
     for req in &closure_region_requirements.outlives_requirements {
+        let subject: &Debug = match &req.subject {
+            ClosureOutlivesSubject::Region(subject) => subject,
+            ClosureOutlivesSubject::Ty(ty) => ty,
+        };
         with_msg(&format!(
             "where {:?}: {:?}",
-            req.free_region,
+            subject,
             req.outlived_free_region,
         ))?;
     }
diff --git a/src/librustc_mir/borrow_check/nll/region_infer/mod.rs b/src/librustc_mir/borrow_check/nll/region_infer/mod.rs
index 4759185d226..4a1eca38bc7 100644
--- a/src/librustc_mir/borrow_check/nll/region_infer/mod.rs
+++ b/src/librustc_mir/borrow_check/nll/region_infer/mod.rs
@@ -15,7 +15,8 @@ use rustc::infer::NLLRegionVariableOrigin;
 use rustc::infer::RegionVariableOrigin;
 use rustc::infer::SubregionOrigin;
 use rustc::infer::region_constraints::{GenericKind, VarOrigins};
-use rustc::mir::{ClosureOutlivesRequirement, ClosureRegionRequirements, Location, Mir};
+use rustc::mir::{ClosureOutlivesRequirement, ClosureOutlivesSubject, ClosureRegionRequirements,
+                 Location, Mir};
 use rustc::ty::{self, RegionVid};
 use rustc_data_structures::indexed_vec::IndexVec;
 use std::fmt;
@@ -339,12 +340,12 @@ impl<'tcx> RegionInferenceContext<'tcx> {
     /// Perform region inference and report errors if we see any
     /// unsatisfiable constraints. If this is a closure, returns the
     /// region requirements to propagate to our creator, if any.
-    pub(super) fn solve(
+    pub(super) fn solve<'gcx>(
         &mut self,
-        infcx: &InferCtxt<'_, '_, 'tcx>,
+        infcx: &InferCtxt<'_, 'gcx, 'tcx>,
         mir: &Mir<'tcx>,
         mir_def_id: DefId,
-    ) -> Option<ClosureRegionRequirements> {
+    ) -> Option<ClosureRegionRequirements<'gcx>> {
         assert!(self.inferred_values.is_none(), "values already inferred");
 
         self.propagate_constraints(mir);
@@ -559,10 +560,10 @@ impl<'tcx> RegionInferenceContext<'tcx> {
     /// If `propagated_outlives_requirements` is `Some`, then we will
     /// push unsatisfied obligations into there. Otherwise, we'll
     /// report them as errors.
-    fn check_universal_regions(
+    fn check_universal_regions<'gcx>(
         &self,
-        infcx: &InferCtxt<'_, '_, 'tcx>,
-        mut propagated_outlives_requirements: Option<&mut Vec<ClosureOutlivesRequirement>>,
+        infcx: &InferCtxt<'_, 'gcx, 'tcx>,
+        mut propagated_outlives_requirements: Option<&mut Vec<ClosureOutlivesRequirement<'gcx>>>,
     ) {
         // The universal regions are always found in a prefix of the
         // full list.
@@ -583,9 +584,17 @@ impl<'tcx> RegionInferenceContext<'tcx> {
                 propagated_outlives_requirements.extend(outlives_requirements.drain(..));
             } else {
                 for outlives_requirement in outlives_requirements.drain(..) {
+                    let fr = match outlives_requirement.subject {
+                        ClosureOutlivesSubject::Region(fr) => fr,
+                        _ => span_bug!(
+                            outlives_requirement.blame_span,
+                            "check_universal_region() produced requirement w/ non-region subject"
+                        ),
+                    };
+
                     self.report_error(
                         infcx,
-                        outlives_requirement.free_region,
+                        fr,
                         outlives_requirement.outlived_free_region,
                         outlives_requirement.blame_span,
                     );
@@ -602,11 +611,11 @@ impl<'tcx> RegionInferenceContext<'tcx> {
     ///
     /// Things that are to be propagated are accumulated into the
     /// `outlives_requirements` vector.
-    fn check_universal_region(
+    fn check_universal_region<'gcx>(
         &self,
-        infcx: &InferCtxt<'_, '_, 'tcx>,
+        infcx: &InferCtxt<'_, 'gcx, 'tcx>,
         longer_fr: RegionVid,
-        propagated_outlives_requirements: &mut Vec<ClosureOutlivesRequirement>,
+        propagated_outlives_requirements: &mut Vec<ClosureOutlivesRequirement<'gcx>>,
     ) {
         let inferred_values = self.inferred_values.as_ref().unwrap();
 
@@ -645,7 +654,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
 
                 // Push the constraint `fr-: shorter_fr+`
                 propagated_outlives_requirements.push(ClosureOutlivesRequirement {
-                    free_region: fr_minus,
+                    subject: ClosureOutlivesSubject::Region(fr_minus),
                     outlived_free_region: shorter_fr_plus,
                     blame_span: blame_span,
                 });
@@ -773,7 +782,7 @@ pub trait ClosureRegionRequirementsExt {
     );
 }
 
-impl ClosureRegionRequirementsExt for ClosureRegionRequirements {
+impl<'gcx> ClosureRegionRequirementsExt for ClosureRegionRequirements<'gcx> {
     /// Given an instance T of the closure type, this method
     /// instantiates the "extra" requirements that we computed for the
     /// closure into the inference context. This has the effect of
@@ -815,17 +824,29 @@ impl ClosureRegionRequirementsExt for ClosureRegionRequirements {
 
         // Create the predicates.
         for outlives_requirement in &self.outlives_requirements {
-            let region = closure_mapping[outlives_requirement.free_region];
             let outlived_region = closure_mapping[outlives_requirement.outlived_free_region];
-            debug!(
-                "apply_requirements: region={:?} outlived_region={:?} outlives_requirements={:?}",
-                region,
-                outlived_region,
-                outlives_requirement
-            );
+
             // FIXME, this origin is not entirely suitable.
             let origin = SubregionOrigin::CallRcvr(outlives_requirement.blame_span);
-            infcx.sub_regions(origin, outlived_region, region);
+
+            match outlives_requirement.subject {
+                ClosureOutlivesSubject::Region(region) => {
+                    let region = closure_mapping[region];
+                    debug!(
+                        "apply_requirements: region={:?} \
+                         outlived_region={:?} \
+                         outlives_requirements={:?}",
+                        region,
+                        outlived_region,
+                        outlives_requirement
+                    );
+                    infcx.sub_regions(origin, outlived_region, region);
+                }
+
+                ClosureOutlivesSubject::Ty(_ty) => {
+                    bug!("TODO not yet implemented -- closure outlives subject of a type");
+                }
+            }
         }
     }
 }