diff --git a/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs b/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs index 266a80187c5..0cb4b15b127 100644 --- a/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs +++ b/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs @@ -10,7 +10,6 @@ use rustc_middle::traits::ObligationCause; use rustc_middle::ty::{self, GenericArgKind, Ty, TyCtxt, TypeFoldable, TypeVisitableExt}; use rustc_span::Span; -use rustc_trait_selection::solve::deeply_normalize; use rustc_trait_selection::traits::query::type_op::custom::CustomTypeOp; use rustc_trait_selection::traits::query::type_op::{TypeOp, TypeOpOutput}; use rustc_trait_selection::traits::ScrubbedTraitError; @@ -283,8 +282,9 @@ fn normalize_and_add_type_outlives_constraints( ) -> Ty<'tcx> { let result = CustomTypeOp::new( |ocx| { - deeply_normalize( - ocx.infcx.at(&ObligationCause::dummy_with_span(self.span), self.param_env), + ocx.deeply_normalize( + &ObligationCause::dummy_with_span(self.span), + self.param_env, ty, ) .map_err(|_: Vec>| NoSolution) diff --git a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs index 594d28eda7a..f7bebc2697d 100644 --- a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs +++ b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs @@ -10,7 +10,7 @@ use rustc_hir::{GenericParamKind, ImplItemKind}; use rustc_infer::infer::outlives::env::OutlivesEnvironment; use rustc_infer::infer::{self, InferCtxt, TyCtxtInferExt}; -use rustc_infer::traits::{util, FulfillmentErrorLike}; +use rustc_infer::traits::util; use rustc_middle::ty::error::{ExpectedFound, TypeError}; use rustc_middle::ty::fold::BottomUpFolder; use rustc_middle::ty::util::ExplicitSelf; @@ -764,10 +764,7 @@ pub(super) fn collect_return_position_impl_trait_in_trait_tys<'tcx>( Ok(&*tcx.arena.alloc(remapped_types)) } -struct ImplTraitInTraitCollector<'a, 'tcx, E> -where - E: FulfillmentErrorLike<'tcx>, -{ +struct ImplTraitInTraitCollector<'a, 'tcx, E> { ocx: &'a ObligationCtxt<'a, 'tcx, E>, types: FxIndexMap, ty::GenericArgsRef<'tcx>)>, span: Span, @@ -777,7 +774,7 @@ struct ImplTraitInTraitCollector<'a, 'tcx, E> impl<'a, 'tcx, E> ImplTraitInTraitCollector<'a, 'tcx, E> where - E: FulfillmentErrorLike<'tcx>, + E: 'tcx, { fn new( ocx: &'a ObligationCtxt<'a, 'tcx, E>, @@ -791,7 +788,7 @@ fn new( impl<'tcx, E> TypeFolder> for ImplTraitInTraitCollector<'_, 'tcx, E> where - E: FulfillmentErrorLike<'tcx>, + E: 'tcx, { fn interner(&self) -> TyCtxt<'tcx> { self.ocx.infcx.tcx diff --git a/compiler/rustc_hir_analysis/src/coherence/orphan.rs b/compiler/rustc_hir_analysis/src/coherence/orphan.rs index 1e7bb63e6ea..61ac4af0151 100644 --- a/compiler/rustc_hir_analysis/src/coherence/orphan.rs +++ b/compiler/rustc_hir_analysis/src/coherence/orphan.rs @@ -12,11 +12,8 @@ use rustc_middle::ty::{TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor}; use rustc_middle::{bug, span_bug}; use rustc_span::def_id::{DefId, LocalDefId}; -use rustc_trait_selection::traits::{ - self, IsFirstInputType, ScrubbedTraitError, UncoveredTyParams, -}; +use rustc_trait_selection::traits::{self, IsFirstInputType, UncoveredTyParams}; use rustc_trait_selection::traits::{OrphanCheckErr, OrphanCheckMode}; -use rustc_trait_selection::traits::{StructurallyNormalizeExt, TraitEngineExt}; #[instrument(level = "debug", skip(tcx))] pub(crate) fn orphan_check_impl( @@ -319,13 +316,12 @@ fn orphan_check<'tcx>( } let ty = if infcx.next_trait_solver() { - let mut fulfill_cx = - >>::new(&infcx); - infcx - .at(&cause, ty::ParamEnv::empty()) - .structurally_normalize(ty, &mut *fulfill_cx) - .map(|ty| infcx.resolve_vars_if_possible(ty)) - .unwrap_or(ty) + ocx.structurally_normalize( + &cause, + ty::ParamEnv::empty(), + infcx.resolve_vars_if_possible(ty), + ) + .unwrap_or(ty) } else { ty }; diff --git a/compiler/rustc_infer/src/infer/canonical/query_response.rs b/compiler/rustc_infer/src/infer/canonical/query_response.rs index 4917f936f4e..d7dd6a1e7cf 100644 --- a/compiler/rustc_infer/src/infer/canonical/query_response.rs +++ b/compiler/rustc_infer/src/infer/canonical/query_response.rs @@ -15,8 +15,8 @@ use crate::infer::region_constraints::{Constraint, RegionConstraintData}; use crate::infer::{DefineOpaqueTypes, InferCtxt, InferOk, InferResult}; use crate::traits::query::NoSolution; -use crate::traits::{FulfillmentErrorLike, TraitEngine}; use crate::traits::{Obligation, ObligationCause, PredicateObligation}; +use crate::traits::{ScrubbedTraitError, TraitEngine}; use rustc_data_structures::captures::Captures; use rustc_index::Idx; use rustc_index::IndexVec; @@ -50,11 +50,11 @@ impl<'tcx> InferCtxt<'tcx> { /// - Finally, if any of the obligations result in a hard error, /// then `Err(NoSolution)` is returned. #[instrument(skip(self, inference_vars, answer, fulfill_cx), level = "trace")] - pub fn make_canonicalized_query_response>( + pub fn make_canonicalized_query_response( &self, inference_vars: CanonicalVarValues<'tcx>, answer: T, - fulfill_cx: &mut dyn TraitEngine<'tcx, E>, + fulfill_cx: &mut dyn TraitEngine<'tcx, ScrubbedTraitError<'tcx>>, ) -> Result, NoSolution> where T: Debug + TypeFoldable>, @@ -97,11 +97,11 @@ pub fn make_query_response_ignoring_pending_obligations( /// Helper for `make_canonicalized_query_response` that does /// everything up until the final canonicalization. #[instrument(skip(self, fulfill_cx), level = "debug")] - fn make_query_response>( + fn make_query_response( &self, inference_vars: CanonicalVarValues<'tcx>, answer: T, - fulfill_cx: &mut dyn TraitEngine<'tcx, E>, + fulfill_cx: &mut dyn TraitEngine<'tcx, ScrubbedTraitError<'tcx>>, ) -> Result, NoSolution> where T: Debug + TypeFoldable>, diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs index 5183d9e2d6e..72c4e1b511e 100644 --- a/compiler/rustc_infer/src/infer/mod.rs +++ b/compiler/rustc_infer/src/infer/mod.rs @@ -12,8 +12,7 @@ pub use ValuePairs::*; use crate::traits::{ - self, FulfillmentErrorLike, ObligationCause, ObligationInspector, PredicateObligations, - TraitEngine, + self, ObligationCause, ObligationInspector, PredicateObligations, TraitEngine, }; use error_reporting::TypeErrCtxt; use free_regions::RegionRelations; @@ -738,7 +737,7 @@ pub fn build(&mut self) -> InferCtxt<'tcx> { impl<'tcx, T> InferOk<'tcx, T> { /// Extracts `value`, registering any obligations into `fulfill_cx`. - pub fn into_value_registering_obligations>( + pub fn into_value_registering_obligations( self, infcx: &InferCtxt<'tcx>, fulfill_cx: &mut dyn TraitEngine<'tcx, E>, diff --git a/compiler/rustc_infer/src/traits/engine.rs b/compiler/rustc_infer/src/traits/engine.rs index 1d6875d0f8e..026b2c1b905 100644 --- a/compiler/rustc_infer/src/traits/engine.rs +++ b/compiler/rustc_infer/src/traits/engine.rs @@ -7,7 +7,32 @@ use super::{ObligationCause, PredicateObligation}; -pub trait TraitEngine<'tcx, E: FulfillmentErrorLike<'tcx>>: 'tcx { +/// A trait error with most of its information removed. This is the error +/// returned by an `ObligationCtxt` by default, and suitable if you just +/// want to see if a predicate holds, and don't particularly care about the +/// error itself (except for if it's an ambiguity or true error). +/// +/// use `ObligationCtxt::new_with_diagnostics` to get a `FulfillmentError`. +#[derive(Clone, Debug)] +pub enum ScrubbedTraitError<'tcx> { + /// A real error. This goal definitely does not hold. + TrueError, + /// An ambiguity. This goal may hold if further inference is done. + Ambiguity, + /// An old-solver-style cycle error, which will fatal. + Cycle(Vec>), +} + +impl<'tcx> ScrubbedTraitError<'tcx> { + pub fn is_true_error(&self) -> bool { + match self { + ScrubbedTraitError::TrueError => true, + ScrubbedTraitError::Ambiguity | ScrubbedTraitError::Cycle(_) => false, + } + } +} + +pub trait TraitEngine<'tcx, E: 'tcx>: 'tcx { /// Requires that `ty` must implement the trait with `def_id` in /// the given environment. This trait must not have any type /// parameters (except for `Self`). @@ -73,10 +98,6 @@ fn drain_unstalled_obligations( ) -> Vec>; } -pub trait FulfillmentErrorLike<'tcx>: Debug + 'tcx { - fn is_true_error(&self) -> bool; -} - -pub trait FromSolverError<'tcx, E>: FulfillmentErrorLike<'tcx> { +pub trait FromSolverError<'tcx, E>: Debug + 'tcx { fn from_solver_error(infcx: &InferCtxt<'tcx>, error: E) -> Self; } diff --git a/compiler/rustc_infer/src/traits/mod.rs b/compiler/rustc_infer/src/traits/mod.rs index e9c2d81aa0a..ca6c6570e07 100644 --- a/compiler/rustc_infer/src/traits/mod.rs +++ b/compiler/rustc_infer/src/traits/mod.rs @@ -22,7 +22,7 @@ pub use self::SelectionError::*; use crate::infer::InferCtxt; -pub use self::engine::{FromSolverError, FulfillmentErrorLike, TraitEngine}; +pub use self::engine::{FromSolverError, ScrubbedTraitError, TraitEngine}; pub use self::project::MismatchedProjectionTypes; pub(crate) use self::project::UndoLog; pub use self::project::{ diff --git a/compiler/rustc_macros/src/extension.rs b/compiler/rustc_macros/src/extension.rs index 5377bbdfeab..bbaa477237b 100644 --- a/compiler/rustc_macros/src/extension.rs +++ b/compiler/rustc_macros/src/extension.rs @@ -6,6 +6,7 @@ use syn::{ braced, parse_macro_input, Attribute, Generics, ImplItem, Pat, PatIdent, Path, Signature, Token, TraitItem, TraitItemConst, TraitItemFn, TraitItemMacro, TraitItemType, Type, Visibility, + WhereClause, }; pub(crate) fn extension( @@ -13,7 +14,7 @@ pub(crate) fn extension( input: proc_macro::TokenStream, ) -> proc_macro::TokenStream { let ExtensionAttr { vis, trait_ } = parse_macro_input!(attr as ExtensionAttr); - let Impl { attrs, generics, self_ty, items } = parse_macro_input!(input as Impl); + let Impl { attrs, generics, self_ty, items, wc } = parse_macro_input!(input as Impl); let headers: Vec<_> = items .iter() .map(|item| match item { @@ -59,7 +60,7 @@ pub(crate) fn extension( #(#headers)* } - impl #generics #trait_ for #self_ty { + impl #generics #trait_ for #self_ty #wc { #(#items)* } } @@ -133,6 +134,7 @@ struct Impl { generics: Generics, self_ty: Type, items: Vec, + wc: Option, } impl Parse for Impl { @@ -141,6 +143,7 @@ fn parse(input: ParseStream<'_>) -> syn::Result { let _: Token![impl] = input.parse()?; let generics = input.parse()?; let self_ty = input.parse()?; + let wc = input.parse()?; let content; let _brace_token = braced!(content in input); @@ -149,6 +152,6 @@ fn parse(input: ParseStream<'_>) -> syn::Result { items.push(content.parse()?); } - Ok(Impl { attrs, generics, self_ty, items }) + Ok(Impl { attrs, generics, self_ty, items, wc }) } } diff --git a/compiler/rustc_trait_selection/src/solve/fulfill.rs b/compiler/rustc_trait_selection/src/solve/fulfill.rs index 3de4aee0927..dc13941e5d7 100644 --- a/compiler/rustc_trait_selection/src/solve/fulfill.rs +++ b/compiler/rustc_trait_selection/src/solve/fulfill.rs @@ -6,8 +6,8 @@ use rustc_infer::traits::query::NoSolution; use rustc_infer::traits::solve::{CandidateSource, GoalSource, MaybeCause}; use rustc_infer::traits::{ - self, FromSolverError, FulfillmentErrorLike, MismatchedProjectionTypes, Obligation, - ObligationCause, ObligationCauseCode, PredicateObligation, SelectionError, TraitEngine, + self, FromSolverError, MismatchedProjectionTypes, Obligation, ObligationCause, + ObligationCauseCode, PredicateObligation, SelectionError, TraitEngine, }; use rustc_middle::bug; use rustc_middle::ty::error::{ExpectedFound, TypeError}; @@ -31,7 +31,7 @@ /// /// It is also likely that we want to use slightly different datastructures /// here as this will have to deal with far more root goals than `evaluate_all`. -pub struct FulfillmentCtxt<'tcx, E: FulfillmentErrorLike<'tcx>> { +pub struct FulfillmentCtxt<'tcx, E: 'tcx> { obligations: ObligationStorage<'tcx>, /// The snapshot in which this context was created. Using the context @@ -93,7 +93,7 @@ fn on_fulfillment_overflow(&mut self, infcx: &InferCtxt<'tcx>) { } } -impl<'tcx, E: FulfillmentErrorLike<'tcx>> FulfillmentCtxt<'tcx, E> { +impl<'tcx, E: 'tcx> FulfillmentCtxt<'tcx, E> { pub fn new(infcx: &InferCtxt<'tcx>) -> FulfillmentCtxt<'tcx, E> { assert!( infcx.next_trait_solver(), @@ -123,8 +123,9 @@ fn inspect_evaluated_obligation( } } -impl<'tcx, E: FromSolverError<'tcx, NextSolverError<'tcx>>> TraitEngine<'tcx, E> - for FulfillmentCtxt<'tcx, E> +impl<'tcx, E> TraitEngine<'tcx, E> for FulfillmentCtxt<'tcx, E> +where + E: FromSolverError<'tcx, NextSolverError<'tcx>>, { #[instrument(level = "trace", skip(self, infcx))] fn register_predicate_obligation( diff --git a/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs b/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs index dca14e20fb3..1f27978e5a6 100644 --- a/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs +++ b/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs @@ -12,7 +12,6 @@ use rustc_ast_ir::try_visit; use rustc_ast_ir::visit::VisitorResult; use rustc_infer::infer::{DefineOpaqueTypes, InferCtxt, InferOk}; -use rustc_infer::traits::FulfillmentErrorLike as _; use rustc_macros::extension; use rustc_middle::traits::query::NoSolution; use rustc_middle::traits::solve::{inspect, QueryResult}; diff --git a/compiler/rustc_trait_selection/src/solve/normalize.rs b/compiler/rustc_trait_selection/src/solve/normalize.rs index 4211129a4e1..c60d1aed415 100644 --- a/compiler/rustc_trait_selection/src/solve/normalize.rs +++ b/compiler/rustc_trait_selection/src/solve/normalize.rs @@ -1,3 +1,4 @@ +use std::fmt::Debug; use std::marker::PhantomData; use crate::traits::error_reporting::{OverflowCause, TypeErrCtxtExt}; @@ -6,7 +7,7 @@ use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_infer::infer::at::At; use rustc_infer::infer::InferCtxt; -use rustc_infer::traits::{FromSolverError, FulfillmentErrorLike, Obligation, TraitEngine}; +use rustc_infer::traits::{FromSolverError, Obligation, TraitEngine}; use rustc_middle::traits::ObligationCause; use rustc_middle::ty::{self, Ty, TyCtxt, UniverseIndex}; use rustc_middle::ty::{FallibleTypeFolder, TypeFolder, TypeSuperFoldable}; @@ -16,14 +17,11 @@ /// Deeply normalize all aliases in `value`. This does not handle inference and expects /// its input to be already fully resolved. -pub fn deeply_normalize< - 'tcx, +pub fn deeply_normalize<'tcx, T, E>(at: At<'_, 'tcx>, value: T) -> Result> +where T: TypeFoldable>, E: FromSolverError<'tcx, NextSolverError<'tcx>>, ->( - at: At<'_, 'tcx>, - value: T, -) -> Result> { +{ assert!(!value.has_escaping_bound_vars()); deeply_normalize_with_skipped_universes(at, value, vec![]) } @@ -34,15 +32,15 @@ pub fn deeply_normalize< /// Additionally takes a list of universes which represents the binders which have been /// entered before passing `value` to the function. This is currently needed for /// `normalize_erasing_regions`, which skips binders as it walks through a type. -pub fn deeply_normalize_with_skipped_universes< - 'tcx, - T: TypeFoldable>, - E: FromSolverError<'tcx, NextSolverError<'tcx>>, ->( +pub fn deeply_normalize_with_skipped_universes<'tcx, T, E>( at: At<'_, 'tcx>, value: T, universes: Vec>, -) -> Result> { +) -> Result> +where + T: TypeFoldable>, + E: FromSolverError<'tcx, NextSolverError<'tcx>>, +{ let fulfill_cx = FulfillmentCtxt::new(at.infcx); let mut folder = NormalizationFolder { at, fulfill_cx, depth: 0, universes, _errors: PhantomData }; @@ -50,7 +48,7 @@ pub fn deeply_normalize_with_skipped_universes< value.try_fold_with(&mut folder) } -struct NormalizationFolder<'me, 'tcx, E: FulfillmentErrorLike<'tcx>> { +struct NormalizationFolder<'me, 'tcx, E> { at: At<'me, 'tcx>, fulfill_cx: FulfillmentCtxt<'tcx, E>, depth: usize, @@ -58,7 +56,10 @@ struct NormalizationFolder<'me, 'tcx, E: FulfillmentErrorLike<'tcx>> { _errors: PhantomData, } -impl<'tcx, E: FromSolverError<'tcx, NextSolverError<'tcx>>> NormalizationFolder<'_, 'tcx, E> { +impl<'tcx, E> NormalizationFolder<'_, 'tcx, E> +where + E: FromSolverError<'tcx, NextSolverError<'tcx>>, +{ fn normalize_alias_ty(&mut self, alias_ty: Ty<'tcx>) -> Result, Vec> { assert!(matches!(alias_ty.kind(), ty::Alias(..))); @@ -150,8 +151,9 @@ fn normalize_unevaluated_const( } } -impl<'tcx, E: FromSolverError<'tcx, NextSolverError<'tcx>>> FallibleTypeFolder> - for NormalizationFolder<'_, 'tcx, E> +impl<'tcx, E> FallibleTypeFolder> for NormalizationFolder<'_, 'tcx, E> +where + E: FromSolverError<'tcx, NextSolverError<'tcx>> + Debug, { type Error = Vec; diff --git a/compiler/rustc_trait_selection/src/traits/engine.rs b/compiler/rustc_trait_selection/src/traits/engine.rs index 397f9cf2638..811f61d2bf3 100644 --- a/compiler/rustc_trait_selection/src/traits/engine.rs +++ b/compiler/rustc_trait_selection/src/traits/engine.rs @@ -21,7 +21,6 @@ use rustc_infer::infer::outlives::env::OutlivesEnvironment; use rustc_infer::infer::RegionResolutionError; use rustc_infer::infer::{DefineOpaqueTypes, InferCtxt, InferOk}; -use rustc_infer::traits::FulfillmentErrorLike; use rustc_macros::extension; use rustc_middle::arena::ArenaAllocatable; use rustc_middle::traits::query::NoSolution; @@ -32,10 +31,9 @@ use rustc_middle::ty::{self, Ty, TyCtxt}; #[extension(pub trait TraitEngineExt<'tcx, E>)] -impl< - 'tcx, +impl<'tcx, E> dyn TraitEngine<'tcx, E> +where E: FromSolverError<'tcx, NextSolverError<'tcx>> + FromSolverError<'tcx, OldSolverError<'tcx>>, -> dyn TraitEngine<'tcx, E> { fn new(infcx: &InferCtxt<'tcx>) -> Box { if infcx.next_trait_solver() { @@ -73,7 +71,7 @@ pub fn new(infcx: &'a InferCtxt<'tcx>) -> Self { impl<'a, 'tcx, E> ObligationCtxt<'a, 'tcx, E> where - E: FulfillmentErrorLike<'tcx>, + E: 'tcx, { pub fn register_obligation(&self, obligation: PredicateObligation<'tcx>) { self.engine.borrow_mut().register_predicate_obligation(self.infcx, obligation); @@ -231,7 +229,20 @@ pub fn resolve_regions( ) -> Vec> { self.infcx.resolve_regions(outlives_env) } +} +impl<'tcx> ObligationCtxt<'_, 'tcx, FulfillmentError<'tcx>> { + pub fn assumed_wf_types_and_report_errors( + &self, + param_env: ty::ParamEnv<'tcx>, + def_id: LocalDefId, + ) -> Result>, ErrorGuaranteed> { + self.assumed_wf_types(param_env, def_id) + .map_err(|errors| self.infcx.err_ctxt().report_fulfillment_errors(errors)) + } +} + +impl<'tcx> ObligationCtxt<'_, 'tcx, ScrubbedTraitError<'tcx>> { pub fn make_canonicalized_query_response( &self, inference_vars: CanonicalVarValues<'tcx>, @@ -249,17 +260,6 @@ pub fn make_canonicalized_query_response( } } -impl<'tcx> ObligationCtxt<'_, 'tcx, FulfillmentError<'tcx>> { - pub fn assumed_wf_types_and_report_errors( - &self, - param_env: ty::ParamEnv<'tcx>, - def_id: LocalDefId, - ) -> Result>, ErrorGuaranteed> { - self.assumed_wf_types(param_env, def_id) - .map_err(|errors| self.infcx.err_ctxt().report_fulfillment_errors(errors)) - } -} - impl<'tcx, E> ObligationCtxt<'_, 'tcx, E> where E: FromSolverError<'tcx, NextSolverError<'tcx>>, diff --git a/compiler/rustc_trait_selection/src/traits/fulfill.rs b/compiler/rustc_trait_selection/src/traits/fulfill.rs index 59802a26043..8ab9d5754c0 100644 --- a/compiler/rustc_trait_selection/src/traits/fulfill.rs +++ b/compiler/rustc_trait_selection/src/traits/fulfill.rs @@ -6,7 +6,7 @@ use rustc_data_structures::obligation_forest::{Error, ForestObligation, Outcome}; use rustc_data_structures::obligation_forest::{ObligationForest, ObligationProcessor}; use rustc_infer::infer::DefineOpaqueTypes; -use rustc_infer::traits::{FromSolverError, FulfillmentErrorLike, ProjectionCacheKey}; +use rustc_infer::traits::{FromSolverError, ProjectionCacheKey}; use rustc_infer::traits::{PolyTraitObligation, SelectionError, TraitEngine}; use rustc_middle::bug; use rustc_middle::mir::interpret::ErrorHandled; @@ -50,7 +50,7 @@ fn as_cache_key(&self) -> Self::CacheKey { /// along. Once all type inference constraints have been generated, the /// method `select_all_or_error` can be used to report any remaining /// ambiguous cases as errors. -pub struct FulfillmentContext<'tcx, E: FulfillmentErrorLike<'tcx>> { +pub struct FulfillmentContext<'tcx, E: 'tcx> { /// A list of all obligations that have been registered with this /// fulfillment context. predicates: ObligationForest>, @@ -78,7 +78,10 @@ pub struct PendingPredicateObligation<'tcx> { #[cfg(target_pointer_width = "64")] rustc_data_structures::static_assert_size!(PendingPredicateObligation<'_>, 72); -impl<'tcx, E: FromSolverError<'tcx, OldSolverError<'tcx>>> FulfillmentContext<'tcx, E> { +impl<'tcx, E> FulfillmentContext<'tcx, E> +where + E: FromSolverError<'tcx, OldSolverError<'tcx>>, +{ /// Creates a new fulfillment context. pub(super) fn new(infcx: &InferCtxt<'tcx>) -> FulfillmentContext<'tcx, E> { assert!( @@ -106,8 +109,11 @@ fn select(&mut self, selcx: SelectionContext<'_, 'tcx>) -> Vec { // FIXME: if we kept the original cache key, we could mark projection // obligations as complete for the projection cache here. - let errors: Vec = - outcome.errors.into_iter().map(|err| E::from_solver_error(infcx, err)).collect(); + let errors: Vec = outcome + .errors + .into_iter() + .map(|err| E::from_solver_error(infcx, OldSolverError(err))) + .collect(); debug!( "select({} predicates remaining, {} errors) done", @@ -119,8 +125,9 @@ fn select(&mut self, selcx: SelectionContext<'_, 'tcx>) -> Vec { } } -impl<'tcx, E: FromSolverError<'tcx, OldSolverError<'tcx>>> TraitEngine<'tcx, E> - for FulfillmentContext<'tcx, E> +impl<'tcx, E> TraitEngine<'tcx, E> for FulfillmentContext<'tcx, E> +where + E: FromSolverError<'tcx, OldSolverError<'tcx>>, { #[inline] fn register_predicate_obligation( @@ -144,7 +151,7 @@ fn collect_remaining_errors(&mut self, infcx: &InferCtxt<'tcx>) -> Vec { self.predicates .to_errors(FulfillmentErrorCode::Ambiguity { overflow: None }) .into_iter() - .map(|err| E::from_solver_error(infcx, err)) + .map(|err| E::from_solver_error(infcx, OldSolverError(err))) .collect() } @@ -843,22 +850,25 @@ fn args_infer_vars<'a, 'tcx>( .filter_map(TyOrConstInferVar::maybe_from_generic_arg) } -pub type OldSolverError<'tcx> = Error, FulfillmentErrorCode<'tcx>>; +#[derive(Debug)] +pub struct OldSolverError<'tcx>( + Error, FulfillmentErrorCode<'tcx>>, +); impl<'tcx> FromSolverError<'tcx, OldSolverError<'tcx>> for FulfillmentError<'tcx> { fn from_solver_error(_infcx: &InferCtxt<'tcx>, error: OldSolverError<'tcx>) -> Self { - let mut iter = error.backtrace.into_iter(); + let mut iter = error.0.backtrace.into_iter(); let obligation = iter.next().unwrap().obligation; // The root obligation is the last item in the backtrace - if there's only // one item, then it's the same as the main obligation let root_obligation = iter.next_back().map_or_else(|| obligation.clone(), |e| e.obligation); - FulfillmentError::new(obligation, error.error, root_obligation) + FulfillmentError::new(obligation, error.0.error, root_obligation) } } impl<'tcx> FromSolverError<'tcx, OldSolverError<'tcx>> for ScrubbedTraitError<'tcx> { fn from_solver_error(_infcx: &InferCtxt<'tcx>, error: OldSolverError<'tcx>) -> Self { - match error.error { + match error.0.error { FulfillmentErrorCode::Select(_) | FulfillmentErrorCode::Project(_) | FulfillmentErrorCode::Subtype(_, _) diff --git a/compiler/rustc_trait_selection/src/traits/mod.rs b/compiler/rustc_trait_selection/src/traits/mod.rs index 9aaa8adbd67..d918945dbed 100644 --- a/compiler/rustc_trait_selection/src/traits/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/mod.rs @@ -71,37 +71,6 @@ pub use rustc_infer::traits::*; -/// A trait error with most of its information removed. This is the error -/// returned by an [`ObligationCtxt`] by default, and suitable if you just -/// want to see if a predicate holds, and don't particularly care about the -/// error itself (except for if it's an ambiguity or true error). -/// -/// use [`ObligationCtxt::new_with_diagnostics`] to get a [`FulfillmentError`]. -#[derive(Clone, Debug)] -pub enum ScrubbedTraitError<'tcx> { - /// A real error. This goal definitely does not hold. - TrueError, - /// An ambiguity. This goal may hold if further inference is done. - Ambiguity, - /// An old-solver-style cycle error, which will fatal. - Cycle(Vec>), -} - -impl<'tcx> ScrubbedTraitError<'tcx> { - fn is_true_error(&self) -> bool { - match self { - ScrubbedTraitError::TrueError => true, - ScrubbedTraitError::Ambiguity | ScrubbedTraitError::Cycle(_) => false, - } - } -} - -impl<'tcx> FulfillmentErrorLike<'tcx> for ScrubbedTraitError<'tcx> { - fn is_true_error(&self) -> bool { - self.is_true_error() - } -} - pub struct FulfillmentError<'tcx> { pub obligation: PredicateObligation<'tcx>, pub code: FulfillmentErrorCode<'tcx>, @@ -133,12 +102,6 @@ pub fn is_true_error(&self) -> bool { } } -impl<'tcx> FulfillmentErrorLike<'tcx> for FulfillmentError<'tcx> { - fn is_true_error(&self) -> bool { - self.is_true_error() - } -} - impl<'tcx> Debug for FulfillmentError<'tcx> { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { write!(f, "FulfillmentError({:?},{:?})", self.obligation, self.code) diff --git a/compiler/rustc_trait_selection/src/traits/normalize.rs b/compiler/rustc_trait_selection/src/traits/normalize.rs index 4e5ca2ee92e..db30521d776 100644 --- a/compiler/rustc_trait_selection/src/traits/normalize.rs +++ b/compiler/rustc_trait_selection/src/traits/normalize.rs @@ -46,14 +46,15 @@ fn normalize>>(&self, value: T) -> InferOk<'tcx, T> /// existing fulfillment context in the old solver. Once we also eagerly prove goals with /// the old solver or have removed the old solver, remove `traits::fully_normalize` and /// rename this function to `At::fully_normalize`. - fn deeply_normalize< - T: TypeFoldable>, - E: FromSolverError<'tcx, NextSolverError<'tcx>>, - >( + fn deeply_normalize( self, value: T, fulfill_cx: &mut dyn TraitEngine<'tcx, E>, - ) -> Result> { + ) -> Result> + where + T: TypeFoldable>, + E: FromSolverError<'tcx, NextSolverError<'tcx>>, + { if self.infcx.next_trait_solver() { crate::solve::deeply_normalize(self, value) } else { diff --git a/compiler/rustc_trait_selection/src/traits/query/type_op/implied_outlives_bounds.rs b/compiler/rustc_trait_selection/src/traits/query/type_op/implied_outlives_bounds.rs index 54fa0749618..b38841db923 100644 --- a/compiler/rustc_trait_selection/src/traits/query/type_op/implied_outlives_bounds.rs +++ b/compiler/rustc_trait_selection/src/traits/query/type_op/implied_outlives_bounds.rs @@ -1,8 +1,6 @@ -use crate::solve; use crate::traits::query::NoSolution; use crate::traits::wf; use crate::traits::ObligationCtxt; -use crate::traits::ScrubbedTraitError; use rustc_infer::infer::canonical::Canonical; use rustc_infer::infer::outlives::components::{push_outlives_components, Component}; @@ -263,11 +261,9 @@ pub fn compute_implied_outlives_bounds_compat_inner<'tcx>( let mut ty_a = ocx.infcx.resolve_vars_if_possible(ty_a); // Need to manually normalize in the new solver as `wf::obligations` does not. if ocx.infcx.next_trait_solver() { - ty_a = solve::deeply_normalize( - ocx.infcx.at(&ObligationCause::dummy(), param_env), - ty_a, - ) - .map_err(|_errs: Vec>| NoSolution)?; + ty_a = ocx + .deeply_normalize(&ObligationCause::dummy(), param_env, ty_a) + .map_err(|_| NoSolution)?; } let mut components = smallvec![]; push_outlives_components(tcx, ty_a, &mut components); diff --git a/compiler/rustc_trait_selection/src/traits/structural_normalize.rs b/compiler/rustc_trait_selection/src/traits/structural_normalize.rs index a160fc033a2..9d657ade86b 100644 --- a/compiler/rustc_trait_selection/src/traits/structural_normalize.rs +++ b/compiler/rustc_trait_selection/src/traits/structural_normalize.rs @@ -1,5 +1,5 @@ use rustc_infer::infer::at::At; -use rustc_infer::traits::{FulfillmentErrorLike, TraitEngine}; +use rustc_infer::traits::TraitEngine; use rustc_macros::extension; use rustc_middle::ty::{self, Ty}; @@ -7,7 +7,7 @@ #[extension(pub trait StructurallyNormalizeExt<'tcx>)] impl<'tcx> At<'_, 'tcx> { - fn structurally_normalize>( + fn structurally_normalize( &self, ty: Ty<'tcx>, fulfill_cx: &mut dyn TraitEngine<'tcx, E>,