diff options
Diffstat (limited to 'compiler/rustc_trait_selection/src')
13 files changed, 101 insertions, 141 deletions
diff --git a/compiler/rustc_trait_selection/src/solve/delegate.rs b/compiler/rustc_trait_selection/src/solve/delegate.rs index 5793ac2fc31..c53689b211d 100644 --- a/compiler/rustc_trait_selection/src/solve/delegate.rs +++ b/compiler/rustc_trait_selection/src/solve/delegate.rs @@ -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() + } } }; diff --git a/compiler/rustc_trait_selection/src/traits/auto_trait.rs b/compiler/rustc_trait_selection/src/traits/auto_trait.rs index 934fe9ec47c..52ba5621d31 100644 --- a/compiler/rustc_trait_selection/src/traits/auto_trait.rs +++ b/compiler/rustc_trait_selection/src/traits/auto_trait.rs @@ -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 diff --git a/compiler/rustc_trait_selection/src/traits/coherence.rs b/compiler/rustc_trait_selection/src/traits/coherence.rs index f8fb297e36c..3cd11d7c8e8 100644 --- a/compiler/rustc_trait_selection/src/traits/coherence.rs +++ b/compiler/rustc_trait_selection/src/traits/coherence.rs @@ -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(), diff --git a/compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs b/compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs index a068f25fe35..bd4e3dd7d8d 100644 --- a/compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs +++ b/compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs @@ -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) } diff --git a/compiler/rustc_trait_selection/src/traits/fulfill.rs b/compiler/rustc_trait_selection/src/traits/fulfill.rs index e3ad21e352a..29e60e3c428 100644 --- a/compiler/rustc_trait_selection/src/traits/fulfill.rs +++ b/compiler/rustc_trait_selection/src/traits/fulfill.rs @@ -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() diff --git a/compiler/rustc_trait_selection/src/traits/misc.rs b/compiler/rustc_trait_selection/src/traits/misc.rs index 3e65194577e..3b17fa6b032 100644 --- a/compiler/rustc_trait_selection/src/traits/misc.rs +++ b/compiler/rustc_trait_selection/src/traits/misc.rs @@ -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); diff --git a/compiler/rustc_trait_selection/src/traits/mod.rs b/compiler/rustc_trait_selection/src/traits/mod.rs index f5d9b50359c..1c84f2171bc 100644 --- a/compiler/rustc_trait_selection/src/traits/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/mod.rs @@ -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); diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs index 0803dd74b89..a75c07c2e8c 100644 --- a/compiler/rustc_trait_selection/src/traits/project.rs +++ b/compiler/rustc_trait_selection/src/traits/project.rs @@ -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)) diff --git a/compiler/rustc_trait_selection/src/traits/query/evaluate_obligation.rs b/compiler/rustc_trait_selection/src/traits/query/evaluate_obligation.rs index bb44645a4ce..9e1a2a3e7d2 100644 --- a/compiler/rustc_trait_selection/src/traits/query/evaluate_obligation.rs +++ b/compiler/rustc_trait_selection/src/traits/query/evaluate_obligation.rs @@ -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) diff --git a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs index e027586563e..03fde1d1598 100644 --- a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs +++ b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs @@ -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; } diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index 635d3bc99b1..b1e5e526315 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -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; - } - - // 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; + 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, } - - // 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(()); } diff --git a/compiler/rustc_trait_selection/src/traits/specialize/mod.rs b/compiler/rustc_trait_selection/src/traits/specialize/mod.rs index 0e45f7a195f..5bf3dbcbc32 100644 --- a/compiler/rustc_trait_selection/src/traits/specialize/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/specialize/mod.rs @@ -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( diff --git a/compiler/rustc_trait_selection/src/traits/vtable.rs b/compiler/rustc_trait_selection/src/traits/vtable.rs index ed221e2a183..bb56d6eaf54 100644 --- a/compiler/rustc_trait_selection/src/traits/vtable.rs +++ b/compiler/rustc_trait_selection/src/traits/vtable.rs @@ -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 = |
