Make TraitEngines generic over error

This commit is contained in:
Michael Goulet 2024-06-01 14:12:34 -04:00
parent 084ccd2390
commit 54b2b7d460
23 changed files with 253 additions and 157 deletions

View File

@ -13,6 +13,7 @@
use rustc_trait_selection::solve::deeply_normalize; 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::custom::CustomTypeOp;
use rustc_trait_selection::traits::query::type_op::{TypeOp, TypeOpOutput}; use rustc_trait_selection::traits::query::type_op::{TypeOp, TypeOpOutput};
use rustc_trait_selection::traits::FulfillmentError;
use crate::{ use crate::{
constraints::OutlivesConstraint, constraints::OutlivesConstraint,
@ -286,7 +287,7 @@ fn normalize_and_add_type_outlives_constraints(
ocx.infcx.at(&ObligationCause::dummy_with_span(self.span), self.param_env), ocx.infcx.at(&ObligationCause::dummy_with_span(self.span), self.param_env),
ty, ty,
) )
.map_err(|_| NoSolution) .map_err(|_: Vec<FulfillmentError<'tcx>>| NoSolution)
}, },
"normalize type outlives obligation", "normalize type outlives obligation",
) )

View File

@ -10,7 +10,7 @@
use rustc_hir::{GenericParamKind, ImplItemKind}; use rustc_hir::{GenericParamKind, ImplItemKind};
use rustc_infer::infer::outlives::env::OutlivesEnvironment; use rustc_infer::infer::outlives::env::OutlivesEnvironment;
use rustc_infer::infer::{self, InferCtxt, TyCtxtInferExt}; 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::error::{ExpectedFound, TypeError};
use rustc_middle::ty::fold::BottomUpFolder; use rustc_middle::ty::fold::BottomUpFolder;
use rustc_middle::ty::util::ExplicitSelf; use rustc_middle::ty::util::ExplicitSelf;
@ -25,7 +25,7 @@
use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt; use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt;
use rustc_trait_selection::traits::outlives_bounds::InferCtxtExt as _; use rustc_trait_selection::traits::outlives_bounds::InferCtxtExt as _;
use rustc_trait_selection::traits::{ use rustc_trait_selection::traits::{
self, ObligationCause, ObligationCauseCode, ObligationCtxt, Reveal, self, FulfillmentError, ObligationCause, ObligationCauseCode, ObligationCtxt, Reveal,
}; };
use std::borrow::Cow; use std::borrow::Cow;
use std::iter; use std::iter;

View File

