Skip to content

Commit 6dbb9d4

Browse files
committed
Don't use projection cache or candidate cache in intercrate mode
Fixes rust-lang#88969 It appears that *just* disabling the evaluation cache (in rust-lang#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.
1 parent db1fb85 commit 6dbb9d4

File tree

3 files changed

+43
-6
lines changed

3 files changed

+43
-6
lines changed

compiler/rustc_trait_selection/src/traits/project.rs

+24-6
Original file line numberDiff line numberDiff line change
@@ -844,6 +844,10 @@ fn opt_normalize_projection_type<'a, 'b, 'tcx>(
844844
obligations: &mut Vec<PredicateObligation<'tcx>>,
845845
) -> Result<Option<Ty<'tcx>>, InProgress> {
846846
let infcx = selcx.infcx();
847+
// Don't use the projection cache in intercrate mode -
848+
// the `infcx` may be re-used between intercrate in non-intercrate
849+
// mode, which could lead to using incorrect cache results.
850+
let use_cache = !selcx.is_intercrate();
847851

848852
let projection_ty = infcx.resolve_vars_if_possible(projection_ty);
849853
let cache_key = ProjectionCacheKey::new(projection_ty);
@@ -856,7 +860,11 @@ fn opt_normalize_projection_type<'a, 'b, 'tcx>(
856860
// bounds. It might be the case that we want two distinct caches,
857861
// or else another kind of cache entry.
858862

859-
let cache_result = infcx.inner.borrow_mut().projection_cache().try_start(cache_key);
863+
let cache_result = if use_cache {
864+
infcx.inner.borrow_mut().projection_cache().try_start(cache_key)
865+
} else {
866+
Ok(())
867+
};
860868
match cache_result {
861869
Ok(()) => debug!("no cache"),
862870
Err(ProjectionCacheEntry::Ambiguous) => {
@@ -881,7 +889,9 @@ fn opt_normalize_projection_type<'a, 'b, 'tcx>(
881889
// should ensure that, unless this happens within a snapshot that's
882890
// rolled back, fulfillment or evaluation will notice the cycle.
883891

884-
infcx.inner.borrow_mut().projection_cache().recur(cache_key);
892+
if use_cache {
893+
infcx.inner.borrow_mut().projection_cache().recur(cache_key);
894+
}
885895
return Err(InProgress);
886896
}
887897
Err(ProjectionCacheEntry::Recur) => {
@@ -963,20 +973,26 @@ fn opt_normalize_projection_type<'a, 'b, 'tcx>(
963973
.map_or(false, |res| res.must_apply_considering_regions())
964974
});
965975

966-
infcx.inner.borrow_mut().projection_cache().insert_ty(cache_key, result.clone());
976+
if use_cache {
977+
infcx.inner.borrow_mut().projection_cache().insert_ty(cache_key, result.clone());
978+
}
967979
obligations.extend(result.obligations);
968980
Ok(Some(result.value))
969981
}
970982
Ok(ProjectedTy::NoProgress(projected_ty)) => {
971983
debug!(?projected_ty, "opt_normalize_projection_type: no progress");
972984
let result = Normalized { value: projected_ty, obligations: vec![] };
973-
infcx.inner.borrow_mut().projection_cache().insert_ty(cache_key, result.clone());
985+
if use_cache {
986+
infcx.inner.borrow_mut().projection_cache().insert_ty(cache_key, result.clone());
987+
}
974988
// No need to extend `obligations`.
975989
Ok(Some(result.value))
976990
}
977991
Err(ProjectionTyError::TooManyCandidates) => {
978992
debug!("opt_normalize_projection_type: too many candidates");
979-
infcx.inner.borrow_mut().projection_cache().ambiguous(cache_key);
993+
if use_cache {
994+
infcx.inner.borrow_mut().projection_cache().ambiguous(cache_key);
995+
}
980996
Ok(None)
981997
}
982998
Err(ProjectionTyError::TraitSelectionError(_)) => {
@@ -986,7 +1002,9 @@ fn opt_normalize_projection_type<'a, 'b, 'tcx>(
9861002
// Trait`, which when processed will cause the error to be
9871003
// reported later
9881004

989-
infcx.inner.borrow_mut().projection_cache().error(cache_key);
1005+
if use_cache {
1006+
infcx.inner.borrow_mut().projection_cache().error(cache_key);
1007+
}
9901008
let result = normalize_to_error(selcx, param_env, projection_ty, cause, depth);
9911009
obligations.extend(result.obligations);
9921010
Ok(Some(result.value))

compiler/rustc_trait_selection/src/traits/select/mod.rs

+18
Original file line numberDiff line numberDiff line change
@@ -314,6 +314,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
314314
self.infcx.tcx
315315
}
316316

317+
pub fn is_intercrate(&self) -> bool {
318+
self.intercrate
319+
}
320+
317321
/// Returns `true` if the trait predicate is considerd `const` to this selection context.
318322
pub fn is_trait_predicate_const(&self, pred: ty::TraitPredicate<'_>) -> bool {
319323
match pred.constness {
@@ -1197,6 +1201,13 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
11971201
param_env: ty::ParamEnv<'tcx>,
11981202
cache_fresh_trait_pred: ty::PolyTraitPredicate<'tcx>,
11991203
) -> Option<SelectionResult<'tcx, SelectionCandidate<'tcx>>> {
1204+
// Neither the global nor local cache is aware of intercrate
1205+
// mode, so don't do any caching. In particular, we might
1206+
// re-use the same `InferCtxt` with both an intercrate
1207+
// and non-intercrate `SelectionContext`
1208+
if self.intercrate {
1209+
return None;
1210+
}
12001211
let tcx = self.tcx();
12011212
let pred = &cache_fresh_trait_pred.skip_binder();
12021213
let trait_ref = pred.trait_ref;
@@ -1233,6 +1244,13 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
12331244
&self,
12341245
result: &SelectionResult<'tcx, SelectionCandidate<'tcx>>,
12351246
) -> bool {
1247+
// Neither the global nor local cache is aware of intercrate
1248+
// mode, so don't do any caching. In particular, we might
1249+
// re-use the same `InferCtxt` with both an intercrate
1250+
// and non-intercrate `SelectionContext`
1251+
if self.intercrate {
1252+
return false;
1253+
}
12361254
match result {
12371255
Ok(Some(SelectionCandidate::ParamCandidate(trait_ref))) => !trait_ref.needs_infer(),
12381256
_ => true,

src/test/ui/coherence/coherence-projection-conflict-orphan.stderr

+1
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ LL | impl<A:Iterator> Foo<A::Item> for A { }
88
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `i32`
99
|
1010
= note: upstream crates may add a new impl of trait `std::iter::Iterator` for type `i32` in future versions
11+
= note: upstream crates may add a new impl of trait `std::iter::Iterator` for type `i32` in future versions
1112

1213
error: aborting due to previous error
1314

0 commit comments

Comments
 (0)