]> git.lizzy.rs Git - rust.git/commitdiff
move `implied_bounds` into regionck
authorNiko Matsakis <niko@alum.mit.edu>
Wed, 14 Jun 2017 16:46:14 +0000 (12:46 -0400)
committerNiko Matsakis <niko@alum.mit.edu>
Sat, 17 Jun 2017 09:39:48 +0000 (05:39 -0400)
src/librustc/middle/free_region.rs
src/librustc/ty/wf.rs
src/librustc_typeck/check/regionck.rs

index 6a21bdc19e0915b2ade6bf1ebb69e59a0e9a8d92..de738fba30e928796ff762229671555fd07360ff 100644 (file)
@@ -18,7 +18,6 @@
 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
@@ -136,23 +135,6 @@ pub fn is_empty(&self) -> bool {
         self.relation.is_empty()
     }
 
-    pub fn relate_free_regions_from_implied_bounds(&mut self,
-                                                   implied_bounds: &[ImpliedBound<'tcx>])
-    {
-        debug!("relate_free_regions_from_implied_bounds()");
-        for implied_bound in implied_bounds {
-            debug!("implied bound: {:?}", implied_bound);
-            match *implied_bound {
-                ImpliedBound::RegionSubRegion(a, b) => {
-                    self.relate_regions(a, b);
-                }
-                ImpliedBound::RegionSubParam(..) |
-                ImpliedBound::RegionSubProjection(..) => {
-                }
-            }
-        }
-    }
-
     pub fn relate_free_regions_from_predicates(&mut self,
                                                predicates: &[ty::Predicate<'tcx>]) {
         debug!("relate_free_regions_from_predicates(predicates={:?})", predicates);
@@ -177,7 +159,7 @@ pub fn relate_free_regions_from_predicates(&mut self,
 
     // Record that `'sup:'sub`. Or, put another way, `'sub <= 'sup`.
     // (with the exception that `'static: 'x` is not notable)
-    fn relate_regions(&mut self, sub: Region<'tcx>, sup: Region<'tcx>) {
+    pub fn relate_regions(&mut self, sub: Region<'tcx>, sup: Region<'tcx>) {
         if (is_free(sub) || *sub == ty::ReStatic) && is_free(sup) {
             self.relation.add(sub, sup)
         }
index aa2c9802e54737bff9bf52eb372ee1740f704129..2eb0acac4f7ec398b363c62186b43417f76d81b4 100644 (file)
@@ -10,7 +10,6 @@
 
 use hir::def_id::DefId;
 use infer::InferCtxt;
-use ty::outlives::Component;
 use ty::subst::Substs;
 use traits;
 use ty::{self, ToPredicate, Ty, TyCtxt, TypeFoldable};
@@ -107,133 +106,6 @@ pub fn predicate_obligations<'a, 'gcx, 'tcx>(infcx: &InferCtxt<'a, 'gcx, 'tcx>,
     wf.normalize()
 }
 
-/// 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`.
-#[derive(Debug)]
-pub enum ImpliedBound<'tcx> {
-    RegionSubRegion(ty::Region<'tcx>, ty::Region<'tcx>),
-    RegionSubParam(ty::Region<'tcx>, ty::ParamTy),
-    RegionSubProjection(ty::Region<'tcx>, ty::ProjectionTy<'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.
-pub fn implied_bounds<'a, 'gcx, 'tcx>(
-    infcx: &'a InferCtxt<'a, 'gcx, 'tcx>,
-    param_env: ty::ParamEnv<'tcx>,
-    body_id: ast::NodeId,
-    ty: Ty<'tcx>,
-    span: Span)
-    -> Vec<ImpliedBound<'tcx>>
-{
-    // Sometimes when we ask what it takes for T: WF, we get back that
-    // U: WF is required; in that case, we push U onto this stack and
-    // process it next. Currently (at least) these resulting
-    // predicates are always guaranteed to be a subset of the original
-    // type, so we need not fear non-termination.
-    let mut wf_types = vec![ty];
-
-    let mut implied_bounds = vec![];
-
-    while let Some(ty) = wf_types.pop() {
-        // Compute the obligations for `ty` to be well-formed. If `ty` is
-        // an unresolved inference variable, just substituted an empty set
-        // -- because the return type here is going to be things we *add*
-        // to the environment, it's always ok for this set to be smaller
-        // 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 = obligations(infcx, param_env, body_id, ty, span).unwrap_or(vec![]);
-
-        // From the full set of obligations, just filter down to the
-        // region relationships.
-        implied_bounds.extend(
-            obligations
-            .into_iter()
-            .flat_map(|obligation| {
-                assert!(!obligation.has_escaping_regions());
-                match obligation.predicate {
-                    ty::Predicate::Trait(..) |
-                    ty::Predicate::Equate(..) |
-                    ty::Predicate::Subtype(..) |
-                    ty::Predicate::Projection(..) |
-                    ty::Predicate::ClosureKind(..) |
-                    ty::Predicate::ObjectSafe(..) =>
-                        vec![],
-
-                    ty::Predicate::WellFormed(subty) => {
-                        wf_types.push(subty);
-                        vec![]
-                    }
-
-                    ty::Predicate::RegionOutlives(ref data) =>
-                        match infcx.tcx.no_late_bound_regions(data) {
-                            None =>
-                                vec![],
-                            Some(ty::OutlivesPredicate(r_a, r_b)) =>
-                                vec![ImpliedBound::RegionSubRegion(r_b, r_a)],
-                        },
-
-                    ty::Predicate::TypeOutlives(ref data) =>
-                        match infcx.tcx.no_late_bound_regions(data) {
-                            None => vec![],
-                            Some(ty::OutlivesPredicate(ty_a, r_b)) => {
-                                let ty_a = infcx.resolve_type_vars_if_possible(&ty_a);
-                                let components = infcx.tcx.outlives_components(ty_a);
-                                implied_bounds_from_components(r_b, components)
-                            }
-                        },
-                }}));
-    }
-
-    implied_bounds
-}
-
-/// When we have an implied bound that `T: 'a`, we can further break
-/// this down to determine what relationships would have to hold for
-/// `T: 'a` to hold. We get to assume that the caller has validated
-/// those relationships.
-fn implied_bounds_from_components<'tcx>(sub_region: ty::Region<'tcx>,
-                                        sup_components: Vec<Component<'tcx>>)
-                                        -> Vec<ImpliedBound<'tcx>>
-{
-    sup_components
-        .into_iter()
-        .flat_map(|component| {
-            match component {
-                Component::Region(r) =>
-                    vec![ImpliedBound::RegionSubRegion(sub_region, r)],
-                Component::Param(p) =>
-                    vec![ImpliedBound::RegionSubParam(sub_region, p)],
-                Component::Projection(p) =>
-                    vec![ImpliedBound::RegionSubProjection(sub_region, p)],
-                Component::EscapingProjection(_) =>
-                    // If the projection has escaping regions, don't
-                    // try to infer any implied bounds even for its
-                    // free components. This is conservative, because
-                    // the caller will still have to prove that those
-                    // free components outlive `sub_region`. But the
-                    // idea is that the WAY that the caller proves
-                    // that may change in the future and we want to
-                    // give ourselves room to get smarter here.
-                    vec![],
-                Component::UnresolvedInferenceVariable(..) =>
-                    vec![],
-            }
-        })
-        .collect()
-}
-
 struct WfPredicates<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
     infcx: &'a InferCtxt<'a, 'gcx, 'tcx>,
     param_env: ty::ParamEnv<'tcx>,
index 952321c946bf67475d4a606c5a97139468fa6477..bbcd0eadef7505c907fdcfe921e493a5a517f041 100644 (file)
@@ -94,7 +94,8 @@
 use rustc::ty::{self, Ty, TypeFoldable};
 use rustc::infer::{self, GenericKind, SubregionOrigin, VerifyBound};
 use rustc::ty::adjustment;
-use rustc::ty::wf::ImpliedBound;
+use rustc::ty::outlives::Component;
+use rustc::ty::wf;
 
 use std::mem;
 use std::ops::Deref;
@@ -196,6 +197,24 @@ pub struct RegionCtxt<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
 
 }
 
+/// 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`.
+#[derive(Debug)]
+enum ImpliedBound<'tcx> {
+    RegionSubRegion(ty::Region<'tcx>, ty::Region<'tcx>),
+    RegionSubParam(ty::Region<'tcx>, ty::ParamTy),
+    RegionSubProjection(ty::Region<'tcx>, ty::ProjectionTy<'tcx>),
+}
+
 impl<'a, 'gcx, 'tcx> Deref for RegionCtxt<'a, 'gcx, 'tcx> {
     type Target = FnCtxt<'a, 'gcx, 'tcx>;
     fn deref(&self) -> &Self::Target {
@@ -386,11 +405,7 @@ fn relate_free_regions(&mut self,
         for &ty in fn_sig_tys {
             let ty = self.resolve_type(ty);
             debug!("relate_free_regions(t={:?})", ty);
-            let implied_bounds =
-                ty::wf::implied_bounds(self, self.fcx.param_env, body_id, ty, span);
-
-            // Record any relations between free regions that we observe into the free-region-map.
-            self.free_region_map.relate_free_regions_from_implied_bounds(&implied_bounds);
+            let implied_bounds = self.implied_bounds(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
@@ -410,16 +425,18 @@ fn relate_free_regions(&mut self,
                     ImpliedBound::RegionSubProjection(r_a, projection_b) => {
                         self.region_bound_pairs.push((r_a, GenericKind::Projection(projection_b)));
                     }
-                    ImpliedBound::RegionSubRegion(..) => {
+                    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. (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.)
+                        // 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);
                     }
                 }
             }
@@ -428,6 +445,112 @@ fn relate_free_regions(&mut self,
         debug!("<< relate_free_regions");
     }
 
+    /// 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.
+    fn implied_bounds(&mut self, body_id: ast::NodeId, ty: Ty<'tcx>, span: Span)
+                      -> Vec<ImpliedBound<'tcx>> {
+        // Sometimes when we ask what it takes for T: WF, we get back that
+        // U: WF is required; in that case, we push U onto this stack and
+        // process it next. Currently (at least) these resulting
+        // predicates are always guaranteed to be a subset of the original
+        // type, so we need not fear non-termination.
+        let mut wf_types = vec![ty];
+
+        let mut implied_bounds = vec![];
+
+        while let Some(ty) = wf_types.pop() {
+            // Compute the obligations for `ty` to be well-formed. If `ty` is
+            // an unresolved inference variable, just substituted an empty set
+            // -- because the return type here is going to be things we *add*
+            // to the environment, it's always ok for this set to be smaller
+            // 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, self.fcx.param_env, body_id, ty, span)
+                .unwrap_or(vec![]);
+
+            // From the full set of obligations, just filter down to the
+            // region relationships.
+            implied_bounds.extend(
+                obligations
+                    .into_iter()
+                    .flat_map(|obligation| {
+                        assert!(!obligation.has_escaping_regions());
+                        match obligation.predicate {
+                            ty::Predicate::Trait(..) |
+                            ty::Predicate::Equate(..) |
+                            ty::Predicate::Subtype(..) |
+                            ty::Predicate::Projection(..) |
+                            ty::Predicate::ClosureKind(..) |
+                            ty::Predicate::ObjectSafe(..) =>
+                                vec![],
+
+                            ty::Predicate::WellFormed(subty) => {
+                                wf_types.push(subty);
+                                vec![]
+                            }
+
+                            ty::Predicate::RegionOutlives(ref data) =>
+                                match self.tcx.no_late_bound_regions(data) {
+                                    None =>
+                                        vec![],
+                                    Some(ty::OutlivesPredicate(r_a, r_b)) =>
+                                        vec![ImpliedBound::RegionSubRegion(r_b, r_a)],
+                                },
+
+                            ty::Predicate::TypeOutlives(ref data) =>
+                                match self.tcx.no_late_bound_regions(data) {
+                                    None => vec![],
+                                    Some(ty::OutlivesPredicate(ty_a, r_b)) => {
+                                        let ty_a = self.resolve_type_vars_if_possible(&ty_a);
+                                        let components = self.tcx.outlives_components(ty_a);
+                                        self.implied_bounds_from_components(r_b, components)
+                                    }
+                                },
+                        }}));
+        }
+
+        implied_bounds
+    }
+
+    /// When we have an implied bound that `T: 'a`, we can further break
+    /// this down to determine what relationships would have to hold for
+    /// `T: 'a` to hold. We get to assume that the caller has validated
+    /// those relationships.
+    fn implied_bounds_from_components(&self,
+                                      sub_region: ty::Region<'tcx>,
+                                      sup_components: Vec<Component<'tcx>>)
+                                      -> Vec<ImpliedBound<'tcx>>
+    {
+        sup_components
+            .into_iter()
+            .flat_map(|component| {
+                match component {
+                    Component::Region(r) =>
+                        vec![ImpliedBound::RegionSubRegion(sub_region, r)],
+                    Component::Param(p) =>
+                        vec![ImpliedBound::RegionSubParam(sub_region, p)],
+                    Component::Projection(p) =>
+                        vec![ImpliedBound::RegionSubProjection(sub_region, p)],
+                    Component::EscapingProjection(_) =>
+                    // If the projection has escaping regions, don't
+                    // try to infer any implied bounds even for its
+                    // free components. This is conservative, because
+                    // the caller will still have to prove that those
+                    // free components outlive `sub_region`. But the
+                    // idea is that the WAY that the caller proves
+                    // that may change in the future and we want to
+                    // give ourselves room to get smarter here.
+                        vec![],
+                    Component::UnresolvedInferenceVariable(..) =>
+                        vec![],
+                }
+            })
+            .collect()
+    }
+
     fn resolve_regions_and_report_errors(&self) {
         self.fcx.resolve_regions_and_report_errors(self.subject_def_id,
                                                    &self.region_maps,
@@ -1353,25 +1476,25 @@ pub fn type_must_outlive(&self,
 
     fn components_must_outlive(&self,
                                origin: infer::SubregionOrigin<'tcx>,
-                               components: Vec<ty::outlives::Component<'tcx>>,
+                               components: Vec<Component<'tcx>>,
                                region: ty::Region<'tcx>)
     {
         for component in components {
             let origin = origin.clone();
             match component {
-                ty::outlives::Component::Region(region1) => {
+                Component::Region(region1) => {
                     self.sub_regions(origin, region, region1);
                 }
-                ty::outlives::Component::Param(param_ty) => {
+                Component::Param(param_ty) => {
                     self.param_ty_must_outlive(origin, region, param_ty);
                 }
-                ty::outlives::Component::Projection(projection_ty) => {
+                Component::Projection(projection_ty) => {
                     self.projection_must_outlive(origin, region, projection_ty);
                 }
-                ty::outlives::Component::EscapingProjection(subcomponents) => {
+                Component::EscapingProjection(subcomponents) => {
                     self.components_must_outlive(origin, subcomponents, region);
                 }
-                ty::outlives::Component::UnresolvedInferenceVariable(v) => {
+                Component::UnresolvedInferenceVariable(v) => {
                     // ignore this, we presume it will yield an error
                     // later, since if a type variable is not resolved by
                     // this point it never will be