diff options
| author | bors <bors@rust-lang.org> | 2024-04-21 19:05:08 +0000 |
|---|---|---|
| committer | bors <bors@rust-lang.org> | 2024-04-21 19:05:08 +0000 |
| commit | 1b3fba066c21e7c3471fca710783fc1e6546a1ca (patch) | |
| tree | 0e936e66f719a601a24c71c1bdc779837ee3f9cd | |
| parent | f22a0c2d9f9cd83dfe84b65e9fa1b3fa8303c7b5 (diff) | |
| parent | 5a2b335e498202e4470ccccd6cc32b0b4133738e (diff) | |
| download | rust-1b3fba066c21e7c3471fca710783fc1e6546a1ca.tar.gz rust-1b3fba066c21e7c3471fca710783fc1e6546a1ca.zip | |
Auto merge of #124203 - lukas-code:delete-deleting-caches, r=compiler-errors
fix normalizing in different `ParamEnv`s with the same `InferCtxt` This PR changes the key of the projection cache from just `AliasTy` to `(AliasTy, ParamEnv)` to allow normalizing in different `ParamEnv`s without resetting caches. Previously, normalizing the same alias in different param envs would always reuse the cached result from the first normalization, which is incorrect if the projection clauses in the param env have changed. Fixing this bug allows us to get rid of `InferCtxt::clear_caches`, which was only used by the `AutoTraitFinder`, because it requires normalizing in different param envs. r? `@fmease`
8 files changed, 25 insertions, 29 deletions
diff --git a/compiler/rustc_hir_analysis/src/collect/item_bounds.rs b/compiler/rustc_hir_analysis/src/collect/item_bounds.rs index c2205815ba6..02291cc603e 100644 --- a/compiler/rustc_hir_analysis/src/collect/item_bounds.rs +++ b/compiler/rustc_hir_analysis/src/collect/item_bounds.rs @@ -4,7 +4,7 @@ use rustc_data_structures::fx::FxIndexSet; use rustc_hir as hir; use rustc_infer::traits::util; use rustc_middle::ty::GenericArgs; -use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable, TypeFolder}; +use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable}; use rustc_span::def_id::{DefId, LocalDefId}; use rustc_span::Span; @@ -214,7 +214,7 @@ impl<'tcx> TypeFolder<TyCtxt<'tcx>> for AssocTyToOpaque<'tcx> { { self.tcx.type_of(projection_ty.def_id).instantiate(self.tcx, projection_ty.args) } else { - ty + ty.super_fold_with(self) } } } diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs index 355fcf59495..81130d69151 100644 --- a/compiler/rustc_infer/src/infer/mod.rs +++ b/compiler/rustc_infer/src/infer/mod.rs @@ -1521,15 +1521,6 @@ impl<'tcx> InferCtxt<'tcx> { closure_kind_ty.to_opt_closure_kind() } - /// Clears the selection, evaluation, and projection caches. This is useful when - /// repeatedly attempting to select an `Obligation` while changing only - /// its `ParamEnv`, since `FulfillmentContext` doesn't use probing. - pub fn clear_caches(&self) { - self.selection_cache.clear(); - self.evaluation_cache.clear(); - self.inner.borrow_mut().projection_cache().clear(); - } - pub fn universe(&self) -> ty::UniverseIndex { self.universe.get() } diff --git a/compiler/rustc_infer/src/traits/project.rs b/compiler/rustc_infer/src/traits/project.rs index 31ceb234332..c6ffba59638 100644 --- a/compiler/rustc_infer/src/traits/project.rs +++ b/compiler/rustc_infer/src/traits/project.rs @@ -78,11 +78,12 @@ pub struct ProjectionCacheStorage<'tcx> { #[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)] pub struct ProjectionCacheKey<'tcx> { ty: ty::AliasTy<'tcx>, + param_env: ty::ParamEnv<'tcx>, } impl<'tcx> ProjectionCacheKey<'tcx> { - pub fn new(ty: ty::AliasTy<'tcx>) -> Self { - Self { ty } + pub fn new(ty: ty::AliasTy<'tcx>, param_env: ty::ParamEnv<'tcx>) -> Self { + Self { ty, param_env } } } diff --git a/compiler/rustc_trait_selection/src/traits/auto_trait.rs b/compiler/rustc_trait_selection/src/traits/auto_trait.rs index 73e94da165f..f9e7ed9dcbb 100644 --- a/compiler/rustc_trait_selection/src/traits/auto_trait.rs +++ b/compiler/rustc_trait_selection/src/traits/auto_trait.rs @@ -152,7 +152,6 @@ impl<'tcx> AutoTraitFinder<'tcx> { with {:?}", trait_ref, full_env ); - infcx.clear_caches(); // At this point, we already have all of the bounds we need. FulfillmentContext is used // to store all of the necessary region/lifetime bounds in the InferContext, as well as @@ -176,9 +175,7 @@ impl<'tcx> AutoTraitFinder<'tcx> { AutoTraitResult::PositiveImpl(auto_trait_callback(info)) } -} -impl<'tcx> AutoTraitFinder<'tcx> { /// The core logic responsible for computing the bounds for our synthesized impl. /// /// To calculate the bounds, we call `SelectionContext.select` in a loop. Like @@ -255,8 +252,6 @@ impl<'tcx> AutoTraitFinder<'tcx> { let dummy_cause = ObligationCause::dummy(); while let Some(pred) = predicates.pop_front() { - infcx.clear_caches(); - if !already_visited.insert(pred) { continue; } diff --git a/compiler/rustc_trait_selection/src/traits/fulfill.rs b/compiler/rustc_trait_selection/src/traits/fulfill.rs index fbff78304ac..8cd9f39d5d8 100644 --- a/compiler/rustc_trait_selection/src/traits/fulfill.rs +++ b/compiler/rustc_trait_selection/src/traits/fulfill.rs @@ -758,9 +758,9 @@ impl<'a, 'tcx> FulfillProcessor<'a, 'tcx> { // no type variables present, can use evaluation for better caching. // FIXME: consider caching errors too. if self.selcx.infcx.predicate_must_hold_considering_regions(obligation) { - if let Some(key) = ProjectionCacheKey::from_poly_projection_predicate( + if let Some(key) = ProjectionCacheKey::from_poly_projection_obligation( &mut self.selcx, - project_obligation.predicate, + &project_obligation, ) { // If `predicate_must_hold_considering_regions` succeeds, then we've // evaluated all sub-obligations. We can therefore mark the 'root' diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs index 67865bfcaa3..ca0b50864a8 100644 --- a/compiler/rustc_trait_selection/src/traits/project.rs +++ b/compiler/rustc_trait_selection/src/traits/project.rs @@ -344,7 +344,7 @@ pub(super) fn opt_normalize_projection_type<'a, 'b, 'tcx>( let use_cache = !selcx.is_intercrate(); let projection_ty = infcx.resolve_vars_if_possible(projection_ty); - let cache_key = ProjectionCacheKey::new(projection_ty); + let cache_key = ProjectionCacheKey::new(projection_ty, param_env); // FIXME(#20304) For now, I am caching here, which is good, but it // means we don't capture the type variables that are created in @@ -2105,27 +2105,28 @@ fn assoc_ty_own_obligations<'cx, 'tcx>( } pub(crate) trait ProjectionCacheKeyExt<'cx, 'tcx>: Sized { - fn from_poly_projection_predicate( + fn from_poly_projection_obligation( selcx: &mut SelectionContext<'cx, 'tcx>, - predicate: ty::PolyProjectionPredicate<'tcx>, + obligation: &PolyProjectionObligation<'tcx>, ) -> Option<Self>; } impl<'cx, 'tcx> ProjectionCacheKeyExt<'cx, 'tcx> for ProjectionCacheKey<'tcx> { - fn from_poly_projection_predicate( + fn from_poly_projection_obligation( selcx: &mut SelectionContext<'cx, 'tcx>, - predicate: ty::PolyProjectionPredicate<'tcx>, + obligation: &PolyProjectionObligation<'tcx>, ) -> Option<Self> { let infcx = selcx.infcx; // We don't do cross-snapshot caching of obligations with escaping regions, // so there's no cache key to use - predicate.no_bound_vars().map(|predicate| { + obligation.predicate.no_bound_vars().map(|predicate| { ProjectionCacheKey::new( // We don't attempt to match up with a specific type-variable state // from a specific call to `opt_normalize_projection_type` - if // there's no precise match, the original cache entry is "stranded" // anyway. infcx.resolve_vars_if_possible(predicate.projection_ty), + obligation.param_env, ) }) } diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index 10370c7898b..fc12fed3537 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -815,7 +815,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // `EvaluatedToOkModuloRegions`), and skip re-evaluating the // sub-obligations. if let Some(key) = - ProjectionCacheKey::from_poly_projection_predicate(self, data) + ProjectionCacheKey::from_poly_projection_obligation( + self, + &project_obligation, + ) { if let Some(cached_res) = self .infcx @@ -844,8 +847,9 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { && (eval_rslt == EvaluatedToOk || eval_rslt == EvaluatedToOkModuloRegions) && let Some(key) = - ProjectionCacheKey::from_poly_projection_predicate( - self, data, + ProjectionCacheKey::from_poly_projection_obligation( + self, + &project_obligation, ) { // If the result is something that we can cache, then mark this diff --git a/tests/ui/impl-trait/in-trait/nested-rpitit-bounds.rs b/tests/ui/impl-trait/in-trait/nested-rpitit-bounds.rs index 3a173efb32d..10c2a811243 100644 --- a/tests/ui/impl-trait/in-trait/nested-rpitit-bounds.rs +++ b/tests/ui/impl-trait/in-trait/nested-rpitit-bounds.rs @@ -6,6 +6,10 @@ trait Foo { fn foo() -> impl Deref<Target = impl Deref<Target = impl Sized>> { &&() } + + fn bar() -> impl Deref<Target = Option<impl Sized>> { + &Some(()) + } } fn main() {} |
