about summary refs log tree commit diff
diff options
context:
space:
mode:
authorNiko Matsakis <niko@alum.mit.edu>2017-11-12 05:25:13 -0500
committerNiko Matsakis <niko@alum.mit.edu>2017-12-04 08:51:13 -0500
commitc45307fae1f261eac006816329780a7a01b2d0dc (patch)
tree83ea1dde39a24d6c6b79c7c5480b2156b8253d27
parent1f33145ae91cbe095616c92ace63c93b61e5b4e9 (diff)
downloadrust-c45307fae1f261eac006816329780a7a01b2d0dc.tar.gz
rust-c45307fae1f261eac006816329780a7a01b2d0dc.zip
extract the code to create `OutlivesBounds` into its own module
Now it can be reused by the NLL code.
-rw-r--r--src/librustc/infer/outlives/env.rs105
-rw-r--r--src/librustc/infer/outlives/implied_bounds.rs103
2 files changed, 110 insertions, 98 deletions
diff --git a/src/librustc/infer/outlives/env.rs b/src/librustc/infer/outlives/env.rs
index 9f00fc78cc0..43e782ac130 100644
--- a/src/librustc/infer/outlives/env.rs
+++ b/src/librustc/infer/outlives/env.rs
@@ -8,9 +8,9 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-use infer::{InferCtxt, GenericKind};
+use infer::{GenericKind, InferCtxt};
 use infer::outlives::free_region_map::FreeRegionMap;
-use infer::outlives::implied_bounds::ImpliedBound;
+use infer::outlives::implied_bounds::{self, OutlivesBound};
 use ty::{self, Ty};
 
 use syntax::ast;
@@ -50,7 +50,7 @@ impl<'a, 'gcx: 'tcx, 'tcx: 'a> OutlivesEnvironment<'tcx> {
             region_bound_pairs: vec![],
         };
 
-        env.init_free_regions_from_predicates();
+        env.add_outlives_bounds(None, implied_bounds::explicit_outlives_bounds(param_env));
 
         env
     }
@@ -144,65 +144,54 @@ impl<'a, 'gcx: 'tcx, 'tcx: 'a> OutlivesEnvironment<'tcx> {
         for &ty in fn_sig_tys {
             let ty = infcx.resolve_type_vars_if_possible(&ty);
             debug!("add_implied_bounds: ty = {}", ty);
-            let implied_bounds = infcx.implied_bounds(self.param_env, body_id, ty, span);
-
-            // But also record other relationships, such as `T:'x`,
-            // that don't go into the free-region-map but which we use
-            // here.
-            for implication in implied_bounds {
-                debug!("add_implied_bounds: implication={:?}", implication);
-                match implication {
-                    ImpliedBound::RegionSubRegion(
-                        r_a @ &ty::ReEarlyBound(_),
-                        &ty::ReVar(vid_b),
-                    ) |
-                    ImpliedBound::RegionSubRegion(r_a @ &ty::ReFree(_), &ty::ReVar(vid_b)) => {
-                        infcx.add_given(r_a, vid_b);
-                    }
-                    ImpliedBound::RegionSubParam(r_a, param_b) => {
-                        self.region_bound_pairs
-                            .push((r_a, GenericKind::Param(param_b)));
-                    }
-                    ImpliedBound::RegionSubProjection(r_a, projection_b) => {
-                        self.region_bound_pairs
-                            .push((r_a, GenericKind::Projection(projection_b)));
-                    }
-                    ImpliedBound::RegionSubRegion(r_a, r_b) => {
-                        // In principle, we could record (and take
-                        // advantage of) every relationship here, but
-                        // we are also free not to -- it simply means
-                        // strictly less that we can successfully type
-                        // check. Right now we only look for things
-                        // relationships between free regions. (It may
-                        // also be that we should revise our inference
-                        // system to be more general and to make use
-                        // of *every* relationship that arises here,
-                        // but presently we do not.)
-                        self.free_region_map.relate_regions(r_a, r_b);
-                    }
-                }
-            }
+            let implied_bounds = infcx.implied_outlives_bounds(self.param_env, body_id, ty, span);
+            self.add_outlives_bounds(Some(infcx), implied_bounds)
         }
     }
 
