summaryrefslogtreecommitdiffstats
path: root/compiler/rustc_trait_selection/src/traits/fulfill.rs
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/rustc_trait_selection/src/traits/fulfill.rs')
-rw-r--r--compiler/rustc_trait_selection/src/traits/fulfill.rs80
1 files changed, 34 insertions, 46 deletions
diff --git a/compiler/rustc_trait_selection/src/traits/fulfill.rs b/compiler/rustc_trait_selection/src/traits/fulfill.rs
index 2f85c32b5..cf9d9315f 100644
--- a/compiler/rustc_trait_selection/src/traits/fulfill.rs
+++ b/compiler/rustc_trait_selection/src/traits/fulfill.rs
@@ -4,7 +4,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::{SelectionError, TraitEngine, TraitObligation};
+use rustc_infer::traits::{PolyTraitObligation, SelectionError, TraitEngine};
use rustc_middle::mir::interpret::ErrorHandled;
use rustc_middle::ty::abstract_const::NotConstEvaluatable;
use rustc_middle::ty::error::{ExpectedFound, TypeError};
@@ -50,20 +50,15 @@ impl<'tcx> ForestObligation for PendingPredicateObligation<'tcx> {
/// method `select_all_or_error` can be used to report any remaining
/// ambiguous cases as errors.
pub struct FulfillmentContext<'tcx> {
- // A list of all obligations that have been registered with this
- // fulfillment context.
+ /// A list of all obligations that have been registered with this
+ /// fulfillment context.
predicates: ObligationForest<PendingPredicateObligation<'tcx>>,
- // Is it OK to register obligations into this infcx inside
- // an infcx snapshot?
- //
- // The "primary fulfillment" in many cases in typeck lives
- // outside of any snapshot, so any use of it inside a snapshot
- // will lead to trouble and therefore is checked against, but
- // other fulfillment contexts sometimes do live inside of
- // a snapshot (they don't *straddle* a snapshot, so there
- // is no trouble there).
- usable_in_snapshot: bool,
+ /// The snapshot in which this context was created. Using the context
+ /// outside of this snapshot leads to subtle bugs if the snapshot
+ /// gets rolled back. Because of this we explicitly check that we only
+ /// use the context in exactly this snapshot.
+ usable_in_snapshot: usize,
}
#[derive(Clone, Debug)]
@@ -80,18 +75,17 @@ pub struct PendingPredicateObligation<'tcx> {
#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
static_assert_size!(PendingPredicateObligation<'_>, 72);
-impl<'a, 'tcx> FulfillmentContext<'tcx> {
+impl<'tcx> FulfillmentContext<'tcx> {
/// Creates a new fulfillment context.
- pub(super) fn new() -> FulfillmentContext<'tcx> {
- FulfillmentContext { predicates: ObligationForest::new(), usable_in_snapshot: false }
- }
-
- pub(super) fn new_in_snapshot() -> FulfillmentContext<'tcx> {
- FulfillmentContext { predicates: ObligationForest::new(), usable_in_snapshot: true }
+ pub(super) fn new(infcx: &InferCtxt<'tcx>) -> FulfillmentContext<'tcx> {
+ FulfillmentContext {
+ predicates: ObligationForest::new(),
+ usable_in_snapshot: infcx.num_open_snapshots(),
+ }
}
/// Attempts to select obligations using `selcx`.
- fn select(&mut self, selcx: SelectionContext<'a, 'tcx>) -> Vec<FulfillmentError<'tcx>> {
+ fn select(&mut self, selcx: SelectionContext<'_, 'tcx>) -> Vec<FulfillmentError<'tcx>> {
let span = debug_span!("select", obligation_forest_size = ?self.predicates.len());
let _enter = span.enter();
@@ -116,19 +110,19 @@ impl<'a, 'tcx> FulfillmentContext<'tcx> {
}
impl<'tcx> TraitEngine<'tcx> for FulfillmentContext<'tcx> {
+ #[inline]
fn register_predicate_obligation(
&mut self,
infcx: &InferCtxt<'tcx>,
obligation: PredicateObligation<'tcx>,
) {
+ assert_eq!(self.usable_in_snapshot, infcx.num_open_snapshots());
// this helps to reduce duplicate errors, as well as making
// debug output much nicer to read and so on.
let obligation = infcx.resolve_vars_if_possible(obligation);
debug!(?obligation, "register_predicate_obligation");
- assert!(!infcx.is_in_snapshot() || self.usable_in_snapshot);
-
self.predicates
.register_obligation(PendingPredicateObligation { obligation, stalled_on: vec![] });
}
@@ -332,7 +326,7 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> {
// Evaluation will discard candidates using the leak check.
// This means we need to pass it the bound version of our
// predicate.
- ty::PredicateKind::Clause(ty::Clause::Trait(trait_ref)) => {
+ ty::PredicateKind::Clause(ty::ClauseKind::Trait(trait_ref)) => {
let trait_obligation = obligation.with(infcx.tcx, binder.rebind(trait_ref));
self.process_trait_obligation(
@@ -341,7 +335,7 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> {
&mut pending_obligation.stalled_on,
)
}
- ty::PredicateKind::Clause(ty::Clause::Projection(data)) => {
+ ty::PredicateKind::Clause(ty::ClauseKind::Projection(data)) => {
let project_obligation = obligation.with(infcx.tcx, binder.rebind(data));
self.process_projection_obligation(
@@ -350,30 +344,27 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> {
&mut pending_obligation.stalled_on,
)
}
- ty::PredicateKind::Clause(ty::Clause::RegionOutlives(_))
- | ty::PredicateKind::Clause(ty::Clause::TypeOutlives(_))
- | ty::PredicateKind::Clause(ty::Clause::ConstArgHasType(..))
- | ty::PredicateKind::WellFormed(_)
+ ty::PredicateKind::Clause(ty::ClauseKind::RegionOutlives(_))
+ | ty::PredicateKind::Clause(ty::ClauseKind::TypeOutlives(_))
+ | ty::PredicateKind::Clause(ty::ClauseKind::ConstArgHasType(..))
+ | ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(_))
| ty::PredicateKind::ObjectSafe(_)
| ty::PredicateKind::ClosureKind(..)
| ty::PredicateKind::Subtype(_)
| ty::PredicateKind::Coerce(_)
- | ty::PredicateKind::ConstEvaluatable(..)
+ | ty::PredicateKind::Clause(ty::ClauseKind::ConstEvaluatable(..))
| ty::PredicateKind::ConstEquate(..) => {
let pred =
ty::Binder::dummy(infcx.instantiate_binder_with_placeholders(binder));
ProcessResult::Changed(mk_pending(vec![obligation.with(infcx.tcx, pred)]))
}
ty::PredicateKind::Ambiguous => ProcessResult::Unchanged,
- ty::PredicateKind::TypeWellFormedFromEnv(..) => {
- bug!("TypeWellFormedFromEnv is only used for Chalk")
- }
ty::PredicateKind::AliasRelate(..) => {
bug!("AliasRelate is only used for new solver")
}
},
Some(pred) => match pred {
- ty::PredicateKind::Clause(ty::Clause::Trait(data)) => {
+ ty::PredicateKind::Clause(ty::ClauseKind::Trait(data)) => {
let trait_obligation = obligation.with(infcx.tcx, Binder::dummy(data));
self.process_trait_obligation(
@@ -383,7 +374,7 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> {
)
}
- ty::PredicateKind::Clause(ty::Clause::RegionOutlives(data)) => {
+ ty::PredicateKind::Clause(ty::ClauseKind::RegionOutlives(data)) => {
if infcx.considering_regions {
infcx.region_outlives_predicate(&obligation.cause, Binder::dummy(data));
}
@@ -391,7 +382,7 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> {
ProcessResult::Changed(vec![])
}
- ty::PredicateKind::Clause(ty::Clause::TypeOutlives(ty::OutlivesPredicate(
+ ty::PredicateKind::Clause(ty::ClauseKind::TypeOutlives(ty::OutlivesPredicate(
t_a,
r_b,
))) => {
@@ -401,7 +392,7 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> {
ProcessResult::Changed(vec![])
}
- ty::PredicateKind::Clause(ty::Clause::Projection(ref data)) => {
+ ty::PredicateKind::Clause(ty::ClauseKind::Projection(ref data)) => {
let project_obligation = obligation.with(infcx.tcx, Binder::dummy(*data));
self.process_projection_obligation(
@@ -432,7 +423,7 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> {
}
}
- ty::PredicateKind::WellFormed(arg) => {
+ ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(arg)) => {
match wf::obligations(
self.selcx.infcx,
obligation.param_env,
@@ -497,7 +488,7 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> {
}
}
- ty::PredicateKind::ConstEvaluatable(uv) => {
+ ty::PredicateKind::Clause(ty::ClauseKind::ConstEvaluatable(uv)) => {
match const_evaluatable::is_const_evaluatable(
self.selcx.infcx,
uv,
@@ -537,7 +528,7 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> {
debug!("equating consts:\nc1= {:?}\nc2= {:?}", c1, c2);
use rustc_hir::def::DefKind;
- use ty::ConstKind::Unevaluated;
+ use ty::Unevaluated;
match (c1.kind(), c2.kind()) {
(Unevaluated(a), Unevaluated(b))
if a.def == b.def && tcx.def_kind(a.def) == DefKind::AssocConst =>
@@ -633,13 +624,10 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> {
}
}
ty::PredicateKind::Ambiguous => ProcessResult::Unchanged,
- ty::PredicateKind::TypeWellFormedFromEnv(..) => {
- bug!("TypeWellFormedFromEnv is only used for Chalk")
- }
ty::PredicateKind::AliasRelate(..) => {
bug!("AliasRelate is only used for new solver")
}
- ty::PredicateKind::Clause(ty::Clause::ConstArgHasType(ct, ty)) => {
+ ty::PredicateKind::Clause(ty::ClauseKind::ConstArgHasType(ct, ty)) => {
match self.selcx.infcx.at(&obligation.cause, obligation.param_env).eq(
DefineOpaqueTypes::No,
ct.ty(),
@@ -679,7 +667,7 @@ impl<'a, 'tcx> FulfillProcessor<'a, 'tcx> {
fn process_trait_obligation(
&mut self,
obligation: &PredicateObligation<'tcx>,
- trait_obligation: TraitObligation<'tcx>,
+ trait_obligation: PolyTraitObligation<'tcx>,
stalled_on: &mut Vec<TyOrConstInferVar<'tcx>>,
) -> ProcessResult<PendingPredicateObligation<'tcx>, FulfillmentErrorCode<'tcx>> {
let infcx = self.selcx.infcx;
@@ -695,7 +683,7 @@ impl<'a, 'tcx> FulfillProcessor<'a, 'tcx> {
}
}
- match self.selcx.select(&trait_obligation) {
+ match self.selcx.poly_select(&trait_obligation) {
Ok(Some(impl_source)) => {
debug!("selecting trait at depth {} yielded Ok(Some)", obligation.recursion_depth);
ProcessResult::Changed(mk_pending(impl_source.nested_obligations()))