1
Fork 0

Rollup merge of #131856 - lcnr:typing-mode, r=compiler-errors

TypingMode: merge intercrate, reveal, and defining_opaque_types

This adds `TypingMode` and uses it in most places. We do not yet remove `Reveal` from `param_env`s. This and other future work as tracked in #132279 and via `FIXME`s.

Fetching the `TypingMode` of the `InferCtxt` asserts that the `TypingMode` agrees with `ParamEnv::reveal` to make sure we don't introduce any subtle bugs here. This will be unnecessary once `ParamEnv::reveal` no longer exists.

As the `TypingMode` is now a part of the query input, I've merged the coherence and non-coherence caches for the new solver. I've also enabled the local `infcx` cache during coherence by clearing the cache when forking it with a different `TypingMode`.

#### `TypingMode::from_param_env`

I am using this even in cases where I know that the `param_env` will always be `Reveal::UserFacing`. This is to make it easier to correctly refactor this code in the future, any time we use `Reveal::UserFacing` in a body while not defining its opaque types is incorrect and should use a `TypingMode` which only reveals opaques defined by that body instead, cc #124598

r? ``@compiler-errors``
This commit is contained in:
Matthias Krüger 2024-10-30 06:40:34 +01:00 committed by GitHub
commit 305508f969
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
89 changed files with 537 additions and 532 deletions

View file

