From f8e5fdaab6c4fb99a730fd0712738806c3325127 Mon Sep 17 00:00:00 2001 From: bors Date: Tue, 21 Sep 2021 13:25:14 +0000 Subject: [PATCH] Auto merge of #89125 - Aaron1011:remove-intercrate-cache, r=jackh726 Don't use projection cache or candidate cache in intercrate mode Fixes #88969 It appears that *just* disabling the evaluation cache (in #88994) leads to other issues involving intercrate mode caching. I suspect that since we now always end up performing the full evaluation in intercrate mode, we end up 'polluting' the candidate and projection caches with results that depend on being in intercrate mode in some way. Previously, we might have hit a cached evaluation (stored during non-intercrate mode), and skipped doing this extra work in intercrate mode. The whole situation with intercrate mode caching is turning into a mess. Ideally, we would remove intercrate mode entirely - however, this might require waiting on Chalk. --- .../src/traits/project.rs | 30 +++++++++++++++---- .../src/traits/select/mod.rs | 18 +++++++++++ ...oherence-projection-conflict-orphan.stderr | 1 + 3 files changed, 43 insertions(+), 6 deletions(-) diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs index 7038f16a2c9c4..af546c86d226c 100644 --- a/compiler/rustc_trait_selection/src/traits/project.rs +++ b/compiler/rustc_trait_selection/src/traits/project.rs @@ -844,6 +844,10 @@ fn opt_normalize_projection_type<'a, 'b, 'tcx>( obligations: &mut Vec>, ) -> Result>, InProgress> { let infcx = selcx.infcx(); + // Don't use the projection cache in intercrate mode - + // the `infcx` may be re-used between intercrate in non-intercrate + // mode, which could lead to using incorrect cache results. + let use_cache = !selcx.is_intercrate(); let projection_ty = infcx.resolve_vars_if_possible(projection_ty); let cache_key = ProjectionCacheKey::new(projection_ty); @@ -856,7 +860,11 @@ fn opt_normalize_projection_type<'a, 'b, 'tcx>( // bounds. It might be the case that we want two distinct caches, // or else another kind of cache entry. - let cache_result = infcx.inner.borrow_mut().projection_cache().try_start(cache_key); + let cache_result = if use_cache { + infcx.inner.borrow_mut().projection_cache().try_start(cache_key) + } else { + Ok(()) + }; match cache_result { Ok(()) => debug!("no cache"), Err(ProjectionCacheEntry::Ambiguous) => { @@ -881,7 +889,9 @@ fn opt_normalize_projection_type<'a, 'b, 'tcx>( // should ensure that, unless this happens within a snapshot that's // rolled back, fulfillment or evaluation will notice the cycle. - infcx.inner.borrow_mut().projection_cache().recur(cache_key); + if use_cache { + infcx.inner.borrow_mut().projection_cache().recur(cache_key); + } return Err(InProgress); } Err(ProjectionCacheEntry::Recur) => { @@ -963,20 +973,26 @@ fn opt_normalize_projection_type<'a, 'b, 'tcx>( .map_or(false, |res| res.must_apply_considering_regions()) }); - infcx.inner.borrow_mut().projection_cache().insert_ty(cache_key, result.clone()); + if use_cache { + infcx.inner.borrow_mut().projection_cache().insert_ty(cache_key, result.clone()); + } obligations.extend(result.obligations); Ok(Some(result.value)) } Ok(ProjectedTy::NoProgress(projected_ty)) => { debug!(?projected_ty, "opt_normalize_projection_type: no progress"); let result = Normalized { value: projected_ty, obligations: vec![] }; - infcx.inner.borrow_mut().projection_cache().insert_ty(cache_key, result.clone()); + if use_cache { + infcx.inner.borrow_mut().projection_cache().insert_ty(cache_key, result.clone()); + } // No need to extend `obligations`. Ok(Some(result.value)) } Err(ProjectionTyError::TooManyCandidates) => { debug!("opt_normalize_projection_type: too many candidates"); - infcx.inner.borrow_mut().projection_cache().ambiguous(cache_key); + if use_cache { + infcx.inner.borrow_mut().projection_cache().ambiguous(cache_key); + } Ok(None) } Err(ProjectionTyError::TraitSelectionError(_)) => { @@ -986,7 +1002,9 @@ fn opt_normalize_projection_type<'a, 'b, 'tcx>( // Trait`, which when processed will cause the error to be // reported later - infcx.inner.borrow_mut().projection_cache().error(cache_key); + if use_cache { + infcx.inner.borrow_mut().projection_cache().error(cache_key); + } let result = normalize_to_error(selcx, param_env, projection_ty, cause, depth); obligations.extend(result.obligations); Ok(Some(result.value)) diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index 42a3d780c67c0..cf6f76a932585 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -315,6 +315,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { self.infcx.tcx } + pub fn is_intercrate(&self) -> bool { + self.intercrate + } + /// Returns `true` if the trait predicate is considerd `const` to this selection context. pub fn is_trait_predicate_const(&self, pred: ty::TraitPredicate<'_>) -> bool { match pred.constness { @@ -1201,6 +1205,13 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { param_env: ty::ParamEnv<'tcx>, cache_fresh_trait_pred: ty::PolyTraitPredicate<'tcx>, ) -> Option>> { + // Neither the global nor local cache is aware of intercrate + // mode, so don't do any caching. In particular, we might + // re-use the same `InferCtxt` with both an intercrate + // and non-intercrate `SelectionContext` + if self.intercrate { + return None; + } let tcx = self.tcx(); let pred = &cache_fresh_trait_pred.skip_binder(); let trait_ref = pred.trait_ref; @@ -1237,6 +1248,13 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { &self, result: &SelectionResult<'tcx, SelectionCandidate<'tcx>>, ) -> bool { + // Neither the global nor local cache is aware of intercrate + // mode, so don't do any caching. In particular, we might + // re-use the same `InferCtxt` with both an intercrate + // and non-intercrate `SelectionContext` + if self.intercrate { + return false; + } match result { Ok(Some(SelectionCandidate::ParamCandidate(trait_ref))) => !trait_ref.needs_infer(), _ => true, diff --git a/src/test/ui/coherence/coherence-projection-conflict-orphan.stderr b/src/test/ui/coherence/coherence-projection-conflict-orphan.stderr index 51f6faab3c7e4..9efb5dc75f4f0 100644 --- a/src/test/ui/coherence/coherence-projection-conflict-orphan.stderr +++ b/src/test/ui/coherence/coherence-projection-conflict-orphan.stderr @@ -8,6 +8,7 @@ LL | impl Foo for A { } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `i32` | = note: upstream crates may add a new impl of trait `std::iter::Iterator` for type `i32` in future versions + = note: upstream crates may add a new impl of trait `std::iter::Iterator` for type `i32` in future versions error: aborting due to previous error