Make TraitEngines generic over error
This commit is contained in:
parent
084ccd2390
commit
54b2b7d460
@ -13,6 +13,7 @@
|
||||
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 @@ fn normalize_and_add_type_outlives_constraints(
|
||||
ocx.infcx.at(&ObligationCause::dummy_with_span(self.span), self.param_env),
|
||||
ty,
|
||||
)
|
||||
.map_err(|_| NoSolution)
|
||||
.map_err(|_: Vec<FulfillmentError<'tcx>>| NoSolution)
|
||||
},
|
||||
"normalize type outlives obligation",
|
||||
)
|
||||
|
@ -10,7 +10,7 @@
|
||||
use rustc_hir::{GenericParamKind, ImplItemKind};
|
||||
use rustc_infer::infer::outlives::env::OutlivesEnvironment;
|
||||
use rustc_infer::infer::{self, InferCtxt, TyCtxtInferExt};
|
||||
use rustc_infer::traits::{util, 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::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;
|
||||
|
@ -13,8 +13,8 @@
|
||||
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 = <dyn traits::TraitEngine<'_>>::new(&infcx);
|
||||
let mut fulfill_cx =
|
||||
<dyn traits::TraitEngine<'tcx, FulfillmentError<'tcx>>>::new(&infcx);
|
||||
infcx
|
||||
.at(&cause, ty::ParamEnv::empty())
|
||||
.structurally_normalize(ty, &mut *fulfill_cx)
|
||||
|
@ -15,7 +15,6 @@
|
||||
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::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,
|
||||
};
|
||||
|
@ -11,7 +11,9 @@
|
||||
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<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.
|
||||
/// 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 {
|
||||
typeck_results,
|
||||
fulfillment_cx: RefCell::new(<dyn TraitEngine<'_>>::new(&infcx)),
|
||||
fulfillment_cx: RefCell::new(<dyn TraitEngine<'_, _>>::new(&infcx)),
|
||||
infcx,
|
||||
locals: RefCell::new(Default::default()),
|
||||
deferred_sized_obligations: RefCell::new(Vec::new()),
|
||||
|
@ -15,7 +15,7 @@
|
||||
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 @@ pub fn make_query_response_ignoring_pending_obligations<T>(
|
||||
/// 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 @@ fn make_query_response<T>(
|
||||
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 @@ fn make_query_response<T>(
|
||||
});
|
||||
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 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 @@ pub fn build(&mut self) -> InferCtxt<'tcx> {
|
||||
|
||||
impl<'tcx, T> InferOk<'tcx, T> {
|
||||
/// Extracts `value`, registering any obligations into `fulfill_cx`.
|
||||
pub fn into_value_registering_obligations(
|
||||
pub fn into_value_registering_obligations<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 @@ fn register_predicate_obligations(
|
||||
}
|
||||
|
||||
#[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 @@ fn drain_unstalled_obligations(
|
||||
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::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 fn derived_cause(
|
||||
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 @@ 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> {
|
||||
pub fn polarity(&self) -> ty::PredicatePolarity {
|
||||
self.predicate.skip_binder().polarity
|
||||
|
@ -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> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
use traits::FulfillmentErrorCode::*;
|
||||
|
@ -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 @@ fn resolve_regions(
|
||||
),
|
||||
ty,
|
||||
)
|
||||
.map_err(|_| NoSolution)
|
||||
// TODO:
|
||||
.map_err(|_: Vec<FulfillmentError<'tcx>>| NoSolution)
|
||||
} else {
|
||||
Ok(ty)
|
||||
}
|
||||
|
@ -1,3 +1,4 @@
|
||||
use std::marker::PhantomData;
|
||||
use std::mem;
|
||||
use std::ops::ControlFlow;
|
||||
|
||||
@ -5,14 +6,17 @@
|
||||
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 @@
|
||||
///
|
||||
/// 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 @@ fn on_fulfillment_overflow(&mut self, infcx: &InferCtxt<'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 @@ pub fn new(infcx: &InferCtxt<'tcx>) -> FulfillmentCtxt<'tcx> {
|
||||
FulfillmentCtxt {
|
||||
obligations: Default::default(),
|
||||
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))]
|
||||
fn register_predicate_obligation(
|
||||
&mut self,
|
||||
@ -129,24 +137,22 @@ fn register_predicate_obligation(
|
||||
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 @@ fn select_where_possible(&mut self, infcx: &InferCtxt<'tcx>) -> Vec<FulfillmentE
|
||||
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 @@ 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>(
|
||||
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 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 @@ fn normalize_unevaluated_const(
|
||||
&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 @@ fn normalize_unevaluated_const(
|
||||
}
|
||||
}
|
||||
|
||||
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 @@ fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
|
||||
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 @@ fn fold_const(&mut self, ct: ty::Const<'tcx>) -> ty::Const<'tcx> {
|
||||
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))
|
||||
}
|
||||
}
|
||||
|
@ -11,6 +11,7 @@
|
||||
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_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};
|
||||
|
@ -2,12 +2,15 @@
|
||||
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::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::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<Self> {
|
||||
if infcx.next_trait_solver() {
|
||||
Box::new(NextFulfillmentCtxt::new(infcx))
|
||||
@ -49,12 +55,16 @@ fn new(infcx: &InferCtxt<'tcx>) -> Box<Self> {
|
||||
/// with obligations outside of hir or mir typeck.
|
||||
pub struct ObligationCtxt<'a, '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> {
|
||||
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>) {
|
||||
|
@ -6,7 +6,7 @@
|
||||
use rustc_data_structures::obligation_forest::{Error, ForestObligation, Outcome};
|
||||
use rustc_data_structures::obligation_forest::{ObligationForest, ObligationProcessor};
|
||||
use rustc_infer::infer::DefineOpaqueTypes;
|
||||
use rustc_infer::traits::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 @@ fn as_cache_key(&self) -> Self::CacheKey {
|
||||
/// along. Once all type inference constraints have been generated, the
|
||||
/// method `select_all_or_error` can be used to report any remaining
|
||||
/// ambiguous cases as errors.
|
||||
pub struct FulfillmentContext<'tcx> {
|
||||
pub struct FulfillmentContext<'tcx, E: FulfillmentErrorLike<'tcx>> {
|
||||
/// A list of all obligations that have been registered with this
|
||||
/// fulfillment context.
|
||||
predicates: ObligationForest<PendingPredicateObligation<'tcx>>,
|
||||
@ -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<E>,
|
||||
}
|
||||
|
||||
#[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 @@ pub(super) fn new(infcx: &InferCtxt<'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<FulfillmentError<'tcx>> {
|
||||
fn select(&mut self, selcx: SelectionContext<'_, 'tcx>) -> Vec<E> {
|
||||
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 @@ fn select(&mut self, selcx: SelectionContext<'_, 'tcx>) -> Vec<FulfillmentError<
|
||||
// FIXME: if we kept the original cache key, we could mark projection
|
||||
// obligations as complete for the projection cache here.
|
||||
|
||||
let errors: Vec<FulfillmentError<'tcx>> =
|
||||
outcome.errors.into_iter().map(to_fulfillment_error).collect();
|
||||
let errors: Vec<E> =
|
||||
outcome.errors.into_iter().map(|err| E::from_solver_error(infcx, err)).collect();
|
||||
|
||||
debug!(
|
||||
"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]
|
||||
fn register_predicate_obligation(
|
||||
&mut self,
|
||||
@ -134,18 +140,15 @@ fn register_predicate_obligation(
|
||||
.register_obligation(PendingPredicateObligation { obligation, stalled_on: vec![] });
|
||||
}
|
||||
|
||||
fn collect_remaining_errors(
|
||||
&mut self,
|
||||
_infcx: &InferCtxt<'tcx>,
|
||||
) -> Vec<FulfillmentError<'tcx>> {
|
||||
fn collect_remaining_errors(&mut self, infcx: &InferCtxt<'tcx>) -> Vec<E> {
|
||||
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<FulfillmentError<'tcx>> {
|
||||
fn select_where_possible(&mut self, infcx: &InferCtxt<'tcx>) -> Vec<E> {
|
||||
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<PendingPredicateObligation<'tcx>, 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<PendingPredicateObligation<'tcx>, 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)
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -70,6 +70,49 @@
|
||||
|
||||
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
|
||||
|
@ -3,11 +3,13 @@
|
||||
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 @@ 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
|
||||
/// the old solver or have removed the old solver, remove `traits::fully_normalize` and
|
||||
/// rename this function to `At::fully_normalize`.
|
||||
fn deeply_normalize<T: TypeFoldable<TyCtxt<'tcx>>>(
|
||||
fn deeply_normalize<
|
||||
T: TypeFoldable<TyCtxt<'tcx>>,
|
||||
E: FromSolverError<'tcx, NextSolverError<'tcx>>,
|
||||
>(
|
||||
self,
|
||||
value: T,
|
||||
fulfill_cx: &mut dyn TraitEngine<'tcx>,
|
||||
) -> Result<T, Vec<FulfillmentError<'tcx>>> {
|
||||
fulfill_cx: &mut dyn TraitEngine<'tcx, E>,
|
||||
) -> Result<T, Vec<E>> {
|
||||
if self.infcx.next_trait_solver() {
|
||||
crate::solve::deeply_normalize(self, value)
|
||||
} else {
|
||||
|
@ -9,10 +9,10 @@
|
||||
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 @@ fn query_normalize<T>(self, value: T) -> Result<Normalized<'tcx, T>, NoSolution>
|
||||
};
|
||||
|
||||
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);
|
||||
|
@ -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<FulfillmentError<'tcx>>| NoSolution)?;
|
||||
}
|
||||
let mut components = smallvec![];
|
||||
push_outlives_components(tcx, ty_a, &mut components);
|
||||
|
@ -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 @@
|
||||
|
||||
#[extension(pub trait StructurallyNormalizeExt<'tcx>)]
|
||||
impl<'tcx> At<'_, 'tcx> {
|
||||
fn structurally_normalize(
|
||||
fn structurally_normalize<E: FulfillmentErrorLike<'tcx>>(
|
||||
&self,
|
||||
ty: Ty<'tcx>,
|
||||
fulfill_cx: &mut dyn TraitEngine<'tcx>,
|
||||
) -> Result<Ty<'tcx>, Vec<FulfillmentError<'tcx>>> {
|
||||
fulfill_cx: &mut dyn TraitEngine<'tcx, E>,
|
||||
) -> Result<Ty<'tcx>, Vec<E>> {
|
||||
assert!(!ty.is_ty_var(), "should have resolved vars before calling");
|
||||
|
||||
if self.infcx.next_trait_solver() {
|
||||
|
Loading…
Reference in New Issue
Block a user