// Copyright 2014 The Rust Project Developers. See the COPYRIGHT // file at the top-level directory of this distribution and at // http://rust-lang.org/COPYRIGHT. // // Licensed under the Apache License, Version 2.0 or the MIT license // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. use dep_graph::DepGraph; use infer::{InferCtxt, InferOk}; use ty::{self, Ty, TypeFoldable, ToPolyTraitRef, TyCtxt}; 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::common::ErrorReported; use util::nodemap::{FnvHashSet, NodeMap}; use super::CodeAmbiguity; use super::CodeProjectionError; use super::CodeSelectionError; use super::FulfillmentError; use super::FulfillmentErrorCode; use super::ObligationCause; use super::PredicateObligation; use super::project; use super::select::SelectionContext; use super::Unimplemented; impl<'tcx> ForestObligation for PendingPredicateObligation<'tcx> { type Predicate = ty::Predicate<'tcx>; fn as_predicate(&self) -> &Self::Predicate { &self.obligation.predicate } } pub struct GlobalFulfilledPredicates<'tcx> { set: FnvHashSet>, dep_graph: DepGraph, } /// The fulfillment context is used to drive trait resolution. It /// consists of a list of obligations that must be (eventually) /// satisfied. The job is to track which are satisfied, which yielded /// errors, and which are still pending. At any point, users can call /// `select_where_possible`, and the fulfilment context will try to do /// selection, retaining only those obligations that remain /// ambiguous. This may be helpful in pushing type inference /// 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> { // A list of all obligations that have been registered with this // fulfillment context. predicates: ObligationForest>, // A list of new obligations due to RFC1592. rfc1592_obligations: Vec>, // A set of constraints that regionck must validate. Each // constraint has the form `T:'a`, meaning "some type `T` must // outlive the lifetime 'a". These constraints derive from // instantiated type parameters. So if you had a struct defined // like // // struct Foo { ... } // // then in some expression `let x = Foo { ... }` it will // instantiate the type parameter `T` with a fresh type `$0`. At // the same time, it will record a region obligation of // `$0:'static`. This will get checked later by regionck. (We // can't generally check these things right away because we have // to wait until types are resolved.) // // These are stored in a map keyed to the id of the innermost // enclosing fn body / static initializer expression. This is // because the location where the obligation was incurred can be // relevant with respect to which sublifetime assumptions are in // place. The reason that we store under the fn-id, and not // something more fine-grained, is so that it is easier for // regionck to be sure that it has found *all* the region // obligations (otherwise, it's easy to fail to walk to a // particular node-id). region_obligations: NodeMap>>, } #[derive(Clone)] pub struct RegionObligation<'tcx> { pub sub_region: ty::Region, pub sup_type: Ty<'tcx>, pub cause: ObligationCause<'tcx>, } #[derive(Clone, Debug)] pub struct PendingPredicateObligation<'tcx> { pub obligation: PredicateObligation<'tcx>, pub stalled_on: Vec>, } impl<'a, 'gcx, 'tcx> FulfillmentContext<'tcx> { /// Creates a new fulfillment context. pub fn new() -> FulfillmentContext<'tcx> { FulfillmentContext { predicates: ObligationForest::new(), rfc1592_obligations: Vec::new(), region_obligations: NodeMap(), } } /// "Normalize" a projection type `::X` by /// creating a fresh type variable `$0` as well as a projection /// predicate `::X == $0`. When the /// inference engine runs, it will attempt to find an impl of /// `SomeTrait` or a where clause that lets us unify `$0` with /// something concrete. If this fails, we'll unify `$0` with /// `projection_ty` again. pub fn normalize_projection_type(&mut self, infcx: &InferCtxt<'a, 'gcx, 'tcx>, projection_ty: ty::ProjectionTy<'tcx>, cause: ObligationCause<'tcx>) -> Ty<'tcx> { debug!("normalize_projection_type(projection_ty={:?})", projection_ty); assert!(!projection_ty.has_escaping_regions()); // FIXME(#20304) -- cache let mut selcx = SelectionContext::new(infcx); let normalized = project::normalize_projection_type(&mut selcx, projection_ty, cause, 0); for obligation in normalized.obligations { self.register_predicate_obligation(infcx, obligation); } debug!("normalize_projection_type: result={:?}", normalized.value); normalized.value } pub fn register_builtin_bound(&mut self, infcx: &InferCtxt<'a, 'gcx, 'tcx>, ty: Ty<'tcx>, builtin_bound: ty::BuiltinBound, cause: ObligationCause<'tcx>) { match infcx.tcx.predicate_for_builtin_bound(cause, builtin_bound, 0, ty) { Ok(predicate) => { self.register_predicate_obligation(infcx, predicate); } Err(ErrorReported) => { } } } pub fn register_region_obligation(&mut self, t_a: Ty<'tcx>, r_b: ty::Region, cause: ObligationCause<'tcx>) { register_region_obligation(t_a, r_b, cause, &mut self.region_obligations); } pub fn register_predicate_obligation(&mut self, infcx: &InferCtxt<'a, 'gcx, 'tcx>, obligation: PredicateObligation<'tcx>) { // this helps to reduce duplicate errors, as well as making // debug output much nicer to read and so on. let obligation = infcx.resolve_type_vars_if_possible(&obligation); if infcx.tcx.fulfilled_predicates.borrow().check_duplicate(&obligation.predicate) { return } self.predicates.register_obligation(PendingPredicateObligation { obligation: obligation, stalled_on: vec![] }); } pub fn register_rfc1592_obligation(&mut self, _infcx: &InferCtxt<'a, 'gcx, 'tcx>, obligation: PredicateObligation<'tcx>) { self.rfc1592_obligations.push(obligation); } pub fn region_obligations(&self, body_id: ast::NodeId) -> &[RegionObligation<'tcx>] { match self.region_obligations.get(&body_id) { None => Default::default(), Some(vec) => vec, } } pub fn select_rfc1592_obligations(&mut self, infcx: &InferCtxt<'a, 'gcx, 'tcx>) -> Result<(),Vec>> { while !self.rfc1592_obligations.is_empty() { for obligation in mem::replace(&mut self.rfc1592_obligations, Vec::new()) { self.register_predicate_obligation(infcx, obligation); } self.select_all_or_error(infcx)?; } Ok(()) } pub fn select_all_or_error(&mut self, infcx: &InferCtxt<'a, 'gcx, 'tcx>) -> Result<(),Vec>> { self.select_where_possible(infcx)?; let errors: Vec<_> = self.predicates.to_errors(CodeAmbiguity) .into_iter() .map(|e| to_fulfillment_error(e)) .collect(); if errors.is_empty() { Ok(()) } else { Err(errors) } } pub fn select_where_possible(&mut self, infcx: &InferCtxt<'a, 'gcx, 'tcx>) -> Result<(),Vec>> { let mut selcx = SelectionContext::new(infcx); self.select(&mut selcx) } pub fn pending_obligations(&self) -> Vec> { self.predicates.pending_obligations() } /// 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>) -> Result<(),Vec>> { debug!("select(obligation-forest-size={})", self.predicates.len()); let mut errors = Vec::new(); loop { debug!("select: starting another iteration"); // Process pending obligations. let outcome = self.predicates.process_obligations(&mut FulfillProcessor { selcx: selcx, region_obligations: &mut self.region_obligations, rfc1592_obligations: &mut self.rfc1592_obligations }); debug!("select: outcome={:?}", outcome); // these are obligations that were proven to be true. for pending_obligation in outcome.completed { let predicate = &pending_obligation.obligation.predicate; selcx.tcx().fulfilled_predicates.borrow_mut() .add_if_global(selcx.tcx(), predicate); } errors.extend( outcome.errors.into_iter() .map(|e| to_fulfillment_error(e))); // If nothing new was added, no need to keep looping. if outcome.stalled { break; } } debug!("select({} predicates remaining, {} errors) done", self.predicates.len(), errors.len()); if errors.is_empty() { Ok(()) } else { Err(errors) } } } struct FulfillProcessor<'a, 'b: 'a, 'gcx: 'tcx, 'tcx: 'b> { selcx: &'a mut SelectionContext<'b, 'gcx, 'tcx>, region_obligations: &'a mut NodeMap>>, rfc1592_obligations: &'a mut Vec> } impl<'a, 'b, 'gcx, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'b, 'gcx, 'tcx> { type Obligation = PendingPredicateObligation<'tcx>; type Error = FulfillmentErrorCode<'tcx>; fn process_obligation(&mut self, obligation: &mut Self::Obligation) -> Result>, Self::Error> { process_predicate(self.selcx, obligation, self.region_obligations, self.rfc1592_obligations) .map(|os| os.map(|os| os.into_iter().map(|o| PendingPredicateObligation { obligation: o, stalled_on: vec![] }).collect())) } fn process_backedge<'c, I>(&mut self, cycle: I, _marker: PhantomData<&'c PendingPredicateObligation<'tcx>>) where I: Clone + Iterator>, { if coinductive_match(self.selcx, cycle.clone()) { debug!("process_child_obligations: coinductive match"); } else { let cycle : Vec<_> = cycle.map(|c| c.obligation.clone()).collect(); self.selcx.infcx().report_overflow_error_cycle(&cycle); } } } /// Return the set of type variables contained in a trait ref fn trait_ref_type_vars<'a, 'gcx, 'tcx>(selcx: &mut SelectionContext<'a, 'gcx, 'tcx>, t: ty::PolyTraitRef<'tcx>) -> Vec> { t.skip_binder() // ok b/c this check doesn't care about regions .input_types() .iter() .map(|t| selcx.infcx().resolve_type_vars_if_possible(t)) .filter(|t| t.has_infer_types()) .flat_map(|t| t.walk()) .filter(|t| match t.sty { ty::TyInfer(_) => true, _ => false }) .collect() } /// Processes a predicate obligation and returns either: /// - `Ok(Some(v))` if the predicate is true, presuming that `v` are also true /// - `Ok(None)` if we don't have enough info to be sure /// - `Err` if the predicate does not hold fn process_predicate<'a, 'gcx, 'tcx>( selcx: &mut SelectionContext<'a, 'gcx, 'tcx>, pending_obligation: &mut PendingPredicateObligation<'tcx>, region_obligations: &mut NodeMap>>, rfc1592_obligations: &mut Vec>) -> Result>>, FulfillmentErrorCode<'tcx>> { // if we were stalled on some unresolved variables, first check // whether any of them have been resolved; if not, don't bother // doing more work yet if !pending_obligation.stalled_on.is_empty() { if pending_obligation.stalled_on.iter().all(|&ty| { let resolved_ty = selcx.infcx().shallow_resolve(&ty); resolved_ty == ty // nothing changed here }) { debug!("process_predicate: pending obligation {:?} still stalled on {:?}", selcx.infcx().resolve_type_vars_if_possible(&pending_obligation.obligation), pending_obligation.stalled_on); return Ok(None); } pending_obligation.stalled_on = vec![]; } let obligation = &mut pending_obligation.obligation; if obligation.predicate.has_infer_types() { obligation.predicate = selcx.infcx().resolve_type_vars_if_possible(&obligation.predicate); } match obligation.predicate { ty::Predicate::Trait(ref data) => { if selcx.tcx().fulfilled_predicates.borrow().check_duplicate_trait(data) { return Ok(Some(vec![])); } let trait_obligation = obligation.with(data.clone()); match selcx.select(&trait_obligation) { Ok(Some(vtable)) => { debug!("selecting trait `{:?}` at depth {} yielded Ok(Some)", data, obligation.recursion_depth); Ok(Some(vtable.nested_obligations())) } Ok(None) => { debug!("selecting trait `{:?}` at depth {} yielded Ok(None)", data, obligation.recursion_depth); // This is a bit subtle: for the most part, the // only reason we can fail to make progress on // trait selection is because we don't have enough // information about the types in the trait. One // exception is that we sometimes haven't decided // what kind of closure a closure is. *But*, in // that case, it turns out, the type of the // closure will also change, because the closure // also includes references to its upvars as part // of its type, and those types are resolved at // the same time. pending_obligation.stalled_on = trait_ref_type_vars(selcx, data.to_poly_trait_ref()); debug!("process_predicate: pending obligation {:?} now stalled on {:?}", selcx.infcx().resolve_type_vars_if_possible(obligation), pending_obligation.stalled_on); Ok(None) } Err(selection_err) => { info!("selecting trait `{:?}` at depth {} yielded Err", data, obligation.recursion_depth); Err(CodeSelectionError(selection_err)) } } } ty::Predicate::Equate(ref binder) => { match selcx.infcx().equality_predicate(obligation.cause.span, binder) { Ok(InferOk { obligations, .. }) => { // FIXME(#32730) propagate obligations assert!(obligations.is_empty()); Ok(Some(Vec::new())) }, Err(_) => Err(CodeSelectionError(Unimplemented)), } } ty::Predicate::RegionOutlives(ref binder) => { match selcx.infcx().region_outlives_predicate(obligation.cause.span, binder) { Ok(()) => Ok(Some(Vec::new())), Err(_) => Err(CodeSelectionError(Unimplemented)), } } ty::Predicate::TypeOutlives(ref binder) => { // Check if there are higher-ranked regions. match selcx.tcx().no_late_bound_regions(binder) { // If there are, inspect the underlying type further. None => { // Convert from `Binder>` to `Binder`. let binder = binder.map_bound_ref(|pred| pred.0); // Check if the type has any bound regions. match selcx.tcx().no_late_bound_regions(&binder) { // If so, this obligation is an error (for now). Eventually we should be // able to support additional cases here, like `for<'a> &'a str: 'a`. None => { Err(CodeSelectionError(Unimplemented)) } // Otherwise, we have something of the form // `for<'a> T: 'a where 'a not in T`, which we can treat as `T: 'static`. Some(t_a) => { register_region_obligation(t_a, ty::ReStatic, obligation.cause.clone(), region_obligations); Ok(Some(vec![])) } } } // If there aren't, register the obligation. Some(ty::OutlivesPredicate(t_a, r_b)) => { register_region_obligation(t_a, r_b, obligation.cause.clone(), region_obligations); Ok(Some(vec![])) } } } ty::Predicate::Projection(ref data) => { let project_obligation = obligation.with(data.clone()); match project::poly_project_and_unify_type(selcx, &project_obligation) { Ok(None) => { pending_obligation.stalled_on = trait_ref_type_vars(selcx, data.to_poly_trait_ref()); Ok(None) } Ok(v) => Ok(v), Err(e) => Err(CodeProjectionError(e)) } } ty::Predicate::ObjectSafe(trait_def_id) => { if !selcx.tcx().is_object_safe(trait_def_id) { Err(CodeSelectionError(Unimplemented)) } else { Ok(Some(Vec::new())) } } ty::Predicate::ClosureKind(closure_def_id, kind) => { match selcx.infcx().closure_kind(closure_def_id) { Some(closure_kind) => { if closure_kind.extends(kind) { Ok(Some(vec![])) } else { Err(CodeSelectionError(Unimplemented)) } } None => { Ok(None) } } } ty::Predicate::WellFormed(ty) => { match ty::wf::obligations(selcx.infcx(), obligation.cause.body_id, ty, obligation.cause.span) { None => { pending_obligation.stalled_on = vec![ty]; Ok(None) } s => Ok(s) } } ty::Predicate::Rfc1592(ref inner) => { rfc1592_obligations.push(PredicateObligation { predicate: ty::Predicate::clone(inner), ..obligation.clone() }); Ok(Some(vec![])) } } } /// For defaulted traits, we use a co-inductive strategy to solve, so /// that recursion is ok. This routine returns true if the top of the /// stack (`cycle[0]`): /// - is a defaulted trait, and /// - it also appears in the backtrace at some position `X`; and, /// - all the predicates at positions `X..` between `X` an the top are /// also defaulted traits. fn coinductive_match<'a,'c,'gcx,'tcx,I>(selcx: &mut SelectionContext<'a,'gcx,'tcx>, cycle: I) -> bool where I: Iterator>, 'tcx: 'c { let mut cycle = cycle; cycle .all(|bt_obligation| { let result = coinductive_obligation(selcx, &bt_obligation.obligation); debug!("coinductive_match: bt_obligation={:?} coinductive={}", bt_obligation, result); result }) } fn coinductive_obligation<'a,'gcx,'tcx>(selcx: &SelectionContext<'a,'gcx,'tcx>, obligation: &PredicateObligation<'tcx>) -> bool { match obligation.predicate { ty::Predicate::Trait(ref data) => { selcx.tcx().trait_has_default_impl(data.def_id()) } _ => { false } } } fn register_region_obligation<'tcx>(t_a: Ty<'tcx>, r_b: ty::Region, cause: ObligationCause<'tcx>, region_obligations: &mut NodeMap>>) { let region_obligation = RegionObligation { sup_type: t_a, sub_region: r_b, cause: cause }; debug!("register_region_obligation({:?}, cause={:?})", region_obligation, region_obligation.cause); region_obligations.entry(region_obligation.cause.body_id) .or_insert(vec![]) .push(region_obligation); } impl<'a, 'gcx, 'tcx> GlobalFulfilledPredicates<'gcx> { pub fn new(dep_graph: DepGraph) -> GlobalFulfilledPredicates<'gcx> { GlobalFulfilledPredicates { set: FnvHashSet(), dep_graph: dep_graph, } } pub fn check_duplicate(&self, key: &ty::Predicate<'tcx>) -> bool { if let ty::Predicate::Trait(ref data) = *key { self.check_duplicate_trait(data) } else { false } } pub fn check_duplicate_trait(&self, data: &ty::PolyTraitPredicate<'tcx>) -> bool { // For the global predicate registry, when we find a match, it // may have been computed by some other task, so we want to // add a read from the node corresponding to the predicate // processing to make sure we get the transitive dependencies. if self.set.contains(data) { debug_assert!(data.is_global()); self.dep_graph.read(data.dep_node()); debug!("check_duplicate: global predicate `{:?}` already proved elsewhere", data); true } else { false } } fn add_if_global(&mut self, tcx: TyCtxt<'a, 'gcx, 'tcx>, key: &ty::Predicate<'tcx>) { if let ty::Predicate::Trait(ref data) = *key { // We only add things to the global predicate registry // after the current task has proved them, and hence // already has the required read edges, so we don't need // to add any more edges here. if data.is_global() { if let Some(data) = tcx.lift_to_global(data) { if self.set.insert(data.clone()) { debug!("add_if_global: global predicate `{:?}` added", data); } } } } } } fn to_fulfillment_error<'tcx>( error: Error, FulfillmentErrorCode<'tcx>>) -> FulfillmentError<'tcx> { let obligation = error.backtrace.into_iter().next().unwrap().obligation; FulfillmentError::new(obligation, error.error) }