use crate::infer::InferCtxt; use crate::mir::interpret::{GlobalId, ErrorHandled}; use crate::ty::{self, Ty, TypeFoldable, ToPolyTraitRef}; use crate::ty::error::ExpectedFound; use rustc_data_structures::obligation_forest::{DoCompleted, Error, ForestObligation}; use rustc_data_structures::obligation_forest::{ObligationForest, ObligationProcessor}; use rustc_data_structures::obligation_forest::{ProcessResult}; use std::marker::PhantomData; use super::CodeAmbiguity; use super::CodeProjectionError; use super::CodeSelectionError; use super::engine::{TraitEngine, TraitEngineExt}; use super::{FulfillmentError, FulfillmentErrorCode}; use super::{ObligationCause, PredicateObligation}; use super::project; use super::select::SelectionContext; use super::{Unimplemented, ConstEvalFailure}; impl<'tcx> ForestObligation for PendingPredicateObligation<'tcx> { type Predicate = ty::Predicate<'tcx>; fn as_predicate(&self) -> &Self::Predicate { &self.obligation.predicate } } /// 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 fulfillment 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>, // Should this fulfillment context register type-lives-for-region // obligations on its parent infcx? In some cases, region // obligations are either already known to hold (normalization) or // hopefully verifed elsewhere (type-impls-bound), and therefore // should not be checked. // // Note that if we are normalizing a type that we already // know is well-formed, there should be no harm setting this // to true - all the region variables should be determinable // using the RFC 447 rules, which don't depend on // type-lives-for-region constraints, and because the type // is well-formed, the constraints should hold. register_region_obligations: bool, // 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 } #[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(), register_region_obligations: true, usable_in_snapshot: false, } } pub fn new_in_snapshot() -> FulfillmentContext<'tcx> { FulfillmentContext { predicates: ObligationForest::new(), register_region_obligations: true, usable_in_snapshot: true, } } pub fn new_ignoring_regions() -> FulfillmentContext<'tcx> { FulfillmentContext { predicates: ObligationForest::new(), register_region_obligations: false, usable_in_snapshot: false } } /// Attempts to select obligations using `selcx`. 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, register_region_obligations: self.register_region_obligations }, DoCompleted::No); debug!("select: outcome={:#?}", outcome); // FIXME: if we kept the original cache key, we could mark projection // obligations as complete for the projection cache here. 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) } } } impl<'tcx> TraitEngine<'tcx> for FulfillmentContext<'tcx> { /// "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. fn normalize_projection_type<'a, 'gcx>(&mut self, infcx: &InferCtxt<'a, 'gcx, 'tcx>, param_env: ty::ParamEnv<'tcx>, projection_ty: ty::ProjectionTy<'tcx>, cause: ObligationCause<'tcx>) -> Ty<'tcx> { debug!("normalize_projection_type(projection_ty={:?})", projection_ty); debug_assert!(!projection_ty.has_escaping_bound_vars()); // FIXME(#20304) -- cache let mut selcx = SelectionContext::new(infcx); let mut obligations = vec![]; let normalized_ty = project::normalize_projection_type(&mut selcx, param_env, projection_ty, cause, 0, &mut obligations); self.register_predicate_obligations(infcx, obligations); debug!("normalize_projection_type: result={:?}", normalized_ty); normalized_ty } fn register_predicate_obligation<'a, 'gcx>(&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); debug!("register_predicate_obligation(obligation={:?})", obligation); assert!(!infcx.is_in_snapshot() || self.usable_in_snapshot); self.predicates.register_obligation(PendingPredicateObligation { obligation, stalled_on: vec![] }); } fn select_all_or_error<'a, 'gcx>( &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) } } fn select_where_possible<'a, 'gcx>(&mut self, infcx: &InferCtxt<'a, 'gcx, 'tcx>) -> Result<(),Vec>> { let mut selcx = SelectionContext::new(infcx); self.select(&mut selcx) } fn pending_obligations(&self) -> Vec> { self.predicates.map_pending_obligations(|o| o.obligation.clone()) } } struct FulfillProcessor<'a, 'b: 'a, 'gcx: 'tcx, 'tcx: 'b> { selcx: &'a mut SelectionContext<'b, 'gcx, 'tcx>, register_region_obligations: bool } fn mk_pending(os: Vec>) -> Vec> { os.into_iter().map(|o| PendingPredicateObligation { obligation: o, stalled_on: vec![] }).collect() } impl<'a, 'b, 'gcx, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'b, 'gcx, 'tcx> { type Obligation = PendingPredicateObligation<'tcx>; type Error = FulfillmentErrorCode<'tcx>; /// Processes a predicate obligation and returns either: /// - `Changed(v)` if the predicate is true, presuming that `v` are also true /// - `Unchanged` if we don't have enough info to be sure /// - `Error(e)` if the predicate does not hold /// /// This is always inlined, despite its size, because it has a single /// callsite and it is called *very* frequently. #[inline(always)] fn process_obligation(&mut self, pending_obligation: &mut Self::Obligation) -> ProcessResult { // 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| { // Use the force-inlined variant of shallow_resolve() because this code is hot. let resolved_ty = self.selcx.infcx().inlined_shallow_resolve(&ty); resolved_ty == ty // nothing changed here }) { debug!("process_predicate: pending obligation {:?} still stalled on {:?}", self.selcx.infcx() .resolve_type_vars_if_possible(&pending_obligation.obligation), pending_obligation.stalled_on); return ProcessResult::Unchanged; } pending_obligation.stalled_on = vec![]; } let obligation = &mut pending_obligation.obligation; if obligation.predicate.has_infer_types() { obligation.predicate = self.selcx.infcx().resolve_type_vars_if_possible(&obligation.predicate); } debug!("process_obligation: obligation = {:?}", obligation); match obligation.predicate { ty::Predicate::Trait(ref data) => { let trait_obligation = obligation.with(data.clone()); if data.is_global() { // no type variables present, can use evaluation for better caching. // FIXME: consider caching errors too. if self.selcx.infcx().predicate_must_hold_considering_regions(&obligation) { debug!("selecting trait `{:?}` at depth {} evaluated to holds", data, obligation.recursion_depth); return ProcessResult::Changed(vec![]) } } match self.selcx.select(&trait_obligation) { Ok(Some(vtable)) => { debug!("selecting trait `{:?}` at depth {} yielded Ok(Some)", data, obligation.recursion_depth); ProcessResult::Changed(mk_pending(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. // // FIXME(#32286) logic seems false if no upvars pending_obligation.stalled_on = trait_ref_type_vars(self.selcx, data.to_poly_trait_ref()); debug!("process_predicate: pending obligation {:?} now stalled on {:?}", self.selcx.infcx().resolve_type_vars_if_possible(obligation), pending_obligation.stalled_on); ProcessResult::Unchanged } Err(selection_err) => { info!("selecting trait `{:?}` at depth {} yielded Err", data, obligation.recursion_depth); ProcessResult::Error(CodeSelectionError(selection_err)) } } } ty::Predicate::RegionOutlives(ref binder) => { match self.selcx.infcx().region_outlives_predicate(&obligation.cause, binder) { Ok(()) => ProcessResult::Changed(vec![]), Err(_) => ProcessResult::Error(CodeSelectionError(Unimplemented)), } } ty::Predicate::TypeOutlives(ref binder) => { // Check if there are higher-ranked vars. match binder.no_bound_vars() { // 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 vars. match binder.no_bound_vars() { // 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`. // NOTE: this is duplicate-implemented between here and fulfillment. None => { ProcessResult::Error(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) => { let r_static = self.selcx.tcx().types.re_static; if self.register_region_obligations { self.selcx.infcx().register_region_obligation_with_cause( t_a, r_static, &obligation.cause, ); } ProcessResult::Changed(vec![]) } } } // If there aren't, register the obligation. Some(ty::OutlivesPredicate(t_a, r_b)) => { if self.register_region_obligations { self.selcx.infcx().register_region_obligation_with_cause( t_a, r_b, &obligation.cause, ); } ProcessResult::Changed(vec![]) } } } ty::Predicate::Projection(ref data) => { let project_obligation = obligation.with(data.clone()); match project::poly_project_and_unify_type(self.selcx, &project_obligation) { Ok(None) => { let tcx = self.selcx.tcx(); pending_obligation.stalled_on = trait_ref_type_vars(self.selcx, data.to_poly_trait_ref(tcx)); ProcessResult::Unchanged } Ok(Some(os)) => ProcessResult::Changed(mk_pending(os)), Err(e) => ProcessResult::Error(CodeProjectionError(e)) } } ty::Predicate::ObjectSafe(trait_def_id) => { if !self.selcx.tcx().is_object_safe(trait_def_id) { ProcessResult::Error(CodeSelectionError(Unimplemented)) } else { ProcessResult::Changed(vec![]) } } ty::Predicate::ClosureKind(closure_def_id, closure_substs, kind) => { match self.selcx.infcx().closure_kind(closure_def_id, closure_substs) { Some(closure_kind) => { if closure_kind.extends(kind) { ProcessResult::Changed(vec![]) } else { ProcessResult::Error(CodeSelectionError(Unimplemented)) } } None => { ProcessResult::Unchanged } } } ty::Predicate::WellFormed(ty) => { match ty::wf::obligations(self.selcx.infcx(), obligation.param_env, obligation.cause.body_id, ty, obligation.cause.span) { None => { pending_obligation.stalled_on = vec![ty]; ProcessResult::Unchanged } Some(os) => ProcessResult::Changed(mk_pending(os)) } } ty::Predicate::Subtype(ref subtype) => { match self.selcx.infcx().subtype_predicate(&obligation.cause, obligation.param_env, subtype) { None => { // None means that both are unresolved. pending_obligation.stalled_on = vec![subtype.skip_binder().a, subtype.skip_binder().b]; ProcessResult::Unchanged } Some(Ok(ok)) => { ProcessResult::Changed(mk_pending(ok.obligations)) } Some(Err(err)) => { let expected_found = ExpectedFound::new(subtype.skip_binder().a_is_expected, subtype.skip_binder().a, subtype.skip_binder().b); ProcessResult::Error( FulfillmentErrorCode::CodeSubtypeError(expected_found, err)) } } } ty::Predicate::ConstEvaluatable(def_id, substs) => { match self.selcx.tcx().lift_to_global(&obligation.param_env) { None => { ProcessResult::Unchanged } Some(param_env) => { match self.selcx.tcx().lift_to_global(&substs) { Some(substs) => { let instance = ty::Instance::resolve( self.selcx.tcx().global_tcx(), param_env, def_id, substs, ); if let Some(instance) = instance { let cid = GlobalId { instance, promoted: None, }; match self.selcx.tcx().at(obligation.cause.span) .const_eval(param_env.and(cid)) { Ok(_) => ProcessResult::Changed(vec![]), Err(err) => ProcessResult::Error( CodeSelectionError(ConstEvalFailure(err))) } } else { ProcessResult::Error(CodeSelectionError( ConstEvalFailure(ErrorHandled::TooGeneric) )) } }, None => { pending_obligation.stalled_on = substs.types().collect(); ProcessResult::Unchanged } } } } } } } fn process_backedge<'c, I>(&mut self, cycle: I, _marker: PhantomData<&'c PendingPredicateObligation<'tcx>>) where I: Clone + Iterator>, { if self.selcx.coinductive_match(cycle.clone().map(|s| s.obligation.predicate)) { 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); } } } /// Returns 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() .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::Infer(_) => true, _ => false }) .collect() } 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) }