-    fn init_free_regions_from_predicates(&mut self) {
-        debug!("init_free_regions_from_predicates()");
-        for predicate in self.param_env.caller_bounds {
-            debug!("init_free_regions_from_predicates: predicate={:?}", predicate);
-            match *predicate {
-                ty::Predicate::Projection(..) |
-                ty::Predicate::Trait(..) |
-                ty::Predicate::Equate(..) |
-                ty::Predicate::Subtype(..) |
-                ty::Predicate::WellFormed(..) |
-                ty::Predicate::ObjectSafe(..) |
-                ty::Predicate::ClosureKind(..) |
-                ty::Predicate::TypeOutlives(..) |
-                ty::Predicate::ConstEvaluatable(..) => {
-                    // No region bounds here
+    /// Processes outlives bounds that are known to hold, whether from implied or other sources.
+    ///
+    /// The `infcx` parameter is optional; if the implied bounds may
+    /// contain inference variables, it should be supplied, in which
+    /// case we will register "givens" on the inference context. (See
+    /// `RegionConstraintData`.)
+    fn add_outlives_bounds<I>(
+        &mut self,
+        infcx: Option<&InferCtxt<'a, 'gcx, 'tcx>>,
+        outlives_bounds: I,
+    ) where
+        I: IntoIterator<Item = OutlivesBound<'tcx>>,
+    {
+        // But also record other relationships, such as `T:'x`,
+        // that don't go into the free-region-map but which we use
+        // here.
+        for outlives_bound in outlives_bounds {
+            debug!("add_outlives_bounds: outlives_bound={:?}", outlives_bound);
+            match outlives_bound {
+                OutlivesBound::RegionSubRegion(r_a @ &ty::ReEarlyBound(_), &ty::ReVar(vid_b)) |
+                OutlivesBound::RegionSubRegion(r_a @ &ty::ReFree(_), &ty::ReVar(vid_b)) => {
+                    infcx.expect("no infcx provided but region vars found").add_given(r_a, vid_b);
+                }
+                OutlivesBound::RegionSubParam(r_a, param_b) => {
+                    self.region_bound_pairs
+                        .push((r_a, GenericKind::Param(param_b)));
+                }
+                OutlivesBound::RegionSubProjection(r_a, projection_b) => {
+                    self.region_bound_pairs
+                        .push((r_a, GenericKind::Projection(projection_b)));
                 }
-                ty::Predicate::RegionOutlives(ty::Binder(ty::OutlivesPredicate(r_a, r_b))) => {
-                    self.free_region_map.relate_regions(r_b, r_a);
+                OutlivesBound::RegionSubRegion(r_a, r_b) => {
+                    // In principle, we could record (and take
+                    // advantage of) every relationship here, but
+                    // we are also free not to -- it simply means
+                    // strictly less that we can successfully type
+                    // check. Right now we only look for things
+                    // relationships between free regions. (It may
+                    // also be that we should revise our inference
+                    // system to be more general and to make use
+                    // of *every* relationship that arises here,
+                    // but presently we do not.)
+                    self.free_region_map.relate_regions(r_a, r_b);
                 }
             }
         }
diff --git a/src/librustc/infer/outlives/implied_bounds.rs b/src/librustc/infer/outlives/implied_bounds.rs
index 452ceddd7d6..8a562471ac5 100644
--- a/src/librustc/infer/outlives/implied_bounds.rs
+++ b/src/librustc/infer/outlives/implied_bounds.rs
@@ -16,28 +16,32 @@ use ty::{self, Ty, TypeFoldable};
 use ty::outlives::Component;
 use ty::wf;
 
-/// Implied bounds are region relationships that we deduce
-/// automatically.  The idea is that (e.g.) a caller must check that a
-/// function's argument types are well-formed immediately before
-/// calling that fn, and hence the *callee* can assume that its
-/// argument types are well-formed. This may imply certain relationships
-/// between generic parameters. For example:
-///
-///     fn foo<'a,T>(x: &'a T)
-///
-/// can only be called with a `'a` and `T` such that `&'a T` is WF.
-/// For `&'a T` to be WF, `T: 'a` must hold. So we can assume `T: 'a`.
+/// Outlives bounds are relationships between generic parameters,
+/// whether they both be regions (`'a: 'b`) or whether types are
+/// involved (`T: 'a`).  These relationships can be extracted from the
+/// full set of predicates we understand or also from types (in which
+/// case they are called implied bounds). They are fed to the
+/// `OutlivesEnv` which in turn is supplied to the region checker and
+/// other parts of the inference system.
 #[derive(Debug)]
-pub enum ImpliedBound<'tcx> {
+pub enum OutlivesBound<'tcx> {
     RegionSubRegion(ty::Region<'tcx>, ty::Region<'tcx>),
     RegionSubParam(ty::Region<'tcx>, ty::ParamTy),
     RegionSubProjection(ty::Region<'tcx>, ty::ProjectionTy<'tcx>),
 }
 
 impl<'cx, 'gcx, 'tcx> InferCtxt<'cx, 'gcx, 'tcx> {
-    /// Compute the implied bounds that a callee/impl can assume based on
-    /// the fact that caller/projector has ensured that `ty` is WF.  See
-    /// the `ImpliedBound` type for more details.
+    /// Implied bounds are region relationships that we deduce
+    /// automatically.  The idea is that (e.g.) a caller must check that a
+    /// function's argument types are well-formed immediately before
+    /// calling that fn, and hence the *callee* can assume that its
+    /// argument types are well-formed. This may imply certain relationships
+    /// between generic parameters. For example:
+    ///
+    ///     fn foo<'a,T>(x: &'a T)
+    ///
+    /// can only be called with a `'a` and `T` such that `&'a T` is WF.
+    /// For `&'a T` to be WF, `T: 'a` must hold. So we can assume `T: 'a`.
     ///
     /// # Parameters
     ///
@@ -48,13 +52,13 @@ impl<'cx, 'gcx, 'tcx> InferCtxt<'cx, 'gcx, 'tcx> {
     /// - `ty`, the type that we are supposed to assume is WF.
     /// - `span`, a span to use when normalizing, hopefully not important,
     ///   might be useful if a `bug!` occurs.
-    pub fn implied_bounds(
+    pub fn implied_outlives_bounds(
         &self,
         param_env: ty::ParamEnv<'tcx>,
         body_id: ast::NodeId,
         ty: Ty<'tcx>,
         span: Span,
-    ) -> Vec<ImpliedBound<'tcx>> {
+    ) -> Vec<OutlivesBound<'tcx>> {
         let tcx = self.tcx;
 
         // Sometimes when we ask what it takes for T: WF, we get back that
@@ -76,8 +80,7 @@ impl<'cx, 'gcx, 'tcx> InferCtxt<'cx, 'gcx, 'tcx> {
             // than the ultimate set. (Note: normally there won't be
             // unresolved inference variables here anyway, but there might be
             // during typeck under some circumstances.)
-            let obligations =
-                wf::obligations(self, param_env, body_id, ty, span).unwrap_or(vec![]);
+            let obligations = wf::obligations(self, param_env, body_id, ty, span).unwrap_or(vec![]);
 
             // NB: All of these predicates *ought* to be easily proven
             // true. In fact, their correctness is (mostly) implied by
@@ -105,7 +108,8 @@ impl<'cx, 'gcx, 'tcx> InferCtxt<'cx, 'gcx, 'tcx> {
                 obligations
                     .iter()
                     .filter(|o| o.predicate.has_infer_types())
-                    .cloned());
+                    .cloned(),
+            );
 
             // From the full set of obligations, just filter down to the
             // region relationships.
@@ -125,25 +129,21 @@ impl<'cx, 'gcx, 'tcx> InferCtxt<'cx, 'gcx, 'tcx> {
                         vec![]
                     }
 
-                    ty::Predicate::RegionOutlives(ref data) => {
-                        match data.no_late_bound_regions() {
-                            None => vec![],
-                            Some(ty::OutlivesPredicate(r_a, r_b)) => {
-                                vec![ImpliedBound::RegionSubRegion(r_b, r_a)]
-                            }
+                    ty::Predicate::RegionOutlives(ref data) => match data.no_late_bound_regions() {
+                        None => vec![],
+                        Some(ty::OutlivesPredicate(r_a, r_b)) => {
+                            vec![OutlivesBound::RegionSubRegion(r_b, r_a)]
                         }
-                    }
+                    },
 
-                    ty::Predicate::TypeOutlives(ref data) => {
-                        match data.no_late_bound_regions() {
-                            None => vec![],
-                            Some(ty::OutlivesPredicate(ty_a, r_b)) => {
-                                let ty_a = self.resolve_type_vars_if_possible(&ty_a);
-                                let components = tcx.outlives_components(ty_a);
-                                Self::implied_bounds_from_components(r_b, components)
-                            }
+                    ty::Predicate::TypeOutlives(ref data) => match data.no_late_bound_regions() {
+                        None => vec![],
+                        Some(ty::OutlivesPredicate(ty_a, r_b)) => {
+                            let ty_a = self.resolve_type_vars_if_possible(&ty_a);
+                            let components = tcx.outlives_components(ty_a);
+                            Self::implied_bounds_from_components(r_b, components)
                         }
-                    }
+                    },
                 }
             }));
         }
@@ -165,17 +165,17 @@ impl<'cx, 'gcx, 'tcx> InferCtxt<'cx, 'gcx, 'tcx> {
     fn implied_bounds_from_components(
         sub_region: ty::Region<'tcx>,
         sup_components: Vec<Component<'tcx>>,
-    ) -> Vec<ImpliedBound<'tcx>> {
+    ) -> Vec<OutlivesBound<'tcx>> {
         sup_components
             .into_iter()
             .flat_map(|component| {
                 match component {
                     Component::Region(r) =>
-                        vec![ImpliedBound::RegionSubRegion(sub_region, r)],
+                        vec![OutlivesBound::RegionSubRegion(sub_region, r)],
                     Component::Param(p) =>
-                        vec![ImpliedBound::RegionSubParam(sub_region, p)],
+                        vec![OutlivesBound::RegionSubParam(sub_region, p)],
                     Component::Projection(p) =>
-                        vec![ImpliedBound::RegionSubProjection(sub_region, p)],
+                        vec![OutlivesBound::RegionSubProjection(sub_region, p)],
                     Component::EscapingProjection(_) =>
                     // If the projection has escaping regions, don't
                     // try to infer any implied bounds even for its
@@ -193,3 +193,26 @@ impl<'cx, 'gcx, 'tcx> InferCtxt<'cx, 'gcx, 'tcx> {
             .collect()
     }
 }
+
+pub fn explicit_outlives_bounds<'tcx>(
+    param_env: ty::ParamEnv<'tcx>,
+) -> impl Iterator<Item = OutlivesBound<'tcx>> + 'tcx {
+    debug!("explicit_outlives_bounds()");
+    param_env
+        .caller_bounds
+        .into_iter()
+        .filter_map(move |predicate| match predicate {
+            ty::Predicate::Projection(..) |
+            ty::Predicate::Trait(..) |
+            ty::Predicate::Equate(..) |
+            ty::Predicate::Subtype(..) |
+            ty::Predicate::WellFormed(..) |
+            ty::Predicate::ObjectSafe(..) |
+            ty::Predicate::ClosureKind(..) |
+            ty::Predicate::TypeOutlives(..) |
+            ty::Predicate::ConstEvaluatable(..) => None,
+            ty::Predicate::RegionOutlives(ref data) => data.no_late_bound_regions().map(
+                |ty::OutlivesPredicate(r_a, r_b)| OutlivesBound::RegionSubRegion(r_b, r_a),
+            ),
+        })
+}