about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/librustc/infer/outlives/obligations.rs11
-rw-r--r--src/librustc/infer/outlives/verify.rs97
2 files changed, 59 insertions, 49 deletions
diff --git a/src/librustc/infer/outlives/obligations.rs b/src/librustc/infer/outlives/obligations.rs
index 88ac1e8590d..332859d4f81 100644
--- a/src/librustc/infer/outlives/obligations.rs
+++ b/src/librustc/infer/outlives/obligations.rs
@@ -401,12 +401,9 @@ where
         // Compute the bounds we can derive from the trait definition.
         // These are guaranteed to apply, no matter the inference
         // results.
-        let trait_bounds = self.verify_bound
-            .projection_declared_bounds_from_trait(projection_ty);
-        debug!(
-            "projection_must_outlive: trait_bounds={:?}",
-            trait_bounds
-        );
+        let trait_bounds: Vec<_> = self.verify_bound
+            .projection_declared_bounds_from_trait(projection_ty)
+            .collect();
 
         // If declared bounds list is empty, the only applicable rule is
         // OutlivesProjectionComponent. If there are inference variables,
@@ -451,7 +448,7 @@ where
         if !trait_bounds.is_empty()
             && trait_bounds[1..]
                 .iter()
-                .chain(&approx_env_bounds)
+                .chain(approx_env_bounds.iter().map(|b| &b.1))
                 .all(|b| *b == trait_bounds[0])
         {
             let unique_bound = trait_bounds[0];
diff --git a/src/librustc/infer/outlives/verify.rs b/src/librustc/infer/outlives/verify.rs
index 79fc2df7db9..5b23fc19a9d 100644
--- a/src/librustc/infer/outlives/verify.rs
+++ b/src/librustc/infer/outlives/verify.rs
@@ -14,6 +14,7 @@ use infer::{GenericKind, VerifyBound};
 use traits;
 use ty::subst::{Subst, Substs};
 use ty::{self, Ty, TyCtxt};
+use util::captures::Captures;
 
 /// The `TypeOutlives` struct has the job of "lowering" a `T: 'a`
 /// obligation into a series of `'a: 'b` constraints and "verifys", as
@@ -65,21 +66,15 @@ impl<'cx, 'gcx, 'tcx> VerifyBoundCx<'cx, 'gcx, 'tcx> {
 
         // Start with anything like `T: 'a` we can scrape from the
         // environment
-        let param_bounds =
-            self.declared_generic_bounds_from_env(GenericKind::Param(param_ty))
-            .into_iter();
+        let param_bounds = self.declared_generic_bounds_from_env(GenericKind::Param(param_ty))
+            .into_iter()
+            .map(|outlives| outlives.1);
 
         // Add in the default bound of fn body that applies to all in
         // scope type parameters:
-        let param_bounds =
-            param_bounds
-            .chain(self.implicit_region_bound);
+        let param_bounds = param_bounds.chain(self.implicit_region_bound);
 
-        VerifyBound::AnyBound(
-            param_bounds
-                .map(|r| VerifyBound::OutlivedBy(r))
-                .collect()
-        )
+        VerifyBound::AnyBound(param_bounds.map(|r| VerifyBound::OutlivedBy(r)).collect())
     }
 
     /// Given a projection like `T::Item`, searches the environment
@@ -98,7 +93,7 @@ impl<'cx, 'gcx, 'tcx> VerifyBoundCx<'cx, 'gcx, 'tcx> {
     pub fn projection_approx_declared_bounds_from_env(
         &self,
         projection_ty: ty::ProjectionTy<'tcx>,
-    ) -> Vec<ty::Region<'tcx>> {
+    ) -> Vec<ty::OutlivesPredicate<Ty<'tcx>, ty::Region<'tcx>>> {
         let projection_ty = GenericKind::Projection(projection_ty).to_ty(self.tcx);
         let erased_projection_ty = self.tcx.erase_regions(&projection_ty);
         self.declared_generic_bounds_from_env_with_compare_fn(|ty| {
@@ -117,31 +112,42 @@ impl<'cx, 'gcx, 'tcx> VerifyBoundCx<'cx, 'gcx, 'tcx> {
     pub fn projection_declared_bounds_from_trait(
         &self,
         projection_ty: ty::ProjectionTy<'tcx>,
-    ) -> Vec<ty::Region<'tcx>> {
+    ) -> impl Iterator<Item = ty::Region<'tcx>> + 'cx + Captures<'gcx> {
         self.declared_projection_bounds_from_trait(projection_ty)
     }
 
     pub fn projection_bound(&self, projection_ty: ty::ProjectionTy<'tcx>) -> VerifyBound<'tcx> {
         debug!("projection_bound(projection_ty={:?})", projection_ty);
 
+        let projection_ty_as_ty =
+            self.tcx.mk_projection(projection_ty.item_def_id, projection_ty.substs);
+
         // Search the env for where clauses like `P: 'a`.
-        let env_bounds =
-            self.declared_generic_bounds_from_env(GenericKind::Projection(projection_ty))
-            .into_iter();
+        let env_bounds = self.projection_approx_declared_bounds_from_env(projection_ty)
+            .into_iter()
+            .map(|ty::OutlivesPredicate(ty, r)| {
+                let vb = VerifyBound::OutlivedBy(r);
+                if ty == projection_ty_as_ty {
+                    // Micro-optimize if this is an exact match (this
+                    // occurs often when there are no region variables
+                    // involved).
+                    vb
+                } else {
+                    VerifyBound::IfEq(ty, Box::new(vb))
+                }
+            });
 
         // Extend with bounds that we can find from the trait.
-        let trait_bounds =
-            self.projection_declared_bounds_from_trait(projection_ty)
-            .into_iter();
+        let trait_bounds = self.projection_declared_bounds_from_trait(projection_ty)
+            .into_iter()
+            .map(|r| VerifyBound::OutlivedBy(r));
 
         // see the extensive comment in projection_must_outlive
         let ty = self.tcx
             .mk_projection(projection_ty.item_def_id, projection_ty.substs);
         let recursive_bound = self.recursive_type_bound(ty);
 
-        VerifyBound::AnyBound(
-            env_bounds.chain(trait_bounds).map(|r| VerifyBound::OutlivedBy(r)).collect()
-        ).or(recursive_bound)
+        VerifyBound::AnyBound(env_bounds.chain(trait_bounds).collect()).or(recursive_bound)
     }
 
     fn recursive_type_bound(&self, ty: Ty<'tcx>) -> VerifyBound<'tcx> {
@@ -151,11 +157,12 @@ impl<'cx, 'gcx, 'tcx> VerifyBoundCx<'cx, 'gcx, 'tcx> {
 
         let mut regions = ty.regions();
         regions.retain(|r| !r.is_late_bound()); // ignore late-bound regions
-        bounds.push(
-            VerifyBound::AllBounds(
-                regions.into_iter().map(|r| VerifyBound::OutlivedBy(r)).collect()
-            )
-        );
+        bounds.push(VerifyBound::AllBounds(
+            regions
+                .into_iter()
+                .map(|r| VerifyBound::OutlivedBy(r))
+                .collect(),
+        ));
 
         // remove bounds that must hold, since they are not interesting
         bounds.retain(|b| !b.must_hold());
@@ -176,7 +183,7 @@ impl<'cx, 'gcx, 'tcx> VerifyBoundCx<'cx, 'gcx, 'tcx> {
     fn declared_generic_bounds_from_env(
         &self,
         generic: GenericKind<'tcx>,
-    ) -> Vec<ty::Region<'tcx>> {
+    ) -> Vec<ty::OutlivesPredicate<Ty<'tcx>, ty::Region<'tcx>>> {
         let generic_ty = generic.to_ty(self.tcx);
         self.declared_generic_bounds_from_env_with_compare_fn(|ty| ty == generic_ty)
     }
@@ -184,7 +191,7 @@ impl<'cx, 'gcx, 'tcx> VerifyBoundCx<'cx, 'gcx, 'tcx> {
     fn declared_generic_bounds_from_env_with_compare_fn(
         &self,
         compare_ty: impl Fn(Ty<'tcx>) -> bool,
-    ) -> Vec<ty::Region<'tcx>> {
+    ) -> Vec<ty::OutlivesPredicate<Ty<'tcx>, ty::Region<'tcx>>> {
         let tcx = self.tcx;
 
         // To start, collect bounds from user environment. Note that
@@ -212,14 +219,23 @@ impl<'cx, 'gcx, 'tcx> VerifyBoundCx<'cx, 'gcx, 'tcx> {
                 "declared_generic_bounds_from_env_with_compare_fn: region_bound_pair = {:?}",
                 (r, p)
             );
-            if compare_ty(p.to_ty(tcx)) {
-                Some(r)
+            let p_ty = p.to_ty(tcx);
+            if compare_ty(p_ty) {
+                Some(ty::OutlivesPredicate(p_ty, r))
             } else {
                 None
             }
         });
 
-        param_bounds.chain(from_region_bound_pairs).collect()
+        param_bounds
+            .chain(from_region_bound_pairs)
+            .inspect(|bound| {
+                debug!(
+                    "declared_generic_bounds_from_env_with_compare_fn: result predicate = {:?}",
+                    bound
+                )
+            })
+            .collect()
     }
 
     /// Given a projection like `<T as Foo<'x>>::Bar`, returns any bounds
@@ -237,13 +253,11 @@ impl<'cx, 'gcx, 'tcx> VerifyBoundCx<'cx, 'gcx, 'tcx> {
     fn declared_projection_bounds_from_trait(
         &self,
         projection_ty: ty::ProjectionTy<'tcx>,
-    ) -> Vec<ty::Region<'tcx>> {
+    ) -> impl Iterator<Item = ty::Region<'tcx>> + 'cx + Captures<'gcx> {
         debug!("projection_bounds(projection_ty={:?})", projection_ty);
-        let mut bounds = self.region_bounds_declared_on_associated_item(projection_ty.item_def_id);
-        for r in &mut bounds {
-            *r = r.subst(self.tcx, projection_ty.substs);
-        }
-        bounds
+        let tcx = self.tcx;
+        self.region_bounds_declared_on_associated_item(projection_ty.item_def_id)
+            .map(move |r| r.subst(tcx, projection_ty.substs))
     }
 
     /// Given the def-id of an associated item, returns any region
@@ -279,7 +293,7 @@ impl<'cx, 'gcx, 'tcx> VerifyBoundCx<'cx, 'gcx, 'tcx> {
     fn region_bounds_declared_on_associated_item(
         &self,
         assoc_item_def_id: DefId,
-    ) -> Vec<ty::Region<'tcx>> {
+    ) -> impl Iterator<Item = ty::Region<'tcx>> + 'cx + Captures<'gcx> {
         let tcx = self.tcx;
         let assoc_item = tcx.associated_item(assoc_item_def_id);
         let trait_def_id = assoc_item.container.assert_trait();
@@ -289,7 +303,7 @@ impl<'cx, 'gcx, 'tcx> VerifyBoundCx<'cx, 'gcx, 'tcx> {
         self.collect_outlives_from_predicate_list(
             move |ty| ty == identity_proj,
             traits::elaborate_predicates(tcx, trait_predicates.predicates),
-        ).collect()
+        ).map(|b| b.1)
     }
 
     /// Searches through a predicate list for a predicate `T: 'a`.
@@ -302,12 +316,11 @@ impl<'cx, 'gcx, 'tcx> VerifyBoundCx<'cx, 'gcx, 'tcx> {
         &self,
         compare_ty: impl Fn(Ty<'tcx>) -> bool,
         predicates: impl IntoIterator<Item = impl AsRef<ty::Predicate<'tcx>>>,
-    ) -> impl Iterator<Item = ty::Region<'tcx>> {
+    ) -> impl Iterator<Item = ty::OutlivesPredicate<Ty<'tcx>, ty::Region<'tcx>>> {
         predicates
             .into_iter()
             .filter_map(|p| p.as_ref().to_opt_type_outlives())
             .filter_map(|p| p.no_late_bound_regions())
             .filter(move |p| compare_ty(p.0))
-            .map(|p| p.1)
     }
 }