Skip to content

Commit da0816c

Browse files
committed
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.
1 parent c3c0f80 commit da0816c

File tree

2 files changed

+28
-18
lines changed

2 files changed

+28
-18
lines changed

compiler/rustc_trait_selection/src/traits/project.rs

+24-18
Original file line numberDiff line numberDiff line change
@@ -944,24 +944,30 @@ fn opt_normalize_projection_type<'a, 'b, 'tcx>(
944944
Normalized { value: projected_ty, obligations: projected_obligations }
945945
};
946946

947-
let mut canonical =
948-
SelectionContext::with_query_mode(selcx.infcx(), TraitQueryMode::Canonical);
949-
result.obligations.drain_filter(|projected_obligation| {
950-
// If any global obligations always apply, considering regions, then we don't
951-
// need to include them. The `is_global` check rules out inference variables,
952-
// so there's no need for the caller of `opt_normalize_projection_type`
953-
// to evaluate them.
954-
// Note that we do *not* discard obligations that evaluate to
955-
// `EvaluatedtoOkModuloRegions`. Evaluating these obligations
956-
// inside of a query (e.g. `evaluate_obligation`) can change
957-
// the result to `EvaluatedToOkModuloRegions`, while an
958-
// `EvaluatedToOk` obligation will never change the result.
959-
// See #85360 for more details
960-
projected_obligation.is_global(canonical.tcx())
961-
&& canonical
962-
.evaluate_root_obligation(projected_obligation)
963-
.map_or(false, |res| res.must_apply_considering_regions())
964-
});
947+
// In intercrate mode, things are more complicated, and the 'evaluation result'
948+
// may not be the same as the evaluation result in a normal `SelectionContext`.
949+
// To avoid having to deal with this, always keep all of the sub-obligations
950+
// in intercrate mode.
951+
if !selcx.is_intercrate() {
952+
let mut canonical =
953+
SelectionContext::with_query_mode(selcx.infcx(), TraitQueryMode::Canonical);
954+
result.obligations.drain_filter(|projected_obligation| {
955+
// If any global obligations always apply, considering regions, then we don't
956+
// need to include them. The `is_global` check rules out inference variables,
957+
// so there's no need for the caller of `opt_normalize_projection_type`
958+
// to evaluate them.
959+
// Note that we do *not* discard obligations that evaluate to
960+
// `EvaluatedtoOkModuloRegions`. Evaluating these obligations
961+
// inside of a query (e.g. `evaluate_obligation`) can change
962+
// the result to `EvaluatedToOkModuloRegions`, while an
963+
// `EvaluatedToOk` obligation will never change the result.
964+
// See #85360 for more details
965+
projected_obligation.is_global(canonical.tcx())
966+
&& canonical
967+
.evaluate_root_obligation(projected_obligation)
968+
.map_or(false, |res| res.must_apply_considering_regions())
969+
});
970+
}
965971

966972
infcx.inner.borrow_mut().projection_cache().insert_ty(cache_key, result.clone());
967973
obligations.extend(result.obligations);

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

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

318+
pub fn is_intercrate(&self) -> bool {
319+
self.intercrate
320+
}
321+
318322
/// Returns `true` if the trait predicate is considerd `const` to this selection context.
319323
pub fn is_trait_predicate_const(&self, pred: ty::TraitPredicate<'_>) -> bool {
320324
match pred.constness {

0 commit comments

Comments
 (0)