From 3cc44a569ded1484b0ab4fcc5b8cfd545ea3a4b5 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Sat, 4 Nov 2017 05:37:18 -0400 Subject: [PATCH] do not invoke `required_region_bounds` in `region_obligations` Instead, just search the param env predicates directly. This is equivalent to what we were doing before but more efficient. --- src/librustc/infer/region_obligations.rs | 40 ++++++++++++++++++++---- src/librustc/ty/mod.rs | 6 ++++ 2 files changed, 40 insertions(+), 6 deletions(-) diff --git a/src/librustc/infer/region_obligations.rs b/src/librustc/infer/region_obligations.rs index 4cd9c3f9ae3..05e14daa281 100644 --- a/src/librustc/infer/region_obligations.rs +++ b/src/librustc/infer/region_obligations.rs @@ -470,9 +470,16 @@ fn declared_generic_bounds_from_env( ) -> Vec> { let tcx = self.tcx(); - // To start, collect bounds from user: + // To start, collect bounds from user environment. Note that + // parameter environments are already elaborated, so we don't + // have to worry about that. Comparing using `==` is a bit + // dubious for projections, but it will work for simple cases + // like `T` and `T::Item`. It may not work as well for things + // like `>::Item`. let mut param_bounds = - tcx.required_region_bounds(generic.to_ty(tcx), self.param_env.caller_bounds.to_vec()); + self.collect_outlives_from_predicate_list( + generic.to_ty(tcx), + self.param_env.caller_bounds); // Next, collect regions we scraped from the well-formedness // constraints in the fn signature. To do that, we walk the list @@ -559,10 +566,31 @@ fn region_bounds_declared_on_associated_item( let trait_predicates = tcx.predicates_of(trait_def_id); let identity_substs = Substs::identity_for_item(tcx, assoc_item_def_id); let identity_proj = tcx.mk_projection(assoc_item_def_id, identity_substs); - traits::elaborate_predicates(tcx, trait_predicates.predicates) - .filter_map(|p| p.to_opt_type_outlives()) - .filter_map(|p| tcx.no_late_bound_regions(&p)) - .filter(|p| p.0 == identity_proj) + self.collect_outlives_from_predicate_list( + identity_proj, + traits::elaborate_predicates(tcx, trait_predicates.predicates)) + } + + /// Searches through a predicate list for a predicate `T: 'a`. + /// + /// Careful: does not elaborate predicates, and just uses `==` + /// when comparing `ty` for equality, so `ty` must be something + /// that does not involve inference variables and where you + /// otherwise want a precise match. + fn collect_outlives_from_predicate_list( + &self, + ty: Ty<'tcx>, + predicates: I, + ) -> Vec> + where + I: IntoIterator, + P: AsRef>, + { + predicates + .into_iter() + .filter_map(|p| p.as_ref().to_opt_type_outlives()) + .filter_map(|p| self.tcx().no_late_bound_regions(&p)) + .filter(|p| p.0 == ty) .map(|p| p.1) .collect() } diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index 8973d1e0c5a..a9efb042f3d 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -904,6 +904,12 @@ pub enum Predicate<'tcx> { ConstEvaluatable(DefId, &'tcx Substs<'tcx>), } +impl<'tcx> AsRef> for Predicate<'tcx> { + fn as_ref(&self) -> &Predicate<'tcx> { + self + } +} + impl<'a, 'gcx, 'tcx> Predicate<'tcx> { /// Performs a substitution suitable for going from a /// poly-trait-ref to supertraits that must hold if that