Skip to content

Commit 54b2b7d

Browse files
Make TraitEngines generic over error
1 parent 084ccd2 commit 54b2b7d

File tree

23 files changed

+253
-157
lines changed

23 files changed

+253
-157
lines changed

compiler/rustc_borrowck/src/type_check/constraint_conversion.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ use rustc_span::Span;
1313
use rustc_trait_selection::solve::deeply_normalize;
1414
use rustc_trait_selection::traits::query::type_op::custom::CustomTypeOp;
1515
use rustc_trait_selection::traits::query::type_op::{TypeOp, TypeOpOutput};
16+
use rustc_trait_selection::traits::FulfillmentError;
1617

1718
use crate::{
1819
constraints::OutlivesConstraint,
@@ -286,7 +287,7 @@ impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> {
286287
ocx.infcx.at(&ObligationCause::dummy_with_span(self.span), self.param_env),
287288
ty,
288289
)
289-
.map_err(|_| NoSolution)
290+
.map_err(|_: Vec<FulfillmentError<'tcx>>| NoSolution)
290291
},
291292
"normalize type outlives obligation",
292293
)

compiler/rustc_hir_analysis/src/check/compare_impl_item.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ use rustc_hir::intravisit;
1010
use rustc_hir::{GenericParamKind, ImplItemKind};
1111
use rustc_infer::infer::outlives::env::OutlivesEnvironment;
1212
use rustc_infer::infer::{self, InferCtxt, TyCtxtInferExt};
13-
use rustc_infer::traits::{util, FulfillmentError};
13+
use rustc_infer::traits::util;
1414
use rustc_middle::ty::error::{ExpectedFound, TypeError};
1515
use rustc_middle::ty::fold::BottomUpFolder;
1616
use rustc_middle::ty::util::ExplicitSelf;
@@ -25,7 +25,7 @@ use rustc_trait_selection::regions::InferCtxtRegionExt;
2525
use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt;
2626
use rustc_trait_selection::traits::outlives_bounds::InferCtxtExt as _;
2727
use rustc_trait_selection::traits::{
28-
self, ObligationCause, ObligationCauseCode, ObligationCtxt, Reveal,
28+
self, FulfillmentError, ObligationCause, ObligationCauseCode, ObligationCtxt, Reveal,
2929
};
3030
use std::borrow::Cow;
3131
use std::iter;

