summaryrefslogtreecommitdiffstats
path: root/compiler/rustc_infer/src/traits
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/rustc_infer/src/traits')
-rw-r--r--compiler/rustc_infer/src/traits/engine.rs24
-rw-r--r--compiler/rustc_infer/src/traits/mod.rs3
-rw-r--r--compiler/rustc_infer/src/traits/structural_impls.rs17
-rw-r--r--compiler/rustc_infer/src/traits/util.rs87
4 files changed, 81 insertions, 50 deletions
diff --git a/compiler/rustc_infer/src/traits/engine.rs b/compiler/rustc_infer/src/traits/engine.rs
index d3519f4b3..f75344f20 100644
--- a/compiler/rustc_infer/src/traits/engine.rs
+++ b/compiler/rustc_infer/src/traits/engine.rs
@@ -1,6 +1,5 @@
use crate::infer::InferCtxt;
use crate::traits::Obligation;
-use rustc_data_structures::fx::FxHashMap;
use rustc_hir::def_id::DefId;
use rustc_middle::ty::{self, ToPredicate, Ty};
@@ -37,13 +36,19 @@ pub trait TraitEngine<'tcx>: 'tcx {
obligation: PredicateObligation<'tcx>,
);
- fn select_all_or_error(&mut self, infcx: &InferCtxt<'tcx>) -> Vec<FulfillmentError<'tcx>>;
-
fn select_where_possible(&mut self, infcx: &InferCtxt<'tcx>) -> Vec<FulfillmentError<'tcx>>;
+ fn collect_remaining_errors(&mut self) -> Vec<FulfillmentError<'tcx>>;
+
fn pending_obligations(&self) -> Vec<PredicateObligation<'tcx>>;
- fn relationships(&mut self) -> &mut FxHashMap<ty::TyVid, ty::FoundRelationships>;
+ /// Among all pending obligations, collect those are stalled on a inference variable which has
+ /// changed since the last call to `select_where_possible`. Those obligations are marked as
+ /// successful and returned.
+ fn drain_unstalled_obligations(
+ &mut self,
+ infcx: &InferCtxt<'tcx>,
+ ) -> Vec<PredicateObligation<'tcx>>;
}
pub trait TraitEngineExt<'tcx> {
@@ -52,6 +57,8 @@ pub trait TraitEngineExt<'tcx> {
infcx: &InferCtxt<'tcx>,
obligations: impl IntoIterator<Item = PredicateObligation<'tcx>>,
);
+
+ fn select_all_or_error(&mut self, infcx: &InferCtxt<'tcx>) -> Vec<FulfillmentError<'tcx>>;
}
impl<'tcx, T: ?Sized + TraitEngine<'tcx>> TraitEngineExt<'tcx> for T {
@@ -64,4 +71,13 @@ impl<'tcx, T: ?Sized + TraitEngine<'tcx>> TraitEngineExt<'tcx> for T {
self.register_predicate_obligation(infcx, obligation);
}
}
+
+ fn select_all_or_error(&mut self, infcx: &InferCtxt<'tcx>) -> Vec<FulfillmentError<'tcx>> {
+ let errors = self.select_where_possible(infcx);
+ if !errors.is_empty() {
+ return errors;
+ }
+
+ self.collect_remaining_errors()
+ }
}
diff --git a/compiler/rustc_infer/src/traits/mod.rs b/compiler/rustc_infer/src/traits/mod.rs
index 026713b6a..3a8289966 100644
--- a/compiler/rustc_infer/src/traits/mod.rs
+++ b/compiler/rustc_infer/src/traits/mod.rs
@@ -8,6 +8,7 @@ mod project;
mod structural_impls;
pub mod util;
+use hir::def_id::LocalDefId;
use rustc_hir as hir;
use rustc_middle::ty::error::{ExpectedFound, TypeError};
use rustc_middle::ty::{self, Const, ToPredicate, Ty, TyCtxt};
@@ -146,7 +147,7 @@ impl<'tcx, O> Obligation<'tcx, O> {
pub fn misc(
tcx: TyCtxt<'tcx>,
span: Span,
- body_id: hir::HirId,
+ body_id: LocalDefId,
param_env: ty::ParamEnv<'tcx>,
trait_ref: impl ToPredicate<'tcx, O>,
) -> Obligation<'tcx, O> {
diff --git a/compiler/rustc_infer/src/traits/structural_impls.rs b/compiler/rustc_infer/src/traits/structural_impls.rs
index 1c6ab6a08..3a5273b03 100644
--- a/compiler/rustc_infer/src/traits/structural_impls.rs
+++ b/compiler/rustc_infer/src/traits/structural_impls.rs
@@ -1,8 +1,8 @@
use crate::traits;
use crate::traits::project::Normalized;
-use rustc_middle::ty;
use rustc_middle::ty::fold::{FallibleTypeFolder, TypeFoldable};
use rustc_middle::ty::visit::{TypeVisitable, TypeVisitor};
+use rustc_middle::ty::{self, TyCtxt};
use std::fmt;
use std::ops::ControlFlow;
@@ -61,8 +61,13 @@ impl<'tcx> fmt::Debug for traits::MismatchedProjectionTypes<'tcx> {
///////////////////////////////////////////////////////////////////////////
// TypeFoldable implementations.
-impl<'tcx, O: TypeFoldable<'tcx>> TypeFoldable<'tcx> for traits::Obligation<'tcx, O> {
- fn try_fold_with<F: FallibleTypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> {
+impl<'tcx, O: TypeFoldable<TyCtxt<'tcx>>> TypeFoldable<TyCtxt<'tcx>>
+ for traits::Obligation<'tcx, O>
+{
+ fn try_fold_with<F: FallibleTypeFolder<TyCtxt<'tcx>>>(
+ self,
+ folder: &mut F,
+ ) -> Result<Self, F::Error> {
Ok(traits::Obligation {
cause: self.cause,
recursion_depth: self.recursion_depth,
@@ -72,8 +77,10 @@ impl<'tcx, O: TypeFoldable<'tcx>> TypeFoldable<'tcx> for traits::Obligation<'tcx
}
}
-impl<'tcx, O: TypeVisitable<'tcx>> TypeVisitable<'tcx> for traits::Obligation<'tcx, O> {
- fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
+impl<'tcx, O: TypeVisitable<TyCtxt<'tcx>>> TypeVisitable<TyCtxt<'tcx>>
+ for traits::Obligation<'tcx, O>
+{
+ fn visit_with<V: TypeVisitor<TyCtxt<'tcx>>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
self.predicate.visit_with(visitor)?;
self.param_env.visit_with(visitor)
}
diff --git a/compiler/rustc_infer/src/traits/util.rs b/compiler/rustc_infer/src/traits/util.rs
index cd5bde2a7..c07ff5165 100644
--- a/compiler/rustc_infer/src/traits/util.rs
+++ b/compiler/rustc_infer/src/traits/util.rs
@@ -116,11 +116,11 @@ pub fn elaborate_predicates_with_span<'tcx>(
pub fn elaborate_obligations<'tcx>(
tcx: TyCtxt<'tcx>,
- mut obligations: Vec<PredicateObligation<'tcx>>,
+ obligations: Vec<PredicateObligation<'tcx>>,
) -> Elaborator<'tcx> {
- let mut visited = PredicateSet::new(tcx);
- obligations.retain(|obligation| visited.insert(obligation.predicate));
- Elaborator { stack: obligations, visited }
+ let mut elaborator = Elaborator { stack: Vec::new(), visited: PredicateSet::new(tcx) };
+ elaborator.extend_deduped(obligations);
+ elaborator
}
fn predicate_obligation<'tcx>(
@@ -132,6 +132,15 @@ fn predicate_obligation<'tcx>(
}
impl<'tcx> Elaborator<'tcx> {
+ fn extend_deduped(&mut self, obligations: impl IntoIterator<Item = PredicateObligation<'tcx>>) {
+ // Only keep those bounds that we haven't already seen.
+ // This is necessary to prevent infinite recursion in some
+ // cases. One common case is when people define
+ // `trait Sized: Sized { }` rather than `trait Sized { }`.
+ // let visited = &mut self.visited;
+ self.stack.extend(obligations.into_iter().filter(|o| self.visited.insert(o.predicate)));
+ }
+
pub fn filter_to_traits(self) -> FilterToTraits<Self> {
FilterToTraits::new(self)
}
@@ -145,40 +154,34 @@ impl<'tcx> Elaborator<'tcx> {
// Get predicates declared on the trait.
let predicates = tcx.super_predicates_of(data.def_id());
- let obligations = predicates.predicates.iter().map(|&(mut pred, span)| {
- // when parent predicate is non-const, elaborate it to non-const predicates.
- if data.constness == ty::BoundConstness::NotConst {
- pred = pred.without_const(tcx);
- }
-
- let cause = obligation.cause.clone().derived_cause(
- bound_predicate.rebind(data),
- |derived| {
- traits::ImplDerivedObligation(Box::new(
- traits::ImplDerivedObligationCause {
- derived,
- impl_def_id: data.def_id(),
- span,
- },
- ))
- },
- );
- predicate_obligation(
- pred.subst_supertrait(tcx, &bound_predicate.rebind(data.trait_ref)),
- obligation.param_env,
- cause,
- )
- });
+ let obligations =
+ predicates.predicates.iter().enumerate().map(|(index, &(mut pred, span))| {
+ // when parent predicate is non-const, elaborate it to non-const predicates.
+ if data.constness == ty::BoundConstness::NotConst {
+ pred = pred.without_const(tcx);
+ }
+
+ let cause = obligation.cause.clone().derived_cause(
+ bound_predicate.rebind(data),
+ |derived| {
+ traits::ImplDerivedObligation(Box::new(
+ traits::ImplDerivedObligationCause {
+ derived,
+ impl_or_alias_def_id: data.def_id(),
+ impl_def_predicate_index: Some(index),
+ span,
+ },
+ ))
+ },
+ );
+ predicate_obligation(
+ pred.subst_supertrait(tcx, &bound_predicate.rebind(data.trait_ref)),
+ obligation.param_env,
+ cause,
+ )
+ });
debug!(?data, ?obligations, "super_predicates");
-
- // Only keep those bounds that we haven't already seen.
- // This is necessary to prevent infinite recursion in some
- // cases. One common case is when people define
- // `trait Sized: Sized { }` rather than `trait Sized { }`.
- let visited = &mut self.visited;
- let obligations = obligations.filter(|o| visited.insert(o.predicate));
-
- self.stack.extend(obligations);
+ self.extend_deduped(obligations);
}
ty::PredicateKind::WellFormed(..) => {
// Currently, we do not elaborate WF predicates,
@@ -235,10 +238,9 @@ impl<'tcx> Elaborator<'tcx> {
return;
}
- let visited = &mut self.visited;
let mut components = smallvec![];
push_outlives_components(tcx, ty_max, &mut components);
- self.stack.extend(
+ self.extend_deduped(
components
.into_iter()
.filter_map(|component| match component {
@@ -278,7 +280,6 @@ impl<'tcx> Elaborator<'tcx> {
.map(|predicate_kind| {
bound_predicate.rebind(predicate_kind).to_predicate(tcx)
})
- .filter(|&predicate| visited.insert(predicate))
.map(|predicate| {
predicate_obligation(
predicate,
@@ -292,6 +293,12 @@ impl<'tcx> Elaborator<'tcx> {
// Nothing to elaborate
}
ty::PredicateKind::Ambiguous => {}
+ ty::PredicateKind::AliasEq(..) => {
+ // No
+ }
+ ty::PredicateKind::Clause(ty::Clause::ConstArgHasType(..)) => {
+ // Nothing to elaborate
+ }
}
}
}