@ -7,13 +7,13 @@ use rustc_infer::infer::canonical::{
Canonical, CanonicalExt as _, CanonicalQueryInput, CanonicalVarInfo, CanonicalVarValues,
};
use rustc_infer::infer::{InferCtxt, RegionVariableOrigin, TyCtxtInferExt};
use rustc_infer::traits::ObligationCause;
use rustc_infer::traits::solve::Goal;
use rustc_infer::traits::{ObligationCause, Reveal};
use rustc_middle::ty::fold::TypeFoldable;
use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitableExt as _};
use rustc_span::{DUMMY_SP, ErrorGuaranteed, Span};
use rustc_type_ir::solve::{Certainty, NoSolution, SolverMode};
use tracing::trace;
use rustc_type_ir::TypingMode;
use rustc_type_ir::solve::{Certainty, NoSolution};
use crate::traits::specialization_graph;
@ -47,7 +47,6 @@ impl<'tcx> rustc_next_trait_solver::delegate::SolverDelegate for SolverDelegate<
fn build_with_canonical<V>(
interner: TyCtxt<'tcx>,
solver_mode: SolverMode,
canonical: &CanonicalQueryInput<'tcx, V>,
) -> (Self, V, CanonicalVarValues<'tcx>)
where
@ -56,10 +55,6 @@ impl<'tcx> rustc_next_trait_solver::delegate::SolverDelegate for SolverDelegate<
let (infcx, value, vars) = interner
.infer_ctxt()
.with_next_trait_solver(true)
.intercrate(match solver_mode {
SolverMode::Normal => false,
SolverMode::Coherence => true,
})
.build_with_canonical(DUMMY_SP, canonical);
(SolverDelegate(infcx), value, vars)
}
@ -195,7 +190,6 @@ impl<'tcx> rustc_next_trait_solver::delegate::SolverDelegate for SolverDelegate<
fn fetch_eligible_assoc_item(
&self,
param_env: ty::ParamEnv<'tcx>,
goal_trait_ref: ty::TraitRef<'tcx>,
trait_assoc_def_id: DefId,
impl_def_id: DefId,
@ -211,12 +205,12 @@ impl<'tcx> rustc_next_trait_solver::delegate::SolverDelegate for SolverDelegate<
// and the obligation is monomorphic, otherwise passes such as
// transmute checking and polymorphic MIR optimizations could
// get a result which isn't correct for all monomorphizations.
if param_env.reveal() == Reveal::All {
let poly_trait_ref = self.resolve_vars_if_possible(goal_trait_ref);
!poly_trait_ref.still_further_specializable()
} else {
trace!(?node_item.item.def_id, "not eligible due to default");
false
match self.typing_mode_unchecked() {
TypingMode::Coherence | TypingMode::Analysis { .. } => false,
TypingMode::PostAnalysis => {
let poly_trait_ref = self.resolve_vars_if_possible(goal_trait_ref);
!poly_trait_ref.still_further_specializable()
}
}
};

View file

@ -10,6 +10,7 @@ use rustc_infer::infer::DefineOpaqueTypes;
use rustc_middle::mir::interpret::ErrorHandled;
use rustc_middle::ty::{Region, RegionVid};
use tracing::debug;
use ty::TypingMode;
use super::*;
use crate::errors::UnableToConstructConstantValue;
@ -79,7 +80,7 @@ impl<'tcx> AutoTraitFinder<'tcx> {
let trait_ref = ty::TraitRef::new(tcx, trait_did, [ty]);
let infcx = tcx.infer_ctxt().build();
let infcx = tcx.infer_ctxt().build(TypingMode::non_body_analysis());
let mut selcx = SelectionContext::new(&infcx);
for polarity in [ty::PredicatePolarity::Positive, ty::PredicatePolarity::Negative] {
let result = selcx.select(&Obligation::new(
@ -99,7 +100,7 @@ impl<'tcx> AutoTraitFinder<'tcx> {
}
}
let infcx = tcx.infer_ctxt().build();
let infcx = tcx.infer_ctxt().build(TypingMode::non_body_analysis());
let mut fresh_preds = FxIndexSet::default();
// Due to the way projections are handled by SelectionContext, we need to run

View file

@ -18,7 +18,7 @@ use rustc_middle::traits::solve::{CandidateSource, Certainty, Goal};
use rustc_middle::traits::specialization_graph::OverlapMode;
use rustc_middle::ty::fast_reject::DeepRejectCtxt;
use rustc_middle::ty::visit::{TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor};
use rustc_middle::ty::{self, Ty, TyCtxt};
use rustc_middle::ty::{self, Ty, TyCtxt, TypingMode};
pub use rustc_next_trait_solver::coherence::*;
use rustc_next_trait_solver::solve::SolverDelegateEvalExt;
use rustc_span::symbol::sym;
@ -195,9 +195,8 @@ fn overlap<'tcx>(
let infcx = tcx
.infer_ctxt()
.skip_leak_check(skip_leak_check.is_yes())
.intercrate(true)
.with_next_trait_solver(tcx.next_trait_solver_in_coherence())
.build();
.build(TypingMode::Coherence);
let selcx = &mut SelectionContext::new(&infcx);
if track_ambiguity_causes.is_yes() {
selcx.enable_tracking_intercrate_ambiguity_causes();
@ -419,7 +418,7 @@ fn impl_intersection_has_negative_obligation(
// N.B. We need to unify impl headers *with* intercrate mode, even if proving negative predicates
// do not need intercrate mode enabled.
let ref infcx = tcx.infer_ctxt().intercrate(true).with_next_trait_solver(true).build();
let ref infcx = tcx.infer_ctxt().with_next_trait_solver(true).build(TypingMode::Coherence);
let root_universe = infcx.universe();
assert_eq!(root_universe, ty::UniverseIndex::ROOT);
@ -570,7 +569,9 @@ fn try_prove_negated_where_clause<'tcx>(
// the *existence* of a negative goal, not the non-existence of a positive goal.
// Without this, we over-eagerly register coherence ambiguity candidates when
// impl candidates do exist.
let ref infcx = root_infcx.fork_with_intercrate(false);
// FIXME(#132279): `TypingMode::non_body_analysis` is a bit questionable here as it
// would cause us to reveal opaque types to leak their auto traits.
let ref infcx = root_infcx.fork_with_typing_mode(TypingMode::non_body_analysis());
let ocx = ObligationCtxt::new(infcx);
ocx.register_obligation(Obligation::new(
infcx.tcx,
@ -714,7 +715,10 @@ impl<'a, 'tcx> ProofTreeVisitor<'tcx> for AmbiguityCausesVisitor<'a, 'tcx> {
// It is only relevant that a goal is unknowable if it would have otherwise
// failed.
let non_intercrate_infcx = infcx.fork_with_intercrate(false);
// FIXME(#132279): Forking with `TypingMode::non_body_analysis` is a bit questionable
// as it would allow us to reveal opaque types, potentially causing unexpected
// cycles.
let non_intercrate_infcx = infcx.fork_with_typing_mode(TypingMode::non_body_analysis());
if non_intercrate_infcx.predicate_may_hold(&Obligation::new(
infcx.tcx,
ObligationCause::dummy(),

View file

@ -14,7 +14,7 @@ use rustc_middle::query::Providers;
use rustc_middle::ty::{
self, EarlyBinder, ExistentialPredicateStableCmpExt as _, GenericArgs, Ty, TyCtxt,
TypeFoldable, TypeFolder, TypeSuperFoldable, TypeSuperVisitable, TypeVisitable,
TypeVisitableExt, TypeVisitor, Upcast,
TypeVisitableExt, TypeVisitor, TypingMode, Upcast,
};
use rustc_span::Span;
use rustc_span::symbol::Symbol;
@ -718,7 +718,7 @@ fn receiver_is_dispatchable<'tcx>(
Obligation::new(tcx, ObligationCause::dummy(), param_env, predicate)
};
let infcx = tcx.infer_ctxt().build();
let infcx = tcx.infer_ctxt().build(TypingMode::non_body_analysis());
// the receiver is dispatchable iff the obligation holds
infcx.predicate_must_hold_modulo_regions(&obligation)
}

View file

@ -1,8 +1,9 @@
use rustc_hir as hir;
use rustc_infer::infer::{BoundRegionConversionTime, DefineOpaqueTypes, InferCtxt};
use rustc_infer::traits::{ImplSource, Obligation, PredicateObligation};
use rustc_middle::span_bug;
use rustc_middle::ty::fast_reject::DeepRejectCtxt;
use rustc_middle::{span_bug, ty};
use rustc_middle::ty::{self, TypingMode};
use rustc_type_ir::solve::NoSolution;
use thin_vec::ThinVec;
@ -19,7 +20,7 @@ pub fn evaluate_host_effect_obligation<'tcx>(
selcx: &mut SelectionContext<'_, 'tcx>,
obligation: &HostEffectObligation<'tcx>,
) -> Result<ThinVec<PredicateObligation<'tcx>>, EvaluationFailure> {
if selcx.infcx.intercrate {
if matches!(selcx.infcx.typing_mode(obligation.param_env), TypingMode::Coherence) {
span_bug!(
obligation.cause.span,
"should not select host obligation in old solver in intercrate mode"

View file

@ -13,7 +13,7 @@ use rustc_middle::bug;
use rustc_middle::mir::interpret::ErrorHandled;
use rustc_middle::ty::abstract_const::NotConstEvaluatable;
use rustc_middle::ty::error::{ExpectedFound, TypeError};
use rustc_middle::ty::{self, Binder, Const, GenericArgsRef, TypeVisitableExt};
use rustc_middle::ty::{self, Binder, Const, GenericArgsRef, TypeVisitableExt, TypingMode};
use thin_vec::ThinVec;
use tracing::{debug, debug_span, instrument};
@ -760,7 +760,9 @@ impl<'a, 'tcx> FulfillProcessor<'a, 'tcx> {
stalled_on: &mut Vec<TyOrConstInferVar>,
) -> ProcessResult<PendingPredicateObligation<'tcx>, FulfillmentErrorCode<'tcx>> {
let infcx = self.selcx.infcx;
if obligation.predicate.is_global() && !self.selcx.is_intercrate() {
if obligation.predicate.is_global()
&& !matches!(infcx.typing_mode(obligation.param_env), TypingMode::Coherence)
{
// no type variables present, can use evaluation for better caching.
// FIXME: consider caching errors too.
if infcx.predicate_must_hold_considering_regions(obligation) {
@ -813,11 +815,13 @@ impl<'a, 'tcx> FulfillProcessor<'a, 'tcx> {
stalled_on: &mut Vec<TyOrConstInferVar>,
) -> ProcessResult<PendingPredicateObligation<'tcx>, FulfillmentErrorCode<'tcx>> {
let tcx = self.selcx.tcx();
if obligation.predicate.is_global() && !self.selcx.is_intercrate() {
let infcx = self.selcx.infcx;
if obligation.predicate.is_global()
&& !matches!(infcx.typing_mode(obligation.param_env), TypingMode::Coherence)
{
// no type variables present, can use evaluation for better caching.
// FIXME: consider caching errors too.
if self.selcx.infcx.predicate_must_hold_considering_regions(obligation) {
if infcx.predicate_must_hold_considering_regions(obligation) {
if let Some(key) = ProjectionCacheKey::from_poly_projection_obligation(
&mut self.selcx,
&project_obligation,
@ -825,8 +829,7 @@ impl<'a, 'tcx> FulfillProcessor<'a, 'tcx> {
// If `predicate_must_hold_considering_regions` succeeds, then we've
// evaluated all sub-obligations. We can therefore mark the 'root'
// obligation as complete, and skip evaluating sub-obligations.
self.selcx
.infcx
infcx
.inner
.borrow_mut()
.projection_cache()

View file

@ -8,7 +8,7 @@ use rustc_data_structures::fx::FxIndexSet;
use rustc_hir as hir;
use rustc_infer::infer::outlives::env::OutlivesEnvironment;
use rustc_infer::infer::{RegionResolutionError, TyCtxtInferExt};
use rustc_middle::ty::{self, AdtDef, Ty, TyCtxt, TypeVisitableExt};
use rustc_middle::ty::{self, AdtDef, Ty, TyCtxt, TypeVisitableExt, TypingMode};
use super::outlives_bounds::InferCtxtExt;
use crate::regions::InferCtxtRegionExt;
@ -143,7 +143,7 @@ pub fn type_allowed_to_implement_const_param_ty<'tcx>(
let mut infringing_inner_tys = vec![];
for inner_ty in inner_tys {
// We use an ocx per inner ty for better diagnostics
let infcx = tcx.infer_ctxt().build();
let infcx = tcx.infer_ctxt().build(TypingMode::non_body_analysis());
let ocx = traits::ObligationCtxt::new_with_diagnostics(&infcx);
ocx.register_bound(
@ -200,7 +200,7 @@ pub fn all_fields_implement_trait<'tcx>(
for variant in adt.variants() {
for field in &variant.fields {
// Do this per-field to get better error messages.
let infcx = tcx.infer_ctxt().build();
let infcx = tcx.infer_ctxt().build(TypingMode::non_body_analysis());
let ocx = traits::ObligationCtxt::new_with_diagnostics(&infcx);
let unnormalized_ty = field.ty(tcx, args);

View file

@ -34,7 +34,8 @@ use rustc_middle::ty::error::{ExpectedFound, TypeError};
use rustc_middle::ty::fold::TypeFoldable;
use rustc_middle::ty::visit::{TypeVisitable, TypeVisitableExt};
use rustc_middle::ty::{
self, GenericArgs, GenericArgsRef, Ty, TyCtxt, TypeFolder, TypeSuperVisitable, Upcast,
self, GenericArgs, GenericArgsRef, Ty, TyCtxt, TypeFolder, TypeSuperVisitable, TypingMode,
Upcast,
};
use rustc_span::Span;
use rustc_span::def_id::DefId;
@ -274,7 +275,7 @@ fn do_normalize_predicates<'tcx>(
// by wfcheck anyway, so I'm not sure we have to check
// them here too, and we will remove this function when
// we move over to lazy normalization *anyway*.
let infcx = tcx.infer_ctxt().ignoring_regions().build();
let infcx = tcx.infer_ctxt().ignoring_regions().build(TypingMode::non_body_analysis());
let ocx = ObligationCtxt::new_with_diagnostics(&infcx);
let predicates = ocx.normalize(&cause, elaborated_env, predicates);
@ -475,11 +476,11 @@ pub fn normalize_param_env_or_error<'tcx>(
/// Normalizes the predicates and checks whether they hold in an empty environment. If this
/// returns true, then either normalize encountered an error or one of the predicates did not
/// hold. Used when creating vtables to check for unsatisfiable methods.
/// hold. Used when creating vtables to check for unsatisfiable methods. This should not be
/// used during analysis.
pub fn impossible_predicates<'tcx>(tcx: TyCtxt<'tcx>, predicates: Vec<ty::Clause<'tcx>>) -> bool {
debug!("impossible_predicates(predicates={:?})", predicates);
let infcx = tcx.infer_ctxt().build();
let infcx = tcx.infer_ctxt().build(TypingMode::PostAnalysis);
let param_env = ty::ParamEnv::reveal_all();
let ocx = ObligationCtxt::new(&infcx);
let predicates = ocx.normalize(&ObligationCause::dummy(), param_env, predicates);
@ -568,8 +569,11 @@ fn is_impossible_associated_item(
// since that method *may* have some substitutions where the predicates hold.
//
// This replicates the logic we use in coherence.
let infcx =
tcx.infer_ctxt().ignoring_regions().with_next_trait_solver(true).intercrate(true).build();
let infcx = tcx
.infer_ctxt()
.ignoring_regions()
.with_next_trait_solver(true)
.build(TypingMode::Coherence);
let param_env = ty::ParamEnv::empty();
let fresh_args = infcx.fresh_args_for_item(tcx.def_span(impl_def_id), impl_def_id);

View file

@ -334,11 +334,6 @@ pub(super) fn opt_normalize_projection_term<'a, 'b, 'tcx>(
) -> Result<Option<Term<'tcx>>, InProgress> {
let infcx = selcx.infcx;
debug_assert!(!selcx.infcx.next_trait_solver());
// 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_term = infcx.resolve_vars_if_possible(projection_term);
let cache_key = ProjectionCacheKey::new(projection_term, param_env);
@ -349,13 +344,8 @@ pub(super) fn opt_normalize_projection_term<'a, 'b, 'tcx>(
// would not benefit from caching when proving `T: Trait<U=Foo>`
// bounds. It might be the case that we want two distinct caches,
// or else another kind of cache entry.
let cache_result = if use_cache {
infcx.inner.borrow_mut().projection_cache().try_start(cache_key)
} else {
Ok(())
};
match cache_result {
let cache_entry = infcx.inner.borrow_mut().projection_cache().try_start(cache_key);
match cache_entry {
Ok(()) => debug!("no cache"),
Err(ProjectionCacheEntry::Ambiguous) => {
// If we found ambiguity the last time, that means we will continue
@ -378,10 +368,7 @@ pub(super) fn opt_normalize_projection_term<'a, 'b, 'tcx>(
// Cache that normalizing this projection resulted in a cycle. This
// should ensure that, unless this happens within a snapshot that's
// rolled back, fulfillment or evaluation will notice the cycle.
if use_cache {
infcx.inner.borrow_mut().projection_cache().recur(cache_key);
}
infcx.inner.borrow_mut().projection_cache().recur(cache_key);
return Err(InProgress);
}
Err(ProjectionCacheEntry::Recur) => {
@ -445,26 +432,20 @@ pub(super) fn opt_normalize_projection_term<'a, 'b, 'tcx>(
let mut deduped = SsoHashSet::with_capacity(result.obligations.len());
result.obligations.retain(|obligation| deduped.insert(obligation.clone()));
if use_cache {
infcx.inner.borrow_mut().projection_cache().insert_term(cache_key, result.clone());
}
infcx.inner.borrow_mut().projection_cache().insert_term(cache_key, result.clone());
obligations.extend(result.obligations);
Ok(Some(result.value))
}
Ok(Projected::NoProgress(projected_ty)) => {
let result =
Normalized { value: projected_ty, obligations: PredicateObligations::new() };
if use_cache {
infcx.inner.borrow_mut().projection_cache().insert_term(cache_key, result.clone());
}
infcx.inner.borrow_mut().projection_cache().insert_term(cache_key, result.clone());
// No need to extend `obligations`.
Ok(Some(result.value))
}
Err(ProjectionError::TooManyCandidates) => {
debug!("opt_normalize_projection_type: too many candidates");
if use_cache {
infcx.inner.borrow_mut().projection_cache().ambiguous(cache_key);
}
infcx.inner.borrow_mut().projection_cache().ambiguous(cache_key);
Ok(None)
}
Err(ProjectionError::TraitSelectionError(_)) => {
@ -473,10 +454,7 @@ pub(super) fn opt_normalize_projection_term<'a, 'b, 'tcx>(
// just return `ty::err` but add the obligation `T :
// Trait`, which when processed will cause the error to be
// reported later
if use_cache {
infcx.inner.borrow_mut().projection_cache().error(cache_key);
}
infcx.inner.borrow_mut().projection_cache().error(cache_key);
let result = normalize_to_error(selcx, param_env, projection_term, cause, depth);
obligations.extend(result.obligations);
Ok(Some(result.value))

View file

@ -87,7 +87,6 @@ impl<'tcx> InferCtxt<'tcx> {
Ok(result)
})
} else {
assert!(!self.intercrate);
let c_pred =
self.canonicalize_query(param_env.and(obligation.predicate), &mut _orig_values);
self.tcx.at(obligation.cause.span).evaluate_obligation(c_pred)

View file

@ -16,7 +16,7 @@ use rustc_infer::traits::{
Obligation, ObligationCause, PolyTraitObligation, PredicateObligations, SelectionError,
};
use rustc_middle::ty::fast_reject::DeepRejectCtxt;
use rustc_middle::ty::{self, ToPolyTraitRef, Ty, TypeVisitableExt};
use rustc_middle::ty::{self, ToPolyTraitRef, Ty, TypeVisitableExt, TypingMode};
use rustc_middle::{bug, span_bug};
use tracing::{debug, instrument, trace};
@ -790,7 +790,9 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
//
// Note that this is only sound as projection candidates of opaque types
// are always applicable for auto traits.
} else if self.infcx.intercrate {
} else if let TypingMode::Coherence =
self.infcx.typing_mode(obligation.param_env)
{
// We do not emit auto trait candidates for opaque types in coherence.
// Doing so can result in weird dependency cycles.
candidates.ambiguous = true;
@ -930,7 +932,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
) -> Option<ty::PolyExistentialTraitRef<'tcx>> {
// Don't drop any candidates in intercrate mode, as it's incomplete.
// (Not that it matters, since `Unsize` is not a stable trait.)
if self.infcx.intercrate {
//
// FIXME(@lcnr): This should probably only trigger during analysis,
// disabling candidates during codegen is also questionable.
if let TypingMode::Coherence = self.infcx.typing_mode(param_env) {
return None;
}

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(());
}

View file

@ -19,7 +19,9 @@ use rustc_infer::infer::DefineOpaqueTypes;
use rustc_middle::bug;
use rustc_middle::query::LocalCrate;
use rustc_middle::ty::print::PrintTraitRefExt as _;
use rustc_middle::ty::{self, GenericArgsRef, ImplSubject, Ty, TyCtxt, TypeVisitableExt};
use rustc_middle::ty::{
self, GenericArgsRef, ImplSubject, Ty, TyCtxt, TypeVisitableExt, TypingMode,
};
use rustc_session::lint::builtin::{COHERENCE_LEAK_CHECK, ORDER_DEPENDENT_TRAIT_OBJECTS};
use rustc_span::{DUMMY_SP, ErrorGuaranteed, Span, sym};
use specialization_graph::GraphExt;
@ -184,7 +186,7 @@ pub(super) fn specializes(tcx: TyCtxt<'_>, (impl1_def_id, impl2_def_id): (DefId,
let penv = tcx.param_env(impl1_def_id);
// Create an infcx, taking the predicates of impl1 as assumptions:
let infcx = tcx.infer_ctxt().build();
let infcx = tcx.infer_ctxt().build(TypingMode::non_body_analysis());
// Attempt to prove that impl2 applies, given all of the above.
fulfill_implication(

View file

@ -9,7 +9,8 @@ use rustc_infer::traits::util::PredicateSet;
use rustc_middle::bug;
use rustc_middle::query::Providers;
use rustc_middle::ty::{
self, GenericArgs, GenericParamDefKind, Ty, TyCtxt, TypeVisitableExt, Upcast, VtblEntry,
self, GenericArgs, GenericParamDefKind, Ty, TyCtxt, TypeVisitableExt, TypingMode, Upcast,
VtblEntry,
};
use rustc_span::{DUMMY_SP, Span, sym};
use smallvec::{SmallVec, smallvec};
@ -439,7 +440,7 @@ fn trait_refs_are_compatible<'tcx>(
return false;
}
let infcx = tcx.infer_ctxt().build();
let infcx = tcx.infer_ctxt().build(TypingMode::PostAnalysis);
let param_env = ty::ParamEnv::reveal_all();
let ocx = ObligationCtxt::new(&infcx);
let hr_source_principal =