compiler/rustc_hir_analysis/src/coherence/orphan.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,8 @@ use rustc_middle::ty::{TypeSuperVisitable, TypeVisitable, TypeVisitableExt, Type
1313
use rustc_middle::{bug, span_bug};
1414
use rustc_span::def_id::{DefId, LocalDefId};
1515
use rustc_trait_selection::traits::{self, IsFirstInputType, UncoveredTyParams};
16+
use rustc_trait_selection::traits::{FulfillmentError, StructurallyNormalizeExt, TraitEngineExt};
1617
use rustc_trait_selection::traits::{OrphanCheckErr, OrphanCheckMode};
17-
use rustc_trait_selection::traits::{StructurallyNormalizeExt, TraitEngineExt};
1818

1919
#[instrument(level = "debug", skip(tcx))]
2020
pub(crate) fn orphan_check_impl(
@@ -317,7 +317,8 @@ fn orphan_check<'tcx>(
317317
}
318318

319319
let ty = if infcx.next_trait_solver() {
320-
let mut fulfill_cx = <dyn traits::TraitEngine<'_>>::new(&infcx);
320+
let mut fulfill_cx =
321+
<dyn traits::TraitEngine<'tcx, FulfillmentError<'tcx>>>::new(&infcx);
321322
infcx
322323
.at(&cause, ty::ParamEnv::empty())
323324
.structurally_normalize(ty, &mut *fulfill_cx)

compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@ use rustc_errors::{
1515
use rustc_hir as hir;
1616
use rustc_hir::def::{DefKind, Res};
1717
use rustc_hir::def_id::{DefId, LocalDefId};
18-
use rustc_infer::traits::FulfillmentError;
1918
use rustc_middle::bug;
2019
use rustc_middle::query::Key;
2120
use rustc_middle::ty::print::{PrintPolyTraitRefExt as _, PrintTraitRefExt as _};
@@ -28,6 +27,7 @@ use rustc_span::edit_distance::find_best_match_for_name;
2827
use rustc_span::symbol::{kw, sym, Ident};
2928
use rustc_span::BytePos;
3029
use rustc_span::{Span, Symbol, DUMMY_SP};
30+
use rustc_trait_selection::traits::FulfillmentError;
3131
use rustc_trait_selection::traits::{
3232
object_safety_violations_for_assoc_item, TraitAliasExpansionInfo,
3333
};

compiler/rustc_hir_typeck/src/typeck_root_ctxt.rs

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,9 @@ use rustc_middle::ty::{self, Ty, TyCtxt};
1111
use rustc_span::def_id::LocalDefIdMap;
1212
use rustc_span::Span;
1313
use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt;
14-
use rustc_trait_selection::traits::{self, PredicateObligation, TraitEngine, TraitEngineExt as _};
14+
use rustc_trait_selection::traits::{
15+
self, FulfillmentError, PredicateObligation, TraitEngine, TraitEngineExt as _,
16+
};
1517

1618
use std::cell::RefCell;
1719
use std::ops::Deref;
@@ -34,7 +36,7 @@ pub(crate) struct TypeckRootCtxt<'tcx> {
3436

3537
pub(super) locals: RefCell<HirIdMap<Ty<'tcx>>>,
3638

37-
pub(super) fulfillment_cx: RefCell<Box<dyn TraitEngine<'tcx>>>,
39+
pub(super) fulfillment_cx: RefCell<Box<dyn TraitEngine<'tcx, FulfillmentError<'tcx>>>>,
3840

3941
/// Some additional `Sized` obligations badly affect type inference.
4042
/// These obligations are added in a later stage of typeck.
@@ -83,7 +85,7 @@ impl<'tcx> TypeckRootCtxt<'tcx> {
8385

8486
TypeckRootCtxt {
8587
typeck_results,
86-
fulfillment_cx: RefCell::new(<dyn TraitEngine<'_>>::new(&infcx)),
88+
fulfillment_cx: RefCell::new(<dyn TraitEngine<'_, _>>::new(&infcx)),
8789
infcx,
8890
locals: RefCell::new(Default::default()),
8991
deferred_sized_obligations: RefCell::new(Vec::new()),

compiler/rustc_infer/src/infer/canonical/query_response.rs

Lines changed: 9 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ use crate::infer::canonical::{
1515
use crate::infer::region_constraints::{Constraint, RegionConstraintData};
1616
use crate::infer::{DefineOpaqueTypes, InferCtxt, InferOk, InferResult};
1717
use crate::traits::query::NoSolution;
18-
use crate::traits::TraitEngine;
18+
use crate::traits::{FulfillmentErrorLike, TraitEngine};
1919
use crate::traits::{Obligation, ObligationCause, PredicateObligation};
2020
use rustc_data_structures::captures::Captures;
2121
use rustc_index::Idx;
@@ -50,11 +50,11 @@ impl<'tcx> InferCtxt<'tcx> {
5050
/// - Finally, if any of the obligations result in a hard error,
5151
/// then `Err(NoSolution)` is returned.
5252
#[instrument(skip(self, inference_vars, answer, fulfill_cx), level = "trace")]
53-
pub fn make_canonicalized_query_response<T>(
53+
pub fn make_canonicalized_query_response<T, E: FulfillmentErrorLike<'tcx>>(
5454
&self,
5555
inference_vars: CanonicalVarValues<'tcx>,
5656
answer: T,
57-
fulfill_cx: &mut dyn TraitEngine<'tcx>,
57+
fulfill_cx: &mut dyn TraitEngine<'tcx, E>,
5858
) -> Result<CanonicalQueryResponse<'tcx, T>, NoSolution>
5959
where
6060
T: Debug + TypeFoldable<TyCtxt<'tcx>>,
@@ -97,31 +97,25 @@ impl<'tcx> InferCtxt<'tcx> {
9797
/// Helper for `make_canonicalized_query_response` that does
9898
/// everything up until the final canonicalization.
9999
#[instrument(skip(self, fulfill_cx), level = "debug")]
100-
fn make_query_response<T>(
100+
fn make_query_response<T, E: FulfillmentErrorLike<'tcx>>(
101101
&self,
102102
inference_vars: CanonicalVarValues<'tcx>,
103103
answer: T,
104-
fulfill_cx: &mut dyn TraitEngine<'tcx>,
104+
fulfill_cx: &mut dyn TraitEngine<'tcx, E>,
105105
) -> Result<QueryResponse<'tcx, T>, NoSolution>
106106
where
107107
T: Debug + TypeFoldable<TyCtxt<'tcx>>,
108108
{
109109
let tcx = self.tcx;
110110

111111
// Select everything, returning errors.
112-
let true_errors = fulfill_cx.select_where_possible(self);
113-
debug!("true_errors = {:#?}", true_errors);
112+
let errors = fulfill_cx.select_all_or_error(self);
114113

115-
if !true_errors.is_empty() {
116-
// FIXME -- we don't indicate *why* we failed to solve
117-
debug!("make_query_response: true_errors={:#?}", true_errors);
114+
// True error!
115+
if errors.iter().any(|e| e.is_true_error()) {
118116
return Err(NoSolution);
119117
}
120118

121-
// Anything left unselected *now* must be an ambiguity.
122-
let ambig_errors = fulfill_cx.select_all_or_error(self);
123-
debug!("ambig_errors = {:#?}", ambig_errors);
124-
125119
let region_obligations = self.take_registered_region_obligations();
126120
debug!(?region_obligations);
127121
let region_constraints = self.with_region_constraints(|region_constraints| {
@@ -135,8 +129,7 @@ impl<'tcx> InferCtxt<'tcx> {
135129
});
136130
debug!(?region_constraints);
137131

138-
let certainty =
139-
if ambig_errors.is_empty() { Certainty::Proven } else { Certainty::Ambiguous };
132+
let certainty = if errors.is_empty() { Certainty::Proven } else { Certainty::Ambiguous };
140133

141134
let opaque_types = self.take_opaque_types_for_query_response();
142135

compiler/rustc_infer/src/infer/mod.rs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,8 @@ pub use SubregionOrigin::*;
1212
pub use ValuePairs::*;
1313

1414
use crate::traits::{
15-
self, ObligationCause, ObligationInspector, PredicateObligations, TraitEngine,
15+
self, FulfillmentErrorLike, ObligationCause, ObligationInspector, PredicateObligations,
16+
TraitEngine,
1617
};
1718
use error_reporting::TypeErrCtxt;
1819
use free_regions::RegionRelations;
@@ -737,10 +738,10 @@ impl<'tcx> InferCtxtBuilder<'tcx> {
737738

738739
impl<'tcx, T> InferOk<'tcx, T> {
739740
/// Extracts `value`, registering any obligations into `fulfill_cx`.
740-
pub fn into_value_registering_obligations(
741+
pub fn into_value_registering_obligations<E: FulfillmentErrorLike<'tcx>>(
741742
self,
742743
infcx: &InferCtxt<'tcx>,
743-
fulfill_cx: &mut dyn TraitEngine<'tcx>,
744+
fulfill_cx: &mut dyn TraitEngine<'tcx, E>,
744745
) -> T {
745746
let InferOk { value, obligations } = self;
746747
fulfill_cx.register_predicate_obligations(infcx, obligations);

compiler/rustc_infer/src/traits/engine.rs

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
1+
use std::fmt::Debug;
2+
13
use crate::infer::InferCtxt;
24
use crate::traits::Obligation;
35
use rustc_hir::def_id::DefId;
46
use rustc_middle::ty::{self, Ty, Upcast};
57

6-
use super::FulfillmentError;
78
use super::{ObligationCause, PredicateObligation};
89

9-
pub trait TraitEngine<'tcx>: 'tcx {
10+
pub trait TraitEngine<'tcx, E: FulfillmentErrorLike<'tcx>>: 'tcx {
1011
/// Requires that `ty` must implement the trait with `def_id` in
1112
/// the given environment. This trait must not have any type
1213
/// parameters (except for `Self`).
@@ -47,12 +48,12 @@ pub trait TraitEngine<'tcx>: 'tcx {
4748
}
4849

4950
#[must_use]
50-
fn select_where_possible(&mut self, infcx: &InferCtxt<'tcx>) -> Vec<FulfillmentError<'tcx>>;
51+
fn select_where_possible(&mut self, infcx: &InferCtxt<'tcx>) -> Vec<E>;
5152

52-
fn collect_remaining_errors(&mut self, infcx: &InferCtxt<'tcx>) -> Vec<FulfillmentError<'tcx>>;
53+
fn collect_remaining_errors(&mut self, infcx: &InferCtxt<'tcx>) -> Vec<E>;
5354

5455
#[must_use]
55-
fn select_all_or_error(&mut self, infcx: &InferCtxt<'tcx>) -> Vec<FulfillmentError<'tcx>> {
56+
fn select_all_or_error(&mut self, infcx: &InferCtxt<'tcx>) -> Vec<E> {
5657
let errors = self.select_where_possible(infcx);
5758
if !errors.is_empty() {
5859
return errors;
@@ -71,3 +72,11 @@ pub trait TraitEngine<'tcx>: 'tcx {
7172
infcx: &InferCtxt<'tcx>,
7273
) -> Vec<PredicateObligation<'tcx>>;
7374
}
75+
76+
pub trait FulfillmentErrorLike<'tcx>: Debug + 'tcx {
77+
fn is_true_error(&self) -> bool;
78+
}
79+
80+
pub trait FromSolverError<'tcx, E>: FulfillmentErrorLike<'tcx> {
81+
fn from_solver_error(infcx: &InferCtxt<'tcx>, error: E) -> Self;
82+
}

compiler/rustc_infer/src/traits/mod.rs

Lines changed: 2 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ pub use self::ImplSource::*;
2323
pub use self::SelectionError::*;
2424
use crate::infer::InferCtxt;
2525

26-
pub use self::engine::TraitEngine;
26+
pub use self::engine::{FromSolverError, FulfillmentErrorLike, TraitEngine};
2727
pub use self::project::MismatchedProjectionTypes;
2828
pub(crate) use self::project::UndoLog;
2929
pub use self::project::{
@@ -124,15 +124,7 @@ pub type Selection<'tcx> = ImplSource<'tcx, PredicateObligation<'tcx>>;
124124
pub type ObligationInspector<'tcx> =
125125
fn(&InferCtxt<'tcx>, &PredicateObligation<'tcx>, Result<Certainty, NoSolution>);
126126

127-
pub struct FulfillmentError<'tcx> {
128-
pub obligation: PredicateObligation<'tcx>,
129-
pub code: FulfillmentErrorCode<'tcx>,
130-
/// Diagnostics only: the 'root' obligation which resulted in
131-
/// the failure to process `obligation`. This is the obligation
132-
/// that was initially passed to `register_predicate_obligation`
133-
pub root_obligation: PredicateObligation<'tcx>,
134-
}
135-
127+
// TODO: Pull this down too
136128
#[derive(Clone)]
137129
pub enum FulfillmentErrorCode<'tcx> {
138130
/// Inherently impossible to fulfill; this trait is implemented if and only
@@ -198,28 +190,6 @@ impl<'tcx, O> Obligation<'tcx, O> {
198190
}
199191
}
200192

201-
impl<'tcx> FulfillmentError<'tcx> {
202-
pub fn new(
203-
obligation: PredicateObligation<'tcx>,
204-
code: FulfillmentErrorCode<'tcx>,
205-
root_obligation: PredicateObligation<'tcx>,
206-
) -> FulfillmentError<'tcx> {
207-
FulfillmentError { obligation, code, root_obligation }
208-
}
209-
210-
pub fn is_true_error(&self) -> bool {
211-
match self.code {
212-
FulfillmentErrorCode::Select(_)
213-
| FulfillmentErrorCode::Project(_)
214-
| FulfillmentErrorCode::Subtype(_, _)
215-
| FulfillmentErrorCode::ConstEquate(_, _) => true,
216-
FulfillmentErrorCode::Cycle(_) | FulfillmentErrorCode::Ambiguity { overflow: _ } => {
217-
false
218-
}
219-
}
220-
}
221-
}
222-
223193
impl<'tcx> PolyTraitObligation<'tcx> {
224194
pub fn polarity(&self) -> ty::PredicatePolarity {
225195
self.predicate.skip_binder().polarity

compiler/rustc_infer/src/traits/structural_impls.rs

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -29,12 +29,6 @@ impl<'tcx, O: fmt::Debug> fmt::Debug for traits::Obligation<'tcx, O> {
2929
}
3030
}
3131

32-
impl<'tcx> fmt::Debug for traits::FulfillmentError<'tcx> {
33-
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
34-
write!(f, "FulfillmentError({:?},{:?})", self.obligation, self.code)
35-
}
36-
}
37-
3832
impl<'tcx> fmt::Debug for traits::FulfillmentErrorCode<'tcx> {
3933
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
4034
use traits::FulfillmentErrorCode::*;

compiler/rustc_trait_selection/src/regions.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
use crate::traits::FulfillmentError;
12
use rustc_infer::infer::outlives::env::OutlivesEnvironment;
23
use rustc_infer::infer::{InferCtxt, RegionResolutionError};
34
use rustc_macros::extension;
@@ -27,7 +28,8 @@ impl<'tcx> InferCtxt<'tcx> {
2728
),
2829
ty,
2930
)
30-
.map_err(|_| NoSolution)
31+
// TODO:
32+
.map_err(|_: Vec<FulfillmentError<'tcx>>| NoSolution)
3133
} else {
3234
Ok(ty)
3335
}

0 commit comments

Comments
 (0)