TypingMode 🤔
This commit is contained in:
parent
2dece5bb62
commit
f51ec110a7
75 changed files with 513 additions and 506 deletions
|
@ -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()
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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(),
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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))
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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(());
|
||||
}
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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 =
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue