From fdad385618bc260ac02b1c1f741bef18138bd300 Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Fri, 17 Dec 2021 12:32:51 -0500 Subject: [PATCH 1/2] Discard region-related bounds from `ParamEnv` when predicate is global This allows us to use global caches in more places, since we can drop predicates containing inference variables. --- .../src/traits/select/mod.rs | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index 85016a701f3b1..9901d2c7006ff 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -723,6 +723,27 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // out the param env and get better caching. debug!("in global"); obligation.param_env = obligation.param_env.without_caller_bounds(); + } else if !self.intercrate + && obligation.predicate.is_global(self.tcx()) + && obligation.param_env.has_free_regions(self.tcx()) + { + // Strip out bounds that only reference regions + let new_bounds: Vec<_> = obligation + .param_env + .caller_bounds() + .iter() + .filter(|bound| match bound.kind().skip_binder() { + ty::PredicateKind::RegionOutlives(_) | ty::PredicateKind::TypeOutlives(_) => { + false + } + _ => true, + }) + .collect(); + obligation.param_env = ty::ParamEnv::new( + self.tcx().intern_predicates(&new_bounds), + obligation.param_env.reveal(), + obligation.param_env.constness(), + ); } let stack = self.push_stack(previous_stack, &obligation); From 835fc8a97a173159030a82c4f9811db6eb8afb23 Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Mon, 20 Dec 2021 12:10:30 -0500 Subject: [PATCH 2/2] Be more conservative about discarding bounds --- .../src/traits/select/mod.rs | 39 ++++++++++++++++++- 1 file changed, 37 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index 9901d2c7006ff..84294e8726ae6 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -733,12 +733,47 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { .caller_bounds() .iter() .filter(|bound| match bound.kind().skip_binder() { - ty::PredicateKind::RegionOutlives(_) | ty::PredicateKind::TypeOutlives(_) => { - false + predicate @ ty::PredicateKind::RegionOutlives(_) => { + // A bound involving early-bound regions + // (e.g. `fn foo<'a, 'b>() where 'a: 'b or + // `fn bar<'a>() where 'a: 'static + //) + // cannot affect the evaluation of a predicate with no + // free regions. Such a predicate only gives us information + // about some specific caller-chosen lifetime, and does not + // give us any information about any bound regions within + // our predicate (e.g. `for<'a> T: MyTrait<'a>`). Since + // we checked above that our predicate does not include any + // free regions (which includes early-bound regions), we know + // that it's safe to discard a predicate involving only + // early-bound regions. + // + // If a `RegionOutLives` predicate has any late-bound regions, + // we choose to keep it. This might be overly conservative, + // but should be safe in all cases. + predicate.has_late_bound_regions() } + // If we have a predicate like `T: 'static`, then we need to keep + // it, since it could legitimately affect the evaluation of our predicate. + // For exmaple, we could be evaluating `T: MyTrait`, and find + // `impl MyTrait for T {}`. + // + // We also keep any `TypeOutlives` predicates involving any late-bound + // regions. This is probably overly conservative, but ensures that we don't + // run into any weird situations with impossible-to-satisfiy predicates + // (e.g. `for<'a> &'a u8: 'static). + predicate @ ty::PredicateKind::TypeOutlives(outlives) => { + *outlives.1 == ty::ReStatic || predicate.has_late_bound_regions() + } + // We assume that all other bounds can potentially affect + // the evaluation of our predicates, so we keep them _ => true, }) .collect(); + + // Replace the `ParamEnv` with a new one, which differs + // only be the removal of some of the caller bounds. This will + // allow us to use the global cache in more cases. obligation.param_env = ty::ParamEnv::new( self.tcx().intern_predicates(&new_bounds), obligation.param_env.reveal(),