Make TraitEngines generic over error
This commit is contained in:
@@ -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<E>,
|
||||
}
|
||||
|
||||
#[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<FulfillmentError<'tcx>> {
|
||||
let mut errors: Vec<_> = self
|
||||
.obligations
|
||||
fn collect_remaining_errors(&mut self, infcx: &InferCtxt<'tcx>) -> Vec<E> {
|
||||
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<FulfillmentError<'tcx>> {
|
||||
fn select_where_possible(&mut self, infcx: &InferCtxt<'tcx>) -> Vec<E> {
|
||||
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>,
|
||||
|
||||
@@ -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};
|
||||
|
||||
|
||||
@@ -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<TyCtxt<'tcx>>>(
|
||||
pub fn deeply_normalize<
|
||||
'tcx,
|
||||
T: TypeFoldable<TyCtxt<'tcx>>,
|
||||
E: FromSolverError<'tcx, NextSolverError<'tcx>>,
|
||||
>(
|
||||
at: At<'_, 'tcx>,
|
||||
value: T,
|
||||
) -> Result<T, Vec<FulfillmentError<'tcx>>> {
|
||||
) -> Result<T, Vec<E>> {
|
||||
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<TyCtxt<'tcx>>>(
|
||||
/// 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<TyCtxt<'tcx>>>(
|
||||
pub fn deeply_normalize_with_skipped_universes<
|
||||
'tcx,
|
||||
T: TypeFoldable<TyCtxt<'tcx>>,
|
||||
E: FromSolverError<'tcx, NextSolverError<'tcx>>,
|
||||
>(
|
||||
at: At<'_, 'tcx>,
|
||||
value: T,
|
||||
universes: Vec<Option<UniverseIndex>>,
|
||||
) -> Result<T, Vec<FulfillmentError<'tcx>>> {
|
||||
) -> Result<T, Vec<E>> {
|
||||
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<Option<UniverseIndex>>,
|
||||
_errors: PhantomData<E>,
|
||||
}
|
||||
|
||||
impl<'tcx> NormalizationFolder<'_, 'tcx> {
|
||||
fn normalize_alias_ty(
|
||||
&mut self,
|
||||
alias_ty: Ty<'tcx>,
|
||||
) -> Result<Ty<'tcx>, Vec<FulfillmentError<'tcx>>> {
|
||||
impl<'tcx, E: FromSolverError<'tcx, NextSolverError<'tcx>>> NormalizationFolder<'_, 'tcx, E> {
|
||||
fn normalize_alias_ty(&mut self, alias_ty: Ty<'tcx>) -> Result<Ty<'tcx>, Vec<E>> {
|
||||
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<ty::Const<'tcx>, Vec<FulfillmentError<'tcx>>> {
|
||||
) -> Result<ty::Const<'tcx>, Vec<E>> {
|
||||
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<TyCtxt<'tcx>> for NormalizationFolder<'_, 'tcx> {
|
||||
type Error = Vec<FulfillmentError<'tcx>>;
|
||||
impl<'tcx, E: FromSolverError<'tcx, NextSolverError<'tcx>>> FallibleTypeFolder<TyCtxt<'tcx>>
|
||||
for NormalizationFolder<'_, 'tcx, E>
|
||||
{
|
||||
type Error = Vec<E>;
|
||||
|
||||
fn interner(&self) -> TyCtxt<'tcx> {
|
||||
self.at.infcx.tcx
|
||||
@@ -242,7 +253,8 @@ impl<'tcx> TypeFolder<TyCtxt<'tcx>> for DeeplyNormalizeForDiagnosticsFolder<'_,
|
||||
ty,
|
||||
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> {
|
||||
@@ -251,6 +263,7 @@ impl<'tcx> TypeFolder<TyCtxt<'tcx>> for DeeplyNormalizeForDiagnosticsFolder<'_,
|
||||
ct,
|
||||
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))
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user