Make TraitEngines generic over error
This commit is contained in:
parent
084ccd2390
commit
54b2b7d460
23 changed files with 253 additions and 157 deletions
|
@ -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<T>(
|
||||
pub fn make_canonicalized_query_response<T, E: FulfillmentErrorLike<'tcx>>(
|
||||
&self,
|
||||
inference_vars: CanonicalVarValues<'tcx>,
|
||||
answer: T,
|
||||
fulfill_cx: &mut dyn TraitEngine<'tcx>,
|
||||
fulfill_cx: &mut dyn TraitEngine<'tcx, E>,
|
||||
) -> Result<CanonicalQueryResponse<'tcx, T>, NoSolution>
|
||||
where
|
||||
T: Debug + TypeFoldable<TyCtxt<'tcx>>,
|
||||
|
@ -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<T>(
|
||||
fn make_query_response<T, E: FulfillmentErrorLike<'tcx>>(
|
||||
&self,
|
||||
inference_vars: CanonicalVarValues<'tcx>,
|
||||
answer: T,
|
||||
fulfill_cx: &mut dyn TraitEngine<'tcx>,
|
||||
fulfill_cx: &mut dyn TraitEngine<'tcx, E>,
|
||||
) -> Result<QueryResponse<'tcx, T>, NoSolution>
|
||||
where
|
||||
T: Debug + TypeFoldable<TyCtxt<'tcx>>,
|
||||
|
@ -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();
|
||||
|
||||
|
|
|
@ -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<E: FulfillmentErrorLike<'tcx>>(
|
||||
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);
|
||||
|
|
|
@ -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<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]
|
||||
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);
|
||||
if !errors.is_empty() {
|
||||
return errors;
|
||||
|
@ -71,3 +72,11 @@ pub trait TraitEngine<'tcx>: 'tcx {
|
|||
infcx: &InferCtxt<'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;
|
||||
}
|
||||
|
|
|
@ -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<Certainty, NoSolution>);
|
||||
|
||||
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
|
||||
|
|
|
@ -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::*;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue