use dep_graph::DepGraph;
use infer::{InferCtxt, InferOk};
use ty::{self, Ty, TypeFoldable, ToPolyTraitRef, TyCtxt, ToPredicate};
-use ty::subst::Subst;
use rustc_data_structures::obligation_forest::{ObligationForest, Error};
use rustc_data_structures::obligation_forest::{ForestObligation, ObligationProcessor};
use std::marker::PhantomData;
-use std::mem;
use syntax::ast;
use util::nodemap::{FxHashSet, NodeMap};
use hir::def_id::DefId;
use super::CodeAmbiguity;
use super::CodeProjectionError;
use super::CodeSelectionError;
-use super::{FulfillmentError, FulfillmentErrorCode, SelectionError};
-use super::{ObligationCause, BuiltinDerivedObligation};
-use super::{PredicateObligation, TraitObligation, Obligation};
+use super::{FulfillmentError, FulfillmentErrorCode};
+use super::{ObligationCause, PredicateObligation, Obligation};
use super::project;
use super::select::SelectionContext;
use super::Unimplemented;
// obligations (otherwise, it's easy to fail to walk to a
// particular node-id).
region_obligations: NodeMap<Vec<RegionObligation<'tcx>>>,
-
- // A list of obligations that need to be deferred to
- // a later time for them to be properly fulfilled.
- deferred_obligations: Vec<DeferredObligation<'tcx>>,
}
#[derive(Clone)]
pub stalled_on: Vec<Ty<'tcx>>,
}
-/// An obligation which cannot be fulfilled in the context
-/// it was registered in, such as auto trait obligations on
-/// `impl Trait`, which require the concrete type to be
-/// available, only guaranteed after finishing type-checking.
-#[derive(Clone, Debug)]
-pub struct DeferredObligation<'tcx> {
- pub predicate: ty::PolyTraitPredicate<'tcx>,
- pub cause: ObligationCause<'tcx>
-}
-
-impl<'a, 'gcx, 'tcx> DeferredObligation<'tcx> {
- /// If possible, create a `DeferredObligation` from
- /// a trait predicate which had failed selection,
- /// but could succeed later.
- pub fn from_select_error(tcx: TyCtxt<'a, 'gcx, 'tcx>,
- obligation: &TraitObligation<'tcx>,
- selection_err: &SelectionError<'tcx>)
- -> Option<DeferredObligation<'tcx>> {
- if let Unimplemented = *selection_err {
- if DeferredObligation::must_defer(tcx, &obligation.predicate) {
- return Some(DeferredObligation {
- predicate: obligation.predicate.clone(),
- cause: obligation.cause.clone()
- });
- }
- }
-
- None
- }
-
- /// Returns true if the given trait predicate can be
- /// fulfilled at a later time.
- pub fn must_defer(tcx: TyCtxt<'a, 'gcx, 'tcx>,
- predicate: &ty::PolyTraitPredicate<'tcx>)
- -> bool {
- // Auto trait obligations on `impl Trait`.
- if tcx.trait_has_default_impl(predicate.def_id()) {
- let substs = predicate.skip_binder().trait_ref.substs;
- if substs.types().count() == 1 && substs.regions().next().is_none() {
- if let ty::TyAnon(..) = predicate.skip_binder().self_ty().sty {
- return true;
- }
- }
- }
-
- false
- }
-
- /// If possible, return the nested obligations required
- /// to fulfill this obligation.
- pub fn try_select(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>)
- -> Option<Vec<PredicateObligation<'tcx>>> {
- if let ty::TyAnon(def_id, substs) = self.predicate.skip_binder().self_ty().sty {
- let ty = if def_id.is_local() {
- tcx.item_types.borrow().get(&def_id).cloned()
- } else {
- Some(tcx.item_type(def_id))
- };
- // We can resolve the `impl Trait` to its concrete type.
- if let Some(concrete_ty) = ty.subst(tcx, substs) {
- let predicate = ty::TraitRef {
- def_id: self.predicate.def_id(),
- substs: tcx.mk_substs_trait(concrete_ty, &[])
- }.to_predicate();
-
- let original_obligation = Obligation::new(self.cause.clone(),
- self.predicate.clone());
- let cause = original_obligation.derived_cause(BuiltinDerivedObligation);
- return Some(vec![Obligation::new(cause, predicate)]);
- }
- }
-
- None
- }
-
- /// Return the `PredicateObligation` this was created from.
- pub fn to_obligation(&self) -> PredicateObligation<'tcx> {
- let predicate = ty::Predicate::Trait(self.predicate.clone());
- Obligation::new(self.cause.clone(), predicate)
- }
-
- /// Return an error as if this obligation had failed.
- pub fn to_error(&self) -> FulfillmentError<'tcx> {
- FulfillmentError::new(self.to_obligation(), CodeSelectionError(Unimplemented))
- }
-}
-
impl<'a, 'gcx, 'tcx> FulfillmentContext<'tcx> {
/// Creates a new fulfillment context.
pub fn new() -> FulfillmentContext<'tcx> {
FulfillmentContext {
predicates: ObligationForest::new(),
region_obligations: NodeMap(),
- deferred_obligations: vec![],
}
}
{
self.select_where_possible(infcx)?;
- // Fail all of the deferred obligations that haven't
- // been otherwise removed from the context.
- let deferred_errors = self.deferred_obligations.iter()
- .map(|d| d.to_error());
-
let errors: Vec<_> =
self.predicates.to_errors(CodeAmbiguity)
.into_iter()
.map(|e| to_fulfillment_error(e))
- .chain(deferred_errors)
.collect();
if errors.is_empty() {
Ok(())
self.predicates.pending_obligations()
}
- pub fn take_deferred_obligations(&mut self) -> Vec<DeferredObligation<'tcx>> {
- mem::replace(&mut self.deferred_obligations, vec![])
- }
-
/// Attempts to select obligations using `selcx`. If `only_new_obligations` is true, then it
/// only attempts to select obligations that haven't been seen before.
fn select(&mut self, selcx: &mut SelectionContext<'a, 'gcx, 'tcx>)
let outcome = self.predicates.process_obligations(&mut FulfillProcessor {
selcx: selcx,
region_obligations: &mut self.region_obligations,
- deferred_obligations: &mut self.deferred_obligations
});
debug!("select: outcome={:?}", outcome);
struct FulfillProcessor<'a, 'b: 'a, 'gcx: 'tcx, 'tcx: 'b> {
selcx: &'a mut SelectionContext<'b, 'gcx, 'tcx>,
region_obligations: &'a mut NodeMap<Vec<RegionObligation<'tcx>>>,
- deferred_obligations: &'a mut Vec<DeferredObligation<'tcx>>
}
impl<'a, 'b, 'gcx, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'b, 'gcx, 'tcx> {
{
process_predicate(self.selcx,
obligation,
- self.region_obligations,
- self.deferred_obligations)
+ self.region_obligations)
.map(|os| os.map(|os| os.into_iter().map(|o| PendingPredicateObligation {
obligation: o,
stalled_on: vec![]
fn process_predicate<'a, 'gcx, 'tcx>(
selcx: &mut SelectionContext<'a, 'gcx, 'tcx>,
pending_obligation: &mut PendingPredicateObligation<'tcx>,
- region_obligations: &mut NodeMap<Vec<RegionObligation<'tcx>>>,
- deferred_obligations: &mut Vec<DeferredObligation<'tcx>>)
+ region_obligations: &mut NodeMap<Vec<RegionObligation<'tcx>>>)
-> Result<Option<Vec<PredicateObligation<'tcx>>>,
FulfillmentErrorCode<'tcx>>
{
info!("selecting trait `{:?}` at depth {} yielded Err",
data, obligation.recursion_depth);
- let defer = DeferredObligation::from_select_error(selcx.tcx(),
- &trait_obligation,
- &selection_err);
- if let Some(deferred_obligation) = defer {
- if let Some(nested) = deferred_obligation.try_select(selcx.tcx()) {
- Ok(Some(nested))
- } else {
- // Pretend that the obligation succeeded,
- // but record it for later.
- deferred_obligations.push(deferred_obligation);
- Ok(Some(vec![]))
- }
- } else {
- Err(CodeSelectionError(selection_err))
- }
+ Err(CodeSelectionError(selection_err))
}
}
}
// already has the required read edges, so we don't need
// to add any more edges here.
if data.is_global() {
- // Don't cache predicates which were fulfilled
- // by deferring them for later fulfillment.
- if DeferredObligation::must_defer(tcx, data) {
- return;
- }
-
if let Some(data) = tcx.lift_to_global(data) {
if self.set.insert(data.clone()) {
debug!("add_if_global: global predicate `{:?}` added", data);