@ -13,8 +13,8 @@
use rustc_middle::{bug, span_bug}; use rustc_middle::{bug, span_bug};
use rustc_span::def_id::{DefId, LocalDefId}; use rustc_span::def_id::{DefId, LocalDefId};
use rustc_trait_selection::traits::{self, IsFirstInputType, UncoveredTyParams}; 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::{OrphanCheckErr, OrphanCheckMode};
use rustc_trait_selection::traits::{StructurallyNormalizeExt, TraitEngineExt};
#[instrument(level = "debug", skip(tcx))] #[instrument(level = "debug", skip(tcx))]
pub(crate) fn orphan_check_impl( pub(crate) fn orphan_check_impl(
@ -317,7 +317,8 @@ fn orphan_check<'tcx>(
} }
let ty = if infcx.next_trait_solver() { let ty = if infcx.next_trait_solver() {
let mut fulfill_cx = <dyn traits::TraitEngine<'_>>::new(&infcx); let mut fulfill_cx =
<dyn traits::TraitEngine<'tcx, FulfillmentError<'tcx>>>::new(&infcx);
infcx infcx
.at(&cause, ty::ParamEnv::empty()) .at(&cause, ty::ParamEnv::empty())
.structurally_normalize(ty, &mut *fulfill_cx) .structurally_normalize(ty, &mut *fulfill_cx)

View File

@ -15,7 +15,6 @@
use rustc_hir as hir; use rustc_hir as hir;
use rustc_hir::def::{DefKind, Res}; use rustc_hir::def::{DefKind, Res};
use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir::def_id::{DefId, LocalDefId};
use rustc_infer::traits::FulfillmentError;
use rustc_middle::bug; use rustc_middle::bug;
use rustc_middle::query::Key; use rustc_middle::query::Key;
use rustc_middle::ty::print::{PrintPolyTraitRefExt as _, PrintTraitRefExt as _}; use rustc_middle::ty::print::{PrintPolyTraitRefExt as _, PrintTraitRefExt as _};
@ -28,6 +27,7 @@
use rustc_span::symbol::{kw, sym, Ident}; use rustc_span::symbol::{kw, sym, Ident};
use rustc_span::BytePos; use rustc_span::BytePos;
use rustc_span::{Span, Symbol, DUMMY_SP}; use rustc_span::{Span, Symbol, DUMMY_SP};
use rustc_trait_selection::traits::FulfillmentError;
use rustc_trait_selection::traits::{ use rustc_trait_selection::traits::{
object_safety_violations_for_assoc_item, TraitAliasExpansionInfo, object_safety_violations_for_assoc_item, TraitAliasExpansionInfo,
}; };

View File

@ -11,7 +11,9 @@
use rustc_span::def_id::LocalDefIdMap; use rustc_span::def_id::LocalDefIdMap;
use rustc_span::Span; use rustc_span::Span;
use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt; 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::cell::RefCell;
use std::ops::Deref; use std::ops::Deref;
@ -34,7 +36,7 @@ pub(crate) struct TypeckRootCtxt<'tcx> {
pub(super) locals: RefCell<HirIdMap<Ty<'tcx>>>, pub(super) locals: RefCell<HirIdMap<Ty<'tcx>>>,
pub(super) fulfillment_cx: RefCell<Box<dyn TraitEngine<'tcx>>>, pub(super) fulfillment_cx: RefCell<Box<dyn TraitEngine<'tcx, FulfillmentError<'tcx>>>>,
/// Some additional `Sized` obligations badly affect type inference. /// Some additional `Sized` obligations badly affect type inference.
/// These obligations are added in a later stage of typeck. /// These obligations are added in a later stage of typeck.
@ -83,7 +85,7 @@ pub fn new(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Self {
TypeckRootCtxt { TypeckRootCtxt {
typeck_results, typeck_results,
fulfillment_cx: RefCell::new(<dyn TraitEngine<'_>>::new(&infcx)), fulfillment_cx: RefCell::new(<dyn TraitEngine<'_, _>>::new(&infcx)),
infcx, infcx,
locals: RefCell::new(Default::default()), locals: RefCell::new(Default::default()),
deferred_sized_obligations: RefCell::new(Vec::new()), deferred_sized_obligations: RefCell::new(Vec::new()),

View File

@ -15,7 +15,7 @@
use crate::infer::region_constraints::{Constraint, RegionConstraintData}; use crate::infer::region_constraints::{Constraint, RegionConstraintData};
use crate::infer::{DefineOpaqueTypes, InferCtxt, InferOk, InferResult}; use crate::infer::{DefineOpaqueTypes, InferCtxt, InferOk, InferResult};
use crate::traits::query::NoSolution; use crate::traits::query::NoSolution;
use crate::traits::TraitEngine; use crate::traits::{FulfillmentErrorLike, TraitEngine};
use crate::traits::{Obligation, ObligationCause, PredicateObligation}; use crate::traits::{Obligation, ObligationCause, PredicateObligation};
use rustc_data_structures::captures::Captures; use rustc_data_structures::captures::Captures;
use rustc_index::Idx; use rustc_index::Idx;
@ -50,11 +50,11 @@ impl<'tcx> InferCtxt<'tcx> {
/// - Finally, if any of the obligations result in a hard error, /// - Finally, if any of the obligations result in a hard error,
/// then `Err(NoSolution)` is returned. /// then `Err(NoSolution)` is returned.
#[instrument(skip(self, inference_vars, answer, fulfill_cx), level = "trace")] #[instrument(skip(self, inference_vars, answer, fulfill_cx), level = "trace")]
pub fn make_canonicalized_query_response<T>( pub fn make_canonicalized_query_response<T, E: FulfillmentErrorLike<'tcx>>(
&self, &self,
inference_vars: CanonicalVarValues<'tcx>, inference_vars: CanonicalVarValues<'tcx>,
answer: T, answer: T,
fulfill_cx: &mut dyn TraitEngine<'tcx>, fulfill_cx: &mut dyn TraitEngine<'tcx, E>,
) -> Result<CanonicalQueryResponse<'tcx, T>, NoSolution> ) -> Result<CanonicalQueryResponse<'tcx, T>, NoSolution>
where where
T: Debug + TypeFoldable<TyCtxt<'tcx>>, T: Debug + TypeFoldable<TyCtxt<'tcx>>,
@ -97,11 +97,11 @@ pub fn make_query_response_ignoring_pending_obligations<T>(
/// Helper for `make_canonicalized_query_response` that does /// Helper for `make_canonicalized_query_response` that does
/// everything up until the final canonicalization. /// everything up until the final canonicalization.
#[instrument(skip(self, fulfill_cx), level = "debug")] #[instrument(skip(self, fulfill_cx), level = "debug")]
fn make_query_response<T>( fn make_query_response<T, E: FulfillmentErrorLike<'tcx>>(
&self, &self,
inference_vars: CanonicalVarValues<'tcx>, inference_vars: CanonicalVarValues<'tcx>,
answer: T, answer: T,
fulfill_cx: &mut dyn TraitEngine<'tcx>, fulfill_cx: &mut dyn TraitEngine<'tcx, E>,
) -> Result<QueryResponse<'tcx, T>, NoSolution> ) -> Result<QueryResponse<'tcx, T>, NoSolution>
where where
T: Debug + TypeFoldable<TyCtxt<'tcx>>, T: Debug + TypeFoldable<TyCtxt<'tcx>>,
@ -109,19 +109,13 @@ fn make_query_response<T>(
let tcx = self.tcx; let tcx = self.tcx;
// Select everything, returning errors. // Select everything, returning errors.
let true_errors = fulfill_cx.select_where_possible(self); let errors = fulfill_cx.select_all_or_error(self);
debug!("true_errors = {:#?}", true_errors);
if !true_errors.is_empty() { // True error!
// FIXME -- we don't indicate *why* we failed to solve if errors.iter().any(|e| e.is_true_error()) {
debug!("make_query_response: true_errors={:#?}", true_errors);
return Err(NoSolution); 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(); let region_obligations = self.take_registered_region_obligations();
debug!(?region_obligations); debug!(?region_obligations);
let region_constraints = self.with_region_constraints(|region_constraints| { let region_constraints = self.with_region_constraints(|region_constraints| {
@ -135,8 +129,7 @@ fn make_query_response<T>(
}); });
debug!(?region_constraints); debug!(?region_constraints);
let certainty = let certainty = if errors.is_empty() { Certainty::Proven } else { Certainty::Ambiguous };
if ambig_errors.is_empty() { Certainty::Proven } else { Certainty::Ambiguous };
let opaque_types = self.take_opaque_types_for_query_response(); let opaque_types = self.take_opaque_types_for_query_response();

View File

@ -12,7 +12,8 @@
pub use ValuePairs::*; pub use ValuePairs::*;
use crate::traits::{ use crate::traits::{
self, ObligationCause, ObligationInspector, PredicateObligations, TraitEngine, self, FulfillmentErrorLike, ObligationCause, ObligationInspector, PredicateObligations,
TraitEngine,
}; };
use error_reporting::TypeErrCtxt; use error_reporting::TypeErrCtxt;
use free_regions::RegionRelations; use free_regions::RegionRelations;
@ -737,10 +738,10 @@ pub fn build(&mut self) -> InferCtxt<'tcx> {
impl<'tcx, T> InferOk<'tcx, T> { impl<'tcx, T> InferOk<'tcx, T> {
/// Extracts `value`, registering any obligations into `fulfill_cx`. /// Extracts `value`, registering any obligations into `fulfill_cx`.
pub fn into_value_registering_obligations( pub fn into_value_registering_obligations<E: FulfillmentErrorLike<'tcx>>(
self, self,
infcx: &InferCtxt<'tcx>, infcx: &InferCtxt<'tcx>,
fulfill_cx: &mut dyn TraitEngine<'tcx>, fulfill_cx: &mut dyn TraitEngine<'tcx, E>,
) -> T { ) -> T {
let InferOk { value, obligations } = self; let InferOk { value, obligations } = self;
fulfill_cx.register_predicate_obligations(infcx, obligations); fulfill_cx.register_predicate_obligations(infcx, obligations);

View File

@ -1,12 +1,13 @@
use std::fmt::Debug;
use crate::infer::InferCtxt; use crate::infer::InferCtxt;
use crate::traits::Obligation; use crate::traits::Obligation;
use rustc_hir::def_id::DefId; use rustc_hir::def_id::DefId;
use rustc_middle::ty::{self, Ty, Upcast}; use rustc_middle::ty::{self, Ty, Upcast};
use super::FulfillmentError;
use super::{ObligationCause, PredicateObligation}; 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 /// Requires that `ty` must implement the trait with `def_id` in
/// the given environment. This trait must not have any type /// the given environment. This trait must not have any type
/// parameters (except for `Self`). /// parameters (except for `Self`).
@ -47,12 +48,12 @@ fn register_predicate_obligations(
} }
#[must_use] #[must_use]
fn select_where_possible(&mut self, infcx: &InferCtxt<'tcx>) -> Vec<FulfillmentError<'tcx>>; fn select_where_possible(&mut self, infcx: &InferCtxt<'tcx>) -> Vec<E>;
fn collect_remaining_errors(&mut self, infcx: &InferCtxt<'tcx>) -> Vec<FulfillmentError<'tcx>>; fn collect_remaining_errors(&mut self, infcx: &InferCtxt<'tcx>) -> Vec<E>;
#[must_use] #[must_use]
fn select_all_or_error(&mut self, infcx: &InferCtxt<'tcx>) -> Vec<FulfillmentError<'tcx>> { fn select_all_or_error(&mut self, infcx: &InferCtxt<'tcx>) -> Vec<E> {
let errors = self.select_where_possible(infcx); let errors = self.select_where_possible(infcx);
if !errors.is_empty() { if !errors.is_empty() {
return errors; return errors;
@ -71,3 +72,11 @@ fn drain_unstalled_obligations(
infcx: &InferCtxt<'tcx>, infcx: &InferCtxt<'tcx>,
) -> Vec<PredicateObligation<'tcx>>; ) -> Vec<PredicateObligation<'tcx>>;
} }
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;
}

View File

@ -23,7 +23,7 @@
pub use self::SelectionError::*; pub use self::SelectionError::*;
use crate::infer::InferCtxt; use crate::infer::InferCtxt;
pub use self::engine::TraitEngine; pub use self::engine::{FromSolverError, FulfillmentErrorLike, TraitEngine};
pub use self::project::MismatchedProjectionTypes; pub use self::project::MismatchedProjectionTypes;
pub(crate) use self::project::UndoLog; pub(crate) use self::project::UndoLog;
pub use self::project::{ pub use self::project::{
@ -124,15 +124,7 @@ pub fn derived_cause(
pub type ObligationInspector<'tcx> = pub type ObligationInspector<'tcx> =
fn(&InferCtxt<'tcx>, &PredicateObligation<'tcx>, Result<Certainty, NoSolution>); fn(&InferCtxt<'tcx>, &PredicateObligation<'tcx>, Result<Certainty, NoSolution>);
pub struct FulfillmentError<'tcx> { // TODO: Pull this down too
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>,
}
#[derive(Clone)] #[derive(Clone)]
pub enum FulfillmentErrorCode<'tcx> { pub enum FulfillmentErrorCode<'tcx> {
/// Inherently impossible to fulfill; this trait is implemented if and only /// Inherently impossible to fulfill; this trait is implemented if and only
@ -198,28 +190,6 @@ pub fn with<P>(
} }
} }
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> { impl<'tcx> PolyTraitObligation<'tcx> {
pub fn polarity(&self) -> ty::PredicatePolarity { pub fn polarity(&self) -> ty::PredicatePolarity {
self.predicate.skip_binder().polarity self.predicate.skip_binder().polarity

View File

@ -29,12 +29,6 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
} }
} }
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> { impl<'tcx> fmt::Debug for traits::FulfillmentErrorCode<'tcx> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
use traits::FulfillmentErrorCode::*; use traits::FulfillmentErrorCode::*;

View File

@ -1,3 +1,4 @@
use crate::traits::FulfillmentError;
use rustc_infer::infer::outlives::env::OutlivesEnvironment; use rustc_infer::infer::outlives::env::OutlivesEnvironment;
use rustc_infer::infer::{InferCtxt, RegionResolutionError}; use rustc_infer::infer::{InferCtxt, RegionResolutionError};
use rustc_macros::extension; use rustc_macros::extension;
@ -27,7 +28,8 @@ fn resolve_regions(
), ),
ty, ty,
) )
.map_err(|_| NoSolution) // TODO:
.map_err(|_: Vec<FulfillmentError<'tcx>>| NoSolution)
} else { } else {
Ok(ty) Ok(ty)
} }

View File

@ -1,3 +1,4 @@
use std::marker::PhantomData;
use std::mem; use std::mem;
use std::ops::ControlFlow; use std::ops::ControlFlow;
@ -5,14 +6,17 @@
use rustc_infer::traits::query::NoSolution; use rustc_infer::traits::query::NoSolution;
use rustc_infer::traits::solve::{CandidateSource, GoalSource, MaybeCause}; use rustc_infer::traits::solve::{CandidateSource, GoalSource, MaybeCause};
use rustc_infer::traits::{ use rustc_infer::traits::{
self, FulfillmentError, FulfillmentErrorCode, MismatchedProjectionTypes, Obligation, self, FromSolverError, FulfillmentErrorCode, FulfillmentErrorLike, MismatchedProjectionTypes,
ObligationCause, ObligationCauseCode, PredicateObligation, SelectionError, TraitEngine, Obligation, ObligationCause, ObligationCauseCode, PredicateObligation, SelectionError,
TraitEngine,
}; };
use rustc_middle::bug; use rustc_middle::bug;
use rustc_middle::ty::error::{ExpectedFound, TypeError}; use rustc_middle::ty::error::{ExpectedFound, TypeError};
use rustc_middle::ty::{self, TyCtxt}; use rustc_middle::ty::{self, TyCtxt};
use rustc_span::symbol::sym; use rustc_span::symbol::sym;
use crate::traits::FulfillmentError;
use super::eval_ctxt::GenerateProofTree; use super::eval_ctxt::GenerateProofTree;
use super::inspect::{self, ProofTreeInferCtxtExt, ProofTreeVisitor}; use super::inspect::{self, ProofTreeInferCtxtExt, ProofTreeVisitor};
use super::{Certainty, InferCtxtEvalExt}; use super::{Certainty, InferCtxtEvalExt};
@ -28,7 +32,7 @@
/// ///
/// It is also likely that we want to use slightly different datastructures /// 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`. /// 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>, obligations: ObligationStorage<'tcx>,
/// The snapshot in which this context was created. Using the context /// 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 /// gets rolled back. Because of this we explicitly check that we only
/// use the context in exactly this snapshot. /// use the context in exactly this snapshot.
usable_in_snapshot: usize, usable_in_snapshot: usize,
_errors: PhantomData<E>,
} }
#[derive(Default)] #[derive(Default)]
@ -89,8 +94,8 @@ fn on_fulfillment_overflow(&mut self, infcx: &InferCtxt<'tcx>) {
} }
} }
impl<'tcx> FulfillmentCtxt<'tcx> { impl<'tcx, E: FulfillmentErrorLike<'tcx>> FulfillmentCtxt<'tcx, E> {
pub fn new(infcx: &InferCtxt<'tcx>) -> FulfillmentCtxt<'tcx> { pub fn new(infcx: &InferCtxt<'tcx>) -> FulfillmentCtxt<'tcx, E> {
assert!( assert!(
infcx.next_trait_solver(), infcx.next_trait_solver(),
"new trait solver fulfillment context created when \ "new trait solver fulfillment context created when \
@ -99,6 +104,7 @@ pub fn new(infcx: &InferCtxt<'tcx>) -> FulfillmentCtxt<'tcx> {
FulfillmentCtxt { FulfillmentCtxt {
obligations: Default::default(), obligations: Default::default(),
usable_in_snapshot: infcx.num_open_snapshots(), usable_in_snapshot: infcx.num_open_snapshots(),
_errors: PhantomData,
} }
} }
@ -118,7 +124,9 @@ fn inspect_evaluated_obligation(
} }
} }
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))] #[instrument(level = "trace", skip(self, infcx))]
fn register_predicate_obligation( fn register_predicate_obligation(
&mut self, &mut self,
@ -129,24 +137,22 @@ fn register_predicate_obligation(
self.obligations.register(obligation); self.obligations.register(obligation);
} }
fn collect_remaining_errors(&mut self, infcx: &InferCtxt<'tcx>) -> Vec<FulfillmentError<'tcx>> { fn collect_remaining_errors(&mut self, infcx: &InferCtxt<'tcx>) -> Vec<E> {
let mut errors: Vec<_> = self self.obligations
.obligations
.pending .pending
.drain(..) .drain(..)
.map(|obligation| fulfillment_error_for_stalled(infcx, obligation)) .map(|obligation| NextSolverError::Ambiguity(obligation))
.collect(); .chain(
self.obligations
errors.extend(self.obligations.overflowed.drain(..).map(|obligation| FulfillmentError { .overflowed
obligation: find_best_leaf_obligation(infcx, &obligation, true), .drain(..)
code: FulfillmentErrorCode::Ambiguity { overflow: Some(true) }, .map(|obligation| NextSolverError::Overflow(obligation)),
root_obligation: obligation, )
})); .map(|e| E::from_solver_error(infcx, e))
.collect()
errors
} }
fn select_where_possible(&mut self, infcx: &InferCtxt<'tcx>) -> Vec<FulfillmentError<'tcx>> { fn select_where_possible(&mut self, infcx: &InferCtxt<'tcx>) -> Vec<E> {
assert_eq!(self.usable_in_snapshot, infcx.num_open_snapshots()); assert_eq!(self.usable_in_snapshot, infcx.num_open_snapshots());
let mut errors = Vec::new(); let mut errors = Vec::new();
for i in 0.. { for i in 0.. {
@ -164,7 +170,10 @@ fn select_where_possible(&mut self, infcx: &InferCtxt<'tcx>) -> Vec<FulfillmentE
let (changed, certainty) = match result { let (changed, certainty) = match result {
Ok(result) => result, Ok(result) => result,
Err(NoSolution) => { Err(NoSolution) => {
errors.push(fulfillment_error_for_no_solution(infcx, obligation)); errors.push(E::from_solver_error(
infcx,
NextSolverError::TrueError(obligation),
));
continue; continue;
} }
}; };
@ -195,6 +204,28 @@ fn drain_unstalled_obligations(
} }
} }
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>( fn fulfillment_error_for_no_solution<'tcx>(
infcx: &InferCtxt<'tcx>, infcx: &InferCtxt<'tcx>,
root_obligation: PredicateObligation<'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>( fn find_best_leaf_obligation<'tcx>(
infcx: &InferCtxt<'tcx>, infcx: &InferCtxt<'tcx>,
obligation: &PredicateObligation<'tcx>, obligation: &PredicateObligation<'tcx>,

View File

@ -40,7 +40,7 @@
mod trait_goals; mod trait_goals;
pub use eval_ctxt::{EvalCtxt, GenerateProofTree, InferCtxtEvalExt, InferCtxtSelectExt}; 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(crate) use normalize::deeply_normalize_for_diagnostics;
pub use normalize::{deeply_normalize, deeply_normalize_with_skipped_universes}; pub use normalize::{deeply_normalize, deeply_normalize_with_skipped_universes};

View File

@ -1,23 +1,29 @@
use std::marker::PhantomData;
use crate::traits::error_reporting::{OverflowCause, TypeErrCtxtExt}; use crate::traits::error_reporting::{OverflowCause, TypeErrCtxtExt};
use crate::traits::query::evaluate_obligation::InferCtxtExt; 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_data_structures::stack::ensure_sufficient_stack;
use rustc_infer::infer::at::At; use rustc_infer::infer::at::At;
use rustc_infer::infer::InferCtxt; 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::traits::ObligationCause;
use rustc_middle::ty::{self, Ty, TyCtxt, UniverseIndex}; use rustc_middle::ty::{self, Ty, TyCtxt, UniverseIndex};
use rustc_middle::ty::{FallibleTypeFolder, TypeFolder, TypeSuperFoldable}; use rustc_middle::ty::{FallibleTypeFolder, TypeFolder, TypeSuperFoldable};
use rustc_middle::ty::{TypeFoldable, TypeVisitableExt}; 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 /// Deeply normalize all aliases in `value`. This does not handle inference and expects
/// its input to be already fully resolved. /// its input to be already fully resolved.
pub fn deeply_normalize<'tcx, T: TypeFoldable<TyCtxt<'tcx>>>( pub fn deeply_normalize<
'tcx,
T: TypeFoldable<TyCtxt<'tcx>>,
E: FromSolverError<'tcx, NextSolverError<'tcx>>,
>(
at: At<'_, 'tcx>, at: At<'_, 'tcx>,
value: T, value: T,
) -> Result<T, Vec<FulfillmentError<'tcx>>> { ) -> Result<T, Vec<E>> {
assert!(!value.has_escaping_bound_vars()); assert!(!value.has_escaping_bound_vars());
deeply_normalize_with_skipped_universes(at, value, vec![]) deeply_normalize_with_skipped_universes(at, value, vec![])
} }
@ -28,29 +34,32 @@ pub fn deeply_normalize<'tcx, T: TypeFoldable<TyCtxt<'tcx>>>(
/// Additionally takes a list of universes which represents the binders which have been /// 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 /// entered before passing `value` to the function. This is currently needed for
/// `normalize_erasing_regions`, which skips binders as it walks through a type. /// `normalize_erasing_regions`, which skips binders as it walks through a type.
pub fn deeply_normalize_with_skipped_universes<'tcx, T: TypeFoldable<TyCtxt<'tcx>>>( pub fn deeply_normalize_with_skipped_universes<
'tcx,
T: TypeFoldable<TyCtxt<'tcx>>,
E: FromSolverError<'tcx, NextSolverError<'tcx>>,
>(
at: At<'_, 'tcx>, at: At<'_, 'tcx>,
value: T, value: T,
universes: Vec<Option<UniverseIndex>>, universes: Vec<Option<UniverseIndex>>,
) -> Result<T, Vec<FulfillmentError<'tcx>>> { ) -> Result<T, Vec<E>> {
let fulfill_cx = FulfillmentCtxt::new(at.infcx); 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) value.try_fold_with(&mut folder)
} }
struct NormalizationFolder<'me, 'tcx> { struct NormalizationFolder<'me, 'tcx, E: FulfillmentErrorLike<'tcx>> {
at: At<'me, 'tcx>, at: At<'me, 'tcx>,
fulfill_cx: FulfillmentCtxt<'tcx>, fulfill_cx: FulfillmentCtxt<'tcx, E>,
depth: usize, depth: usize,
universes: Vec<Option<UniverseIndex>>, universes: Vec<Option<UniverseIndex>>,
_errors: PhantomData<E>,
} }
impl<'tcx> NormalizationFolder<'_, 'tcx> { impl<'tcx, E: FromSolverError<'tcx, NextSolverError<'tcx>>> NormalizationFolder<'_, 'tcx, E> {
fn normalize_alias_ty( fn normalize_alias_ty(&mut self, alias_ty: Ty<'tcx>) -> Result<Ty<'tcx>, Vec<E>> {
&mut self,
alias_ty: Ty<'tcx>,
) -> Result<Ty<'tcx>, Vec<FulfillmentError<'tcx>>> {
assert!(matches!(alias_ty.kind(), ty::Alias(..))); assert!(matches!(alias_ty.kind(), ty::Alias(..)));
let infcx = self.at.infcx; let infcx = self.at.infcx;
@ -101,7 +110,7 @@ fn normalize_unevaluated_const(
&mut self, &mut self,
ty: Ty<'tcx>, ty: Ty<'tcx>,
uv: ty::UnevaluatedConst<'tcx>, uv: ty::UnevaluatedConst<'tcx>,
) -> Result<ty::Const<'tcx>, Vec<FulfillmentError<'tcx>>> { ) -> Result<ty::Const<'tcx>, Vec<E>> {
let infcx = self.at.infcx; let infcx = self.at.infcx;
let tcx = infcx.tcx; let tcx = infcx.tcx;
let recursion_limit = tcx.recursion_limit(); let recursion_limit = tcx.recursion_limit();
@ -141,8 +150,10 @@ fn normalize_unevaluated_const(
} }
} }
impl<'tcx> FallibleTypeFolder<TyCtxt<'tcx>> for NormalizationFolder<'_, 'tcx> { impl<'tcx, E: FromSolverError<'tcx, NextSolverError<'tcx>>> FallibleTypeFolder<TyCtxt<'tcx>>
type Error = Vec<FulfillmentError<'tcx>>; for NormalizationFolder<'_, 'tcx, E>
{
type Error = Vec<E>;
fn interner(&self) -> TyCtxt<'tcx> { fn interner(&self) -> TyCtxt<'tcx> {
self.at.infcx.tcx self.at.infcx.tcx
@ -242,7 +253,8 @@ fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
ty, ty,
vec![None; ty.outer_exclusive_binder().as_usize()], vec![None; ty.outer_exclusive_binder().as_usize()],
) )
.unwrap_or_else(|_| ty.super_fold_with(self)) // TODO:
.unwrap_or_else(|_: Vec<FulfillmentError<'tcx>>| ty.super_fold_with(self))
} }
fn fold_const(&mut self, ct: ty::Const<'tcx>) -> ty::Const<'tcx> { fn fold_const(&mut self, ct: ty::Const<'tcx>) -> ty::Const<'tcx> {
@ -251,6 +263,7 @@ fn fold_const(&mut self, ct: ty::Const<'tcx>) -> ty::Const<'tcx> {
ct, ct,
vec![None; ct.outer_exclusive_binder().as_usize()], vec![None; ct.outer_exclusive_binder().as_usize()],
) )
.unwrap_or_else(|_| ct.super_fold_with(self)) // TODO:
.unwrap_or_else(|_: Vec<FulfillmentError<'tcx>>| ct.super_fold_with(self))
} }
} }

View File

@ -11,6 +11,7 @@
use crate::traits::select::IntercrateAmbiguityCause; use crate::traits::select::IntercrateAmbiguityCause;
use crate::traits::NormalizeExt; use crate::traits::NormalizeExt;
use crate::traits::SkipLeakCheck; use crate::traits::SkipLeakCheck;
use crate::traits::{util, FulfillmentErrorCode};
use crate::traits::{ use crate::traits::{
Obligation, ObligationCause, PredicateObligation, PredicateObligations, SelectionContext, Obligation, ObligationCause, PredicateObligation, PredicateObligations, SelectionContext,
}; };
@ -19,7 +20,6 @@
use rustc_hir::def::DefKind; use rustc_hir::def::DefKind;
use rustc_hir::def_id::DefId; use rustc_hir::def_id::DefId;
use rustc_infer::infer::{DefineOpaqueTypes, InferCtxt, TyCtxtInferExt}; use rustc_infer::infer::{DefineOpaqueTypes, InferCtxt, TyCtxtInferExt};
use rustc_infer::traits::{util, FulfillmentErrorCode};
use rustc_middle::bug; use rustc_middle::bug;
use rustc_middle::traits::query::NoSolution; use rustc_middle::traits::query::NoSolution;
use rustc_middle::traits::solve::{CandidateSource, Certainty, Goal}; use rustc_middle::traits::solve::{CandidateSource, Certainty, Goal};

View File

@ -2,12 +2,15 @@
use std::fmt::Debug; use std::fmt::Debug;
use super::FulfillmentContext; use super::FulfillmentContext;
use super::TraitEngine; use super::{FromSolverError, TraitEngine};
use crate::regions::InferCtxtRegionExt; use crate::regions::InferCtxtRegionExt;
use crate::solve::FulfillmentCtxt as NextFulfillmentCtxt; use crate::solve::FulfillmentCtxt as NextFulfillmentCtxt;
use crate::solve::NextSolverError;
use crate::traits::error_reporting::TypeErrCtxtExt; use crate::traits::error_reporting::TypeErrCtxtExt;
use crate::traits::fulfill::OldSolverError;
use crate::traits::NormalizeExt; use crate::traits::NormalizeExt;
use crate::traits::StructurallyNormalizeExt; use crate::traits::StructurallyNormalizeExt;
use crate::traits::{FulfillmentError, Obligation, ObligationCause, PredicateObligation};
use rustc_data_structures::fx::FxIndexSet; use rustc_data_structures::fx::FxIndexSet;
use rustc_errors::ErrorGuaranteed; use rustc_errors::ErrorGuaranteed;
use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir::def_id::{DefId, LocalDefId};
@ -18,7 +21,6 @@
use rustc_infer::infer::outlives::env::OutlivesEnvironment; use rustc_infer::infer::outlives::env::OutlivesEnvironment;
use rustc_infer::infer::RegionResolutionError; use rustc_infer::infer::RegionResolutionError;
use rustc_infer::infer::{DefineOpaqueTypes, InferCtxt, InferOk}; use rustc_infer::infer::{DefineOpaqueTypes, InferCtxt, InferOk};
use rustc_infer::traits::{FulfillmentError, Obligation, ObligationCause, PredicateObligation};
use rustc_macros::extension; use rustc_macros::extension;
use rustc_middle::arena::ArenaAllocatable; use rustc_middle::arena::ArenaAllocatable;
use rustc_middle::traits::query::NoSolution; use rustc_middle::traits::query::NoSolution;
@ -28,8 +30,12 @@
use rustc_middle::ty::Variance; use rustc_middle::ty::Variance;
use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_middle::ty::{self, Ty, TyCtxt};
#[extension(pub trait TraitEngineExt<'tcx>)] #[extension(pub trait TraitEngineExt<'tcx, E>)]
impl<'tcx> dyn TraitEngine<'tcx> { impl<
'tcx,
E: FromSolverError<'tcx, NextSolverError<'tcx>> + FromSolverError<'tcx, OldSolverError<'tcx>>,
> dyn TraitEngine<'tcx, E>
{
fn new(infcx: &InferCtxt<'tcx>) -> Box<Self> { fn new(infcx: &InferCtxt<'tcx>) -> Box<Self> {
if infcx.next_trait_solver() { if infcx.next_trait_solver() {
Box::new(NextFulfillmentCtxt::new(infcx)) Box::new(NextFulfillmentCtxt::new(infcx))
@ -49,12 +55,16 @@ fn new(infcx: &InferCtxt<'tcx>) -> Box<Self> {
/// with obligations outside of hir or mir typeck. /// with obligations outside of hir or mir typeck.
pub struct ObligationCtxt<'a, 'tcx> { pub struct ObligationCtxt<'a, 'tcx> {
pub infcx: &'a InferCtxt<'tcx>, pub infcx: &'a InferCtxt<'tcx>,
engine: RefCell<Box<dyn TraitEngine<'tcx>>>, engine: RefCell<Box<dyn TraitEngine<'tcx, FulfillmentError<'tcx>>>>,
} }
impl<'a, 'tcx> ObligationCtxt<'a, 'tcx> { impl<'a, 'tcx> ObligationCtxt<'a, 'tcx> {
pub fn new(infcx: &'a InferCtxt<'tcx>) -> Self { pub fn new(infcx: &'a InferCtxt<'tcx>) -> Self {
Self { infcx, engine: RefCell::new(<dyn TraitEngine<'_>>::new(infcx)) } // TODO:
Self {
infcx,
engine: RefCell::new(<dyn TraitEngine<'tcx, FulfillmentError<'tcx>>>::new(infcx)),
}
} }
pub fn register_obligation(&self, obligation: PredicateObligation<'tcx>) { pub fn register_obligation(&self, obligation: PredicateObligation<'tcx>) {

View File

@ -6,7 +6,7 @@
use rustc_data_structures::obligation_forest::{Error, ForestObligation, Outcome}; use rustc_data_structures::obligation_forest::{Error, ForestObligation, Outcome};
use rustc_data_structures::obligation_forest::{ObligationForest, ObligationProcessor}; use rustc_data_structures::obligation_forest::{ObligationForest, ObligationProcessor};
use rustc_infer::infer::DefineOpaqueTypes; 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_infer::traits::{PolyTraitObligation, SelectionError, TraitEngine};
use rustc_middle::bug; use rustc_middle::bug;
use rustc_middle::mir::interpret::ErrorHandled; use rustc_middle::mir::interpret::ErrorHandled;
@ -50,7 +50,7 @@ fn as_cache_key(&self) -> Self::CacheKey {
/// along. Once all type inference constraints have been generated, the /// along. Once all type inference constraints have been generated, the
/// method `select_all_or_error` can be used to report any remaining /// method `select_all_or_error` can be used to report any remaining
/// ambiguous cases as errors. /// 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 /// A list of all obligations that have been registered with this
/// fulfillment context. /// fulfillment context.
predicates: ObligationForest<PendingPredicateObligation<'tcx>>, predicates: ObligationForest<PendingPredicateObligation<'tcx>>,
@ -60,6 +60,8 @@ pub struct FulfillmentContext<'tcx> {
/// gets rolled back. Because of this we explicitly check that we only /// gets rolled back. Because of this we explicitly check that we only
/// use the context in exactly this snapshot. /// use the context in exactly this snapshot.
usable_in_snapshot: usize, usable_in_snapshot: usize,
_errors: PhantomData<E>,
} }
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
@ -76,9 +78,9 @@ pub struct PendingPredicateObligation<'tcx> {
#[cfg(target_pointer_width = "64")] #[cfg(target_pointer_width = "64")]
rustc_data_structures::static_assert_size!(PendingPredicateObligation<'_>, 72); 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. /// 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!( assert!(
!infcx.next_trait_solver(), !infcx.next_trait_solver(),
"old trait solver fulfillment context created when \ "old trait solver fulfillment context created when \
@ -87,13 +89,15 @@ pub(super) fn new(infcx: &InferCtxt<'tcx>) -> FulfillmentContext<'tcx> {
FulfillmentContext { FulfillmentContext {
predicates: ObligationForest::new(), predicates: ObligationForest::new(),
usable_in_snapshot: infcx.num_open_snapshots(), usable_in_snapshot: infcx.num_open_snapshots(),
_errors: PhantomData,
} }
} }
/// Attempts to select obligations using `selcx`. /// Attempts to select obligations using `selcx`.
fn select(&mut self, selcx: SelectionContext<'_, 'tcx>) -> Vec<FulfillmentError<'tcx>> { fn select(&mut self, selcx: SelectionContext<'_, 'tcx>) -> Vec<E> {
let span = debug_span!("select", obligation_forest_size = ?self.predicates.len()); let span = debug_span!("select", obligation_forest_size = ?self.predicates.len());
let _enter = span.enter(); let _enter = span.enter();
let infcx = selcx.infcx;
// Process pending obligations. // Process pending obligations.
let outcome: Outcome<_, _> = let outcome: Outcome<_, _> =
@ -102,8 +106,8 @@ fn select(&mut self, selcx: SelectionContext<'_, 'tcx>) -> Vec<FulfillmentError<
// FIXME: if we kept the original cache key, we could mark projection // FIXME: if we kept the original cache key, we could mark projection
// obligations as complete for the projection cache here. // obligations as complete for the projection cache here.
let errors: Vec<FulfillmentError<'tcx>> = let errors: Vec<E> =
outcome.errors.into_iter().map(to_fulfillment_error).collect(); outcome.errors.into_iter().map(|err| E::from_solver_error(infcx, err)).collect();
debug!( debug!(
"select({} predicates remaining, {} errors) done", "select({} predicates remaining, {} errors) done",
@ -115,7 +119,9 @@ fn select(&mut self, selcx: SelectionContext<'_, 'tcx>) -> Vec<FulfillmentError<
} }
} }
impl<'tcx> TraitEngine<'tcx> for FulfillmentContext<'tcx> { impl<'tcx, E: FromSolverError<'tcx, OldSolverError<'tcx>>> TraitEngine<'tcx, E>
for FulfillmentContext<'tcx, E>
{
#[inline] #[inline]
fn register_predicate_obligation( fn register_predicate_obligation(
&mut self, &mut self,
@ -134,18 +140,15 @@ fn register_predicate_obligation(
.register_obligation(PendingPredicateObligation { obligation, stalled_on: vec![] }); .register_obligation(PendingPredicateObligation { obligation, stalled_on: vec![] });
} }
fn collect_remaining_errors( fn collect_remaining_errors(&mut self, infcx: &InferCtxt<'tcx>) -> Vec<E> {
&mut self,
_infcx: &InferCtxt<'tcx>,
) -> Vec<FulfillmentError<'tcx>> {
self.predicates self.predicates
.to_errors(FulfillmentErrorCode::Ambiguity { overflow: None }) .to_errors(FulfillmentErrorCode::Ambiguity { overflow: None })
.into_iter() .into_iter()
.map(to_fulfillment_error) .map(|err| E::from_solver_error(infcx, err))
.collect() .collect()
} }
fn select_where_possible(&mut self, infcx: &InferCtxt<'tcx>) -> Vec<FulfillmentError<'tcx>> { fn select_where_possible(&mut self, infcx: &InferCtxt<'tcx>) -> Vec<E> {
let selcx = SelectionContext::new(infcx); let selcx = SelectionContext::new(infcx);
self.select(selcx) self.select(selcx)
} }
@ -840,13 +843,15 @@ fn args_infer_vars<'a, 'tcx>(
.filter_map(TyOrConstInferVar::maybe_from_generic_arg) .filter_map(TyOrConstInferVar::maybe_from_generic_arg)
} }
fn to_fulfillment_error<'tcx>( pub type OldSolverError<'tcx> = Error<PendingPredicateObligation<'tcx>, FulfillmentErrorCode<'tcx>>;
error: Error<PendingPredicateObligation<'tcx>, FulfillmentErrorCode<'tcx>>,
) -> FulfillmentError<'tcx> { impl<'tcx> FromSolverError<'tcx, OldSolverError<'tcx>> for FulfillmentError<'tcx> {
let mut iter = error.backtrace.into_iter(); fn from_solver_error(_infcx: &InferCtxt<'tcx>, error: OldSolverError<'tcx>) -> Self {
let obligation = iter.next().unwrap().obligation; let mut iter = error.backtrace.into_iter();
// The root obligation is the last item in the backtrace - if there's only let obligation = iter.next().unwrap().obligation;
// one item, then it's the same as the main obligation // The root obligation is the last item in the backtrace - if there's only
let root_obligation = iter.next_back().map_or_else(|| obligation.clone(), |e| e.obligation); // one item, then it's the same as the main obligation
FulfillmentError::new(obligation, error.error, root_obligation) let root_obligation = iter.next_back().map_or_else(|| obligation.clone(), |e| e.obligation);
FulfillmentError::new(obligation, error.error, root_obligation)
}
} }

View File

@ -1,13 +1,13 @@
//! Miscellaneous type-system utilities that are too small to deserve their own modules. //! Miscellaneous type-system utilities that are too small to deserve their own modules.
use crate::regions::InferCtxtRegionExt; use crate::regions::InferCtxtRegionExt;
use crate::traits::{self, ObligationCause}; use crate::traits::{self, FulfillmentError, ObligationCause};
use hir::LangItem; use hir::LangItem;
use rustc_data_structures::fx::FxIndexSet; use rustc_data_structures::fx::FxIndexSet;
use rustc_hir as hir; use rustc_hir as hir;
use rustc_infer::infer::outlives::env::OutlivesEnvironment;
use rustc_infer::infer::{RegionResolutionError, TyCtxtInferExt}; 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 rustc_middle::ty::{self, AdtDef, Ty, TyCtxt, TypeVisitableExt};
use super::outlives_bounds::InferCtxtExt; use super::outlives_bounds::InferCtxtExt;

View File

@ -70,6 +70,49 @@
pub use rustc_infer::traits::*; 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. /// Whether to skip the leak check, as part of a future compatibility warning step.
/// ///
/// The "default" for skip-leak-check corresponds to the current /// The "default" for skip-leak-check corresponds to the current

View File

@ -3,11 +3,13 @@
use super::error_reporting::TypeErrCtxtExt; use super::error_reporting::TypeErrCtxtExt;
use super::SelectionContext; use super::SelectionContext;
use super::{project, with_replaced_escaping_bound_vars, BoundVarReplacer, PlaceholderReplacer}; use super::{project, with_replaced_escaping_bound_vars, BoundVarReplacer, PlaceholderReplacer};
use crate::solve::NextSolverError;
use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_data_structures::stack::ensure_sufficient_stack;
use rustc_infer::infer::at::At; use rustc_infer::infer::at::At;
use rustc_infer::infer::InferOk; use rustc_infer::infer::InferOk;
use rustc_infer::traits::FromSolverError;
use rustc_infer::traits::PredicateObligation; 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_macros::extension;
use rustc_middle::traits::{ObligationCause, ObligationCauseCode, Reveal}; use rustc_middle::traits::{ObligationCause, ObligationCauseCode, Reveal};
use rustc_middle::ty::{self, Ty, TyCtxt, TypeFolder}; use rustc_middle::ty::{self, Ty, TyCtxt, TypeFolder};
@ -44,11 +46,14 @@ fn normalize<T: TypeFoldable<TyCtxt<'tcx>>>(&self, value: T) -> InferOk<'tcx, T>
/// existing fulfillment context in the old solver. Once we also eagerly prove goals with /// 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 /// the old solver or have removed the old solver, remove `traits::fully_normalize` and
/// rename this function to `At::fully_normalize`. /// rename this function to `At::fully_normalize`.
fn deeply_normalize<T: TypeFoldable<TyCtxt<'tcx>>>( fn deeply_normalize<
T: TypeFoldable<TyCtxt<'tcx>>,
E: FromSolverError<'tcx, NextSolverError<'tcx>>,
>(
self, self,
value: T, value: T,
fulfill_cx: &mut dyn TraitEngine<'tcx>, fulfill_cx: &mut dyn TraitEngine<'tcx, E>,
) -> Result<T, Vec<FulfillmentError<'tcx>>> { ) -> Result<T, Vec<E>> {
if self.infcx.next_trait_solver() { if self.infcx.next_trait_solver() {
crate::solve::deeply_normalize(self, value) crate::solve::deeply_normalize(self, value)
} else { } else {

View File

@ -9,10 +9,10 @@
use crate::traits::error_reporting::TypeErrCtxtExt; use crate::traits::error_reporting::TypeErrCtxtExt;
use crate::traits::normalize::needs_normalization; use crate::traits::normalize::needs_normalization;
use crate::traits::{BoundVarReplacer, PlaceholderReplacer}; use crate::traits::{BoundVarReplacer, PlaceholderReplacer};
use crate::traits::{FulfillmentError, Normalized};
use crate::traits::{ObligationCause, PredicateObligation, Reveal}; use crate::traits::{ObligationCause, PredicateObligation, Reveal};
use rustc_data_structures::sso::SsoHashMap; use rustc_data_structures::sso::SsoHashMap;
use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_data_structures::stack::ensure_sufficient_stack;
use rustc_infer::traits::Normalized;
use rustc_macros::extension; use rustc_macros::extension;
use rustc_middle::ty::fold::{FallibleTypeFolder, TypeFoldable, TypeSuperFoldable}; use rustc_middle::ty::fold::{FallibleTypeFolder, TypeFoldable, TypeSuperFoldable};
use rustc_middle::ty::visit::{TypeSuperVisitable, TypeVisitable, TypeVisitableExt}; use rustc_middle::ty::visit::{TypeSuperVisitable, TypeVisitable, TypeVisitableExt};
@ -76,7 +76,10 @@ fn query_normalize<T>(self, value: T) -> Result<Normalized<'tcx, T>, NoSolution>
}; };
if self.infcx.next_trait_solver() { 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![] }), Ok(value) => return Ok(Normalized { value, obligations: vec![] }),
Err(_errors) => { Err(_errors) => {
return Err(NoSolution); return Err(NoSolution);

View File

@ -1,6 +1,7 @@
use crate::solve; use crate::solve;
use crate::traits::query::NoSolution; use crate::traits::query::NoSolution;
use crate::traits::wf; use crate::traits::wf;
use crate::traits::FulfillmentError;
use crate::traits::ObligationCtxt; use crate::traits::ObligationCtxt;
use rustc_infer::infer::canonical::Canonical; 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), ocx.infcx.at(&ObligationCause::dummy(), param_env),
ty_a, ty_a,
) )
.map_err(|_errs| NoSolution)?; // TODO:
.map_err(|_errs: Vec<FulfillmentError<'tcx>>| NoSolution)?;
} }
let mut components = smallvec![]; let mut components = smallvec![];
push_outlives_components(tcx, ty_a, &mut components); push_outlives_components(tcx, ty_a, &mut components);

View File

@ -1,5 +1,5 @@
use rustc_infer::infer::at::At; use rustc_infer::infer::at::At;
use rustc_infer::traits::{FulfillmentError, TraitEngine}; use rustc_infer::traits::{FulfillmentErrorLike, TraitEngine};
use rustc_macros::extension; use rustc_macros::extension;
use rustc_middle::ty::{self, Ty}; use rustc_middle::ty::{self, Ty};
@ -7,11 +7,11 @@
#[extension(pub trait StructurallyNormalizeExt<'tcx>)] #[extension(pub trait StructurallyNormalizeExt<'tcx>)]
impl<'tcx> At<'_, 'tcx> { impl<'tcx> At<'_, 'tcx> {
fn structurally_normalize( fn structurally_normalize<E: FulfillmentErrorLike<'tcx>>(
&self, &self,
ty: Ty<'tcx>, ty: Ty<'tcx>,
fulfill_cx: &mut dyn TraitEngine<'tcx>, fulfill_cx: &mut dyn TraitEngine<'tcx, E>,
) -> Result<Ty<'tcx>, Vec<FulfillmentError<'tcx>>> { ) -> Result<Ty<'tcx>, Vec<E>> {
assert!(!ty.is_ty_var(), "should have resolved vars before calling"); assert!(!ty.is_ty_var(), "should have resolved vars before calling");
if self.infcx.next_trait_solver() { if self.infcx.next_trait_solver() {