TypingMode 🤔

This commit is contained in:
lcnr 2024-10-18 00:28:43 +02:00
parent 2dece5bb62
commit f51ec110a7
75 changed files with 513 additions and 506 deletions

View file

@ -2,6 +2,7 @@
//!
//! [rustc dev guide]: https://rustc-dev-guide.rust-lang.org/traits/resolution.html#selection
use std::assert_matches::assert_matches;
use std::cell::{Cell, RefCell};
use std::fmt::{self, Display};
use std::ops::ControlFlow;
@ -28,7 +29,7 @@ use rustc_middle::ty::error::TypeErrorToStringExt;
use rustc_middle::ty::print::{PrintTraitRefExt as _, with_no_trimmed_paths};
use rustc_middle::ty::{
self, GenericArgsRef, PolyProjectionPredicate, Ty, TyCtxt, TypeFoldable, TypeVisitableExt,
Upcast,
TypingMode, Upcast,
};
use rustc_span::Symbol;
use rustc_span::symbol::sym;
@ -222,7 +223,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
/// Enables tracking of intercrate ambiguity causes. See
/// the documentation of [`Self::intercrate_ambiguity_causes`] for more.
pub fn enable_tracking_intercrate_ambiguity_causes(&mut self) {
assert!(self.is_intercrate());
assert_matches!(self.infcx.typing_mode_unchecked(), TypingMode::Coherence);
assert!(self.intercrate_ambiguity_causes.is_none());
self.intercrate_ambiguity_causes = Some(FxIndexSet::default());
debug!("selcx: enable_tracking_intercrate_ambiguity_causes");
@ -234,7 +235,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
pub fn take_intercrate_ambiguity_causes(
&mut self,
) -> FxIndexSet<IntercrateAmbiguityCause<'tcx>> {
assert!(self.is_intercrate());
assert_matches!(self.infcx.typing_mode_unchecked(), TypingMode::Coherence);
self.intercrate_ambiguity_causes.take().unwrap_or_default()
}
@ -242,10 +243,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
self.infcx.tcx
}
pub fn is_intercrate(&self) -> bool {
self.infcx.intercrate
}
///////////////////////////////////////////////////////////////////////////
// Selection
//
@ -1029,7 +1026,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
previous_stack: TraitObligationStackList<'o, 'tcx>,
mut obligation: PolyTraitObligation<'tcx>,
) -> Result<EvaluationResult, OverflowError> {
if !self.is_intercrate()
if !matches!(self.infcx.typing_mode(obligation.param_env), TypingMode::Coherence)
&& obligation.is_global()
&& obligation.param_env.caller_bounds().iter().all(|bound| bound.has_param())
{
@ -1312,14 +1309,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
param_env: ty::ParamEnv<'tcx>,
trait_pred: ty::PolyTraitPredicate<'tcx>,
) -> Option<EvaluationResult> {
// 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.is_intercrate() {
return None;
}
let tcx = self.tcx();
if self.can_use_global_caches(param_env) {
if let Some(res) = tcx.evaluation_cache.get(&(param_env, trait_pred), tcx) {
@ -1342,14 +1331,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
return;
}
// 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.is_intercrate() {
return;
}
if self.can_use_global_caches(param_env) && !trait_pred.has_infer() {
debug!(?trait_pred, ?result, "insert_evaluation_cache global");
// This may overwrite the cache with the same value
@ -1476,13 +1457,14 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
}
fn is_knowable<'o>(&mut self, stack: &TraitObligationStack<'o, 'tcx>) -> Result<(), Conflict> {
debug!("is_knowable(intercrate={:?})", self.is_intercrate());
if !self.is_intercrate() {
return Ok(());
let obligation = &stack.obligation;
match self.infcx.typing_mode(obligation.param_env) {
TypingMode::Coherence => {}
TypingMode::Analysis { .. } | TypingMode::PostAnalysis => return Ok(()),
}
let obligation = &stack.obligation;
debug!("is_knowable()");
let predicate = self.infcx.resolve_vars_if_possible(obligation.predicate);
// Okay to skip binder because of the nature of the
@ -1502,25 +1484,24 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
return false;
}
// Avoid using the global cache during coherence and just rely
// on the local cache. This effectively disables caching
// during coherence. It is really just a simplification to
// avoid us having to fear that coherence results "pollute"
// the master cache. Since coherence executes pretty quickly,
// it's not worth going to more trouble to increase the
// hit-rate, I don't think.
if self.is_intercrate() {
return false;
match self.infcx.typing_mode(param_env) {
// Avoid using the global cache during coherence and just rely
// on the local cache. It is really just a simplification to
// avoid us having to fear that coherence results "pollute"
// the master cache. Since coherence executes pretty quickly,
// it's not worth going to more trouble to increase the
// hit-rate, I don't think.
TypingMode::Coherence => false,
// Avoid using the global cache when we're defining opaque types
// as their hidden type may impact the result of candidate selection.
TypingMode::Analysis { defining_opaque_types } => defining_opaque_types.is_empty(),
// The global cache is only used if there are no opaque types in
// the defining scope or we're outside of analysis.
//
// FIXME(#132279): This is still incorrect as we treat opaque types
// and default associated items differently between these two modes.
TypingMode::PostAnalysis => true,
}
// Avoid using the global cache when we're defining opaque types
// as their hidden type may impact the result of candidate selection.
if !self.infcx.defining_opaque_types().is_empty() {
return false;
}
// Otherwise, we can use the global cache.
true
}
fn check_candidate_cache(
@ -1528,13 +1509,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
param_env: ty::ParamEnv<'tcx>,
cache_fresh_trait_pred: ty::PolyTraitPredicate<'tcx>,
) -> Option<SelectionResult<'tcx, SelectionCandidate<'tcx>>> {
// 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.is_intercrate() {
return None;
}
let tcx = self.tcx();
let pred = cache_fresh_trait_pred.skip_binder();
@ -1566,13 +1540,6 @@ 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.is_intercrate() {
return false;
}
match result {
Ok(Some(SelectionCandidate::ParamCandidate(trait_ref))) => !trait_ref.has_infer(),
_ => true,
@ -2541,7 +2508,9 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
})?;
nested_obligations.extend(obligations);
if !self.is_intercrate() && impl_trait_header.polarity == ty::ImplPolarity::Reservation {
if impl_trait_header.polarity == ty::ImplPolarity::Reservation
&& !matches!(self.infcx.typing_mode(obligation.param_env), TypingMode::Coherence)
{
debug!("reservation impls only apply in intercrate mode");
return Err(());
}