From 0a032d5a320e25a9134f7a576ed4cf02f1579ebd Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Sat, 1 Jun 2024 13:22:35 -0400 Subject: [PATCH 1/5] Remove unnecessary extension trait --- .../src/infer/canonical/query_response.rs | 2 +- compiler/rustc_infer/src/infer/mod.rs | 2 +- compiler/rustc_infer/src/traits/engine.rs | 36 +++++++++---------- compiler/rustc_infer/src/traits/mod.rs | 2 +- .../src/solve/normalize.rs | 1 - .../src/traits/engine.rs | 4 +-- 6 files changed, 20 insertions(+), 27 deletions(-) diff --git a/compiler/rustc_infer/src/infer/canonical/query_response.rs b/compiler/rustc_infer/src/infer/canonical/query_response.rs index 1732913e19150..1dbc1ae7ddd2c 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::canonical::{ use crate::infer::region_constraints::{Constraint, RegionConstraintData}; use crate::infer::{DefineOpaqueTypes, InferCtxt, InferOk, InferResult}; use crate::traits::query::NoSolution; +use crate::traits::TraitEngine; use crate::traits::{Obligation, ObligationCause, PredicateObligation}; -use crate::traits::{TraitEngine, TraitEngineExt}; use rustc_data_structures::captures::Captures; use rustc_index::Idx; use rustc_index::IndexVec; diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs index c8bb6cf5f9b4c..617e6a245ed7c 100644 --- a/compiler/rustc_infer/src/infer/mod.rs +++ b/compiler/rustc_infer/src/infer/mod.rs @@ -12,7 +12,7 @@ pub use SubregionOrigin::*; pub use ValuePairs::*; use crate::traits::{ - self, ObligationCause, ObligationInspector, PredicateObligations, TraitEngine, TraitEngineExt, + self, ObligationCause, ObligationInspector, PredicateObligations, TraitEngine, }; use error_reporting::TypeErrCtxt; use free_regions::RegionRelations; diff --git a/compiler/rustc_infer/src/traits/engine.rs b/compiler/rustc_infer/src/traits/engine.rs index e27e6a0a4a151..a4bcd9d2c8a4e 100644 --- a/compiler/rustc_infer/src/traits/engine.rs +++ b/compiler/rustc_infer/src/traits/engine.rs @@ -1,7 +1,6 @@ use crate::infer::InferCtxt; use crate::traits::Obligation; use rustc_hir::def_id::DefId; -use rustc_macros::extension; use rustc_middle::ty::{self, Ty, Upcast}; use super::FulfillmentError; @@ -37,34 +36,21 @@ pub trait TraitEngine<'tcx>: 'tcx { obligation: PredicateObligation<'tcx>, ); - #[must_use] - fn select_where_possible(&mut self, infcx: &InferCtxt<'tcx>) -> Vec>; - - fn collect_remaining_errors(&mut self, infcx: &InferCtxt<'tcx>) -> Vec>; - - fn pending_obligations(&self) -> Vec>; - - /// Among all pending obligations, collect those are stalled on a inference variable which has - /// changed since the last call to `select_where_possible`. Those obligations are marked as - /// successful and returned. - fn drain_unstalled_obligations( - &mut self, - infcx: &InferCtxt<'tcx>, - ) -> Vec>; -} - -#[extension(pub trait TraitEngineExt<'tcx>)] -impl<'tcx, T: ?Sized + TraitEngine<'tcx>> T { fn register_predicate_obligations( &mut self, infcx: &InferCtxt<'tcx>, - obligations: impl IntoIterator>, + obligations: Vec>, ) { for obligation in obligations { self.register_predicate_obligation(infcx, obligation); } } + #[must_use] + fn select_where_possible(&mut self, infcx: &InferCtxt<'tcx>) -> Vec>; + + fn collect_remaining_errors(&mut self, infcx: &InferCtxt<'tcx>) -> Vec>; + #[must_use] fn select_all_or_error(&mut self, infcx: &InferCtxt<'tcx>) -> Vec> { let errors = self.select_where_possible(infcx); @@ -74,4 +60,14 @@ impl<'tcx, T: ?Sized + TraitEngine<'tcx>> T { self.collect_remaining_errors(infcx) } + + fn pending_obligations(&self) -> Vec>; + + /// Among all pending obligations, collect those are stalled on a inference variable which has + /// changed since the last call to `select_where_possible`. Those obligations are marked as + /// successful and returned. + fn drain_unstalled_obligations( + &mut self, + infcx: &InferCtxt<'tcx>, + ) -> Vec>; } diff --git a/compiler/rustc_infer/src/traits/mod.rs b/compiler/rustc_infer/src/traits/mod.rs index 0ae4340098bc6..8304fa3c8a2f7 100644 --- a/compiler/rustc_infer/src/traits/mod.rs +++ b/compiler/rustc_infer/src/traits/mod.rs @@ -23,7 +23,7 @@ pub use self::ImplSource::*; pub use self::SelectionError::*; use crate::infer::InferCtxt; -pub use self::engine::{TraitEngine, TraitEngineExt}; +pub use self::engine::TraitEngine; pub use self::project::MismatchedProjectionTypes; pub(crate) use self::project::UndoLog; pub use self::project::{ diff --git a/compiler/rustc_trait_selection/src/solve/normalize.rs b/compiler/rustc_trait_selection/src/solve/normalize.rs index 5d5161e092e31..970848544c5ad 100644 --- a/compiler/rustc_trait_selection/src/solve/normalize.rs +++ b/compiler/rustc_trait_selection/src/solve/normalize.rs @@ -4,7 +4,6 @@ use crate::traits::{BoundVarReplacer, PlaceholderReplacer}; use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_infer::infer::at::At; use rustc_infer::infer::InferCtxt; -use rustc_infer::traits::TraitEngineExt; use rustc_infer::traits::{FulfillmentError, Obligation, TraitEngine}; use rustc_middle::traits::ObligationCause; use rustc_middle::ty::{self, Ty, TyCtxt, UniverseIndex}; diff --git a/compiler/rustc_trait_selection/src/traits/engine.rs b/compiler/rustc_trait_selection/src/traits/engine.rs index 4684c7171d829..6fed24c49e0b1 100644 --- a/compiler/rustc_trait_selection/src/traits/engine.rs +++ b/compiler/rustc_trait_selection/src/traits/engine.rs @@ -18,9 +18,7 @@ use rustc_infer::infer::canonical::{ use rustc_infer::infer::outlives::env::OutlivesEnvironment; use rustc_infer::infer::RegionResolutionError; use rustc_infer::infer::{DefineOpaqueTypes, InferCtxt, InferOk}; -use rustc_infer::traits::{ - FulfillmentError, Obligation, ObligationCause, PredicateObligation, TraitEngineExt as _, -}; +use rustc_infer::traits::{FulfillmentError, Obligation, ObligationCause, PredicateObligation}; use rustc_macros::extension; use rustc_middle::arena::ArenaAllocatable; use rustc_middle::traits::query::NoSolution; From 84d5118d1c2924e8fd86d4ff2114a0cdc6fd4c60 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Sat, 1 Jun 2024 14:12:34 -0400 Subject: [PATCH 2/5] Make TraitEngines generic over error --- .../src/type_check/constraint_conversion.rs | 3 +- .../src/check/compare_impl_item.rs | 4 +- .../src/coherence/orphan.rs | 5 +- .../src/hir_ty_lowering/errors.rs | 2 +- .../rustc_hir_typeck/src/typeck_root_ctxt.rs | 8 +- .../src/infer/canonical/query_response.rs | 25 ++---- compiler/rustc_infer/src/infer/mod.rs | 7 +- compiler/rustc_infer/src/traits/engine.rs | 19 +++-- compiler/rustc_infer/src/traits/mod.rs | 34 +------- .../src/traits/structural_impls.rs | 6 -- compiler/rustc_trait_selection/src/regions.rs | 4 +- .../src/solve/fulfill.rs | 84 ++++++++++++++----- .../rustc_trait_selection/src/solve/mod.rs | 2 +- .../src/solve/normalize.rs | 53 +++++++----- .../src/traits/coherence.rs | 2 +- .../src/traits/engine.rs | 22 +++-- .../src/traits/fulfill.rs | 51 ++++++----- .../rustc_trait_selection/src/traits/misc.rs | 4 +- .../rustc_trait_selection/src/traits/mod.rs | 43 ++++++++++ .../src/traits/normalize.rs | 13 ++- .../src/traits/query/normalize.rs | 7 +- .../query/type_op/implied_outlives_bounds.rs | 4 +- .../src/traits/structural_normalize.rs | 8 +- 23 files changed, 253 insertions(+), 157 deletions(-) diff --git a/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs b/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs index b23ad2e158425..4037f04d0bce8 100644 --- a/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs +++ b/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs @@ -13,6 +13,7 @@ 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::FulfillmentError; use crate::{ constraints::OutlivesConstraint, @@ -286,7 +287,7 @@ impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> { ocx.infcx.at(&ObligationCause::dummy_with_span(self.span), self.param_env), ty, ) - .map_err(|_| NoSolution) + .map_err(|_: Vec>| NoSolution) }, "normalize type outlives obligation", ) 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 db749ef3f81b6..17db1c07383f9 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::intravisit; use rustc_hir::{GenericParamKind, ImplItemKind}; use rustc_infer::infer::outlives::env::OutlivesEnvironment; use rustc_infer::infer::{self, InferCtxt, TyCtxtInferExt}; -use rustc_infer::traits::{util, FulfillmentError}; +use rustc_infer::traits::util; use rustc_middle::ty::error::{ExpectedFound, TypeError}; use rustc_middle::ty::fold::BottomUpFolder; use rustc_middle::ty::util::ExplicitSelf; @@ -25,7 +25,7 @@ use rustc_trait_selection::regions::InferCtxtRegionExt; use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt; use rustc_trait_selection::traits::outlives_bounds::InferCtxtExt as _; use rustc_trait_selection::traits::{ - self, ObligationCause, ObligationCauseCode, ObligationCtxt, Reveal, + self, FulfillmentError, ObligationCause, ObligationCauseCode, ObligationCtxt, Reveal, }; use std::borrow::Cow; use std::iter; diff --git a/compiler/rustc_hir_analysis/src/coherence/orphan.rs b/compiler/rustc_hir_analysis/src/coherence/orphan.rs index bdac0d9b0b407..a4818b25f98cd 100644 --- a/compiler/rustc_hir_analysis/src/coherence/orphan.rs +++ b/compiler/rustc_hir_analysis/src/coherence/orphan.rs @@ -13,8 +13,8 @@ use rustc_middle::ty::{TypeSuperVisitable, TypeVisitable, TypeVisitableExt, Type use rustc_middle::{bug, span_bug}; use rustc_span::def_id::{DefId, LocalDefId}; use rustc_trait_selection::traits::{self, IsFirstInputType, UncoveredTyParams}; +use rustc_trait_selection::traits::{FulfillmentError, StructurallyNormalizeExt, TraitEngineExt}; 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( @@ -317,7 +317,8 @@ fn orphan_check<'tcx>( } let ty = if infcx.next_trait_solver() { - let mut fulfill_cx = >::new(&infcx); + let mut fulfill_cx = + >>::new(&infcx); infcx .at(&cause, ty::ParamEnv::empty()) .structurally_normalize(ty, &mut *fulfill_cx) diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs index 821c56530407d..f646e7de26b9f 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs @@ -15,7 +15,6 @@ use rustc_errors::{ use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::{DefId, LocalDefId}; -use rustc_infer::traits::FulfillmentError; use rustc_middle::bug; use rustc_middle::query::Key; use rustc_middle::ty::print::{PrintPolyTraitRefExt as _, PrintTraitRefExt as _}; @@ -28,6 +27,7 @@ use rustc_span::edit_distance::find_best_match_for_name; use rustc_span::symbol::{kw, sym, Ident}; use rustc_span::BytePos; use rustc_span::{Span, Symbol, DUMMY_SP}; +use rustc_trait_selection::traits::FulfillmentError; use rustc_trait_selection::traits::{ object_safety_violations_for_assoc_item, TraitAliasExpansionInfo, }; diff --git a/compiler/rustc_hir_typeck/src/typeck_root_ctxt.rs b/compiler/rustc_hir_typeck/src/typeck_root_ctxt.rs index 19d6481cc1b8b..0dfc5408f3060 100644 --- a/compiler/rustc_hir_typeck/src/typeck_root_ctxt.rs +++ b/compiler/rustc_hir_typeck/src/typeck_root_ctxt.rs @@ -11,7 +11,9 @@ use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_span::def_id::LocalDefIdMap; use rustc_span::Span; use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt; -use rustc_trait_selection::traits::{self, PredicateObligation, TraitEngine, TraitEngineExt as _}; +use rustc_trait_selection::traits::{ + self, FulfillmentError, PredicateObligation, TraitEngine, TraitEngineExt as _, +}; use std::cell::RefCell; use std::ops::Deref; @@ -34,7 +36,7 @@ pub(crate) struct TypeckRootCtxt<'tcx> { pub(super) locals: RefCell>>, - pub(super) fulfillment_cx: RefCell>>, + pub(super) fulfillment_cx: RefCell>>>, /// Some additional `Sized` obligations badly affect type inference. /// These obligations are added in a later stage of typeck. @@ -83,7 +85,7 @@ impl<'tcx> TypeckRootCtxt<'tcx> { TypeckRootCtxt { typeck_results, - fulfillment_cx: RefCell::new(>::new(&infcx)), + fulfillment_cx: RefCell::new(>::new(&infcx)), infcx, locals: RefCell::new(Default::default()), deferred_sized_obligations: RefCell::new(Vec::new()), diff --git a/compiler/rustc_infer/src/infer/canonical/query_response.rs b/compiler/rustc_infer/src/infer/canonical/query_response.rs index 1dbc1ae7ddd2c..4917f936f4e16 100644 --- a/compiler/rustc_infer/src/infer/canonical/query_response.rs +++ b/compiler/rustc_infer/src/infer/canonical/query_response.rs @@ -15,7 +15,7 @@ use crate::infer::canonical::{ use crate::infer::region_constraints::{Constraint, RegionConstraintData}; use crate::infer::{DefineOpaqueTypes, InferCtxt, InferOk, InferResult}; use crate::traits::query::NoSolution; -use crate::traits::TraitEngine; +use crate::traits::{FulfillmentErrorLike, TraitEngine}; use crate::traits::{Obligation, ObligationCause, PredicateObligation}; use rustc_data_structures::captures::Captures; use rustc_index::Idx; @@ -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>, + fulfill_cx: &mut dyn TraitEngine<'tcx, E>, ) -> Result, NoSolution> where T: Debug + TypeFoldable>, @@ -97,11 +97,11 @@ impl<'tcx> InferCtxt<'tcx> { /// 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>, + fulfill_cx: &mut dyn TraitEngine<'tcx, E>, ) -> Result, NoSolution> where T: Debug + TypeFoldable>, @@ -109,19 +109,13 @@ impl<'tcx> InferCtxt<'tcx> { let tcx = self.tcx; // Select everything, returning errors. - let true_errors = fulfill_cx.select_where_possible(self); - debug!("true_errors = {:#?}", true_errors); + let errors = fulfill_cx.select_all_or_error(self); - if !true_errors.is_empty() { - // FIXME -- we don't indicate *why* we failed to solve - debug!("make_query_response: true_errors={:#?}", true_errors); + // True error! + if errors.iter().any(|e| e.is_true_error()) { return Err(NoSolution); } - // Anything left unselected *now* must be an ambiguity. - let ambig_errors = fulfill_cx.select_all_or_error(self); - debug!("ambig_errors = {:#?}", ambig_errors); - let region_obligations = self.take_registered_region_obligations(); debug!(?region_obligations); let region_constraints = self.with_region_constraints(|region_constraints| { @@ -135,8 +129,7 @@ impl<'tcx> InferCtxt<'tcx> { }); debug!(?region_constraints); - let certainty = - if ambig_errors.is_empty() { Certainty::Proven } else { Certainty::Ambiguous }; + let certainty = if errors.is_empty() { Certainty::Proven } else { Certainty::Ambiguous }; let opaque_types = self.take_opaque_types_for_query_response(); diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs index 617e6a245ed7c..5183d9e2d6ebb 100644 --- a/compiler/rustc_infer/src/infer/mod.rs +++ b/compiler/rustc_infer/src/infer/mod.rs @@ -12,7 +12,8 @@ pub use SubregionOrigin::*; pub use ValuePairs::*; use crate::traits::{ - self, ObligationCause, ObligationInspector, PredicateObligations, TraitEngine, + self, FulfillmentErrorLike, ObligationCause, ObligationInspector, PredicateObligations, + TraitEngine, }; use error_reporting::TypeErrCtxt; use free_regions::RegionRelations; @@ -737,10 +738,10 @@ impl<'tcx> InferCtxtBuilder<'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>, + fulfill_cx: &mut dyn TraitEngine<'tcx, E>, ) -> T { let InferOk { value, obligations } = self; fulfill_cx.register_predicate_obligations(infcx, obligations); diff --git a/compiler/rustc_infer/src/traits/engine.rs b/compiler/rustc_infer/src/traits/engine.rs index a4bcd9d2c8a4e..1d6875d0f8edc 100644 --- a/compiler/rustc_infer/src/traits/engine.rs +++ b/compiler/rustc_infer/src/traits/engine.rs @@ -1,12 +1,13 @@ +use std::fmt::Debug; + use crate::infer::InferCtxt; use crate::traits::Obligation; use rustc_hir::def_id::DefId; use rustc_middle::ty::{self, Ty, Upcast}; -use super::FulfillmentError; use super::{ObligationCause, PredicateObligation}; -pub trait TraitEngine<'tcx>: 'tcx { +pub trait TraitEngine<'tcx, E: FulfillmentErrorLike<'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`). @@ -47,12 +48,12 @@ pub trait TraitEngine<'tcx>: 'tcx { } #[must_use] - fn select_where_possible(&mut self, infcx: &InferCtxt<'tcx>) -> Vec>; + fn select_where_possible(&mut self, infcx: &InferCtxt<'tcx>) -> Vec; - fn collect_remaining_errors(&mut self, infcx: &InferCtxt<'tcx>) -> Vec>; + fn collect_remaining_errors(&mut self, infcx: &InferCtxt<'tcx>) -> Vec; #[must_use] - fn select_all_or_error(&mut self, infcx: &InferCtxt<'tcx>) -> Vec> { + fn select_all_or_error(&mut self, infcx: &InferCtxt<'tcx>) -> Vec { let errors = self.select_where_possible(infcx); if !errors.is_empty() { return errors; @@ -71,3 +72,11 @@ pub trait TraitEngine<'tcx>: 'tcx { infcx: &InferCtxt<'tcx>, ) -> Vec>; } + +pub trait FulfillmentErrorLike<'tcx>: Debug + 'tcx { + fn is_true_error(&self) -> bool; +} + +pub trait FromSolverError<'tcx, E>: FulfillmentErrorLike<'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 8304fa3c8a2f7..26c931876dbdb 100644 --- a/compiler/rustc_infer/src/traits/mod.rs +++ b/compiler/rustc_infer/src/traits/mod.rs @@ -23,7 +23,7 @@ pub use self::ImplSource::*; pub use self::SelectionError::*; use crate::infer::InferCtxt; -pub use self::engine::TraitEngine; +pub use self::engine::{FromSolverError, FulfillmentErrorLike, TraitEngine}; pub use self::project::MismatchedProjectionTypes; pub(crate) use self::project::UndoLog; pub use self::project::{ @@ -124,15 +124,7 @@ pub type Selection<'tcx> = ImplSource<'tcx, PredicateObligation<'tcx>>; pub type ObligationInspector<'tcx> = fn(&InferCtxt<'tcx>, &PredicateObligation<'tcx>, Result); -pub struct FulfillmentError<'tcx> { - pub obligation: PredicateObligation<'tcx>, - pub code: FulfillmentErrorCode<'tcx>, - /// Diagnostics only: the 'root' obligation which resulted in - /// the failure to process `obligation`. This is the obligation - /// that was initially passed to `register_predicate_obligation` - pub root_obligation: PredicateObligation<'tcx>, -} - +// TODO: Pull this down too #[derive(Clone)] pub enum FulfillmentErrorCode<'tcx> { /// Inherently impossible to fulfill; this trait is implemented if and only @@ -198,28 +190,6 @@ impl<'tcx, O> Obligation<'tcx, O> { } } -impl<'tcx> FulfillmentError<'tcx> { - pub fn new( - obligation: PredicateObligation<'tcx>, - code: FulfillmentErrorCode<'tcx>, - root_obligation: PredicateObligation<'tcx>, - ) -> FulfillmentError<'tcx> { - FulfillmentError { obligation, code, root_obligation } - } - - pub fn is_true_error(&self) -> bool { - match self.code { - FulfillmentErrorCode::Select(_) - | FulfillmentErrorCode::Project(_) - | FulfillmentErrorCode::Subtype(_, _) - | FulfillmentErrorCode::ConstEquate(_, _) => true, - FulfillmentErrorCode::Cycle(_) | FulfillmentErrorCode::Ambiguity { overflow: _ } => { - false - } - } - } -} - impl<'tcx> PolyTraitObligation<'tcx> { pub fn polarity(&self) -> ty::PredicatePolarity { self.predicate.skip_binder().polarity diff --git a/compiler/rustc_infer/src/traits/structural_impls.rs b/compiler/rustc_infer/src/traits/structural_impls.rs index b616d37e5b5e3..00abf939807a0 100644 --- a/compiler/rustc_infer/src/traits/structural_impls.rs +++ b/compiler/rustc_infer/src/traits/structural_impls.rs @@ -29,12 +29,6 @@ impl<'tcx, O: fmt::Debug> fmt::Debug for traits::Obligation<'tcx, O> { } } -impl<'tcx> fmt::Debug for traits::FulfillmentError<'tcx> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "FulfillmentError({:?},{:?})", self.obligation, self.code) - } -} - impl<'tcx> fmt::Debug for traits::FulfillmentErrorCode<'tcx> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { use traits::FulfillmentErrorCode::*; diff --git a/compiler/rustc_trait_selection/src/regions.rs b/compiler/rustc_trait_selection/src/regions.rs index 5e0d7da4f06b1..cca5bce03e19b 100644 --- a/compiler/rustc_trait_selection/src/regions.rs +++ b/compiler/rustc_trait_selection/src/regions.rs @@ -1,3 +1,4 @@ +use crate::traits::FulfillmentError; use rustc_infer::infer::outlives::env::OutlivesEnvironment; use rustc_infer::infer::{InferCtxt, RegionResolutionError}; use rustc_macros::extension; @@ -27,7 +28,8 @@ impl<'tcx> InferCtxt<'tcx> { ), ty, ) - .map_err(|_| NoSolution) + // TODO: + .map_err(|_: Vec>| NoSolution) } else { Ok(ty) } diff --git a/compiler/rustc_trait_selection/src/solve/fulfill.rs b/compiler/rustc_trait_selection/src/solve/fulfill.rs index d28cf834032de..040bab1dfae28 100644 --- a/compiler/rustc_trait_selection/src/solve/fulfill.rs +++ b/compiler/rustc_trait_selection/src/solve/fulfill.rs @@ -1,3 +1,4 @@ +use std::marker::PhantomData; use std::mem; use std::ops::ControlFlow; @@ -5,14 +6,17 @@ use rustc_infer::infer::InferCtxt; use rustc_infer::traits::query::NoSolution; use rustc_infer::traits::solve::{CandidateSource, GoalSource, MaybeCause}; use rustc_infer::traits::{ - self, FulfillmentError, FulfillmentErrorCode, MismatchedProjectionTypes, Obligation, - ObligationCause, ObligationCauseCode, PredicateObligation, SelectionError, TraitEngine, + self, FromSolverError, FulfillmentErrorCode, FulfillmentErrorLike, MismatchedProjectionTypes, + Obligation, ObligationCause, ObligationCauseCode, PredicateObligation, SelectionError, + TraitEngine, }; use rustc_middle::bug; use rustc_middle::ty::error::{ExpectedFound, TypeError}; use rustc_middle::ty::{self, TyCtxt}; use rustc_span::symbol::sym; +use crate::traits::FulfillmentError; + use super::eval_ctxt::GenerateProofTree; use super::inspect::{self, ProofTreeInferCtxtExt, ProofTreeVisitor}; use super::{Certainty, InferCtxtEvalExt}; @@ -28,7 +32,7 @@ use super::{Certainty, InferCtxtEvalExt}; /// /// 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> { +pub struct FulfillmentCtxt<'tcx, E: FulfillmentErrorLike<'tcx>> { obligations: ObligationStorage<'tcx>, /// The snapshot in which this context was created. Using the context @@ -36,6 +40,7 @@ pub struct FulfillmentCtxt<'tcx> { /// gets rolled back. Because of this we explicitly check that we only /// use the context in exactly this snapshot. usable_in_snapshot: usize, + _errors: PhantomData, } #[derive(Default)] @@ -89,8 +94,8 @@ impl<'tcx> ObligationStorage<'tcx> { } } -impl<'tcx> FulfillmentCtxt<'tcx> { - pub fn new(infcx: &InferCtxt<'tcx>) -> FulfillmentCtxt<'tcx> { +impl<'tcx, E: FulfillmentErrorLike<'tcx>> FulfillmentCtxt<'tcx, E> { + pub fn new(infcx: &InferCtxt<'tcx>) -> FulfillmentCtxt<'tcx, E> { assert!( infcx.next_trait_solver(), "new trait solver fulfillment context created when \ @@ -99,6 +104,7 @@ impl<'tcx> FulfillmentCtxt<'tcx> { FulfillmentCtxt { obligations: Default::default(), usable_in_snapshot: infcx.num_open_snapshots(), + _errors: PhantomData, } } @@ -118,7 +124,9 @@ impl<'tcx> FulfillmentCtxt<'tcx> { } } -impl<'tcx> TraitEngine<'tcx> for FulfillmentCtxt<'tcx> { +impl<'tcx, E: FromSolverError<'tcx, NextSolverError<'tcx>>> TraitEngine<'tcx, E> + for FulfillmentCtxt<'tcx, E> +{ #[instrument(level = "trace", skip(self, infcx))] fn register_predicate_obligation( &mut self, @@ -129,24 +137,22 @@ impl<'tcx> TraitEngine<'tcx> for FulfillmentCtxt<'tcx> { self.obligations.register(obligation); } - fn collect_remaining_errors(&mut self, infcx: &InferCtxt<'tcx>) -> Vec> { - let mut errors: Vec<_> = self - .obligations + fn collect_remaining_errors(&mut self, infcx: &InferCtxt<'tcx>) -> Vec { + self.obligations .pending .drain(..) - .map(|obligation| fulfillment_error_for_stalled(infcx, obligation)) - .collect(); - - errors.extend(self.obligations.overflowed.drain(..).map(|obligation| FulfillmentError { - obligation: find_best_leaf_obligation(infcx, &obligation, true), - code: FulfillmentErrorCode::Ambiguity { overflow: Some(true) }, - root_obligation: obligation, - })); - - errors + .map(|obligation| NextSolverError::Ambiguity(obligation)) + .chain( + self.obligations + .overflowed + .drain(..) + .map(|obligation| NextSolverError::Overflow(obligation)), + ) + .map(|e| E::from_solver_error(infcx, e)) + .collect() } - fn select_where_possible(&mut self, infcx: &InferCtxt<'tcx>) -> Vec> { + fn select_where_possible(&mut self, infcx: &InferCtxt<'tcx>) -> Vec { assert_eq!(self.usable_in_snapshot, infcx.num_open_snapshots()); let mut errors = Vec::new(); for i in 0.. { @@ -164,7 +170,10 @@ impl<'tcx> TraitEngine<'tcx> for FulfillmentCtxt<'tcx> { let (changed, certainty) = match result { Ok(result) => result, Err(NoSolution) => { - errors.push(fulfillment_error_for_no_solution(infcx, obligation)); + errors.push(E::from_solver_error( + infcx, + NextSolverError::TrueError(obligation), + )); continue; } }; @@ -195,6 +204,28 @@ impl<'tcx> TraitEngine<'tcx> for FulfillmentCtxt<'tcx> { } } +pub enum NextSolverError<'tcx> { + TrueError(PredicateObligation<'tcx>), + Ambiguity(PredicateObligation<'tcx>), + Overflow(PredicateObligation<'tcx>), +} + +impl<'tcx> FromSolverError<'tcx, NextSolverError<'tcx>> for FulfillmentError<'tcx> { + fn from_solver_error(infcx: &InferCtxt<'tcx>, error: NextSolverError<'tcx>) -> Self { + match error { + NextSolverError::TrueError(obligation) => { + fulfillment_error_for_no_solution(infcx, obligation) + } + NextSolverError::Ambiguity(obligation) => { + fulfillment_error_for_stalled(infcx, obligation) + } + NextSolverError::Overflow(obligation) => { + fulfillment_error_for_overflow(infcx, obligation) + } + } + } +} + fn fulfillment_error_for_no_solution<'tcx>( infcx: &InferCtxt<'tcx>, root_obligation: PredicateObligation<'tcx>, @@ -280,6 +311,17 @@ fn fulfillment_error_for_stalled<'tcx>( } } +fn fulfillment_error_for_overflow<'tcx>( + infcx: &InferCtxt<'tcx>, + root_obligation: PredicateObligation<'tcx>, +) -> FulfillmentError<'tcx> { + FulfillmentError { + obligation: find_best_leaf_obligation(infcx, &root_obligation, true), + code: FulfillmentErrorCode::Ambiguity { overflow: Some(true) }, + root_obligation, + } +} + fn find_best_leaf_obligation<'tcx>( infcx: &InferCtxt<'tcx>, obligation: &PredicateObligation<'tcx>, diff --git a/compiler/rustc_trait_selection/src/solve/mod.rs b/compiler/rustc_trait_selection/src/solve/mod.rs index f9febd290fe72..ffeafd0e89f6d 100644 --- a/compiler/rustc_trait_selection/src/solve/mod.rs +++ b/compiler/rustc_trait_selection/src/solve/mod.rs @@ -40,7 +40,7 @@ mod search_graph; mod trait_goals; pub use eval_ctxt::{EvalCtxt, GenerateProofTree, InferCtxtEvalExt, InferCtxtSelectExt}; -pub use fulfill::FulfillmentCtxt; +pub use fulfill::{FulfillmentCtxt, NextSolverError}; pub(crate) use normalize::deeply_normalize_for_diagnostics; pub use normalize::{deeply_normalize, deeply_normalize_with_skipped_universes}; diff --git a/compiler/rustc_trait_selection/src/solve/normalize.rs b/compiler/rustc_trait_selection/src/solve/normalize.rs index 970848544c5ad..f85e5d8746fd6 100644 --- a/compiler/rustc_trait_selection/src/solve/normalize.rs +++ b/compiler/rustc_trait_selection/src/solve/normalize.rs @@ -1,23 +1,29 @@ +use std::marker::PhantomData; + use crate::traits::error_reporting::{OverflowCause, TypeErrCtxtExt}; use crate::traits::query::evaluate_obligation::InferCtxtExt; -use crate::traits::{BoundVarReplacer, PlaceholderReplacer}; +use crate::traits::{BoundVarReplacer, FulfillmentError, PlaceholderReplacer}; use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_infer::infer::at::At; use rustc_infer::infer::InferCtxt; -use rustc_infer::traits::{FulfillmentError, Obligation, TraitEngine}; +use rustc_infer::traits::{FromSolverError, FulfillmentErrorLike, Obligation, TraitEngine}; use rustc_middle::traits::ObligationCause; use rustc_middle::ty::{self, Ty, TyCtxt, UniverseIndex}; use rustc_middle::ty::{FallibleTypeFolder, TypeFolder, TypeSuperFoldable}; use rustc_middle::ty::{TypeFoldable, TypeVisitableExt}; -use super::FulfillmentCtxt; +use super::{FulfillmentCtxt, NextSolverError}; /// 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, T: TypeFoldable>>( +pub fn deeply_normalize< + 'tcx, + T: TypeFoldable>, + E: FromSolverError<'tcx, NextSolverError<'tcx>>, +>( at: At<'_, 'tcx>, value: T, -) -> Result>> { +) -> Result> { assert!(!value.has_escaping_bound_vars()); deeply_normalize_with_skipped_universes(at, value, vec![]) } @@ -28,29 +34,32 @@ pub fn deeply_normalize<'tcx, T: TypeFoldable>>( /// 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>>( +pub fn deeply_normalize_with_skipped_universes< + 'tcx, + T: TypeFoldable>, + E: FromSolverError<'tcx, NextSolverError<'tcx>>, +>( at: At<'_, 'tcx>, value: T, universes: Vec>, -) -> Result>> { +) -> Result> { let fulfill_cx = FulfillmentCtxt::new(at.infcx); - let mut folder = NormalizationFolder { at, fulfill_cx, depth: 0, universes }; + let mut folder = + NormalizationFolder { at, fulfill_cx, depth: 0, universes, _errors: PhantomData }; value.try_fold_with(&mut folder) } -struct NormalizationFolder<'me, 'tcx> { +struct NormalizationFolder<'me, 'tcx, E: FulfillmentErrorLike<'tcx>> { at: At<'me, 'tcx>, - fulfill_cx: FulfillmentCtxt<'tcx>, + fulfill_cx: FulfillmentCtxt<'tcx, E>, depth: usize, universes: Vec>, + _errors: PhantomData, } -impl<'tcx> NormalizationFolder<'_, 'tcx> { - fn normalize_alias_ty( - &mut self, - alias_ty: Ty<'tcx>, - ) -> Result, Vec>> { +impl<'tcx, E: FromSolverError<'tcx, NextSolverError<'tcx>>> NormalizationFolder<'_, 'tcx, E> { + fn normalize_alias_ty(&mut self, alias_ty: Ty<'tcx>) -> Result, Vec> { assert!(matches!(alias_ty.kind(), ty::Alias(..))); let infcx = self.at.infcx; @@ -101,7 +110,7 @@ impl<'tcx> NormalizationFolder<'_, 'tcx> { &mut self, ty: Ty<'tcx>, uv: ty::UnevaluatedConst<'tcx>, - ) -> Result, Vec>> { + ) -> Result, Vec> { let infcx = self.at.infcx; let tcx = infcx.tcx; let recursion_limit = tcx.recursion_limit(); @@ -141,8 +150,10 @@ impl<'tcx> NormalizationFolder<'_, 'tcx> { } } -impl<'tcx> FallibleTypeFolder> for NormalizationFolder<'_, 'tcx> { - type Error = Vec>; +impl<'tcx, E: FromSolverError<'tcx, NextSolverError<'tcx>>> FallibleTypeFolder> + for NormalizationFolder<'_, 'tcx, E> +{ + type Error = Vec; fn interner(&self) -> TyCtxt<'tcx> { self.at.infcx.tcx @@ -242,7 +253,8 @@ impl<'tcx> TypeFolder> for DeeplyNormalizeForDiagnosticsFolder<'_, ty, vec![None; ty.outer_exclusive_binder().as_usize()], ) - .unwrap_or_else(|_| ty.super_fold_with(self)) + // TODO: + .unwrap_or_else(|_: Vec>| ty.super_fold_with(self)) } fn fold_const(&mut self, ct: ty::Const<'tcx>) -> ty::Const<'tcx> { @@ -251,6 +263,7 @@ impl<'tcx> TypeFolder> for DeeplyNormalizeForDiagnosticsFolder<'_, ct, vec![None; ct.outer_exclusive_binder().as_usize()], ) - .unwrap_or_else(|_| ct.super_fold_with(self)) + // TODO: + .unwrap_or_else(|_: Vec>| ct.super_fold_with(self)) } } diff --git a/compiler/rustc_trait_selection/src/traits/coherence.rs b/compiler/rustc_trait_selection/src/traits/coherence.rs index ebdb032dc0e25..33eca1599121b 100644 --- a/compiler/rustc_trait_selection/src/traits/coherence.rs +++ b/compiler/rustc_trait_selection/src/traits/coherence.rs @@ -11,6 +11,7 @@ use crate::solve::{deeply_normalize_for_diagnostics, inspect}; use crate::traits::select::IntercrateAmbiguityCause; use crate::traits::NormalizeExt; use crate::traits::SkipLeakCheck; +use crate::traits::{util, FulfillmentErrorCode}; use crate::traits::{ Obligation, ObligationCause, PredicateObligation, PredicateObligations, SelectionContext, }; @@ -19,7 +20,6 @@ use rustc_errors::{Diag, EmissionGuarantee}; use rustc_hir::def::DefKind; use rustc_hir::def_id::DefId; use rustc_infer::infer::{DefineOpaqueTypes, InferCtxt, TyCtxtInferExt}; -use rustc_infer::traits::{util, FulfillmentErrorCode}; use rustc_middle::bug; use rustc_middle::traits::query::NoSolution; use rustc_middle::traits::solve::{CandidateSource, Certainty, Goal}; diff --git a/compiler/rustc_trait_selection/src/traits/engine.rs b/compiler/rustc_trait_selection/src/traits/engine.rs index 6fed24c49e0b1..b62cd345e510f 100644 --- a/compiler/rustc_trait_selection/src/traits/engine.rs +++ b/compiler/rustc_trait_selection/src/traits/engine.rs @@ -2,12 +2,15 @@ use std::cell::RefCell; use std::fmt::Debug; use super::FulfillmentContext; -use super::TraitEngine; +use super::{FromSolverError, TraitEngine}; use crate::regions::InferCtxtRegionExt; use crate::solve::FulfillmentCtxt as NextFulfillmentCtxt; +use crate::solve::NextSolverError; use crate::traits::error_reporting::TypeErrCtxtExt; +use crate::traits::fulfill::OldSolverError; use crate::traits::NormalizeExt; use crate::traits::StructurallyNormalizeExt; +use crate::traits::{FulfillmentError, Obligation, ObligationCause, PredicateObligation}; use rustc_data_structures::fx::FxIndexSet; use rustc_errors::ErrorGuaranteed; use rustc_hir::def_id::{DefId, LocalDefId}; @@ -18,7 +21,6 @@ use rustc_infer::infer::canonical::{ use rustc_infer::infer::outlives::env::OutlivesEnvironment; use rustc_infer::infer::RegionResolutionError; use rustc_infer::infer::{DefineOpaqueTypes, InferCtxt, InferOk}; -use rustc_infer::traits::{FulfillmentError, Obligation, ObligationCause, PredicateObligation}; use rustc_macros::extension; use rustc_middle::arena::ArenaAllocatable; use rustc_middle::traits::query::NoSolution; @@ -28,8 +30,12 @@ use rustc_middle::ty::Upcast; use rustc_middle::ty::Variance; use rustc_middle::ty::{self, Ty, TyCtxt}; -#[extension(pub trait TraitEngineExt<'tcx>)] -impl<'tcx> dyn TraitEngine<'tcx> { +#[extension(pub trait TraitEngineExt<'tcx, E>)] +impl< + 'tcx, + E: FromSolverError<'tcx, NextSolverError<'tcx>> + FromSolverError<'tcx, OldSolverError<'tcx>>, +> dyn TraitEngine<'tcx, E> +{ fn new(infcx: &InferCtxt<'tcx>) -> Box { if infcx.next_trait_solver() { Box::new(NextFulfillmentCtxt::new(infcx)) @@ -49,12 +55,16 @@ impl<'tcx> dyn TraitEngine<'tcx> { /// with obligations outside of hir or mir typeck. pub struct ObligationCtxt<'a, 'tcx> { pub infcx: &'a InferCtxt<'tcx>, - engine: RefCell>>, + engine: RefCell>>>, } impl<'a, 'tcx> ObligationCtxt<'a, 'tcx> { pub fn new(infcx: &'a InferCtxt<'tcx>) -> Self { - Self { infcx, engine: RefCell::new(>::new(infcx)) } + // TODO: + Self { + infcx, + engine: RefCell::new(>>::new(infcx)), + } } pub fn register_obligation(&self, obligation: PredicateObligation<'tcx>) { diff --git a/compiler/rustc_trait_selection/src/traits/fulfill.rs b/compiler/rustc_trait_selection/src/traits/fulfill.rs index e1afc2a35293a..09fe0196fcfc9 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::ProcessResult; 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::ProjectionCacheKey; +use rustc_infer::traits::{FromSolverError, FulfillmentErrorLike, ProjectionCacheKey}; use rustc_infer::traits::{PolyTraitObligation, SelectionError, TraitEngine}; use rustc_middle::bug; use rustc_middle::mir::interpret::ErrorHandled; @@ -50,7 +50,7 @@ impl<'tcx> ForestObligation for PendingPredicateObligation<'tcx> { /// 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> { +pub struct FulfillmentContext<'tcx, E: FulfillmentErrorLike<'tcx>> { /// A list of all obligations that have been registered with this /// fulfillment context. predicates: ObligationForest>, @@ -60,6 +60,8 @@ pub struct FulfillmentContext<'tcx> { /// gets rolled back. Because of this we explicitly check that we only /// use the context in exactly this snapshot. usable_in_snapshot: usize, + + _errors: PhantomData, } #[derive(Clone, Debug)] @@ -76,9 +78,9 @@ pub struct PendingPredicateObligation<'tcx> { #[cfg(target_pointer_width = "64")] rustc_data_structures::static_assert_size!(PendingPredicateObligation<'_>, 72); -impl<'tcx> FulfillmentContext<'tcx> { +impl<'tcx, E: FromSolverError<'tcx, OldSolverError<'tcx>>> FulfillmentContext<'tcx, E> { /// Creates a new fulfillment context. - pub(super) fn new(infcx: &InferCtxt<'tcx>) -> FulfillmentContext<'tcx> { + pub(super) fn new(infcx: &InferCtxt<'tcx>) -> FulfillmentContext<'tcx, E> { assert!( !infcx.next_trait_solver(), "old trait solver fulfillment context created when \ @@ -87,13 +89,15 @@ impl<'tcx> FulfillmentContext<'tcx> { FulfillmentContext { predicates: ObligationForest::new(), usable_in_snapshot: infcx.num_open_snapshots(), + _errors: PhantomData, } } /// Attempts to select obligations using `selcx`. - fn select(&mut self, selcx: SelectionContext<'_, 'tcx>) -> Vec> { + fn select(&mut self, selcx: SelectionContext<'_, 'tcx>) -> Vec { let span = debug_span!("select", obligation_forest_size = ?self.predicates.len()); let _enter = span.enter(); + let infcx = selcx.infcx; // Process pending obligations. let outcome: Outcome<_, _> = @@ -102,8 +106,8 @@ impl<'tcx> FulfillmentContext<'tcx> { // 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(to_fulfillment_error).collect(); + let errors: Vec = + outcome.errors.into_iter().map(|err| E::from_solver_error(infcx, err)).collect(); debug!( "select({} predicates remaining, {} errors) done", @@ -115,7 +119,9 @@ impl<'tcx> FulfillmentContext<'tcx> { } } -impl<'tcx> TraitEngine<'tcx> for FulfillmentContext<'tcx> { +impl<'tcx, E: FromSolverError<'tcx, OldSolverError<'tcx>>> TraitEngine<'tcx, E> + for FulfillmentContext<'tcx, E> +{ #[inline] fn register_predicate_obligation( &mut self, @@ -134,18 +140,15 @@ impl<'tcx> TraitEngine<'tcx> for FulfillmentContext<'tcx> { .register_obligation(PendingPredicateObligation { obligation, stalled_on: vec![] }); } - fn collect_remaining_errors( - &mut self, - _infcx: &InferCtxt<'tcx>, - ) -> Vec> { + fn collect_remaining_errors(&mut self, infcx: &InferCtxt<'tcx>) -> Vec { self.predicates .to_errors(FulfillmentErrorCode::Ambiguity { overflow: None }) .into_iter() - .map(to_fulfillment_error) + .map(|err| E::from_solver_error(infcx, err)) .collect() } - fn select_where_possible(&mut self, infcx: &InferCtxt<'tcx>) -> Vec> { + fn select_where_possible(&mut self, infcx: &InferCtxt<'tcx>) -> Vec { let selcx = SelectionContext::new(infcx); self.select(selcx) } @@ -840,13 +843,15 @@ fn args_infer_vars<'a, 'tcx>( .filter_map(TyOrConstInferVar::maybe_from_generic_arg) } -fn to_fulfillment_error<'tcx>( - error: Error, FulfillmentErrorCode<'tcx>>, -) -> FulfillmentError<'tcx> { - let mut iter = error.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) +pub type 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 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) + } } diff --git a/compiler/rustc_trait_selection/src/traits/misc.rs b/compiler/rustc_trait_selection/src/traits/misc.rs index a1094d982768b..8b4594926474f 100644 --- a/compiler/rustc_trait_selection/src/traits/misc.rs +++ b/compiler/rustc_trait_selection/src/traits/misc.rs @@ -1,13 +1,13 @@ //! Miscellaneous type-system utilities that are too small to deserve their own modules. use crate::regions::InferCtxtRegionExt; -use crate::traits::{self, ObligationCause}; +use crate::traits::{self, FulfillmentError, ObligationCause}; use hir::LangItem; 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_infer::{infer::outlives::env::OutlivesEnvironment, traits::FulfillmentError}; use rustc_middle::ty::{self, AdtDef, Ty, TyCtxt, TypeVisitableExt}; use super::outlives_bounds::InferCtxtExt; diff --git a/compiler/rustc_trait_selection/src/traits/mod.rs b/compiler/rustc_trait_selection/src/traits/mod.rs index ab4d06f266038..a047f6c9edbc3 100644 --- a/compiler/rustc_trait_selection/src/traits/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/mod.rs @@ -73,6 +73,49 @@ pub use self::util::{with_replaced_escaping_bound_vars, BoundVarReplacer, Placeh pub use rustc_infer::traits::*; +pub struct FulfillmentError<'tcx> { + pub obligation: PredicateObligation<'tcx>, + pub code: FulfillmentErrorCode<'tcx>, + /// Diagnostics only: the 'root' obligation which resulted in + /// the failure to process `obligation`. This is the obligation + /// that was initially passed to `register_predicate_obligation` + pub root_obligation: PredicateObligation<'tcx>, +} + +impl<'tcx> FulfillmentError<'tcx> { + pub fn new( + obligation: PredicateObligation<'tcx>, + code: FulfillmentErrorCode<'tcx>, + root_obligation: PredicateObligation<'tcx>, + ) -> FulfillmentError<'tcx> { + FulfillmentError { obligation, code, root_obligation } + } + + pub fn is_true_error(&self) -> bool { + match self.code { + FulfillmentErrorCode::Select(_) + | FulfillmentErrorCode::Project(_) + | FulfillmentErrorCode::Subtype(_, _) + | FulfillmentErrorCode::ConstEquate(_, _) => true, + FulfillmentErrorCode::Cycle(_) | FulfillmentErrorCode::Ambiguity { overflow: _ } => { + false + } + } + } +} + +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) + } +} + /// Whether to skip the leak check, as part of a future compatibility warning step. /// /// The "default" for skip-leak-check corresponds to the current diff --git a/compiler/rustc_trait_selection/src/traits/normalize.rs b/compiler/rustc_trait_selection/src/traits/normalize.rs index d10aee2d4e29e..4e5ca2ee92e1c 100644 --- a/compiler/rustc_trait_selection/src/traits/normalize.rs +++ b/compiler/rustc_trait_selection/src/traits/normalize.rs @@ -3,11 +3,13 @@ use super::error_reporting::OverflowCause; use super::error_reporting::TypeErrCtxtExt; use super::SelectionContext; use super::{project, with_replaced_escaping_bound_vars, BoundVarReplacer, PlaceholderReplacer}; +use crate::solve::NextSolverError; use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_infer::infer::at::At; use rustc_infer::infer::InferOk; +use rustc_infer::traits::FromSolverError; use rustc_infer::traits::PredicateObligation; -use rustc_infer::traits::{FulfillmentError, Normalized, Obligation, TraitEngine}; +use rustc_infer::traits::{Normalized, Obligation, TraitEngine}; use rustc_macros::extension; use rustc_middle::traits::{ObligationCause, ObligationCauseCode, Reveal}; use rustc_middle::ty::{self, Ty, TyCtxt, TypeFolder}; @@ -44,11 +46,14 @@ impl<'tcx> At<'_, 'tcx> { /// 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>>( + fn deeply_normalize< + T: TypeFoldable>, + E: FromSolverError<'tcx, NextSolverError<'tcx>>, + >( self, value: T, - fulfill_cx: &mut dyn TraitEngine<'tcx>, - ) -> Result>> { + fulfill_cx: &mut dyn TraitEngine<'tcx, E>, + ) -> Result> { if self.infcx.next_trait_solver() { crate::solve::deeply_normalize(self, value) } else { diff --git a/compiler/rustc_trait_selection/src/traits/query/normalize.rs b/compiler/rustc_trait_selection/src/traits/query/normalize.rs index 1b5ffeebc01f8..2c0103e40dff2 100644 --- a/compiler/rustc_trait_selection/src/traits/query/normalize.rs +++ b/compiler/rustc_trait_selection/src/traits/query/normalize.rs @@ -9,10 +9,10 @@ use crate::traits::error_reporting::OverflowCause; use crate::traits::error_reporting::TypeErrCtxtExt; use crate::traits::normalize::needs_normalization; use crate::traits::{BoundVarReplacer, PlaceholderReplacer}; +use crate::traits::{FulfillmentError, Normalized}; use crate::traits::{ObligationCause, PredicateObligation, Reveal}; use rustc_data_structures::sso::SsoHashMap; use rustc_data_structures::stack::ensure_sufficient_stack; -use rustc_infer::traits::Normalized; use rustc_macros::extension; use rustc_middle::ty::fold::{FallibleTypeFolder, TypeFoldable, TypeSuperFoldable}; use rustc_middle::ty::visit::{TypeSuperVisitable, TypeVisitable, TypeVisitableExt}; @@ -76,7 +76,10 @@ impl<'cx, 'tcx> At<'cx, 'tcx> { }; if self.infcx.next_trait_solver() { - match crate::solve::deeply_normalize_with_skipped_universes(self, value, universes) { + // TODO: + match crate::solve::deeply_normalize_with_skipped_universes::<_, FulfillmentError<'tcx>>( + self, value, universes, + ) { Ok(value) => return Ok(Normalized { value, obligations: vec![] }), Err(_errors) => { return Err(NoSolution); 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 00cc77e71e72a..a1bbd21f82961 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,6 +1,7 @@ use crate::solve; use crate::traits::query::NoSolution; use crate::traits::wf; +use crate::traits::FulfillmentError; use crate::traits::ObligationCtxt; use rustc_infer::infer::canonical::Canonical; @@ -266,7 +267,8 @@ pub fn compute_implied_outlives_bounds_compat_inner<'tcx>( ocx.infcx.at(&ObligationCause::dummy(), param_env), ty_a, ) - .map_err(|_errs| NoSolution)?; + // TODO: + .map_err(|_errs: Vec>| 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 96a06e0c16918..a160fc033a2cc 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::{FulfillmentError, TraitEngine}; +use rustc_infer::traits::{FulfillmentErrorLike, TraitEngine}; use rustc_macros::extension; use rustc_middle::ty::{self, Ty}; @@ -7,11 +7,11 @@ use crate::traits::{NormalizeExt, Obligation}; #[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>, - ) -> Result, Vec>> { + fulfill_cx: &mut dyn TraitEngine<'tcx, E>, + ) -> Result, Vec> { assert!(!ty.is_ty_var(), "should have resolved vars before calling"); if self.infcx.next_trait_solver() { From 05d17ac3c8ef0f951756c5ab193bb112b939e009 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Sat, 1 Jun 2024 14:51:31 -0400 Subject: [PATCH 3/5] Opt-in diagnostics reporting to avoid doing extra work in the new solver --- .../src/diagnostics/conflict_errors.rs | 2 +- .../src/region_infer/opaque_types.rs | 2 +- .../src/check_consts/check.rs | 2 +- .../rustc_hir_analysis/src/check/check.rs | 4 +- .../src/check/compare_impl_item.rs | 31 +++-- .../rustc_hir_analysis/src/check/dropck.rs | 2 +- .../rustc_hir_analysis/src/check/entry.rs | 2 +- compiler/rustc_hir_analysis/src/check/mod.rs | 2 +- .../rustc_hir_analysis/src/check/wfcheck.rs | 8 +- .../src/coherence/builtin.rs | 4 +- .../src/hir_ty_lowering/mod.rs | 2 +- .../rustc_hir_analysis/src/hir_wf_check.rs | 2 +- .../src/impl_wf_check/min_specialization.rs | 2 +- compiler/rustc_hir_typeck/src/expr.rs | 2 +- compiler/rustc_hir_typeck/src/method/probe.rs | 2 +- compiler/rustc_hir_typeck/src/op.rs | 2 +- compiler/rustc_mir_transform/src/coroutine.rs | 2 +- compiler/rustc_passes/src/check_attr.rs | 2 +- compiler/rustc_passes/src/layout_test.rs | 2 +- compiler/rustc_trait_selection/src/infer.rs | 18 +-- .../src/solve/fulfill.rs | 13 +- .../src/solve/inspect/analyse.rs | 1 + .../src/traits/coherence.rs | 2 +- .../src/traits/engine.rs | 114 +++++++++++------- .../src/traits/fulfill.rs | 16 ++- .../rustc_trait_selection/src/traits/misc.rs | 2 +- .../rustc_trait_selection/src/traits/mod.rs | 26 +++- compiler/rustc_traits/src/codegen.rs | 3 +- .../src/normalize_projection_ty.rs | 9 +- compiler/rustc_traits/src/type_op.rs | 22 ++-- .../clippy_lints/src/future_not_send.rs | 2 +- 31 files changed, 199 insertions(+), 106 deletions(-) diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs index 7c60d3b4bd876..762a0d19f164a 100644 --- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs @@ -1347,7 +1347,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { return; }; // Try to find predicates on *generic params* that would allow copying `ty` - let ocx = ObligationCtxt::new(self.infcx); + let ocx = ObligationCtxt::new_with_diagnostics(self.infcx); let cause = ObligationCause::misc(span, self.mir_def_id()); ocx.register_bound(cause, self.param_env, ty, def_id); diff --git a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs index f601a9d70739f..06adb686ed48e 100644 --- a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs +++ b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs @@ -340,7 +340,7 @@ fn check_opaque_type_well_formed<'tcx>( .with_next_trait_solver(next_trait_solver) .with_opaque_type_inference(parent_def_id) .build(); - let ocx = ObligationCtxt::new(&infcx); + let ocx = ObligationCtxt::new_with_diagnostics(&infcx); let identity_args = GenericArgs::identity_for_item(tcx, def_id); // Require that the hidden type actually fulfills all the bounds of the opaque type, even without diff --git a/compiler/rustc_const_eval/src/check_consts/check.rs b/compiler/rustc_const_eval/src/check_consts/check.rs index 5fbf5b41109f1..9e01c59a96f9f 100644 --- a/compiler/rustc_const_eval/src/check_consts/check.rs +++ b/compiler/rustc_const_eval/src/check_consts/check.rs @@ -735,7 +735,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> { // which path expressions are getting called on and which path expressions are only used // as function pointers. This is required for correctness. let infcx = tcx.infer_ctxt().build(); - let ocx = ObligationCtxt::new(&infcx); + let ocx = ObligationCtxt::new_with_diagnostics(&infcx); let predicates = tcx.predicates_of(callee).instantiate(tcx, fn_args); let cause = ObligationCause::new( diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs index 3904f14b0f6ea..76b6cbd6e5310 100644 --- a/compiler/rustc_hir_analysis/src/check/check.rs +++ b/compiler/rustc_hir_analysis/src/check/check.rs @@ -342,7 +342,7 @@ fn check_opaque_meets_bounds<'tcx>( let param_env = tcx.param_env(defining_use_anchor); let infcx = tcx.infer_ctxt().with_opaque_type_inference(defining_use_anchor).build(); - let ocx = ObligationCtxt::new(&infcx); + let ocx = ObligationCtxt::new_with_diagnostics(&infcx); let args = match *origin { hir::OpaqueTyOrigin::FnReturn(parent) @@ -1727,7 +1727,7 @@ pub(super) fn check_coroutine_obligations( .with_opaque_type_inference(def_id) .build(); - let ocx = ObligationCtxt::new(&infcx); + let ocx = ObligationCtxt::new_with_diagnostics(&infcx); for (predicate, cause) in &typeck_results.coroutine_stalled_predicates { ocx.register_obligation(Obligation::new(tcx, cause.clone(), param_env, *predicate)); } 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 17db1c07383f9..594d28eda7ac9 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::intravisit; use rustc_hir::{GenericParamKind, ImplItemKind}; use rustc_infer::infer::outlives::env::OutlivesEnvironment; use rustc_infer::infer::{self, InferCtxt, TyCtxtInferExt}; -use rustc_infer::traits::util; +use rustc_infer::traits::{util, FulfillmentErrorLike}; use rustc_middle::ty::error::{ExpectedFound, TypeError}; use rustc_middle::ty::fold::BottomUpFolder; use rustc_middle::ty::util::ExplicitSelf; @@ -225,7 +225,7 @@ fn compare_method_predicate_entailment<'tcx>( let param_env = traits::normalize_param_env_or_error(tcx, param_env, normalize_cause); let infcx = &tcx.infer_ctxt().build(); - let ocx = ObligationCtxt::new(infcx); + let ocx = ObligationCtxt::new_with_diagnostics(infcx); debug!("compare_impl_method: caller_bounds={:?}", param_env.caller_bounds()); @@ -493,7 +493,7 @@ pub(super) fn collect_return_position_impl_trait_in_trait_tys<'tcx>( ); let infcx = &tcx.infer_ctxt().build(); - let ocx = ObligationCtxt::new(infcx); + let ocx = ObligationCtxt::new_with_diagnostics(infcx); // Normalize the impl signature with fresh variables for lifetime inference. let misc_cause = ObligationCause::misc(return_span, impl_m_def_id); @@ -764,17 +764,23 @@ pub(super) fn collect_return_position_impl_trait_in_trait_tys<'tcx>( Ok(&*tcx.arena.alloc(remapped_types)) } -struct ImplTraitInTraitCollector<'a, 'tcx> { - ocx: &'a ObligationCtxt<'a, 'tcx>, +struct ImplTraitInTraitCollector<'a, 'tcx, E> +where + E: FulfillmentErrorLike<'tcx>, +{ + ocx: &'a ObligationCtxt<'a, 'tcx, E>, types: FxIndexMap, ty::GenericArgsRef<'tcx>)>, span: Span, param_env: ty::ParamEnv<'tcx>, body_id: LocalDefId, } -impl<'a, 'tcx> ImplTraitInTraitCollector<'a, 'tcx> { +impl<'a, 'tcx, E> ImplTraitInTraitCollector<'a, 'tcx, E> +where + E: FulfillmentErrorLike<'tcx>, +{ fn new( - ocx: &'a ObligationCtxt<'a, 'tcx>, + ocx: &'a ObligationCtxt<'a, 'tcx, E>, span: Span, param_env: ty::ParamEnv<'tcx>, body_id: LocalDefId, @@ -783,7 +789,10 @@ impl<'a, 'tcx> ImplTraitInTraitCollector<'a, 'tcx> { } } -impl<'tcx> TypeFolder> for ImplTraitInTraitCollector<'_, 'tcx> { +impl<'tcx, E> TypeFolder> for ImplTraitInTraitCollector<'_, 'tcx, E> +where + E: FulfillmentErrorLike<'tcx>, +{ fn interner(&self) -> TyCtxt<'tcx> { self.ocx.infcx.tcx } @@ -1777,7 +1786,7 @@ fn compare_const_predicate_entailment<'tcx>( ); let infcx = tcx.infer_ctxt().build(); - let ocx = ObligationCtxt::new(&infcx); + let ocx = ObligationCtxt::new_with_diagnostics(&infcx); let impl_ct_own_bounds = impl_ct_predicates.instantiate_own(tcx, impl_args); for (predicate, span) in impl_ct_own_bounds { @@ -1910,7 +1919,7 @@ fn compare_type_predicate_entailment<'tcx>( let param_env = ty::ParamEnv::new(tcx.mk_clauses(&hybrid_preds.predicates), Reveal::UserFacing); let param_env = traits::normalize_param_env_or_error(tcx, param_env, normalize_cause); let infcx = tcx.infer_ctxt().build(); - let ocx = ObligationCtxt::new(&infcx); + let ocx = ObligationCtxt::new_with_diagnostics(&infcx); debug!("compare_type_predicate_entailment: caller_bounds={:?}", param_env.caller_bounds()); @@ -1977,7 +1986,7 @@ pub(super) fn check_type_bounds<'tcx>( let rebased_args = impl_ty_args.rebase_onto(tcx, container_id, impl_trait_ref.args); let infcx = tcx.infer_ctxt().build(); - let ocx = ObligationCtxt::new(&infcx); + let ocx = ObligationCtxt::new_with_diagnostics(&infcx); // A synthetic impl Trait for RPITIT desugaring has no HIR, which we currently use to get the // span for an impl's associated type. Instead, for these, use the def_span for the synthesized diff --git a/compiler/rustc_hir_analysis/src/check/dropck.rs b/compiler/rustc_hir_analysis/src/check/dropck.rs index be412dde96803..8ec6dd12a78db 100644 --- a/compiler/rustc_hir_analysis/src/check/dropck.rs +++ b/compiler/rustc_hir_analysis/src/check/dropck.rs @@ -123,7 +123,7 @@ fn ensure_drop_predicates_are_implied_by_item_defn<'tcx>( adt_to_impl_args: GenericArgsRef<'tcx>, ) -> Result<(), ErrorGuaranteed> { let infcx = tcx.infer_ctxt().build(); - let ocx = ObligationCtxt::new(&infcx); + let ocx = ObligationCtxt::new_with_diagnostics(&infcx); // Take the param-env of the adt and instantiate the args that show up in // the implementation's self type. This gives us the assumptions that the diff --git a/compiler/rustc_hir_analysis/src/check/entry.rs b/compiler/rustc_hir_analysis/src/check/entry.rs index 25ac31c16c7cf..cc52a7658020f 100644 --- a/compiler/rustc_hir_analysis/src/check/entry.rs +++ b/compiler/rustc_hir_analysis/src/check/entry.rs @@ -133,7 +133,7 @@ fn check_main_fn_ty(tcx: TyCtxt<'_>, main_def_id: DefId) { main_diagnostics_def_id, ObligationCauseCode::MainFunctionType, ); - let ocx = traits::ObligationCtxt::new(&infcx); + let ocx = traits::ObligationCtxt::new_with_diagnostics(&infcx); let norm_return_ty = ocx.normalize(&cause, param_env, return_ty); ocx.register_bound(cause, param_env, norm_return_ty, term_did); let errors = ocx.select_all_or_error(); diff --git a/compiler/rustc_hir_analysis/src/check/mod.rs b/compiler/rustc_hir_analysis/src/check/mod.rs index 149e7737e3090..da66e1f34fd97 100644 --- a/compiler/rustc_hir_analysis/src/check/mod.rs +++ b/compiler/rustc_hir_analysis/src/check/mod.rs @@ -599,7 +599,7 @@ pub fn check_function_signature<'tcx>( let param_env = ty::ParamEnv::empty(); let infcx = &tcx.infer_ctxt().build(); - let ocx = ObligationCtxt::new(infcx); + let ocx = ObligationCtxt::new_with_diagnostics(infcx); let actual_sig = tcx.fn_sig(fn_id).instantiate_identity(); diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs index 81e3d8c7ece28..750e558be7c9a 100644 --- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs +++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs @@ -37,7 +37,7 @@ use rustc_trait_selection::traits::misc::{ use rustc_trait_selection::traits::outlives_bounds::InferCtxtExt as _; use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt as _; use rustc_trait_selection::traits::{ - self, ObligationCause, ObligationCauseCode, ObligationCtxt, WellFormedLoc, + self, FulfillmentError, ObligationCause, ObligationCauseCode, ObligationCtxt, WellFormedLoc, }; use rustc_type_ir::TypeFlags; @@ -45,13 +45,13 @@ use std::cell::LazyCell; use std::ops::{ControlFlow, Deref}; pub(super) struct WfCheckingCtxt<'a, 'tcx> { - pub(super) ocx: ObligationCtxt<'a, 'tcx>, + pub(super) ocx: ObligationCtxt<'a, 'tcx, FulfillmentError<'tcx>>, span: Span, body_def_id: LocalDefId, param_env: ty::ParamEnv<'tcx>, } impl<'a, 'tcx> Deref for WfCheckingCtxt<'a, 'tcx> { - type Target = ObligationCtxt<'a, 'tcx>; + type Target = ObligationCtxt<'a, 'tcx, FulfillmentError<'tcx>>; fn deref(&self) -> &Self::Target { &self.ocx } @@ -106,7 +106,7 @@ where { let param_env = tcx.param_env(body_def_id); let infcx = &tcx.infer_ctxt().build(); - let ocx = ObligationCtxt::new(infcx); + let ocx = ObligationCtxt::new_with_diagnostics(infcx); let mut wfcx = WfCheckingCtxt { ocx, span, body_def_id, param_env }; diff --git a/compiler/rustc_hir_analysis/src/coherence/builtin.rs b/compiler/rustc_hir_analysis/src/coherence/builtin.rs index 8f0aba1c38c1d..881f5aec1bcdc 100644 --- a/compiler/rustc_hir_analysis/src/coherence/builtin.rs +++ b/compiler/rustc_hir_analysis/src/coherence/builtin.rs @@ -267,7 +267,7 @@ fn visit_implementation_of_dispatch_from_dyn(checker: &Checker<'_>) -> Result<() .join(", "), })); } else { - let ocx = ObligationCtxt::new(&infcx); + let ocx = ObligationCtxt::new_with_diagnostics(&infcx); for field in coerced_fields { ocx.register_obligation(Obligation::new( tcx, @@ -480,7 +480,7 @@ pub fn coerce_unsized_info<'tcx>( }; // Register an obligation for `A: Trait`. - let ocx = ObligationCtxt::new(&infcx); + let ocx = ObligationCtxt::new_with_diagnostics(&infcx); let cause = traits::ObligationCause::misc(span, impl_did); let obligation = Obligation::new( tcx, diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs index 54b7f7f36ed2e..e385716fbfb02 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs @@ -1298,7 +1298,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { .copied() .filter(|&(impl_, _)| { infcx.probe(|_| { - let ocx = ObligationCtxt::new(infcx); + let ocx = ObligationCtxt::new_with_diagnostics(infcx); let self_ty = ocx.normalize(&ObligationCause::dummy(), param_env, self_ty); let impl_args = infcx.fresh_args_for_item(span, impl_); diff --git a/compiler/rustc_hir_analysis/src/hir_wf_check.rs b/compiler/rustc_hir_analysis/src/hir_wf_check.rs index 10101aa046e50..3e15fddf559f3 100644 --- a/compiler/rustc_hir_analysis/src/hir_wf_check.rs +++ b/compiler/rustc_hir_analysis/src/hir_wf_check.rs @@ -67,7 +67,7 @@ fn diagnostic_hir_wf_check<'tcx>( impl<'tcx> Visitor<'tcx> for HirWfCheck<'tcx> { fn visit_ty(&mut self, ty: &'tcx hir::Ty<'tcx>) { let infcx = self.tcx.infer_ctxt().build(); - let ocx = ObligationCtxt::new(&infcx); + let ocx = ObligationCtxt::new_with_diagnostics(&infcx); let tcx_ty = self.icx.lower_ty(ty); // This visitor can walk into binders, resulting in the `tcx_ty` to diff --git a/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs b/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs index 6967cb4d9d0b9..f3ce3ab66553e 100644 --- a/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs +++ b/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs @@ -196,7 +196,7 @@ fn get_impl_args( impl2_node: Node, ) -> Result<(GenericArgsRef<'_>, GenericArgsRef<'_>), ErrorGuaranteed> { let infcx = &tcx.infer_ctxt().build(); - let ocx = ObligationCtxt::new(infcx); + let ocx = ObligationCtxt::new_with_diagnostics(infcx); let param_env = tcx.param_env(impl1_def_id); let impl1_span = tcx.def_span(impl1_def_id); let assumed_wf_types = ocx.assumed_wf_types_and_report_errors(param_env, impl1_def_id)?; diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs index 061d9507a35c7..641f9f386c6ef 100644 --- a/compiler/rustc_hir_typeck/src/expr.rs +++ b/compiler/rustc_hir_typeck/src/expr.rs @@ -3048,7 +3048,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.commit_if_ok(|snapshot| { let outer_universe = self.universe(); - let ocx = ObligationCtxt::new(self); + let ocx = ObligationCtxt::new_with_diagnostics(self); let impl_args = self.fresh_args_for_item(base_expr.span, impl_def_id); let impl_trait_ref = self.tcx.impl_trait_ref(impl_def_id).unwrap().instantiate(self.tcx, impl_args); diff --git a/compiler/rustc_hir_typeck/src/method/probe.rs b/compiler/rustc_hir_typeck/src/method/probe.rs index 97a74b55c5357..12ced49f92ff7 100644 --- a/compiler/rustc_hir_typeck/src/method/probe.rs +++ b/compiler/rustc_hir_typeck/src/method/probe.rs @@ -1390,7 +1390,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { let mut result = ProbeResult::Match; let cause = &self.misc(self.span); - let ocx = ObligationCtxt::new(self); + let ocx = ObligationCtxt::new_with_diagnostics(self); let mut trait_predicate = None; let (mut xform_self_ty, mut xform_ret_ty); diff --git a/compiler/rustc_hir_typeck/src/op.rs b/compiler/rustc_hir_typeck/src/op.rs index 25b74dca12fc5..d774ae2146aa0 100644 --- a/compiler/rustc_hir_typeck/src/op.rs +++ b/compiler/rustc_hir_typeck/src/op.rs @@ -928,7 +928,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let (obligation, _) = self.obligation_for_method(cause, trait_did, lhs_ty, Some(input_types)); // FIXME: This should potentially just add the obligation to the `FnCtxt` - let ocx = ObligationCtxt::new(&self.infcx); + let ocx = ObligationCtxt::new_with_diagnostics(&self.infcx); ocx.register_obligation(obligation); Err(ocx.select_all_or_error()) } diff --git a/compiler/rustc_mir_transform/src/coroutine.rs b/compiler/rustc_mir_transform/src/coroutine.rs index a3e6e5a5a915c..8827ed78be712 100644 --- a/compiler/rustc_mir_transform/src/coroutine.rs +++ b/compiler/rustc_mir_transform/src/coroutine.rs @@ -1608,7 +1608,7 @@ fn check_field_tys_sized<'tcx>( let infcx = tcx.infer_ctxt().ignoring_regions().build(); let param_env = tcx.param_env(def_id); - let ocx = ObligationCtxt::new(&infcx); + let ocx = ObligationCtxt::new_with_diagnostics(&infcx); for field_ty in &coroutine_layout.field_tys { ocx.register_bound( ObligationCause::new( diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index 4fe84b91b8b16..39cb48c1af3aa 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -2321,7 +2321,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { let param_env = ty::ParamEnv::empty(); let infcx = tcx.infer_ctxt().build(); - let ocx = ObligationCtxt::new(&infcx); + let ocx = ObligationCtxt::new_with_diagnostics(&infcx); let span = tcx.def_span(def_id); let fresh_args = infcx.fresh_args_for_item(span, def_id.to_def_id()); diff --git a/compiler/rustc_passes/src/layout_test.rs b/compiler/rustc_passes/src/layout_test.rs index 82d43f078ee27..c9a4765045622 100644 --- a/compiler/rustc_passes/src/layout_test.rs +++ b/compiler/rustc_passes/src/layout_test.rs @@ -54,7 +54,7 @@ pub fn ensure_wf<'tcx>( pred, ); let infcx = tcx.infer_ctxt().build(); - let ocx = traits::ObligationCtxt::new(&infcx); + let ocx = traits::ObligationCtxt::new_with_diagnostics(&infcx); ocx.register_obligation(obligation); let errors = ocx.select_all_or_error(); if !errors.is_empty() { diff --git a/compiler/rustc_trait_selection/src/infer.rs b/compiler/rustc_trait_selection/src/infer.rs index fc852293dff0e..f5d78430c9782 100644 --- a/compiler/rustc_trait_selection/src/infer.rs +++ b/compiler/rustc_trait_selection/src/infer.rs @@ -1,14 +1,16 @@ +use crate::solve::NextSolverError; use crate::traits::query::evaluate_obligation::InferCtxtExt as _; -use crate::traits::{self, ObligationCtxt, SelectionContext}; +use crate::traits::{ + self, FromSolverError, Obligation, ObligationCause, ObligationCtxt, OldSolverError, + SelectionContext, +}; use rustc_hir::def_id::DefId; use rustc_hir::lang_items::LangItem; -use rustc_infer::traits::Obligation; use rustc_macros::extension; use rustc_middle::arena::ArenaAllocatable; use rustc_middle::infer::canonical::{Canonical, CanonicalQueryResponse, QueryResponse}; use rustc_middle::traits::query::NoSolution; -use rustc_middle::traits::ObligationCause; use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable, TypeVisitableExt}; use rustc_middle::ty::{GenericArg, Upcast}; use rustc_span::DUMMY_SP; @@ -94,7 +96,7 @@ impl<'tcx> InferCtxt<'tcx> { ty::TraitRef::new(self.tcx, trait_def_id, [ty]), )) { Ok(Some(selection)) => { - let ocx = ObligationCtxt::new(self); + let ocx = ObligationCtxt::new_with_diagnostics(self); ocx.register_obligations(selection.nested_obligations()); Some(ocx.select_all_or_error()) } @@ -122,19 +124,21 @@ impl<'tcx> InferCtxtBuilder<'tcx> { /// bound for the closure and in part because it is convenient to /// have `'tcx` be free on this function so that we can talk about /// `K: TypeFoldable>`.) - fn enter_canonical_trait_query( + fn enter_canonical_trait_query( self, canonical_key: &Canonical<'tcx, K>, - operation: impl FnOnce(&ObligationCtxt<'_, 'tcx>, K) -> Result, + operation: impl FnOnce(&ObligationCtxt<'_, 'tcx, E>, K) -> Result, ) -> Result, NoSolution> where K: TypeFoldable>, R: Debug + TypeFoldable>, Canonical<'tcx, QueryResponse<'tcx, R>>: ArenaAllocatable<'tcx>, + E: FromSolverError<'tcx, NextSolverError<'tcx>> + + FromSolverError<'tcx, OldSolverError<'tcx>>, { let (infcx, key, canonical_inference_vars) = self.build_with_canonical(DUMMY_SP, canonical_key); - let ocx = ObligationCtxt::new(&infcx); + let ocx = ObligationCtxt::new_generic(&infcx); let value = operation(&ocx, key)?; ocx.make_canonicalized_query_response(canonical_inference_vars, value) } diff --git a/compiler/rustc_trait_selection/src/solve/fulfill.rs b/compiler/rustc_trait_selection/src/solve/fulfill.rs index 040bab1dfae28..d92c903a76ed6 100644 --- a/compiler/rustc_trait_selection/src/solve/fulfill.rs +++ b/compiler/rustc_trait_selection/src/solve/fulfill.rs @@ -15,7 +15,7 @@ use rustc_middle::ty::error::{ExpectedFound, TypeError}; use rustc_middle::ty::{self, TyCtxt}; use rustc_span::symbol::sym; -use crate::traits::FulfillmentError; +use crate::traits::{FulfillmentError, ScrubbedTraitError}; use super::eval_ctxt::GenerateProofTree; use super::inspect::{self, ProofTreeInferCtxtExt, ProofTreeVisitor}; @@ -226,6 +226,17 @@ impl<'tcx> FromSolverError<'tcx, NextSolverError<'tcx>> for FulfillmentError<'tc } } +impl<'tcx> FromSolverError<'tcx, NextSolverError<'tcx>> for ScrubbedTraitError { + fn from_solver_error(_infcx: &InferCtxt<'tcx>, error: NextSolverError<'tcx>) -> Self { + match error { + NextSolverError::TrueError(_) => ScrubbedTraitError::TrueError, + NextSolverError::Ambiguity(_) | NextSolverError::Overflow(_) => { + ScrubbedTraitError::Ambiguity + } + } + } +} + fn fulfillment_error_for_no_solution<'tcx>( infcx: &InferCtxt<'tcx>, root_obligation: PredicateObligation<'tcx>, diff --git a/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs b/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs index 1f27978e5a622..dca14e20fb311 100644 --- a/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs +++ b/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs @@ -12,6 +12,7 @@ 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/traits/coherence.rs b/compiler/rustc_trait_selection/src/traits/coherence.rs index 33eca1599121b..7723f2229bf9e 100644 --- a/compiler/rustc_trait_selection/src/traits/coherence.rs +++ b/compiler/rustc_trait_selection/src/traits/coherence.rs @@ -360,7 +360,7 @@ fn impl_intersection_has_impossible_obligation<'a, 'cx, 'tcx>( let infcx = selcx.infcx; if infcx.next_trait_solver() { - let ocx = ObligationCtxt::new(infcx); + let ocx = ObligationCtxt::new_with_diagnostics(infcx); ocx.register_obligations(obligations.iter().cloned()); let errors_and_ambiguities = ocx.select_all_or_error(); // We only care about the obligations that are *definitely* true errors. diff --git a/compiler/rustc_trait_selection/src/traits/engine.rs b/compiler/rustc_trait_selection/src/traits/engine.rs index b62cd345e510f..333fd4556e3d5 100644 --- a/compiler/rustc_trait_selection/src/traits/engine.rs +++ b/compiler/rustc_trait_selection/src/traits/engine.rs @@ -1,8 +1,8 @@ use std::cell::RefCell; use std::fmt::Debug; -use super::FulfillmentContext; use super::{FromSolverError, TraitEngine}; +use super::{FulfillmentContext, ScrubbedTraitError}; use crate::regions::InferCtxtRegionExt; use crate::solve::FulfillmentCtxt as NextFulfillmentCtxt; use crate::solve::NextSolverError; @@ -21,6 +21,7 @@ use rustc_infer::infer::canonical::{ 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; @@ -53,20 +54,36 @@ impl< /// Used if you want to have pleasant experience when dealing /// with obligations outside of hir or mir typeck. -pub struct ObligationCtxt<'a, 'tcx> { +pub struct ObligationCtxt<'a, 'tcx, E = ScrubbedTraitError> { pub infcx: &'a InferCtxt<'tcx>, - engine: RefCell>>>, + engine: RefCell>>, } -impl<'a, 'tcx> ObligationCtxt<'a, 'tcx> { +impl<'a, 'tcx> ObligationCtxt<'a, 'tcx, FulfillmentError<'tcx>> { + pub fn new_with_diagnostics(infcx: &'a InferCtxt<'tcx>) -> Self { + Self { infcx, engine: RefCell::new(>::new(infcx)) } + } +} + +impl<'a, 'tcx> ObligationCtxt<'a, 'tcx, ScrubbedTraitError> { pub fn new(infcx: &'a InferCtxt<'tcx>) -> Self { - // TODO: - Self { - infcx, - engine: RefCell::new(>>::new(infcx)), - } + Self { infcx, engine: RefCell::new(>::new(infcx)) } + } +} + +impl<'a, 'tcx, E> ObligationCtxt<'a, 'tcx, E> +where + E: FromSolverError<'tcx, NextSolverError<'tcx>> + FromSolverError<'tcx, OldSolverError<'tcx>>, +{ + pub fn new_generic(infcx: &'a InferCtxt<'tcx>) -> Self { + Self { infcx, engine: RefCell::new(>::new(infcx)) } } +} +impl<'a, 'tcx, E> ObligationCtxt<'a, 'tcx, E> +where + E: FulfillmentErrorLike<'tcx>, +{ pub fn register_obligation(&self, obligation: PredicateObligation<'tcx>) { self.engine.borrow_mut().register_predicate_obligation(self.infcx, obligation); } @@ -118,26 +135,6 @@ impl<'a, 'tcx> ObligationCtxt<'a, 'tcx> { self.register_infer_ok_obligations(infer_ok) } - pub fn deeply_normalize>>( - &self, - cause: &ObligationCause<'tcx>, - param_env: ty::ParamEnv<'tcx>, - value: T, - ) -> Result>> { - self.infcx.at(cause, param_env).deeply_normalize(value, &mut **self.engine.borrow_mut()) - } - - pub fn structurally_normalize( - &self, - cause: &ObligationCause<'tcx>, - param_env: ty::ParamEnv<'tcx>, - value: Ty<'tcx>, - ) -> Result, Vec>> { - self.infcx - .at(cause, param_env) - .structurally_normalize(value, &mut **self.engine.borrow_mut()) - } - pub fn eq>( &self, cause: &ObligationCause<'tcx>, @@ -194,12 +191,12 @@ impl<'a, 'tcx> ObligationCtxt<'a, 'tcx> { } #[must_use] - pub fn select_where_possible(&self) -> Vec> { + pub fn select_where_possible(&self) -> Vec { self.engine.borrow_mut().select_where_possible(self.infcx) } #[must_use] - pub fn select_all_or_error(&self) -> Vec> { + pub fn select_all_or_error(&self) -> Vec { self.engine.borrow_mut().select_all_or_error(self.infcx) } @@ -244,6 +241,24 @@ impl<'a, 'tcx> ObligationCtxt<'a, 'tcx> { self.infcx.resolve_regions(outlives_env) } + pub fn make_canonicalized_query_response( + &self, + inference_vars: CanonicalVarValues<'tcx>, + answer: T, + ) -> Result, NoSolution> + where + T: Debug + TypeFoldable>, + Canonical<'tcx, QueryResponse<'tcx, T>>: ArenaAllocatable<'tcx>, + { + self.infcx.make_canonicalized_query_response( + inference_vars, + answer, + &mut **self.engine.borrow_mut(), + ) + } +} + +impl<'tcx> ObligationCtxt<'_, 'tcx, FulfillmentError<'tcx>> { pub fn assumed_wf_types_and_report_errors( &self, param_env: ty::ParamEnv<'tcx>, @@ -252,12 +267,17 @@ impl<'a, 'tcx> ObligationCtxt<'a, 'tcx> { 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>>, +{ pub fn assumed_wf_types( &self, param_env: ty::ParamEnv<'tcx>, def_id: LocalDefId, - ) -> Result>, Vec>> { + ) -> Result>, Vec> { let tcx = self.infcx.tcx; let mut implied_bounds = FxIndexSet::default(); let mut errors = Vec::new(); @@ -289,19 +309,23 @@ impl<'a, 'tcx> ObligationCtxt<'a, 'tcx> { if errors.is_empty() { Ok(implied_bounds) } else { Err(errors) } } - pub fn make_canonicalized_query_response( + pub fn deeply_normalize>>( &self, - inference_vars: CanonicalVarValues<'tcx>, - answer: T, - ) -> Result, NoSolution> - where - T: Debug + TypeFoldable>, - Canonical<'tcx, QueryResponse<'tcx, T>>: ArenaAllocatable<'tcx>, - { - self.infcx.make_canonicalized_query_response( - inference_vars, - answer, - &mut **self.engine.borrow_mut(), - ) + cause: &ObligationCause<'tcx>, + param_env: ty::ParamEnv<'tcx>, + value: T, + ) -> Result> { + self.infcx.at(cause, param_env).deeply_normalize(value, &mut **self.engine.borrow_mut()) + } + + pub fn structurally_normalize( + &self, + cause: &ObligationCause<'tcx>, + param_env: ty::ParamEnv<'tcx>, + value: Ty<'tcx>, + ) -> Result, Vec> { + self.infcx + .at(cause, param_env) + .structurally_normalize(value, &mut **self.engine.borrow_mut()) } } diff --git a/compiler/rustc_trait_selection/src/traits/fulfill.rs b/compiler/rustc_trait_selection/src/traits/fulfill.rs index 09fe0196fcfc9..8746cfa37e2ec 100644 --- a/compiler/rustc_trait_selection/src/traits/fulfill.rs +++ b/compiler/rustc_trait_selection/src/traits/fulfill.rs @@ -16,13 +16,13 @@ use rustc_middle::ty::GenericArgsRef; use rustc_middle::ty::{self, Binder, Const, TypeVisitableExt}; use std::marker::PhantomData; -use super::const_evaluatable; use super::project::{self, ProjectAndUnifyResult}; use super::select::SelectionContext; use super::wf; use super::EvaluationResult; use super::PredicateObligation; use super::Unimplemented; +use super::{const_evaluatable, ScrubbedTraitError}; use super::{FulfillmentError, FulfillmentErrorCode}; use crate::traits::project::PolyProjectionObligation; @@ -855,3 +855,17 @@ impl<'tcx> FromSolverError<'tcx, OldSolverError<'tcx>> for FulfillmentError<'tcx FulfillmentError::new(obligation, error.error, root_obligation) } } + +impl<'tcx> FromSolverError<'tcx, OldSolverError<'tcx>> for ScrubbedTraitError { + fn from_solver_error(_infcx: &InferCtxt<'tcx>, error: OldSolverError<'tcx>) -> Self { + match error.error { + FulfillmentErrorCode::Select(_) + | FulfillmentErrorCode::Project(_) + | FulfillmentErrorCode::Subtype(_, _) + | FulfillmentErrorCode::ConstEquate(_, _) => ScrubbedTraitError::TrueError, + FulfillmentErrorCode::Cycle(_) | FulfillmentErrorCode::Ambiguity { overflow: _ } => { + ScrubbedTraitError::Ambiguity + } + } + } +} diff --git a/compiler/rustc_trait_selection/src/traits/misc.rs b/compiler/rustc_trait_selection/src/traits/misc.rs index 8b4594926474f..baec2268629dc 100644 --- a/compiler/rustc_trait_selection/src/traits/misc.rs +++ b/compiler/rustc_trait_selection/src/traits/misc.rs @@ -137,7 +137,7 @@ pub fn all_fields_implement_trait<'tcx>( for field in &variant.fields { // Do this per-field to get better error messages. let infcx = tcx.infer_ctxt().build(); - let ocx = traits::ObligationCtxt::new(&infcx); + let ocx = traits::ObligationCtxt::new_with_diagnostics(&infcx); let unnormalized_ty = field.ty(tcx, args); if unnormalized_ty.references_error() { diff --git a/compiler/rustc_trait_selection/src/traits/mod.rs b/compiler/rustc_trait_selection/src/traits/mod.rs index a047f6c9edbc3..3e9e4aa2735ef 100644 --- a/compiler/rustc_trait_selection/src/traits/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/mod.rs @@ -46,7 +46,7 @@ pub use self::coherence::{add_placeholder_note, orphan_check_trait_ref, overlapp pub use self::coherence::{InCrate, IsFirstInputType, UncoveredTyParams}; pub use self::coherence::{OrphanCheckErr, OrphanCheckMode, OverlapResult}; pub use self::engine::{ObligationCtxt, TraitEngineExt}; -pub use self::fulfill::{FulfillmentContext, PendingPredicateObligation}; +pub use self::fulfill::{FulfillmentContext, OldSolverError, PendingPredicateObligation}; pub use self::normalize::NormalizeExt; pub use self::object_safety::hir_ty_lowering_object_safety_violations; pub use self::object_safety::is_vtable_safe_method; @@ -73,6 +73,28 @@ pub use self::util::{with_replaced_escaping_bound_vars, BoundVarReplacer, Placeh pub use rustc_infer::traits::*; +// A trait error without any information in it. You likely want to alternately use [`ObligationCtxt::new_with_diagnostics`] to get a [`FulfillmentError`]. +#[derive(Copy, Clone, Debug)] +pub enum ScrubbedTraitError { + TrueError, + Ambiguity, +} + +impl ScrubbedTraitError { + fn is_true_error(&self) -> bool { + match self { + ScrubbedTraitError::TrueError => true, + ScrubbedTraitError::Ambiguity => false, + } + } +} + +impl<'tcx> FulfillmentErrorLike<'tcx> for ScrubbedTraitError { + fn is_true_error(&self) -> bool { + self.is_true_error() + } +} + pub struct FulfillmentError<'tcx> { pub obligation: PredicateObligation<'tcx>, pub code: FulfillmentErrorCode<'tcx>, @@ -453,7 +475,7 @@ pub fn fully_normalize<'tcx, T>( where T: TypeFoldable>, { - let ocx = ObligationCtxt::new(infcx); + let ocx = ObligationCtxt::new_with_diagnostics(infcx); debug!(?value); let normalized_value = ocx.normalize(&cause, param_env, value); debug!(?normalized_value); diff --git a/compiler/rustc_traits/src/codegen.rs b/compiler/rustc_traits/src/codegen.rs index b96b1b67a7407..41f607fb3a8a0 100644 --- a/compiler/rustc_traits/src/codegen.rs +++ b/compiler/rustc_traits/src/codegen.rs @@ -50,7 +50,8 @@ pub fn codegen_select_candidate<'tcx>( // Currently, we use a fulfillment context to completely resolve // all nested obligations. This is because they can inform the // inference of the impl's type parameters. - let ocx = ObligationCtxt::new(&infcx); + // FIXME(-Znext-solver): Doesn't need diagnostics if new solver. + let ocx = ObligationCtxt::new_with_diagnostics(&infcx); let impl_source = selection.map(|obligation| { ocx.register_obligation(obligation); }); diff --git a/compiler/rustc_traits/src/normalize_projection_ty.rs b/compiler/rustc_traits/src/normalize_projection_ty.rs index fee13078250fd..712abf6fcb322 100644 --- a/compiler/rustc_traits/src/normalize_projection_ty.rs +++ b/compiler/rustc_traits/src/normalize_projection_ty.rs @@ -8,7 +8,7 @@ use rustc_trait_selection::traits::query::{ normalize::NormalizationResult, CanonicalAliasGoal, NoSolution, }; use rustc_trait_selection::traits::{ - self, FulfillmentErrorCode, ObligationCause, SelectionContext, + self, FulfillmentError, FulfillmentErrorCode, ObligationCause, ObligationCtxt, SelectionContext, }; use tracing::debug; @@ -29,7 +29,8 @@ fn normalize_canonicalized_projection_ty<'tcx>( tcx.infer_ctxt().enter_canonical_trait_query( &goal, - |ocx, ParamEnvAnd { param_env, value: goal }| { + |ocx: &ObligationCtxt<'_, 'tcx, FulfillmentError<'tcx>>, + ParamEnvAnd { param_env, value: goal }| { debug_assert!(!ocx.infcx.next_trait_solver()); let selcx = &mut SelectionContext::new(ocx.infcx); let cause = ObligationCause::dummy(); @@ -73,7 +74,7 @@ fn normalize_canonicalized_weak_ty<'tcx>( tcx.infer_ctxt().enter_canonical_trait_query( &goal, - |ocx, ParamEnvAnd { param_env, value: goal }| { + |ocx: &ObligationCtxt<'_, 'tcx>, ParamEnvAnd { param_env, value: goal }| { let obligations = tcx.predicates_of(goal.def_id).instantiate_own(tcx, goal.args).map( |(predicate, span)| { traits::Obligation::new( @@ -99,7 +100,7 @@ fn normalize_canonicalized_inherent_projection_ty<'tcx>( tcx.infer_ctxt().enter_canonical_trait_query( &goal, - |ocx, ParamEnvAnd { param_env, value: goal }| { + |ocx: &ObligationCtxt<'_, 'tcx>, ParamEnvAnd { param_env, value: goal }| { let selcx = &mut SelectionContext::new(ocx.infcx); let cause = ObligationCause::dummy(); let mut obligations = vec![]; diff --git a/compiler/rustc_traits/src/type_op.rs b/compiler/rustc_traits/src/type_op.rs index b6a59a4ad3a4c..35b0ede9a2e55 100644 --- a/compiler/rustc_traits/src/type_op.rs +++ b/compiler/rustc_traits/src/type_op.rs @@ -43,10 +43,13 @@ fn type_op_eq<'tcx>( tcx: TyCtxt<'tcx>, canonicalized: Canonical<'tcx, ParamEnvAnd<'tcx, Eq<'tcx>>>, ) -> Result<&'tcx Canonical<'tcx, QueryResponse<'tcx, ()>>, NoSolution> { - tcx.infer_ctxt().enter_canonical_trait_query(&canonicalized, |ocx, key| { - let (param_env, Eq { a, b }) = key.into_parts(); - Ok(ocx.eq(&ObligationCause::dummy(), param_env, a, b)?) - }) + tcx.infer_ctxt().enter_canonical_trait_query( + &canonicalized, + |ocx: &ObligationCtxt<'_, 'tcx>, key| { + let (param_env, Eq { a, b }) = key.into_parts(); + Ok(ocx.eq(&ObligationCause::dummy(), param_env, a, b)?) + }, + ) } fn type_op_normalize<'tcx, T>( @@ -95,10 +98,13 @@ fn type_op_subtype<'tcx>( tcx: TyCtxt<'tcx>, canonicalized: Canonical<'tcx, ParamEnvAnd<'tcx, Subtype<'tcx>>>, ) -> Result<&'tcx Canonical<'tcx, QueryResponse<'tcx, ()>>, NoSolution> { - tcx.infer_ctxt().enter_canonical_trait_query(&canonicalized, |ocx, key| { - let (param_env, Subtype { sub, sup }) = key.into_parts(); - Ok(ocx.sup(&ObligationCause::dummy(), param_env, sup, sub)?) - }) + tcx.infer_ctxt().enter_canonical_trait_query( + &canonicalized, + |ocx: &ObligationCtxt<'_, 'tcx>, key| { + let (param_env, Subtype { sub, sup }) = key.into_parts(); + Ok(ocx.sup(&ObligationCause::dummy(), param_env, sup, sub)?) + }, + ) } fn type_op_prove_predicate<'tcx>( diff --git a/src/tools/clippy/clippy_lints/src/future_not_send.rs b/src/tools/clippy/clippy_lints/src/future_not_send.rs index 192fb611c2d4b..cb1d0de1edff9 100644 --- a/src/tools/clippy/clippy_lints/src/future_not_send.rs +++ b/src/tools/clippy/clippy_lints/src/future_not_send.rs @@ -79,7 +79,7 @@ impl<'tcx> LateLintPass<'tcx> for FutureNotSend { let send_trait = cx.tcx.get_diagnostic_item(sym::Send).unwrap(); let span = decl.output.span(); let infcx = cx.tcx.infer_ctxt().build(); - let ocx = ObligationCtxt::new(&infcx); + let ocx = ObligationCtxt::new_with_diagnostics(&infcx); let cause = traits::ObligationCause::misc(span, fn_def_id); ocx.register_bound(cause, cx.param_env, ret_ty, send_trait); let send_errors = ocx.select_all_or_error(); From a2a5ba42aacd4a3dbaebd546d29a22c6a865db4b Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Sat, 1 Jun 2024 15:00:02 -0400 Subject: [PATCH 4/5] Use ScrubbedTraitError in more places --- .../src/type_check/constraint_conversion.rs | 4 ++-- compiler/rustc_hir_analysis/src/coherence/orphan.rs | 9 +++++---- compiler/rustc_trait_selection/src/regions.rs | 5 ++--- compiler/rustc_trait_selection/src/solve/normalize.rs | 8 +++----- compiler/rustc_trait_selection/src/traits/mod.rs | 9 ++++++++- .../rustc_trait_selection/src/traits/query/normalize.rs | 7 +++---- .../src/traits/query/type_op/implied_outlives_bounds.rs | 5 ++--- 7 files changed, 25 insertions(+), 22 deletions(-) diff --git a/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs b/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs index 4037f04d0bce8..210532e56a5bf 100644 --- a/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs +++ b/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs @@ -13,7 +13,7 @@ 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::FulfillmentError; +use rustc_trait_selection::traits::ScrubbedTraitError; use crate::{ constraints::OutlivesConstraint, @@ -287,7 +287,7 @@ impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> { ocx.infcx.at(&ObligationCause::dummy_with_span(self.span), self.param_env), ty, ) - .map_err(|_: Vec>| NoSolution) + .map_err(|_: Vec| NoSolution) }, "normalize type outlives obligation", ) diff --git a/compiler/rustc_hir_analysis/src/coherence/orphan.rs b/compiler/rustc_hir_analysis/src/coherence/orphan.rs index a4818b25f98cd..d2eb0cb5a7bc7 100644 --- a/compiler/rustc_hir_analysis/src/coherence/orphan.rs +++ b/compiler/rustc_hir_analysis/src/coherence/orphan.rs @@ -12,9 +12,11 @@ use rustc_middle::ty::{TypeFoldable, TypeFolder, TypeSuperFoldable}; 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, UncoveredTyParams}; -use rustc_trait_selection::traits::{FulfillmentError, StructurallyNormalizeExt, TraitEngineExt}; +use rustc_trait_selection::traits::{ + self, IsFirstInputType, ScrubbedTraitError, 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( @@ -317,8 +319,7 @@ fn orphan_check<'tcx>( } let ty = if infcx.next_trait_solver() { - let mut fulfill_cx = - >>::new(&infcx); + let mut fulfill_cx = >::new(&infcx); infcx .at(&cause, ty::ParamEnv::empty()) .structurally_normalize(ty, &mut *fulfill_cx) diff --git a/compiler/rustc_trait_selection/src/regions.rs b/compiler/rustc_trait_selection/src/regions.rs index cca5bce03e19b..3ef3f9ef35851 100644 --- a/compiler/rustc_trait_selection/src/regions.rs +++ b/compiler/rustc_trait_selection/src/regions.rs @@ -1,4 +1,4 @@ -use crate::traits::FulfillmentError; +use crate::traits::ScrubbedTraitError; use rustc_infer::infer::outlives::env::OutlivesEnvironment; use rustc_infer::infer::{InferCtxt, RegionResolutionError}; use rustc_macros::extension; @@ -28,8 +28,7 @@ impl<'tcx> InferCtxt<'tcx> { ), ty, ) - // TODO: - .map_err(|_: Vec>| NoSolution) + .map_err(|_: Vec| NoSolution) } else { Ok(ty) } diff --git a/compiler/rustc_trait_selection/src/solve/normalize.rs b/compiler/rustc_trait_selection/src/solve/normalize.rs index f85e5d8746fd6..5e41e8e8ba923 100644 --- a/compiler/rustc_trait_selection/src/solve/normalize.rs +++ b/compiler/rustc_trait_selection/src/solve/normalize.rs @@ -2,7 +2,7 @@ use std::marker::PhantomData; use crate::traits::error_reporting::{OverflowCause, TypeErrCtxtExt}; use crate::traits::query::evaluate_obligation::InferCtxtExt; -use crate::traits::{BoundVarReplacer, FulfillmentError, PlaceholderReplacer}; +use crate::traits::{BoundVarReplacer, PlaceholderReplacer, ScrubbedTraitError}; use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_infer::infer::at::At; use rustc_infer::infer::InferCtxt; @@ -253,8 +253,7 @@ impl<'tcx> TypeFolder> for DeeplyNormalizeForDiagnosticsFolder<'_, ty, vec![None; ty.outer_exclusive_binder().as_usize()], ) - // TODO: - .unwrap_or_else(|_: Vec>| ty.super_fold_with(self)) + .unwrap_or_else(|_: Vec| ty.super_fold_with(self)) } fn fold_const(&mut self, ct: ty::Const<'tcx>) -> ty::Const<'tcx> { @@ -263,7 +262,6 @@ impl<'tcx> TypeFolder> for DeeplyNormalizeForDiagnosticsFolder<'_, ct, vec![None; ct.outer_exclusive_binder().as_usize()], ) - // TODO: - .unwrap_or_else(|_: Vec>| ct.super_fold_with(self)) + .unwrap_or_else(|_: Vec| ct.super_fold_with(self)) } } diff --git a/compiler/rustc_trait_selection/src/traits/mod.rs b/compiler/rustc_trait_selection/src/traits/mod.rs index 3e9e4aa2735ef..6a00e9aa86c8c 100644 --- a/compiler/rustc_trait_selection/src/traits/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/mod.rs @@ -73,10 +73,17 @@ pub use self::util::{with_replaced_escaping_bound_vars, BoundVarReplacer, Placeh pub use rustc_infer::traits::*; -// A trait error without any information in it. You likely want to alternately use [`ObligationCtxt::new_with_diagnostics`] to get a [`FulfillmentError`]. +/// A trait error without 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(Copy, Clone, Debug)] pub enum ScrubbedTraitError { + /// A real error. This goal definitely does not hold. TrueError, + /// An ambiguity. This goal may hold if further inference is done. Ambiguity, } diff --git a/compiler/rustc_trait_selection/src/traits/query/normalize.rs b/compiler/rustc_trait_selection/src/traits/query/normalize.rs index 2c0103e40dff2..860f50888a59c 100644 --- a/compiler/rustc_trait_selection/src/traits/query/normalize.rs +++ b/compiler/rustc_trait_selection/src/traits/query/normalize.rs @@ -8,8 +8,8 @@ use crate::infer::{InferCtxt, InferOk}; use crate::traits::error_reporting::OverflowCause; use crate::traits::error_reporting::TypeErrCtxtExt; use crate::traits::normalize::needs_normalization; -use crate::traits::{BoundVarReplacer, PlaceholderReplacer}; -use crate::traits::{FulfillmentError, Normalized}; +use crate::traits::Normalized; +use crate::traits::{BoundVarReplacer, PlaceholderReplacer, ScrubbedTraitError}; use crate::traits::{ObligationCause, PredicateObligation, Reveal}; use rustc_data_structures::sso::SsoHashMap; use rustc_data_structures::stack::ensure_sufficient_stack; @@ -76,8 +76,7 @@ impl<'cx, 'tcx> At<'cx, 'tcx> { }; if self.infcx.next_trait_solver() { - // TODO: - match crate::solve::deeply_normalize_with_skipped_universes::<_, FulfillmentError<'tcx>>( + match crate::solve::deeply_normalize_with_skipped_universes::<_, ScrubbedTraitError>( self, value, universes, ) { Ok(value) => return Ok(Normalized { value, obligations: vec![] }), 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 a1bbd21f82961..e4d0a54121925 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,8 @@ use crate::solve; use crate::traits::query::NoSolution; use crate::traits::wf; -use crate::traits::FulfillmentError; use crate::traits::ObligationCtxt; +use crate::traits::ScrubbedTraitError; use rustc_infer::infer::canonical::Canonical; use rustc_infer::infer::outlives::components::{push_outlives_components, Component}; @@ -267,8 +267,7 @@ pub fn compute_implied_outlives_bounds_compat_inner<'tcx>( ocx.infcx.at(&ObligationCause::dummy(), param_env), ty_a, ) - // TODO: - .map_err(|_errs: Vec>| NoSolution)?; + .map_err(|_errs: Vec| NoSolution)?; } let mut components = smallvec![]; push_outlives_components(tcx, ty_a, &mut components); From bb8431338e4250b9f46c50ca9b213fc391cd3797 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Sat, 1 Jun 2024 15:08:44 -0400 Subject: [PATCH 5/5] Move FulfillmentErrorCode to rustc_trait_selection too --- .../rustc_borrowck/src/diagnostics/mod.rs | 6 ++- .../src/diagnostics/mutability_errors.rs | 2 +- .../src/fn_ctxt/suggestions.rs | 2 +- compiler/rustc_infer/src/traits/mod.rs | 21 +--------- .../src/traits/structural_impls.rs | 21 ---------- .../src/solve/fulfill.rs | 7 ++-- .../rustc_trait_selection/src/traits/mod.rs | 40 ++++++++++++++++++- compiler/rustc_traits/src/codegen.rs | 4 +- 8 files changed, 51 insertions(+), 52 deletions(-) diff --git a/compiler/rustc_borrowck/src/diagnostics/mod.rs b/compiler/rustc_borrowck/src/diagnostics/mod.rs index 88172c62a3b2d..1eb67ea367c2d 100644 --- a/compiler/rustc_borrowck/src/diagnostics/mod.rs +++ b/compiler/rustc_borrowck/src/diagnostics/mod.rs @@ -11,7 +11,7 @@ use rustc_hir::def::{CtorKind, Namespace}; use rustc_hir::CoroutineKind; use rustc_index::IndexSlice; use rustc_infer::infer::BoundRegionConversionTime; -use rustc_infer::traits::{FulfillmentErrorCode, SelectionError}; +use rustc_infer::traits::SelectionError; use rustc_middle::bug; use rustc_middle::mir::tcx::PlaceTy; use rustc_middle::mir::{ @@ -29,7 +29,9 @@ use rustc_span::{symbol::sym, Span, Symbol, DUMMY_SP}; use rustc_target::abi::{FieldIdx, VariantIdx}; use rustc_trait_selection::infer::InferCtxtExt; use rustc_trait_selection::traits::error_reporting::suggestions::TypeErrCtxtExt as _; -use rustc_trait_selection::traits::type_known_to_meet_bound_modulo_regions; +use rustc_trait_selection::traits::{ + type_known_to_meet_bound_modulo_regions, FulfillmentErrorCode, +}; use crate::fluent_generated as fluent; diff --git a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs index 78798545c26fa..df1a1411cf5f6 100644 --- a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs @@ -6,7 +6,6 @@ use hir::{ExprKind, Param}; use rustc_errors::{Applicability, Diag}; use rustc_hir::intravisit::Visitor; use rustc_hir::{self as hir, BindingMode, ByRef, Node}; -use rustc_infer::traits; use rustc_middle::bug; use rustc_middle::mir::{Mutability, Place, PlaceRef, ProjectionElem}; use rustc_middle::ty::{self, InstanceDef, Ty, TyCtxt, Upcast}; @@ -18,6 +17,7 @@ use rustc_span::symbol::{kw, Symbol}; use rustc_span::{sym, BytePos, DesugaringKind, Span}; use rustc_target::abi::FieldIdx; use rustc_trait_selection::infer::InferCtxtExt; +use rustc_trait_selection::traits; use rustc_trait_selection::traits::error_reporting::suggestions::TypeErrCtxtExt; use crate::diagnostics::BorrowedContentSource; diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs index 5723b73a328ad..caaf4142f7d1f 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs @@ -22,7 +22,6 @@ use rustc_hir::{ }; use rustc_hir_analysis::collect::suggest_impl_trait; use rustc_hir_analysis::hir_ty_lowering::HirTyLowerer; -use rustc_infer::traits; use rustc_middle::lint::in_external_macro; use rustc_middle::middle::stability::EvalResult; use rustc_middle::span_bug; @@ -36,6 +35,7 @@ use rustc_span::source_map::Spanned; use rustc_span::symbol::{sym, Ident}; use rustc_span::{Span, Symbol}; use rustc_trait_selection::infer::InferCtxtExt; +use rustc_trait_selection::traits; use rustc_trait_selection::traits::error_reporting::suggestions::TypeErrCtxtExt; use rustc_trait_selection::traits::error_reporting::DefIdOrName; use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt as _; diff --git a/compiler/rustc_infer/src/traits/mod.rs b/compiler/rustc_infer/src/traits/mod.rs index 26c931876dbdb..e9c2d81aa0af5 100644 --- a/compiler/rustc_infer/src/traits/mod.rs +++ b/compiler/rustc_infer/src/traits/mod.rs @@ -15,8 +15,7 @@ use hir::def_id::LocalDefId; use rustc_hir as hir; use rustc_middle::traits::query::NoSolution; use rustc_middle::traits::solve::Certainty; -use rustc_middle::ty::error::{ExpectedFound, TypeError}; -use rustc_middle::ty::{self, Const, Ty, TyCtxt, Upcast}; +use rustc_middle::ty::{self, Ty, TyCtxt, Upcast}; use rustc_span::Span; pub use self::ImplSource::*; @@ -124,24 +123,6 @@ pub type Selection<'tcx> = ImplSource<'tcx, PredicateObligation<'tcx>>; pub type ObligationInspector<'tcx> = fn(&InferCtxt<'tcx>, &PredicateObligation<'tcx>, Result); -// TODO: Pull this down too -#[derive(Clone)] -pub enum FulfillmentErrorCode<'tcx> { - /// Inherently impossible to fulfill; this trait is implemented if and only - /// if it is already implemented. - Cycle(Vec>), - Select(SelectionError<'tcx>), - Project(MismatchedProjectionTypes<'tcx>), - Subtype(ExpectedFound>, TypeError<'tcx>), // always comes from a SubtypePredicate - ConstEquate(ExpectedFound>, TypeError<'tcx>), - Ambiguity { - /// Overflow is only `Some(suggest_recursion_limit)` when using the next generation - /// trait solver `-Znext-solver`. With the old solver overflow is eagerly handled by - /// emitting a fatal error instead. - overflow: Option, - }, -} - impl<'tcx, O> Obligation<'tcx, O> { pub fn new( tcx: TyCtxt<'tcx>, diff --git a/compiler/rustc_infer/src/traits/structural_impls.rs b/compiler/rustc_infer/src/traits/structural_impls.rs index 00abf939807a0..b26734a296fd3 100644 --- a/compiler/rustc_infer/src/traits/structural_impls.rs +++ b/compiler/rustc_infer/src/traits/structural_impls.rs @@ -29,27 +29,6 @@ impl<'tcx, O: fmt::Debug> fmt::Debug for traits::Obligation<'tcx, O> { } } -impl<'tcx> fmt::Debug for traits::FulfillmentErrorCode<'tcx> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - use traits::FulfillmentErrorCode::*; - match *self { - Select(ref e) => write!(f, "{e:?}"), - Project(ref e) => write!(f, "{e:?}"), - Subtype(ref a, ref b) => { - write!(f, "CodeSubtypeError({a:?}, {b:?})") - } - ConstEquate(ref a, ref b) => { - write!(f, "CodeConstEquateError({a:?}, {b:?})") - } - Ambiguity { overflow: None } => write!(f, "Ambiguity"), - Ambiguity { overflow: Some(suggest_increasing_limit) } => { - write!(f, "Overflow({suggest_increasing_limit})") - } - Cycle(ref cycle) => write!(f, "Cycle({cycle:?})"), - } - } -} - impl<'tcx> fmt::Debug for traits::MismatchedProjectionTypes<'tcx> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "MismatchedProjectionTypes({:?})", self.err) diff --git a/compiler/rustc_trait_selection/src/solve/fulfill.rs b/compiler/rustc_trait_selection/src/solve/fulfill.rs index d92c903a76ed6..b644f70eee428 100644 --- a/compiler/rustc_trait_selection/src/solve/fulfill.rs +++ b/compiler/rustc_trait_selection/src/solve/fulfill.rs @@ -6,16 +6,15 @@ use rustc_infer::infer::InferCtxt; use rustc_infer::traits::query::NoSolution; use rustc_infer::traits::solve::{CandidateSource, GoalSource, MaybeCause}; use rustc_infer::traits::{ - self, FromSolverError, FulfillmentErrorCode, FulfillmentErrorLike, MismatchedProjectionTypes, - Obligation, ObligationCause, ObligationCauseCode, PredicateObligation, SelectionError, - TraitEngine, + self, FromSolverError, FulfillmentErrorLike, MismatchedProjectionTypes, Obligation, + ObligationCause, ObligationCauseCode, PredicateObligation, SelectionError, TraitEngine, }; use rustc_middle::bug; use rustc_middle::ty::error::{ExpectedFound, TypeError}; use rustc_middle::ty::{self, TyCtxt}; use rustc_span::symbol::sym; -use crate::traits::{FulfillmentError, ScrubbedTraitError}; +use crate::traits::{FulfillmentError, FulfillmentErrorCode, ScrubbedTraitError}; use super::eval_ctxt::GenerateProofTree; use super::inspect::{self, ProofTreeInferCtxtExt, ProofTreeVisitor}; diff --git a/compiler/rustc_trait_selection/src/traits/mod.rs b/compiler/rustc_trait_selection/src/traits/mod.rs index 6a00e9aa86c8c..b1dcce49a942d 100644 --- a/compiler/rustc_trait_selection/src/traits/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/mod.rs @@ -32,6 +32,7 @@ use crate::traits::query::evaluate_obligation::InferCtxtExt as _; use rustc_errors::ErrorGuaranteed; use rustc_middle::query::Providers; use rustc_middle::span_bug; +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, Ty, TyCtxt, TypeFolder, TypeSuperVisitable, Upcast}; @@ -73,7 +74,7 @@ pub use self::util::{with_replaced_escaping_bound_vars, BoundVarReplacer, Placeh pub use rustc_infer::traits::*; -/// A trait error without most of its information removed. This is the error +/// 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). @@ -145,6 +146,43 @@ impl<'tcx> Debug for FulfillmentError<'tcx> { } } +#[derive(Clone)] +pub enum FulfillmentErrorCode<'tcx> { + /// Inherently impossible to fulfill; this trait is implemented if and only + /// if it is already implemented. + Cycle(Vec>), + Select(SelectionError<'tcx>), + Project(MismatchedProjectionTypes<'tcx>), + Subtype(ExpectedFound>, TypeError<'tcx>), // always comes from a SubtypePredicate + ConstEquate(ExpectedFound>, TypeError<'tcx>), + Ambiguity { + /// Overflow is only `Some(suggest_recursion_limit)` when using the next generation + /// trait solver `-Znext-solver`. With the old solver overflow is eagerly handled by + /// emitting a fatal error instead. + overflow: Option, + }, +} + +impl<'tcx> Debug for FulfillmentErrorCode<'tcx> { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match *self { + FulfillmentErrorCode::Select(ref e) => write!(f, "{e:?}"), + FulfillmentErrorCode::Project(ref e) => write!(f, "{e:?}"), + FulfillmentErrorCode::Subtype(ref a, ref b) => { + write!(f, "CodeSubtypeError({a:?}, {b:?})") + } + FulfillmentErrorCode::ConstEquate(ref a, ref b) => { + write!(f, "CodeConstEquateError({a:?}, {b:?})") + } + FulfillmentErrorCode::Ambiguity { overflow: None } => write!(f, "Ambiguity"), + FulfillmentErrorCode::Ambiguity { overflow: Some(suggest_increasing_limit) } => { + write!(f, "Overflow({suggest_increasing_limit})") + } + FulfillmentErrorCode::Cycle(ref cycle) => write!(f, "Cycle({cycle:?})"), + } + } +} + /// Whether to skip the leak check, as part of a future compatibility warning step. /// /// The "default" for skip-leak-check corresponds to the current diff --git a/compiler/rustc_traits/src/codegen.rs b/compiler/rustc_traits/src/codegen.rs index 41f607fb3a8a0..5defb8172716f 100644 --- a/compiler/rustc_traits/src/codegen.rs +++ b/compiler/rustc_traits/src/codegen.rs @@ -4,13 +4,13 @@ // general routines. use rustc_infer::infer::TyCtxtInferExt; -use rustc_infer::traits::FulfillmentErrorCode; use rustc_middle::bug; use rustc_middle::traits::CodegenObligationError; use rustc_middle::ty::{self, TyCtxt, TypeVisitableExt}; use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt; use rustc_trait_selection::traits::{ - ImplSource, Obligation, ObligationCause, ObligationCtxt, SelectionContext, Unimplemented, + FulfillmentErrorCode, ImplSource, Obligation, ObligationCause, ObligationCtxt, + SelectionContext, Unimplemented, }; use tracing::debug;