From da0816c7a3fc9141910a3b7f86d64ffb40ba49cd Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Wed, 15 Sep 2021 18:11:42 -0500 Subject: [PATCH] Disable projection sub-obligation optimization in intercrate mode The meaning of an 'evaluation' in intercrate mode is more complicated than with an normal `SelectionContext`. To avoid potential issues, we now always preserve all projection sub-obligations when in intercrate mode. This avoids needing to answer whether or not `EvaluatedToOk` always means the same thing in intercrate mode as it does normally. --- .../src/traits/project.rs | 42 +++++++++++-------- .../src/traits/select/mod.rs | 4 ++ 2 files changed, 28 insertions(+), 18 deletions(-) diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs index 92db0ca2a7c40..8caa99597b0f1 100644 --- a/compiler/rustc_trait_selection/src/traits/project.rs +++ b/compiler/rustc_trait_selection/src/traits/project.rs @@ -944,24 +944,30 @@ fn opt_normalize_projection_type<'a, 'b, 'tcx>( Normalized { value: projected_ty, obligations: projected_obligations } }; - let mut canonical = - SelectionContext::with_query_mode(selcx.infcx(), TraitQueryMode::Canonical); - result.obligations.drain_filter(|projected_obligation| { - // If any global obligations always apply, considering regions, then we don't - // need to include them. The `is_global` check rules out inference variables, - // so there's no need for the caller of `opt_normalize_projection_type` - // to evaluate them. - // Note that we do *not* discard obligations that evaluate to - // `EvaluatedtoOkModuloRegions`. Evaluating these obligations - // inside of a query (e.g. `evaluate_obligation`) can change - // the result to `EvaluatedToOkModuloRegions`, while an - // `EvaluatedToOk` obligation will never change the result. - // See #85360 for more details - projected_obligation.is_global(canonical.tcx()) - && canonical - .evaluate_root_obligation(projected_obligation) - .map_or(false, |res| res.must_apply_considering_regions()) - }); + // In intercrate mode, things are more complicated, and the 'evaluation result' + // may not be the same as the evaluation result in a normal `SelectionContext`. + // To avoid having to deal with this, always keep all of the sub-obligations + // in intercrate mode. + if !selcx.is_intercrate() { + let mut canonical = + SelectionContext::with_query_mode(selcx.infcx(), TraitQueryMode::Canonical); + result.obligations.drain_filter(|projected_obligation| { + // If any global obligations always apply, considering regions, then we don't + // need to include them. The `is_global` check rules out inference variables, + // so there's no need for the caller of `opt_normalize_projection_type` + // to evaluate them. + // Note that we do *not* discard obligations that evaluate to + // `EvaluatedtoOkModuloRegions`. Evaluating these obligations + // inside of a query (e.g. `evaluate_obligation`) can change + // the result to `EvaluatedToOkModuloRegions`, while an + // `EvaluatedToOk` obligation will never change the result. + // See #85360 for more details + projected_obligation.is_global(canonical.tcx()) + && canonical + .evaluate_root_obligation(projected_obligation) + .map_or(false, |res| res.must_apply_considering_regions()) + }); + } infcx.inner.borrow_mut().projection_cache().insert_ty(cache_key, result.clone()); obligations.extend(result.obligations); diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index 8adf9015933c3..818db1355f18d 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 {