diff options
Diffstat (limited to 'src/librustc_infer/traits')
35 files changed, 44 insertions, 15828 deletions
diff --git a/src/librustc_infer/traits/auto_trait.rs b/src/librustc_infer/traits/auto_trait.rs deleted file mode 100644 index 1a4f899ac85..00000000000 --- a/src/librustc_infer/traits/auto_trait.rs +++ /dev/null @@ -1,837 +0,0 @@ -//! Support code for rustdoc and external tools. -//! You really don't want to be using this unless you need to. - -use super::*; - -use crate::infer::region_constraints::{Constraint, RegionConstraintData}; -use crate::infer::InferCtxt; -use rustc::ty::fold::TypeFolder; -use rustc::ty::{Region, RegionVid}; - -use rustc_data_structures::fx::{FxHashMap, FxHashSet}; - -use std::collections::hash_map::Entry; -use std::collections::VecDeque; - -// FIXME(twk): this is obviously not nice to duplicate like that -#[derive(Eq, PartialEq, Hash, Copy, Clone, Debug)] -pub enum RegionTarget<'tcx> { - Region(Region<'tcx>), - RegionVid(RegionVid), -} - -#[derive(Default, Debug, Clone)] -pub struct RegionDeps<'tcx> { - larger: FxHashSet<RegionTarget<'tcx>>, - smaller: FxHashSet<RegionTarget<'tcx>>, -} - -pub enum AutoTraitResult<A> { - ExplicitImpl, - PositiveImpl(A), - NegativeImpl, -} - -impl<A> AutoTraitResult<A> { - fn is_auto(&self) -> bool { - match *self { - AutoTraitResult::PositiveImpl(_) | AutoTraitResult::NegativeImpl => true, - _ => false, - } - } -} - -pub struct AutoTraitInfo<'cx> { - pub full_user_env: ty::ParamEnv<'cx>, - pub region_data: RegionConstraintData<'cx>, - pub vid_to_region: FxHashMap<ty::RegionVid, ty::Region<'cx>>, -} - -pub struct AutoTraitFinder<'tcx> { - tcx: TyCtxt<'tcx>, -} - -impl<'tcx> AutoTraitFinder<'tcx> { - pub fn new(tcx: TyCtxt<'tcx>) -> Self { - AutoTraitFinder { tcx } - } - - /// Makes a best effort to determine whether and under which conditions an auto trait is - /// implemented for a type. For example, if you have - /// - /// ``` - /// struct Foo<T> { data: Box<T> } - /// ``` - /// - /// then this might return that Foo<T>: Send if T: Send (encoded in the AutoTraitResult type). - /// The analysis attempts to account for custom impls as well as other complex cases. This - /// result is intended for use by rustdoc and other such consumers. - /// - /// (Note that due to the coinductive nature of Send, the full and correct result is actually - /// quite simple to generate. That is, when a type has no custom impl, it is Send iff its field - /// types are all Send. So, in our example, we might have that Foo<T>: Send if Box<T>: Send. - /// But this is often not the best way to present to the user.) - /// - /// Warning: The API should be considered highly unstable, and it may be refactored or removed - /// in the future. - pub fn find_auto_trait_generics<A>( - &self, - ty: Ty<'tcx>, - orig_env: ty::ParamEnv<'tcx>, - trait_did: DefId, - auto_trait_callback: impl Fn(&InferCtxt<'_, 'tcx>, AutoTraitInfo<'tcx>) -> A, - ) -> AutoTraitResult<A> { - let tcx = self.tcx; - - let trait_ref = ty::TraitRef { def_id: trait_did, substs: tcx.mk_substs_trait(ty, &[]) }; - - let trait_pred = ty::Binder::bind(trait_ref); - - let bail_out = tcx.infer_ctxt().enter(|infcx| { - let mut selcx = SelectionContext::with_negative(&infcx, true); - let result = selcx.select(&Obligation::new( - ObligationCause::dummy(), - orig_env, - trait_pred.to_poly_trait_predicate(), - )); - - match result { - Ok(Some(Vtable::VtableImpl(_))) => { - debug!( - "find_auto_trait_generics({:?}): \ - manual impl found, bailing out", - trait_ref - ); - true - } - _ => false, - } - }); - - // If an explicit impl exists, it always takes priority over an auto impl - if bail_out { - return AutoTraitResult::ExplicitImpl; - } - - return tcx.infer_ctxt().enter(|mut infcx| { - let mut fresh_preds = FxHashSet::default(); - - // Due to the way projections are handled by SelectionContext, we need to run - // evaluate_predicates twice: once on the original param env, and once on the result of - // the first evaluate_predicates call. - // - // The problem is this: most of rustc, including SelectionContext and traits::project, - // are designed to work with a concrete usage of a type (e.g., Vec<u8> - // fn<T>() { Vec<T> }. This information will generally never change - given - // the 'T' in fn<T>() { ... }, we'll never know anything else about 'T'. - // If we're unable to prove that 'T' implements a particular trait, we're done - - // there's nothing left to do but error out. - // - // However, synthesizing an auto trait impl works differently. Here, we start out with - // a set of initial conditions - the ParamEnv of the struct/enum/union we're dealing - // with - and progressively discover the conditions we need to fulfill for it to - // implement a certain auto trait. This ends up breaking two assumptions made by trait - // selection and projection: - // - // * We can always cache the result of a particular trait selection for the lifetime of - // an InfCtxt - // * Given a projection bound such as '<T as SomeTrait>::SomeItem = K', if 'T: - // SomeTrait' doesn't hold, then we don't need to care about the 'SomeItem = K' - // - // We fix the first assumption by manually clearing out all of the InferCtxt's caches - // in between calls to SelectionContext.select. This allows us to keep all of the - // intermediate types we create bound to the 'tcx lifetime, rather than needing to lift - // them between calls. - // - // We fix the second assumption by reprocessing the result of our first call to - // evaluate_predicates. Using the example of '<T as SomeTrait>::SomeItem = K', our first - // pass will pick up 'T: SomeTrait', but not 'SomeItem = K'. On our second pass, - // traits::project will see that 'T: SomeTrait' is in our ParamEnv, allowing - // SelectionContext to return it back to us. - - let (new_env, user_env) = match self.evaluate_predicates( - &mut infcx, - trait_did, - ty, - orig_env, - orig_env, - &mut fresh_preds, - false, - ) { - Some(e) => e, - None => return AutoTraitResult::NegativeImpl, - }; - - let (full_env, full_user_env) = self - .evaluate_predicates( - &mut infcx, - trait_did, - ty, - new_env, - user_env, - &mut fresh_preds, - true, - ) - .unwrap_or_else(|| { - panic!("Failed to fully process: {:?} {:?} {:?}", ty, trait_did, orig_env) - }); - - debug!( - "find_auto_trait_generics({:?}): fulfilling \ - with {:?}", - trait_ref, full_env - ); - infcx.clear_caches(); - - // At this point, we already have all of the bounds we need. FulfillmentContext is used - // to store all of the necessary region/lifetime bounds in the InferContext, as well as - // an additional sanity check. - let mut fulfill = FulfillmentContext::new(); - fulfill.register_bound( - &infcx, - full_env, - ty, - trait_did, - ObligationCause::misc(DUMMY_SP, hir::DUMMY_HIR_ID), - ); - fulfill.select_all_or_error(&infcx).unwrap_or_else(|e| { - panic!("Unable to fulfill trait {:?} for '{:?}': {:?}", trait_did, ty, e) - }); - - let body_id_map: FxHashMap<_, _> = infcx - .inner - .borrow() - .region_obligations - .iter() - .map(|&(id, _)| (id, vec![])) - .collect(); - - infcx.process_registered_region_obligations(&body_id_map, None, full_env); - - let region_data = infcx - .inner - .borrow_mut() - .unwrap_region_constraints() - .region_constraint_data() - .clone(); - - let vid_to_region = self.map_vid_to_region(®ion_data); - - let info = AutoTraitInfo { full_user_env, region_data, vid_to_region }; - - return AutoTraitResult::PositiveImpl(auto_trait_callback(&infcx, info)); - }); - } -} - -impl AutoTraitFinder<'tcx> { - /// The core logic responsible for computing the bounds for our synthesized impl. - /// - /// To calculate the bounds, we call `SelectionContext.select` in a loop. Like - /// `FulfillmentContext`, we recursively select the nested obligations of predicates we - /// encounter. However, whenever we encounter an `UnimplementedError` involving a type - /// parameter, we add it to our `ParamEnv`. Since our goal is to determine when a particular - /// type implements an auto trait, Unimplemented errors tell us what conditions need to be met. - /// - /// This method ends up working somewhat similarly to `FulfillmentContext`, but with a few key - /// differences. `FulfillmentContext` works under the assumption that it's dealing with concrete - /// user code. According, it considers all possible ways that a `Predicate` could be met, which - /// isn't always what we want for a synthesized impl. For example, given the predicate `T: - /// Iterator`, `FulfillmentContext` can end up reporting an Unimplemented error for `T: - /// IntoIterator` -- since there's an implementation of `Iterator` where `T: IntoIterator`, - /// `FulfillmentContext` will drive `SelectionContext` to consider that impl before giving up. - /// If we were to rely on `FulfillmentContext`s decision, we might end up synthesizing an impl - /// like this: - /// - /// impl<T> Send for Foo<T> where T: IntoIterator - /// - /// While it might be technically true that Foo implements Send where `T: IntoIterator`, - /// the bound is overly restrictive - it's really only necessary that `T: Iterator`. - /// - /// For this reason, `evaluate_predicates` handles predicates with type variables specially. - /// When we encounter an `Unimplemented` error for a bound such as `T: Iterator`, we immediately - /// add it to our `ParamEnv`, and add it to our stack for recursive evaluation. When we later - /// select it, we'll pick up any nested bounds, without ever inferring that `T: IntoIterator` - /// needs to hold. - /// - /// One additional consideration is supertrait bounds. Normally, a `ParamEnv` is only ever - /// constructed once for a given type. As part of the construction process, the `ParamEnv` will - /// have any supertrait bounds normalized -- e.g., if we have a type `struct Foo<T: Copy>`, the - /// `ParamEnv` will contain `T: Copy` and `T: Clone`, since `Copy: Clone`. When we construct our - /// own `ParamEnv`, we need to do this ourselves, through `traits::elaborate_predicates`, or - /// else `SelectionContext` will choke on the missing predicates. However, this should never - /// show up in the final synthesized generics: we don't want our generated docs page to contain - /// something like `T: Copy + Clone`, as that's redundant. Therefore, we keep track of a - /// separate `user_env`, which only holds the predicates that will actually be displayed to the - /// user. - fn evaluate_predicates( - &self, - infcx: &InferCtxt<'_, 'tcx>, - trait_did: DefId, - ty: Ty<'tcx>, - param_env: ty::ParamEnv<'tcx>, - user_env: ty::ParamEnv<'tcx>, - fresh_preds: &mut FxHashSet<ty::Predicate<'tcx>>, - only_projections: bool, - ) -> Option<(ty::ParamEnv<'tcx>, ty::ParamEnv<'tcx>)> { - let tcx = infcx.tcx; - - let mut select = SelectionContext::with_negative(&infcx, true); - - let mut already_visited = FxHashSet::default(); - let mut predicates = VecDeque::new(); - predicates.push_back(ty::Binder::bind(ty::TraitPredicate { - trait_ref: ty::TraitRef { - def_id: trait_did, - substs: infcx.tcx.mk_substs_trait(ty, &[]), - }, - })); - - let mut computed_preds: FxHashSet<_> = param_env.caller_bounds.iter().cloned().collect(); - let mut user_computed_preds: FxHashSet<_> = - user_env.caller_bounds.iter().cloned().collect(); - - let mut new_env = param_env; - let dummy_cause = ObligationCause::misc(DUMMY_SP, hir::DUMMY_HIR_ID); - - while let Some(pred) = predicates.pop_front() { - infcx.clear_caches(); - - if !already_visited.insert(pred) { - continue; - } - - // Call `infcx.resolve_vars_if_possible` to see if we can - // get rid of any inference variables. - let obligation = infcx.resolve_vars_if_possible(&Obligation::new( - dummy_cause.clone(), - new_env, - pred, - )); - let result = select.select(&obligation); - - match &result { - &Ok(Some(ref vtable)) => { - // If we see an explicit negative impl (e.g., `impl !Send for MyStruct`), - // we immediately bail out, since it's impossible for us to continue. - match vtable { - Vtable::VtableImpl(VtableImplData { impl_def_id, .. }) => { - // Blame 'tidy' for the weird bracket placement. - if infcx.tcx.impl_polarity(*impl_def_id) == ty::ImplPolarity::Negative { - debug!( - "evaluate_nested_obligations: found explicit negative impl\ - {:?}, bailing out", - impl_def_id - ); - return None; - } - } - _ => {} - } - - let obligations = vtable.clone().nested_obligations().into_iter(); - - if !self.evaluate_nested_obligations( - ty, - obligations, - &mut user_computed_preds, - fresh_preds, - &mut predicates, - &mut select, - only_projections, - ) { - return None; - } - } - &Ok(None) => {} - &Err(SelectionError::Unimplemented) => { - if self.is_param_no_infer(pred.skip_binder().trait_ref.substs) { - already_visited.remove(&pred); - self.add_user_pred( - &mut user_computed_preds, - ty::Predicate::Trait(pred, hir::Constness::NotConst), - ); - predicates.push_back(pred); - } else { - debug!( - "evaluate_nested_obligations: `Unimplemented` found, bailing: \ - {:?} {:?} {:?}", - ty, - pred, - pred.skip_binder().trait_ref.substs - ); - return None; - } - } - _ => panic!("Unexpected error for '{:?}': {:?}", ty, result), - }; - - computed_preds.extend(user_computed_preds.iter().cloned()); - let normalized_preds = - elaborate_predicates(tcx, computed_preds.iter().cloned().collect()); - new_env = - ty::ParamEnv::new(tcx.mk_predicates(normalized_preds), param_env.reveal, None); - } - - let final_user_env = ty::ParamEnv::new( - tcx.mk_predicates(user_computed_preds.into_iter()), - user_env.reveal, - None, - ); - debug!( - "evaluate_nested_obligations(ty={:?}, trait_did={:?}): succeeded with '{:?}' \ - '{:?}'", - ty, trait_did, new_env, final_user_env - ); - - return Some((new_env, final_user_env)); - } - - /// This method is designed to work around the following issue: - /// When we compute auto trait bounds, we repeatedly call `SelectionContext.select`, - /// progressively building a `ParamEnv` based on the results we get. - /// However, our usage of `SelectionContext` differs from its normal use within the compiler, - /// in that we capture and re-reprocess predicates from `Unimplemented` errors. - /// - /// This can lead to a corner case when dealing with region parameters. - /// During our selection loop in `evaluate_predicates`, we might end up with - /// two trait predicates that differ only in their region parameters: - /// one containing a HRTB lifetime parameter, and one containing a 'normal' - /// lifetime parameter. For example: - /// - /// T as MyTrait<'a> - /// T as MyTrait<'static> - /// - /// If we put both of these predicates in our computed `ParamEnv`, we'll - /// confuse `SelectionContext`, since it will (correctly) view both as being applicable. - /// - /// To solve this, we pick the 'more strict' lifetime bound -- i.e., the HRTB - /// Our end goal is to generate a user-visible description of the conditions - /// under which a type implements an auto trait. A trait predicate involving - /// a HRTB means that the type needs to work with any choice of lifetime, - /// not just one specific lifetime (e.g., `'static`). - fn add_user_pred<'c>( - &self, - user_computed_preds: &mut FxHashSet<ty::Predicate<'c>>, - new_pred: ty::Predicate<'c>, - ) { - let mut should_add_new = true; - user_computed_preds.retain(|&old_pred| { - match (&new_pred, old_pred) { - (&ty::Predicate::Trait(new_trait, _), ty::Predicate::Trait(old_trait, _)) => { - if new_trait.def_id() == old_trait.def_id() { - let new_substs = new_trait.skip_binder().trait_ref.substs; - let old_substs = old_trait.skip_binder().trait_ref.substs; - - if !new_substs.types().eq(old_substs.types()) { - // We can't compare lifetimes if the types are different, - // so skip checking `old_pred`. - return true; - } - - for (new_region, old_region) in - new_substs.regions().zip(old_substs.regions()) - { - match (new_region, old_region) { - // If both predicates have an `ReLateBound` (a HRTB) in the - // same spot, we do nothing. - ( - ty::RegionKind::ReLateBound(_, _), - ty::RegionKind::ReLateBound(_, _), - ) => {} - - (ty::RegionKind::ReLateBound(_, _), _) - | (_, ty::RegionKind::ReVar(_)) => { - // One of these is true: - // The new predicate has a HRTB in a spot where the old - // predicate does not (if they both had a HRTB, the previous - // match arm would have executed). A HRBT is a 'stricter' - // bound than anything else, so we want to keep the newer - // predicate (with the HRBT) in place of the old predicate. - // - // OR - // - // The old predicate has a region variable where the new - // predicate has some other kind of region. An region - // variable isn't something we can actually display to a user, - // so we choose their new predicate (which doesn't have a region - // varaible). - // - // In both cases, we want to remove the old predicate, - // from `user_computed_preds`, and replace it with the new - // one. Having both the old and the new - // predicate in a `ParamEnv` would confuse `SelectionContext`. - // - // We're currently in the predicate passed to 'retain', - // so we return `false` to remove the old predicate from - // `user_computed_preds`. - return false; - } - (_, ty::RegionKind::ReLateBound(_, _)) - | (ty::RegionKind::ReVar(_), _) => { - // This is the opposite situation as the previous arm. - // One of these is true: - // - // The old predicate has a HRTB lifetime in a place where the - // new predicate does not. - // - // OR - // - // The new predicate has a region variable where the old - // predicate has some other type of region. - // - // We want to leave the old - // predicate in `user_computed_preds`, and skip adding - // new_pred to `user_computed_params`. - should_add_new = false - } - _ => {} - } - } - } - } - _ => {} - } - return true; - }); - - if should_add_new { - user_computed_preds.insert(new_pred); - } - } - - /// This is very similar to `handle_lifetimes`. However, instead of matching `ty::Region`s - /// to each other, we match `ty::RegionVid`s to `ty::Region`s. - fn map_vid_to_region<'cx>( - &self, - regions: &RegionConstraintData<'cx>, - ) -> FxHashMap<ty::RegionVid, ty::Region<'cx>> { - let mut vid_map: FxHashMap<RegionTarget<'cx>, RegionDeps<'cx>> = FxHashMap::default(); - let mut finished_map = FxHashMap::default(); - - for constraint in regions.constraints.keys() { - match constraint { - &Constraint::VarSubVar(r1, r2) => { - { - let deps1 = vid_map.entry(RegionTarget::RegionVid(r1)).or_default(); - deps1.larger.insert(RegionTarget::RegionVid(r2)); - } - - let deps2 = vid_map.entry(RegionTarget::RegionVid(r2)).or_default(); - deps2.smaller.insert(RegionTarget::RegionVid(r1)); - } - &Constraint::RegSubVar(region, vid) => { - { - let deps1 = vid_map.entry(RegionTarget::Region(region)).or_default(); - deps1.larger.insert(RegionTarget::RegionVid(vid)); - } - - let deps2 = vid_map.entry(RegionTarget::RegionVid(vid)).or_default(); - deps2.smaller.insert(RegionTarget::Region(region)); - } - &Constraint::VarSubReg(vid, region) => { - finished_map.insert(vid, region); - } - &Constraint::RegSubReg(r1, r2) => { - { - let deps1 = vid_map.entry(RegionTarget::Region(r1)).or_default(); - deps1.larger.insert(RegionTarget::Region(r2)); - } - - let deps2 = vid_map.entry(RegionTarget::Region(r2)).or_default(); - deps2.smaller.insert(RegionTarget::Region(r1)); - } - } - } - - while !vid_map.is_empty() { - let target = *vid_map.keys().next().expect("Keys somehow empty"); - let deps = vid_map.remove(&target).expect("Entry somehow missing"); - - for smaller in deps.smaller.iter() { - for larger in deps.larger.iter() { - match (smaller, larger) { - (&RegionTarget::Region(_), &RegionTarget::Region(_)) => { - if let Entry::Occupied(v) = vid_map.entry(*smaller) { - let smaller_deps = v.into_mut(); - smaller_deps.larger.insert(*larger); - smaller_deps.larger.remove(&target); - } - - if let Entry::Occupied(v) = vid_map.entry(*larger) { - let larger_deps = v.into_mut(); - larger_deps.smaller.insert(*smaller); - larger_deps.smaller.remove(&target); - } - } - (&RegionTarget::RegionVid(v1), &RegionTarget::Region(r1)) => { - finished_map.insert(v1, r1); - } - (&RegionTarget::Region(_), &RegionTarget::RegionVid(_)) => { - // Do nothing; we don't care about regions that are smaller than vids. - } - (&RegionTarget::RegionVid(_), &RegionTarget::RegionVid(_)) => { - if let Entry::Occupied(v) = vid_map.entry(*smaller) { - let smaller_deps = v.into_mut(); - smaller_deps.larger.insert(*larger); - smaller_deps.larger.remove(&target); - } - - if let Entry::Occupied(v) = vid_map.entry(*larger) { - let larger_deps = v.into_mut(); - larger_deps.smaller.insert(*smaller); - larger_deps.smaller.remove(&target); - } - } - } - } - } - } - finished_map - } - - fn is_param_no_infer(&self, substs: SubstsRef<'_>) -> bool { - return self.is_of_param(substs.type_at(0)) && !substs.types().any(|t| t.has_infer_types()); - } - - pub fn is_of_param(&self, ty: Ty<'_>) -> bool { - return match ty.kind { - ty::Param(_) => true, - ty::Projection(p) => self.is_of_param(p.self_ty()), - _ => false, - }; - } - - fn is_self_referential_projection(&self, p: ty::PolyProjectionPredicate<'_>) -> bool { - match p.ty().skip_binder().kind { - ty::Projection(proj) if proj == p.skip_binder().projection_ty => true, - _ => false, - } - } - - fn evaluate_nested_obligations( - &self, - ty: Ty<'_>, - nested: impl Iterator<Item = Obligation<'tcx, ty::Predicate<'tcx>>>, - computed_preds: &mut FxHashSet<ty::Predicate<'tcx>>, - fresh_preds: &mut FxHashSet<ty::Predicate<'tcx>>, - predicates: &mut VecDeque<ty::PolyTraitPredicate<'tcx>>, - select: &mut SelectionContext<'_, 'tcx>, - only_projections: bool, - ) -> bool { - let dummy_cause = ObligationCause::misc(DUMMY_SP, hir::DUMMY_HIR_ID); - - for (obligation, mut predicate) in nested.map(|o| (o.clone(), o.predicate)) { - let is_new_pred = fresh_preds.insert(self.clean_pred(select.infcx(), predicate)); - - // Resolve any inference variables that we can, to help selection succeed - predicate = select.infcx().resolve_vars_if_possible(&predicate); - - // We only add a predicate as a user-displayable bound if - // it involves a generic parameter, and doesn't contain - // any inference variables. - // - // Displaying a bound involving a concrete type (instead of a generic - // parameter) would be pointless, since it's always true - // (e.g. u8: Copy) - // Displaying an inference variable is impossible, since they're - // an internal compiler detail without a defined visual representation - // - // We check this by calling is_of_param on the relevant types - // from the various possible predicates - match &predicate { - &ty::Predicate::Trait(p, _) => { - if self.is_param_no_infer(p.skip_binder().trait_ref.substs) - && !only_projections - && is_new_pred - { - self.add_user_pred(computed_preds, predicate); - } - predicates.push_back(p); - } - &ty::Predicate::Projection(p) => { - debug!( - "evaluate_nested_obligations: examining projection predicate {:?}", - predicate - ); - - // As described above, we only want to display - // bounds which include a generic parameter but don't include - // an inference variable. - // Additionally, we check if we've seen this predicate before, - // to avoid rendering duplicate bounds to the user. - if self.is_param_no_infer(p.skip_binder().projection_ty.substs) - && !p.ty().skip_binder().has_infer_types() - && is_new_pred - { - debug!( - "evaluate_nested_obligations: adding projection predicate\ - to computed_preds: {:?}", - predicate - ); - - // Under unusual circumstances, we can end up with a self-refeential - // projection predicate. For example: - // <T as MyType>::Value == <T as MyType>::Value - // Not only is displaying this to the user pointless, - // having it in the ParamEnv will cause an issue if we try to call - // poly_project_and_unify_type on the predicate, since this kind of - // predicate will normally never end up in a ParamEnv. - // - // For these reasons, we ignore these weird predicates, - // ensuring that we're able to properly synthesize an auto trait impl - if self.is_self_referential_projection(p) { - debug!( - "evaluate_nested_obligations: encountered a projection - predicate equating a type with itself! Skipping" - ); - } else { - self.add_user_pred(computed_preds, predicate); - } - } - - // There are three possible cases when we project a predicate: - // - // 1. We encounter an error. This means that it's impossible for - // our current type to implement the auto trait - there's bound - // that we could add to our ParamEnv that would 'fix' this kind - // of error, as it's not caused by an unimplemented type. - // - // 2. We successfully project the predicate (Ok(Some(_))), generating - // some subobligations. We then process these subobligations - // like any other generated sub-obligations. - // - // 3. We receieve an 'ambiguous' result (Ok(None)) - // If we were actually trying to compile a crate, - // we would need to re-process this obligation later. - // However, all we care about is finding out what bounds - // are needed for our type to implement a particular auto trait. - // We've already added this obligation to our computed ParamEnv - // above (if it was necessary). Therefore, we don't need - // to do any further processing of the obligation. - // - // Note that we *must* try to project *all* projection predicates - // we encounter, even ones without inference variable. - // This ensures that we detect any projection errors, - // which indicate that our type can *never* implement the given - // auto trait. In that case, we will generate an explicit negative - // impl (e.g. 'impl !Send for MyType'). However, we don't - // try to process any of the generated subobligations - - // they contain no new information, since we already know - // that our type implements the projected-through trait, - // and can lead to weird region issues. - // - // Normally, we'll generate a negative impl as a result of encountering - // a type with an explicit negative impl of an auto trait - // (for example, raw pointers have !Send and !Sync impls) - // However, through some **interesting** manipulations of the type - // system, it's actually possible to write a type that never - // implements an auto trait due to a projection error, not a normal - // negative impl error. To properly handle this case, we need - // to ensure that we catch any potential projection errors, - // and turn them into an explicit negative impl for our type. - debug!("Projecting and unifying projection predicate {:?}", predicate); - - match poly_project_and_unify_type(select, &obligation.with(p)) { - Err(e) => { - debug!( - "evaluate_nested_obligations: Unable to unify predicate \ - '{:?}' '{:?}', bailing out", - ty, e - ); - return false; - } - Ok(Some(v)) => { - // We only care about sub-obligations - // when we started out trying to unify - // some inference variables. See the comment above - // for more infomration - if p.ty().skip_binder().has_infer_types() { - if !self.evaluate_nested_obligations( - ty, - v.clone().iter().cloned(), - computed_preds, - fresh_preds, - predicates, - select, - only_projections, - ) { - return false; - } - } - } - Ok(None) => { - // It's ok not to make progress when hvave no inference variables - - // in that case, we were only performing unifcation to check if an - // error occurred (which would indicate that it's impossible for our - // type to implement the auto trait). - // However, we should always make progress (either by generating - // subobligations or getting an error) when we started off with - // inference variables - if p.ty().skip_binder().has_infer_types() { - panic!("Unexpected result when selecting {:?} {:?}", ty, obligation) - } - } - } - } - &ty::Predicate::RegionOutlives(ref binder) => { - if select.infcx().region_outlives_predicate(&dummy_cause, binder).is_err() { - return false; - } - } - &ty::Predicate::TypeOutlives(ref binder) => { - match ( - binder.no_bound_vars(), - binder.map_bound_ref(|pred| pred.0).no_bound_vars(), - ) { - (None, Some(t_a)) => { - select.infcx().register_region_obligation_with_cause( - t_a, - select.infcx().tcx.lifetimes.re_static, - &dummy_cause, - ); - } - (Some(ty::OutlivesPredicate(t_a, r_b)), _) => { - select.infcx().register_region_obligation_with_cause( - t_a, - r_b, - &dummy_cause, - ); - } - _ => {} - }; - } - _ => panic!("Unexpected predicate {:?} {:?}", ty, predicate), - }; - } - return true; - } - - pub fn clean_pred( - &self, - infcx: &InferCtxt<'_, 'tcx>, - p: ty::Predicate<'tcx>, - ) -> ty::Predicate<'tcx> { - infcx.freshen(p) - } -} - -// Replaces all ReVars in a type with ty::Region's, using the provided map -pub struct RegionReplacer<'a, 'tcx> { - vid_to_region: &'a FxHashMap<ty::RegionVid, ty::Region<'tcx>>, - tcx: TyCtxt<'tcx>, -} - -impl<'a, 'tcx> TypeFolder<'tcx> for RegionReplacer<'a, 'tcx> { - fn tcx<'b>(&'b self) -> TyCtxt<'tcx> { - self.tcx - } - - fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> { - (match r { - &ty::ReVar(vid) => self.vid_to_region.get(&vid).cloned(), - _ => None, - }) - .unwrap_or_else(|| r.super_fold_with(self)) - } -} diff --git a/src/librustc_infer/traits/codegen/mod.rs b/src/librustc_infer/traits/codegen/mod.rs deleted file mode 100644 index bd4129a4de7..00000000000 --- a/src/librustc_infer/traits/codegen/mod.rs +++ /dev/null @@ -1,110 +0,0 @@ -// This file contains various trait resolution methods used by codegen. -// They all assume regions can be erased and monomorphic types. It -// seems likely that they should eventually be merged into more -// general routines. - -use crate::infer::{InferCtxt, TyCtxtInferExt}; -use crate::traits::{ - FulfillmentContext, Obligation, ObligationCause, SelectionContext, TraitEngine, Vtable, -}; -use rustc::ty::fold::TypeFoldable; -use rustc::ty::{self, TyCtxt}; - -/// Attempts to resolve an obligation to a vtable. The result is -/// a shallow vtable resolution, meaning that we do not -/// (necessarily) resolve all nested obligations on the impl. Note -/// that type check should guarantee to us that all nested -/// obligations *could be* resolved if we wanted to. -/// Assumes that this is run after the entire crate has been successfully type-checked. -pub fn codegen_fulfill_obligation<'tcx>( - ty: TyCtxt<'tcx>, - (param_env, trait_ref): (ty::ParamEnv<'tcx>, ty::PolyTraitRef<'tcx>), -) -> Vtable<'tcx, ()> { - // Remove any references to regions; this helps improve caching. - let trait_ref = ty.erase_regions(&trait_ref); - - debug!( - "codegen_fulfill_obligation(trait_ref={:?}, def_id={:?})", - (param_env, trait_ref), - trait_ref.def_id() - ); - - // Do the initial selection for the obligation. This yields the - // shallow result we are looking for -- that is, what specific impl. - ty.infer_ctxt().enter(|infcx| { - let mut selcx = SelectionContext::new(&infcx); - - let obligation_cause = ObligationCause::dummy(); - let obligation = - Obligation::new(obligation_cause, param_env, trait_ref.to_poly_trait_predicate()); - - let selection = match selcx.select(&obligation) { - Ok(Some(selection)) => selection, - Ok(None) => { - // Ambiguity can happen when monomorphizing during trans - // expands to some humongo type that never occurred - // statically -- this humongo type can then overflow, - // leading to an ambiguous result. So report this as an - // overflow bug, since I believe this is the only case - // where ambiguity can result. - bug!( - "Encountered ambiguity selecting `{:?}` during codegen, \ - presuming due to overflow", - trait_ref - ) - } - Err(e) => { - bug!("Encountered error `{:?}` selecting `{:?}` during codegen", e, trait_ref) - } - }; - - debug!("fulfill_obligation: selection={:?}", selection); - - // Currently, we use a fulfillment context to completely resolve - // all nested obligations. This is because they can inform the - // inference of the impl's type parameters. - let mut fulfill_cx = FulfillmentContext::new(); - let vtable = selection.map(|predicate| { - debug!("fulfill_obligation: register_predicate_obligation {:?}", predicate); - fulfill_cx.register_predicate_obligation(&infcx, predicate); - }); - let vtable = infcx.drain_fulfillment_cx_or_panic(&mut fulfill_cx, &vtable); - - info!("Cache miss: {:?} => {:?}", trait_ref, vtable); - vtable - }) -} - -// # Global Cache - -impl<'a, 'tcx> InferCtxt<'a, 'tcx> { - /// Finishes processes any obligations that remain in the - /// fulfillment context, and then returns the result with all type - /// variables removed and regions erased. Because this is intended - /// for use after type-check has completed, if any errors occur, - /// it will panic. It is used during normalization and other cases - /// where processing the obligations in `fulfill_cx` may cause - /// type inference variables that appear in `result` to be - /// unified, and hence we need to process those obligations to get - /// the complete picture of the type. - fn drain_fulfillment_cx_or_panic<T>( - &self, - fulfill_cx: &mut FulfillmentContext<'tcx>, - result: &T, - ) -> T - where - T: TypeFoldable<'tcx>, - { - debug!("drain_fulfillment_cx_or_panic()"); - - // In principle, we only need to do this so long as `result` - // contains unbound type parameters. It could be a slight - // optimization to stop iterating early. - if let Err(errors) = fulfill_cx.select_all_or_error(self) { - bug!("Encountered errors `{:?}` resolving bounds after type-checking", errors); - } - - let result = self.resolve_vars_if_possible(result); - self.tcx.erase_regions(&result) - } -} diff --git a/src/librustc_infer/traits/coherence.rs b/src/librustc_infer/traits/coherence.rs deleted file mode 100644 index 0dec5ae6da5..00000000000 --- a/src/librustc_infer/traits/coherence.rs +++ /dev/null @@ -1,540 +0,0 @@ -//! See Rustc Guide chapters on [trait-resolution] and [trait-specialization] for more info on how -//! this works. -//! -//! [trait-resolution]: https://rust-lang.github.io/rustc-guide/traits/resolution.html -//! [trait-specialization]: https://rust-lang.github.io/rustc-guide/traits/specialization.html - -use crate::infer::{CombinedSnapshot, InferOk, TyCtxtInferExt}; -use crate::traits::select::IntercrateAmbiguityCause; -use crate::traits::SkipLeakCheck; -use crate::traits::{self, Normalized, Obligation, ObligationCause, SelectionContext}; -use rustc::ty::fold::TypeFoldable; -use rustc::ty::subst::Subst; -use rustc::ty::{self, Ty, TyCtxt}; -use rustc_hir::def_id::{DefId, LOCAL_CRATE}; -use rustc_span::symbol::sym; -use rustc_span::DUMMY_SP; - -/// Whether we do the orphan check relative to this crate or -/// to some remote crate. -#[derive(Copy, Clone, Debug)] -enum InCrate { - Local, - Remote, -} - -#[derive(Debug, Copy, Clone)] -pub enum Conflict { - Upstream, - Downstream, -} - -pub struct OverlapResult<'tcx> { - pub impl_header: ty::ImplHeader<'tcx>, - pub intercrate_ambiguity_causes: Vec<IntercrateAmbiguityCause>, - - /// `true` if the overlap might've been permitted before the shift - /// to universes. - pub involves_placeholder: bool, -} - -pub fn add_placeholder_note(err: &mut rustc_errors::DiagnosticBuilder<'_>) { - err.note( - "this behavior recently changed as a result of a bug fix; \ - see rust-lang/rust#56105 for details", - ); -} - -/// If there are types that satisfy both impls, invokes `on_overlap` -/// with a suitably-freshened `ImplHeader` with those types -/// substituted. Otherwise, invokes `no_overlap`. -pub fn overlapping_impls<F1, F2, R>( - tcx: TyCtxt<'_>, - impl1_def_id: DefId, - impl2_def_id: DefId, - skip_leak_check: SkipLeakCheck, - on_overlap: F1, - no_overlap: F2, -) -> R -where - F1: FnOnce(OverlapResult<'_>) -> R, - F2: FnOnce() -> R, -{ - debug!( - "overlapping_impls(\ - impl1_def_id={:?}, \ - impl2_def_id={:?})", - impl1_def_id, impl2_def_id, - ); - - let overlaps = tcx.infer_ctxt().enter(|infcx| { - let selcx = &mut SelectionContext::intercrate(&infcx); - overlap(selcx, skip_leak_check, impl1_def_id, impl2_def_id).is_some() - }); - - if !overlaps { - return no_overlap(); - } - - // In the case where we detect an error, run the check again, but - // this time tracking intercrate ambuiguity causes for better - // diagnostics. (These take time and can lead to false errors.) - tcx.infer_ctxt().enter(|infcx| { - let selcx = &mut SelectionContext::intercrate(&infcx); - selcx.enable_tracking_intercrate_ambiguity_causes(); - on_overlap(overlap(selcx, skip_leak_check, impl1_def_id, impl2_def_id).unwrap()) - }) -} - -fn with_fresh_ty_vars<'cx, 'tcx>( - selcx: &mut SelectionContext<'cx, 'tcx>, - param_env: ty::ParamEnv<'tcx>, - impl_def_id: DefId, -) -> ty::ImplHeader<'tcx> { - let tcx = selcx.tcx(); - let impl_substs = selcx.infcx().fresh_substs_for_item(DUMMY_SP, impl_def_id); - - let header = ty::ImplHeader { - impl_def_id, - self_ty: tcx.type_of(impl_def_id).subst(tcx, impl_substs), - trait_ref: tcx.impl_trait_ref(impl_def_id).subst(tcx, impl_substs), - predicates: tcx.predicates_of(impl_def_id).instantiate(tcx, impl_substs).predicates, - }; - - let Normalized { value: mut header, obligations } = - traits::normalize(selcx, param_env, ObligationCause::dummy(), &header); - - header.predicates.extend(obligations.into_iter().map(|o| o.predicate)); - header -} - -/// Can both impl `a` and impl `b` be satisfied by a common type (including -/// where-clauses)? If so, returns an `ImplHeader` that unifies the two impls. -fn overlap<'cx, 'tcx>( - selcx: &mut SelectionContext<'cx, 'tcx>, - skip_leak_check: SkipLeakCheck, - a_def_id: DefId, - b_def_id: DefId, -) -> Option<OverlapResult<'tcx>> { - debug!("overlap(a_def_id={:?}, b_def_id={:?})", a_def_id, b_def_id); - - selcx.infcx().probe_maybe_skip_leak_check(skip_leak_check.is_yes(), |snapshot| { - overlap_within_probe(selcx, a_def_id, b_def_id, snapshot) - }) -} - -fn overlap_within_probe( - selcx: &mut SelectionContext<'cx, 'tcx>, - a_def_id: DefId, - b_def_id: DefId, - snapshot: &CombinedSnapshot<'_, 'tcx>, -) -> Option<OverlapResult<'tcx>> { - // For the purposes of this check, we don't bring any placeholder - // types into scope; instead, we replace the generic types with - // fresh type variables, and hence we do our evaluations in an - // empty environment. - let param_env = ty::ParamEnv::empty(); - - let a_impl_header = with_fresh_ty_vars(selcx, param_env, a_def_id); - let b_impl_header = with_fresh_ty_vars(selcx, param_env, b_def_id); - - debug!("overlap: a_impl_header={:?}", a_impl_header); - debug!("overlap: b_impl_header={:?}", b_impl_header); - - // Do `a` and `b` unify? If not, no overlap. - let obligations = match selcx - .infcx() - .at(&ObligationCause::dummy(), param_env) - .eq_impl_headers(&a_impl_header, &b_impl_header) - { - Ok(InferOk { obligations, value: () }) => obligations, - Err(_) => { - return None; - } - }; - - debug!("overlap: unification check succeeded"); - - // Are any of the obligations unsatisfiable? If so, no overlap. - let infcx = selcx.infcx(); - let opt_failing_obligation = a_impl_header - .predicates - .iter() - .chain(&b_impl_header.predicates) - .map(|p| infcx.resolve_vars_if_possible(p)) - .map(|p| Obligation { - cause: ObligationCause::dummy(), - param_env, - recursion_depth: 0, - predicate: p, - }) - .chain(obligations) - .find(|o| !selcx.predicate_may_hold_fatal(o)); - // FIXME: the call to `selcx.predicate_may_hold_fatal` above should be ported - // to the canonical trait query form, `infcx.predicate_may_hold`, once - // the new system supports intercrate mode (which coherence needs). - - if let Some(failing_obligation) = opt_failing_obligation { - debug!("overlap: obligation unsatisfiable {:?}", failing_obligation); - return None; - } - - let impl_header = selcx.infcx().resolve_vars_if_possible(&a_impl_header); - let intercrate_ambiguity_causes = selcx.take_intercrate_ambiguity_causes(); - debug!("overlap: intercrate_ambiguity_causes={:#?}", intercrate_ambiguity_causes); - - let involves_placeholder = match selcx.infcx().region_constraints_added_in_snapshot(snapshot) { - Some(true) => true, - _ => false, - }; - - Some(OverlapResult { impl_header, intercrate_ambiguity_causes, involves_placeholder }) -} - -pub fn trait_ref_is_knowable<'tcx>( - tcx: TyCtxt<'tcx>, - trait_ref: ty::TraitRef<'tcx>, -) -> Option<Conflict> { - debug!("trait_ref_is_knowable(trait_ref={:?})", trait_ref); - if orphan_check_trait_ref(tcx, trait_ref, InCrate::Remote).is_ok() { - // A downstream or cousin crate is allowed to implement some - // substitution of this trait-ref. - return Some(Conflict::Downstream); - } - - if trait_ref_is_local_or_fundamental(tcx, trait_ref) { - // This is a local or fundamental trait, so future-compatibility - // is no concern. We know that downstream/cousin crates are not - // allowed to implement a substitution of this trait ref, which - // means impls could only come from dependencies of this crate, - // which we already know about. - return None; - } - - // This is a remote non-fundamental trait, so if another crate - // can be the "final owner" of a substitution of this trait-ref, - // they are allowed to implement it future-compatibly. - // - // However, if we are a final owner, then nobody else can be, - // and if we are an intermediate owner, then we don't care - // about future-compatibility, which means that we're OK if - // we are an owner. - if orphan_check_trait_ref(tcx, trait_ref, InCrate::Local).is_ok() { - debug!("trait_ref_is_knowable: orphan check passed"); - return None; - } else { - debug!("trait_ref_is_knowable: nonlocal, nonfundamental, unowned"); - return Some(Conflict::Upstream); - } -} - -pub fn trait_ref_is_local_or_fundamental<'tcx>( - tcx: TyCtxt<'tcx>, - trait_ref: ty::TraitRef<'tcx>, -) -> bool { - trait_ref.def_id.krate == LOCAL_CRATE || tcx.has_attr(trait_ref.def_id, sym::fundamental) -} - -pub enum OrphanCheckErr<'tcx> { - NonLocalInputType(Vec<(Ty<'tcx>, bool /* Is this the first input type? */)>), - UncoveredTy(Ty<'tcx>, Option<Ty<'tcx>>), -} - -/// Checks the coherence orphan rules. `impl_def_id` should be the -/// `DefId` of a trait impl. To pass, either the trait must be local, or else -/// two conditions must be satisfied: -/// -/// 1. All type parameters in `Self` must be "covered" by some local type constructor. -/// 2. Some local type must appear in `Self`. -pub fn orphan_check(tcx: TyCtxt<'_>, impl_def_id: DefId) -> Result<(), OrphanCheckErr<'_>> { - debug!("orphan_check({:?})", impl_def_id); - - // We only except this routine to be invoked on implementations - // of a trait, not inherent implementations. - let trait_ref = tcx.impl_trait_ref(impl_def_id).unwrap(); - debug!("orphan_check: trait_ref={:?}", trait_ref); - - // If the *trait* is local to the crate, ok. - if trait_ref.def_id.is_local() { - debug!("trait {:?} is local to current crate", trait_ref.def_id); - return Ok(()); - } - - orphan_check_trait_ref(tcx, trait_ref, InCrate::Local) -} - -/// Checks whether a trait-ref is potentially implementable by a crate. -/// -/// The current rule is that a trait-ref orphan checks in a crate C: -/// -/// 1. Order the parameters in the trait-ref in subst order - Self first, -/// others linearly (e.g., `<U as Foo<V, W>>` is U < V < W). -/// 2. Of these type parameters, there is at least one type parameter -/// in which, walking the type as a tree, you can reach a type local -/// to C where all types in-between are fundamental types. Call the -/// first such parameter the "local key parameter". -/// - e.g., `Box<LocalType>` is OK, because you can visit LocalType -/// going through `Box`, which is fundamental. -/// - similarly, `FundamentalPair<Vec<()>, Box<LocalType>>` is OK for -/// the same reason. -/// - but (knowing that `Vec<T>` is non-fundamental, and assuming it's -/// not local), `Vec<LocalType>` is bad, because `Vec<->` is between -/// the local type and the type parameter. -/// 3. Every type parameter before the local key parameter is fully known in C. -/// - e.g., `impl<T> T: Trait<LocalType>` is bad, because `T` might be -/// an unknown type. -/// - but `impl<T> LocalType: Trait<T>` is OK, because `LocalType` -/// occurs before `T`. -/// 4. Every type in the local key parameter not known in C, going -/// through the parameter's type tree, must appear only as a subtree of -/// a type local to C, with only fundamental types between the type -/// local to C and the local key parameter. -/// - e.g., `Vec<LocalType<T>>>` (or equivalently `Box<Vec<LocalType<T>>>`) -/// is bad, because the only local type with `T` as a subtree is -/// `LocalType<T>`, and `Vec<->` is between it and the type parameter. -/// - similarly, `FundamentalPair<LocalType<T>, T>` is bad, because -/// the second occurrence of `T` is not a subtree of *any* local type. -/// - however, `LocalType<Vec<T>>` is OK, because `T` is a subtree of -/// `LocalType<Vec<T>>`, which is local and has no types between it and -/// the type parameter. -/// -/// The orphan rules actually serve several different purposes: -/// -/// 1. They enable link-safety - i.e., 2 mutually-unknowing crates (where -/// every type local to one crate is unknown in the other) can't implement -/// the same trait-ref. This follows because it can be seen that no such -/// type can orphan-check in 2 such crates. -/// -/// To check that a local impl follows the orphan rules, we check it in -/// InCrate::Local mode, using type parameters for the "generic" types. -/// -/// 2. They ground negative reasoning for coherence. If a user wants to -/// write both a conditional blanket impl and a specific impl, we need to -/// make sure they do not overlap. For example, if we write -/// ``` -/// impl<T> IntoIterator for Vec<T> -/// impl<T: Iterator> IntoIterator for T -/// ``` -/// We need to be able to prove that `Vec<$0>: !Iterator` for every type $0. -/// We can observe that this holds in the current crate, but we need to make -/// sure this will also hold in all unknown crates (both "independent" crates, -/// which we need for link-safety, and also child crates, because we don't want -/// child crates to get error for impl conflicts in a *dependency*). -/// -/// For that, we only allow negative reasoning if, for every assignment to the -/// inference variables, every unknown crate would get an orphan error if they -/// try to implement this trait-ref. To check for this, we use InCrate::Remote -/// mode. That is sound because we already know all the impls from known crates. -/// -/// 3. For non-#[fundamental] traits, they guarantee that parent crates can -/// add "non-blanket" impls without breaking negative reasoning in dependent -/// crates. This is the "rebalancing coherence" (RFC 1023) restriction. -/// -/// For that, we only a allow crate to perform negative reasoning on -/// non-local-non-#[fundamental] only if there's a local key parameter as per (2). -/// -/// Because we never perform negative reasoning generically (coherence does -/// not involve type parameters), this can be interpreted as doing the full -/// orphan check (using InCrate::Local mode), substituting non-local known -/// types for all inference variables. -/// -/// This allows for crates to future-compatibly add impls as long as they -/// can't apply to types with a key parameter in a child crate - applying -/// the rules, this basically means that every type parameter in the impl -/// must appear behind a non-fundamental type (because this is not a -/// type-system requirement, crate owners might also go for "semantic -/// future-compatibility" involving things such as sealed traits, but -/// the above requirement is sufficient, and is necessary in "open world" -/// cases). -/// -/// Note that this function is never called for types that have both type -/// parameters and inference variables. -fn orphan_check_trait_ref<'tcx>( - tcx: TyCtxt<'tcx>, - trait_ref: ty::TraitRef<'tcx>, - in_crate: InCrate, -) -> Result<(), OrphanCheckErr<'tcx>> { - debug!("orphan_check_trait_ref(trait_ref={:?}, in_crate={:?})", trait_ref, in_crate); - - if trait_ref.needs_infer() && trait_ref.needs_subst() { - bug!( - "can't orphan check a trait ref with both params and inference variables {:?}", - trait_ref - ); - } - - // Given impl<P1..=Pn> Trait<T1..=Tn> for T0, an impl is valid only - // if at least one of the following is true: - // - // - Trait is a local trait - // (already checked in orphan_check prior to calling this function) - // - All of - // - At least one of the types T0..=Tn must be a local type. - // Let Ti be the first such type. - // - No uncovered type parameters P1..=Pn may appear in T0..Ti (excluding Ti) - // - fn uncover_fundamental_ty<'tcx>( - tcx: TyCtxt<'tcx>, - ty: Ty<'tcx>, - in_crate: InCrate, - ) -> Vec<Ty<'tcx>> { - if fundamental_ty(ty) && ty_is_non_local(ty, in_crate).is_some() { - ty.walk_shallow().flat_map(|ty| uncover_fundamental_ty(tcx, ty, in_crate)).collect() - } else { - vec![ty] - } - } - - let mut non_local_spans = vec![]; - for (i, input_ty) in - trait_ref.input_types().flat_map(|ty| uncover_fundamental_ty(tcx, ty, in_crate)).enumerate() - { - debug!("orphan_check_trait_ref: check ty `{:?}`", input_ty); - let non_local_tys = ty_is_non_local(input_ty, in_crate); - if non_local_tys.is_none() { - debug!("orphan_check_trait_ref: ty_is_local `{:?}`", input_ty); - return Ok(()); - } else if let ty::Param(_) = input_ty.kind { - debug!("orphan_check_trait_ref: uncovered ty: `{:?}`", input_ty); - let local_type = trait_ref - .input_types() - .flat_map(|ty| uncover_fundamental_ty(tcx, ty, in_crate)) - .find(|ty| ty_is_non_local_constructor(ty, in_crate).is_none()); - - debug!("orphan_check_trait_ref: uncovered ty local_type: `{:?}`", local_type); - - return Err(OrphanCheckErr::UncoveredTy(input_ty, local_type)); - } - if let Some(non_local_tys) = non_local_tys { - for input_ty in non_local_tys { - non_local_spans.push((input_ty, i == 0)); - } - } - } - // If we exit above loop, never found a local type. - debug!("orphan_check_trait_ref: no local type"); - Err(OrphanCheckErr::NonLocalInputType(non_local_spans)) -} - -fn ty_is_non_local<'t>(ty: Ty<'t>, in_crate: InCrate) -> Option<Vec<Ty<'t>>> { - match ty_is_non_local_constructor(ty, in_crate) { - Some(ty) => { - if !fundamental_ty(ty) { - Some(vec![ty]) - } else { - let tys: Vec<_> = ty - .walk_shallow() - .filter_map(|t| ty_is_non_local(t, in_crate)) - .flat_map(|i| i) - .collect(); - if tys.is_empty() { None } else { Some(tys) } - } - } - None => None, - } -} - -fn fundamental_ty(ty: Ty<'_>) -> bool { - match ty.kind { - ty::Ref(..) => true, - ty::Adt(def, _) => def.is_fundamental(), - _ => false, - } -} - -fn def_id_is_local(def_id: DefId, in_crate: InCrate) -> bool { - match in_crate { - // The type is local to *this* crate - it will not be - // local in any other crate. - InCrate::Remote => false, - InCrate::Local => def_id.is_local(), - } -} - -fn ty_is_non_local_constructor<'tcx>(ty: Ty<'tcx>, in_crate: InCrate) -> Option<Ty<'tcx>> { - debug!("ty_is_non_local_constructor({:?})", ty); - - match ty.kind { - ty::Bool - | ty::Char - | ty::Int(..) - | ty::Uint(..) - | ty::Float(..) - | ty::Str - | ty::FnDef(..) - | ty::FnPtr(_) - | ty::Array(..) - | ty::Slice(..) - | ty::RawPtr(..) - | ty::Ref(..) - | ty::Never - | ty::Tuple(..) - | ty::Param(..) - | ty::Projection(..) => Some(ty), - - ty::Placeholder(..) | ty::Bound(..) | ty::Infer(..) => match in_crate { - InCrate::Local => Some(ty), - // The inference variable might be unified with a local - // type in that remote crate. - InCrate::Remote => None, - }, - - ty::Adt(def, _) => { - if def_id_is_local(def.did, in_crate) { - None - } else { - Some(ty) - } - } - ty::Foreign(did) => { - if def_id_is_local(did, in_crate) { - None - } else { - Some(ty) - } - } - ty::Opaque(..) => { - // This merits some explanation. - // Normally, opaque types are not involed when performing - // coherence checking, since it is illegal to directly - // implement a trait on an opaque type. However, we might - // end up looking at an opaque type during coherence checking - // if an opaque type gets used within another type (e.g. as - // a type parameter). This requires us to decide whether or - // not an opaque type should be considered 'local' or not. - // - // We choose to treat all opaque types as non-local, even - // those that appear within the same crate. This seems - // somewhat suprising at first, but makes sense when - // you consider that opaque types are supposed to hide - // the underlying type *within the same crate*. When an - // opaque type is used from outside the module - // where it is declared, it should be impossible to observe - // anyything about it other than the traits that it implements. - // - // The alternative would be to look at the underlying type - // to determine whether or not the opaque type itself should - // be considered local. However, this could make it a breaking change - // to switch the underlying ('defining') type from a local type - // to a remote type. This would violate the rule that opaque - // types should be completely opaque apart from the traits - // that they implement, so we don't use this behavior. - Some(ty) - } - - ty::Dynamic(ref tt, ..) => { - if let Some(principal) = tt.principal() { - if def_id_is_local(principal.def_id(), in_crate) { None } else { Some(ty) } - } else { - Some(ty) - } - } - - ty::Error => None, - - ty::UnnormalizedProjection(..) - | ty::Closure(..) - | ty::Generator(..) - | ty::GeneratorWitness(..) => bug!("ty_is_local invoked on unexpected type: {:?}", ty), - } -} diff --git a/src/librustc_infer/traits/engine.rs b/src/librustc_infer/traits/engine.rs index e23810dd161..a95257ba682 100644 --- a/src/librustc_infer/traits/engine.rs +++ b/src/librustc_infer/traits/engine.rs @@ -1,9 +1,9 @@ use crate::infer::InferCtxt; use crate::traits::Obligation; -use rustc::ty::{self, ToPredicate, Ty, TyCtxt, WithConstness}; use rustc_hir::def_id::DefId; +use rustc_middle::ty::{self, ToPredicate, Ty, WithConstness}; -use super::{FulfillmentContext, FulfillmentError}; +use super::FulfillmentError; use super::{ObligationCause, PredicateObligation}; pub trait TraitEngine<'tcx>: 'tcx { @@ -76,9 +76,3 @@ impl<T: ?Sized + TraitEngine<'tcx>> TraitEngineExt<'tcx> for T { } } } - -impl dyn TraitEngine<'tcx> { - pub fn new(_tcx: TyCtxt<'tcx>) -> Box<Self> { - Box::new(FulfillmentContext::new()) - } -} diff --git a/src/librustc_infer/traits/error_reporting/mod.rs b/src/librustc_infer/traits/error_reporting/mod.rs index 63c3f827c2e..9206166d0bd 100644 --- a/src/librustc_infer/traits/error_reporting/mod.rs +++ b/src/librustc_infer/traits/error_reporting/mod.rs @@ -1,452 +1,16 @@ -pub mod on_unimplemented; -pub mod suggestions; +use super::ObjectSafetyViolation; -use super::{ - ConstEvalFailure, EvaluationResult, FulfillmentError, FulfillmentErrorCode, - MismatchedProjectionTypes, ObjectSafetyViolation, Obligation, ObligationCause, - ObligationCauseCode, OnUnimplementedDirective, OnUnimplementedNote, - OutputTypeParameterMismatch, Overflow, PredicateObligation, SelectionContext, SelectionError, - TraitNotObjectSafe, -}; - -use crate::infer::error_reporting::{TyCategory, TypeAnnotationNeeded as ErrorCode}; -use crate::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; -use crate::infer::{self, InferCtxt, TyCtxtInferExt}; -use rustc::mir::interpret::ErrorHandled; -use rustc::session::DiagnosticMessageId; -use rustc::ty::error::ExpectedFound; -use rustc::ty::fast_reject; -use rustc::ty::fold::TypeFolder; -use rustc::ty::SubtypePredicate; -use rustc::ty::{ - self, AdtKind, ToPolyTraitRef, ToPredicate, Ty, TyCtxt, TypeFoldable, WithConstness, -}; +use crate::infer::InferCtxt; use rustc_ast::ast; -use rustc_data_structures::fx::{FxHashMap, FxHashSet}; +use rustc_data_structures::fx::FxHashSet; use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder}; use rustc_hir as hir; -use rustc_hir::def_id::{DefId, LOCAL_CRATE}; -use rustc_hir::{QPath, TyKind, WhereBoundPredicate, WherePredicate}; -use rustc_span::source_map::SourceMap; -use rustc_span::{ExpnKind, Span, DUMMY_SP}; +use rustc_hir::def_id::DefId; +use rustc_middle::ty::TyCtxt; +use rustc_span::Span; use std::fmt; impl<'a, 'tcx> InferCtxt<'a, 'tcx> { - pub fn report_fulfillment_errors( - &self, - errors: &[FulfillmentError<'tcx>], - body_id: Option<hir::BodyId>, - fallback_has_occurred: bool, - ) { - #[derive(Debug)] - struct ErrorDescriptor<'tcx> { - predicate: ty::Predicate<'tcx>, - index: Option<usize>, // None if this is an old error - } - - let mut error_map: FxHashMap<_, Vec<_>> = self - .reported_trait_errors - .borrow() - .iter() - .map(|(&span, predicates)| { - ( - span, - predicates - .iter() - .map(|&predicate| ErrorDescriptor { predicate, index: None }) - .collect(), - ) - }) - .collect(); - - for (index, error) in errors.iter().enumerate() { - // We want to ignore desugarings here: spans are equivalent even - // if one is the result of a desugaring and the other is not. - let mut span = error.obligation.cause.span; - let expn_data = span.ctxt().outer_expn_data(); - if let ExpnKind::Desugaring(_) = expn_data.kind { - span = expn_data.call_site; - } - - error_map.entry(span).or_default().push(ErrorDescriptor { - predicate: error.obligation.predicate, - index: Some(index), - }); - - self.reported_trait_errors - .borrow_mut() - .entry(span) - .or_default() - .push(error.obligation.predicate.clone()); - } - - // We do this in 2 passes because we want to display errors in order, though - // maybe it *is* better to sort errors by span or something. - let mut is_suppressed = vec![false; errors.len()]; - for (_, error_set) in error_map.iter() { - // We want to suppress "duplicate" errors with the same span. - for error in error_set { - if let Some(index) = error.index { - // Suppress errors that are either: - // 1) strictly implied by another error. - // 2) implied by an error with a smaller index. - for error2 in error_set { - if error2.index.map_or(false, |index2| is_suppressed[index2]) { - // Avoid errors being suppressed by already-suppressed - // errors, to prevent all errors from being suppressed - // at once. - continue; - } - - if self.error_implies(&error2.predicate, &error.predicate) - && !(error2.index >= error.index - && self.error_implies(&error.predicate, &error2.predicate)) - { - info!("skipping {:?} (implied by {:?})", error, error2); - is_suppressed[index] = true; - break; - } - } - } - } - } - - for (error, suppressed) in errors.iter().zip(is_suppressed) { - if !suppressed { - self.report_fulfillment_error(error, body_id, fallback_has_occurred); - } - } - } - - // returns if `cond` not occurring implies that `error` does not occur - i.e., that - // `error` occurring implies that `cond` occurs. - fn error_implies(&self, cond: &ty::Predicate<'tcx>, error: &ty::Predicate<'tcx>) -> bool { - if cond == error { - return true; - } - - let (cond, error) = match (cond, error) { - (&ty::Predicate::Trait(..), &ty::Predicate::Trait(ref error, _)) => (cond, error), - _ => { - // FIXME: make this work in other cases too. - return false; - } - }; - - for implication in super::elaborate_predicates(self.tcx, vec![*cond]) { - if let ty::Predicate::Trait(implication, _) = implication { - let error = error.to_poly_trait_ref(); - let implication = implication.to_poly_trait_ref(); - // FIXME: I'm just not taking associated types at all here. - // Eventually I'll need to implement param-env-aware - // `Γ₁ ⊦ φ₁ => Γ₂ ⊦ φ₂` logic. - let param_env = ty::ParamEnv::empty(); - if self.can_sub(param_env, error, implication).is_ok() { - debug!("error_implies: {:?} -> {:?} -> {:?}", cond, error, implication); - return true; - } - } - } - - false - } - - fn report_fulfillment_error( - &self, - error: &FulfillmentError<'tcx>, - body_id: Option<hir::BodyId>, - fallback_has_occurred: bool, - ) { - debug!("report_fulfillment_error({:?})", error); - match error.code { - FulfillmentErrorCode::CodeSelectionError(ref selection_error) => { - self.report_selection_error( - &error.obligation, - selection_error, - fallback_has_occurred, - error.points_at_arg_span, - ); - } - FulfillmentErrorCode::CodeProjectionError(ref e) => { - self.report_projection_error(&error.obligation, e); - } - FulfillmentErrorCode::CodeAmbiguity => { - self.maybe_report_ambiguity(&error.obligation, body_id); - } - FulfillmentErrorCode::CodeSubtypeError(ref expected_found, ref err) => { - self.report_mismatched_types( - &error.obligation.cause, - expected_found.expected, - expected_found.found, - err.clone(), - ) - .emit(); - } - } - } - - fn report_projection_error( - &self, - obligation: &PredicateObligation<'tcx>, - error: &MismatchedProjectionTypes<'tcx>, - ) { - let predicate = self.resolve_vars_if_possible(&obligation.predicate); - - if predicate.references_error() { - return; - } - - self.probe(|_| { - let err_buf; - let mut err = &error.err; - let mut values = None; - - // try to find the mismatched types to report the error with. - // - // this can fail if the problem was higher-ranked, in which - // cause I have no idea for a good error message. - if let ty::Predicate::Projection(ref data) = predicate { - let mut selcx = SelectionContext::new(self); - let (data, _) = self.replace_bound_vars_with_fresh_vars( - obligation.cause.span, - infer::LateBoundRegionConversionTime::HigherRankedType, - data, - ); - let mut obligations = vec![]; - let normalized_ty = super::normalize_projection_type( - &mut selcx, - obligation.param_env, - data.projection_ty, - obligation.cause.clone(), - 0, - &mut obligations, - ); - - debug!( - "report_projection_error obligation.cause={:?} obligation.param_env={:?}", - obligation.cause, obligation.param_env - ); - - debug!( - "report_projection_error normalized_ty={:?} data.ty={:?}", - normalized_ty, data.ty - ); - - let is_normalized_ty_expected = match &obligation.cause.code { - ObligationCauseCode::ItemObligation(_) - | ObligationCauseCode::BindingObligation(_, _) - | ObligationCauseCode::ObjectCastObligation(_) => false, - _ => true, - }; - - if let Err(error) = self.at(&obligation.cause, obligation.param_env).eq_exp( - is_normalized_ty_expected, - normalized_ty, - data.ty, - ) { - values = Some(infer::ValuePairs::Types(ExpectedFound::new( - is_normalized_ty_expected, - normalized_ty, - data.ty, - ))); - - err_buf = error; - err = &err_buf; - } - } - - let msg = format!("type mismatch resolving `{}`", predicate); - let error_id = (DiagnosticMessageId::ErrorId(271), Some(obligation.cause.span), msg); - let fresh = self.tcx.sess.one_time_diagnostics.borrow_mut().insert(error_id); - if fresh { - let mut diag = struct_span_err!( - self.tcx.sess, - obligation.cause.span, - E0271, - "type mismatch resolving `{}`", - predicate - ); - self.note_type_err(&mut diag, &obligation.cause, None, values, err); - self.note_obligation_cause(&mut diag, obligation); - diag.emit(); - } - }); - } - - fn fuzzy_match_tys(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> bool { - /// returns the fuzzy category of a given type, or None - /// if the type can be equated to any type. - fn type_category(t: Ty<'_>) -> Option<u32> { - match t.kind { - ty::Bool => Some(0), - ty::Char => Some(1), - ty::Str => Some(2), - ty::Int(..) | ty::Uint(..) | ty::Infer(ty::IntVar(..)) => Some(3), - ty::Float(..) | ty::Infer(ty::FloatVar(..)) => Some(4), - ty::Ref(..) | ty::RawPtr(..) => Some(5), - ty::Array(..) | ty::Slice(..) => Some(6), - ty::FnDef(..) | ty::FnPtr(..) => Some(7), - ty::Dynamic(..) => Some(8), - ty::Closure(..) => Some(9), - ty::Tuple(..) => Some(10), - ty::Projection(..) => Some(11), - ty::Param(..) => Some(12), - ty::Opaque(..) => Some(13), - ty::Never => Some(14), - ty::Adt(adt, ..) => match adt.adt_kind() { - AdtKind::Struct => Some(15), - AdtKind::Union => Some(16), - AdtKind::Enum => Some(17), - }, - ty::Generator(..) => Some(18), - ty::Foreign(..) => Some(19), - ty::GeneratorWitness(..) => Some(20), - ty::Placeholder(..) | ty::Bound(..) | ty::Infer(..) | ty::Error => None, - ty::UnnormalizedProjection(..) => bug!("only used with chalk-engine"), - } - } - - match (type_category(a), type_category(b)) { - (Some(cat_a), Some(cat_b)) => match (&a.kind, &b.kind) { - (&ty::Adt(def_a, _), &ty::Adt(def_b, _)) => def_a == def_b, - _ => cat_a == cat_b, - }, - // infer and error can be equated to all types - _ => true, - } - } - - fn describe_generator(&self, body_id: hir::BodyId) -> Option<&'static str> { - self.tcx.hir().body(body_id).generator_kind.map(|gen_kind| match gen_kind { - hir::GeneratorKind::Gen => "a generator", - hir::GeneratorKind::Async(hir::AsyncGeneratorKind::Block) => "an async block", - hir::GeneratorKind::Async(hir::AsyncGeneratorKind::Fn) => "an async function", - hir::GeneratorKind::Async(hir::AsyncGeneratorKind::Closure) => "an async closure", - }) - } - - fn find_similar_impl_candidates( - &self, - trait_ref: ty::PolyTraitRef<'tcx>, - ) -> Vec<ty::TraitRef<'tcx>> { - let simp = fast_reject::simplify_type(self.tcx, trait_ref.skip_binder().self_ty(), true); - let all_impls = self.tcx.all_impls(trait_ref.def_id()); - - match simp { - Some(simp) => all_impls - .iter() - .filter_map(|&def_id| { - let imp = self.tcx.impl_trait_ref(def_id).unwrap(); - let imp_simp = fast_reject::simplify_type(self.tcx, imp.self_ty(), true); - if let Some(imp_simp) = imp_simp { - if simp != imp_simp { - return None; - } - } - - Some(imp) - }) - .collect(), - None => { - all_impls.iter().map(|&def_id| self.tcx.impl_trait_ref(def_id).unwrap()).collect() - } - } - } - - fn report_similar_impl_candidates( - &self, - impl_candidates: Vec<ty::TraitRef<'tcx>>, - err: &mut DiagnosticBuilder<'_>, - ) { - if impl_candidates.is_empty() { - return; - } - - let len = impl_candidates.len(); - let end = if impl_candidates.len() <= 5 { impl_candidates.len() } else { 4 }; - - let normalize = |candidate| { - self.tcx.infer_ctxt().enter(|ref infcx| { - let normalized = infcx - .at(&ObligationCause::dummy(), ty::ParamEnv::empty()) - .normalize(candidate) - .ok(); - match normalized { - Some(normalized) => format!("\n {:?}", normalized.value), - None => format!("\n {:?}", candidate), - } - }) - }; - - // Sort impl candidates so that ordering is consistent for UI tests. - let mut normalized_impl_candidates = - impl_candidates.iter().map(normalize).collect::<Vec<String>>(); - - // Sort before taking the `..end` range, - // because the ordering of `impl_candidates` may not be deterministic: - // https://github.com/rust-lang/rust/pull/57475#issuecomment-455519507 - normalized_impl_candidates.sort(); - - err.help(&format!( - "the following implementations were found:{}{}", - normalized_impl_candidates[..end].join(""), - if len > 5 { format!("\nand {} others", len - 4) } else { String::new() } - )); - } - - /// Reports that an overflow has occurred and halts compilation. We - /// halt compilation unconditionally because it is important that - /// overflows never be masked -- they basically represent computations - /// whose result could not be truly determined and thus we can't say - /// if the program type checks or not -- and they are unusual - /// occurrences in any case. - pub fn report_overflow_error<T>( - &self, - obligation: &Obligation<'tcx, T>, - suggest_increasing_limit: bool, - ) -> ! - where - T: fmt::Display + TypeFoldable<'tcx>, - { - let predicate = self.resolve_vars_if_possible(&obligation.predicate); - let mut err = struct_span_err!( - self.tcx.sess, - obligation.cause.span, - E0275, - "overflow evaluating the requirement `{}`", - predicate - ); - - if suggest_increasing_limit { - self.suggest_new_overflow_limit(&mut err); - } - - self.note_obligation_cause_code( - &mut err, - &obligation.predicate, - &obligation.cause.code, - &mut vec![], - ); - - err.emit(); - self.tcx.sess.abort_if_errors(); - bug!(); - } - - /// Reports that a cycle was detected which led to overflow and halts - /// compilation. This is equivalent to `report_overflow_error` except - /// that we can give a more helpful error message (and, in particular, - /// we do not suggest increasing the overflow limit, which is not - /// going to help). - pub fn report_overflow_error_cycle(&self, cycle: &[PredicateObligation<'tcx>]) -> ! { - let cycle = self.resolve_vars_if_possible(&cycle.to_owned()); - assert!(!cycle.is_empty()); - - debug!("report_overflow_error_cycle: cycle={:?}", cycle); - - self.report_overflow_error(&cycle[0], false); - } - pub fn report_extra_impl_obligation( &self, error_span: Span, @@ -456,12 +20,12 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { requirement: &dyn fmt::Display, ) -> DiagnosticBuilder<'tcx> { let msg = "impl has stricter requirements than trait"; - let sp = self.tcx.sess.source_map().def_span(error_span); + let sp = self.tcx.sess.source_map().guess_head_span(error_span); let mut err = struct_span_err!(self.tcx.sess, sp, E0276, "{}", msg); if let Some(trait_item_span) = self.tcx.hir().span_if_local(trait_item_def_id) { - let span = self.tcx.sess.source_map().def_span(trait_item_span); + let span = self.tcx.sess.source_map().guess_head_span(trait_item_span); err.span_label(span, format!("definition of `{}` from trait", item_name)); } @@ -469,550 +33,6 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { err } - - /// Gets the parent trait chain start - fn get_parent_trait_ref( - &self, - code: &ObligationCauseCode<'tcx>, - ) -> Option<(String, Option<Span>)> { - match code { - &ObligationCauseCode::BuiltinDerivedObligation(ref data) => { - let parent_trait_ref = self.resolve_vars_if_possible(&data.parent_trait_ref); - match self.get_parent_trait_ref(&data.parent_code) { - Some(t) => Some(t), - None => { - let ty = parent_trait_ref.skip_binder().self_ty(); - let span = - TyCategory::from_ty(ty).map(|(_, def_id)| self.tcx.def_span(def_id)); - Some((ty.to_string(), span)) - } - } - } - _ => None, - } - } - - pub fn report_selection_error( - &self, - obligation: &PredicateObligation<'tcx>, - error: &SelectionError<'tcx>, - fallback_has_occurred: bool, - points_at_arg: bool, - ) { - let tcx = self.tcx; - let span = obligation.cause.span; - - let mut err = match *error { - SelectionError::Unimplemented => { - if let ObligationCauseCode::CompareImplMethodObligation { - item_name, - impl_item_def_id, - trait_item_def_id, - } - | ObligationCauseCode::CompareImplTypeObligation { - item_name, - impl_item_def_id, - trait_item_def_id, - } = obligation.cause.code - { - self.report_extra_impl_obligation( - span, - item_name, - impl_item_def_id, - trait_item_def_id, - &format!("`{}`", obligation.predicate), - ) - .emit(); - return; - } - match obligation.predicate { - ty::Predicate::Trait(ref trait_predicate, _) => { - let trait_predicate = self.resolve_vars_if_possible(trait_predicate); - - if self.tcx.sess.has_errors() && trait_predicate.references_error() { - return; - } - let trait_ref = trait_predicate.to_poly_trait_ref(); - let (post_message, pre_message, type_def) = self - .get_parent_trait_ref(&obligation.cause.code) - .map(|(t, s)| { - ( - format!(" in `{}`", t), - format!("within `{}`, ", t), - s.map(|s| (format!("within this `{}`", t), s)), - ) - }) - .unwrap_or_default(); - - let OnUnimplementedNote { message, label, note, enclosing_scope } = - self.on_unimplemented_note(trait_ref, obligation); - let have_alt_message = message.is_some() || label.is_some(); - let is_try = self - .tcx - .sess - .source_map() - .span_to_snippet(span) - .map(|s| &s == "?") - .unwrap_or(false); - let is_from = format!("{}", trait_ref.print_only_trait_path()) - .starts_with("std::convert::From<"); - let (message, note) = if is_try && is_from { - ( - Some(format!( - "`?` couldn't convert the error to `{}`", - trait_ref.self_ty(), - )), - Some( - "the question mark operation (`?`) implicitly performs a \ - conversion on the error value using the `From` trait" - .to_owned(), - ), - ) - } else { - (message, note) - }; - - let mut err = struct_span_err!( - self.tcx.sess, - span, - E0277, - "{}", - message.unwrap_or_else(|| format!( - "the trait bound `{}` is not satisfied{}", - trait_ref.without_const().to_predicate(), - post_message, - )) - ); - - let explanation = - if obligation.cause.code == ObligationCauseCode::MainFunctionType { - "consider using `()`, or a `Result`".to_owned() - } else { - format!( - "{}the trait `{}` is not implemented for `{}`", - pre_message, - trait_ref.print_only_trait_path(), - trait_ref.self_ty(), - ) - }; - - if self.suggest_add_reference_to_arg( - &obligation, - &mut err, - &trait_ref, - points_at_arg, - have_alt_message, - ) { - self.note_obligation_cause(&mut err, obligation); - err.emit(); - return; - } - if let Some(ref s) = label { - // If it has a custom `#[rustc_on_unimplemented]` - // error message, let's display it as the label! - err.span_label(span, s.as_str()); - err.help(&explanation); - } else { - err.span_label(span, explanation); - } - if let Some((msg, span)) = type_def { - err.span_label(span, &msg); - } - if let Some(ref s) = note { - // If it has a custom `#[rustc_on_unimplemented]` note, let's display it - err.note(s.as_str()); - } - if let Some(ref s) = enclosing_scope { - let enclosing_scope_span = tcx.def_span( - tcx.hir() - .opt_local_def_id(obligation.cause.body_id) - .unwrap_or_else(|| { - tcx.hir().body_owner_def_id(hir::BodyId { - hir_id: obligation.cause.body_id, - }) - }), - ); - - err.span_label(enclosing_scope_span, s.as_str()); - } - - self.suggest_borrow_on_unsized_slice(&obligation.cause.code, &mut err); - self.suggest_fn_call(&obligation, &mut err, &trait_ref, points_at_arg); - self.suggest_remove_reference(&obligation, &mut err, &trait_ref); - self.suggest_semicolon_removal(&obligation, &mut err, span, &trait_ref); - self.note_version_mismatch(&mut err, &trait_ref); - if self.suggest_impl_trait(&mut err, span, &obligation, &trait_ref) { - err.emit(); - return; - } - - // Try to report a help message - if !trait_ref.has_infer_types_or_consts() - && self.predicate_can_apply(obligation.param_env, trait_ref) - { - // If a where-clause may be useful, remind the - // user that they can add it. - // - // don't display an on-unimplemented note, as - // these notes will often be of the form - // "the type `T` can't be frobnicated" - // which is somewhat confusing. - self.suggest_restricting_param_bound( - &mut err, - &trait_ref, - obligation.cause.body_id, - ); - } else { - if !have_alt_message { - // Can't show anything else useful, try to find similar impls. - let impl_candidates = self.find_similar_impl_candidates(trait_ref); - self.report_similar_impl_candidates(impl_candidates, &mut err); - } - self.suggest_change_mut( - &obligation, - &mut err, - &trait_ref, - points_at_arg, - ); - } - - // If this error is due to `!: Trait` not implemented but `(): Trait` is - // implemented, and fallback has occurred, then it could be due to a - // variable that used to fallback to `()` now falling back to `!`. Issue a - // note informing about the change in behaviour. - if trait_predicate.skip_binder().self_ty().is_never() - && fallback_has_occurred - { - let predicate = trait_predicate.map_bound(|mut trait_pred| { - trait_pred.trait_ref.substs = self.tcx.mk_substs_trait( - self.tcx.mk_unit(), - &trait_pred.trait_ref.substs[1..], - ); - trait_pred - }); - let unit_obligation = Obligation { - predicate: ty::Predicate::Trait( - predicate, - hir::Constness::NotConst, - ), - ..obligation.clone() - }; - if self.predicate_may_hold(&unit_obligation) { - err.note( - "the trait is implemented for `()`. \ - Possibly this error has been caused by changes to \ - Rust's type-inference algorithm (see issue #48950 \ - <https://github.com/rust-lang/rust/issues/48950> \ - for more information). Consider whether you meant to use \ - the type `()` here instead.", - ); - } - } - - err - } - - ty::Predicate::Subtype(ref predicate) => { - // Errors for Subtype predicates show up as - // `FulfillmentErrorCode::CodeSubtypeError`, - // not selection error. - span_bug!(span, "subtype requirement gave wrong error: `{:?}`", predicate) - } - - ty::Predicate::RegionOutlives(ref predicate) => { - let predicate = self.resolve_vars_if_possible(predicate); - let err = self - .region_outlives_predicate(&obligation.cause, &predicate) - .err() - .unwrap(); - struct_span_err!( - self.tcx.sess, - span, - E0279, - "the requirement `{}` is not satisfied (`{}`)", - predicate, - err, - ) - } - - ty::Predicate::Projection(..) | ty::Predicate::TypeOutlives(..) => { - let predicate = self.resolve_vars_if_possible(&obligation.predicate); - struct_span_err!( - self.tcx.sess, - span, - E0280, - "the requirement `{}` is not satisfied", - predicate - ) - } - - ty::Predicate::ObjectSafe(trait_def_id) => { - let violations = self.tcx.object_safety_violations(trait_def_id); - report_object_safety_error(self.tcx, span, trait_def_id, violations) - } - - ty::Predicate::ClosureKind(closure_def_id, closure_substs, kind) => { - let found_kind = self.closure_kind(closure_def_id, closure_substs).unwrap(); - let closure_span = self - .tcx - .sess - .source_map() - .def_span(self.tcx.hir().span_if_local(closure_def_id).unwrap()); - let hir_id = self.tcx.hir().as_local_hir_id(closure_def_id).unwrap(); - let mut err = struct_span_err!( - self.tcx.sess, - closure_span, - E0525, - "expected a closure that implements the `{}` trait, \ - but this closure only implements `{}`", - kind, - found_kind - ); - - err.span_label( - closure_span, - format!("this closure implements `{}`, not `{}`", found_kind, kind), - ); - err.span_label( - obligation.cause.span, - format!("the requirement to implement `{}` derives from here", kind), - ); - - // Additional context information explaining why the closure only implements - // a particular trait. - if let Some(tables) = self.in_progress_tables { - let tables = tables.borrow(); - match (found_kind, tables.closure_kind_origins().get(hir_id)) { - (ty::ClosureKind::FnOnce, Some((span, name))) => { - err.span_label( - *span, - format!( - "closure is `FnOnce` because it moves the \ - variable `{}` out of its environment", - name - ), - ); - } - (ty::ClosureKind::FnMut, Some((span, name))) => { - err.span_label( - *span, - format!( - "closure is `FnMut` because it mutates the \ - variable `{}` here", - name - ), - ); - } - _ => {} - } - } - - err.emit(); - return; - } - - ty::Predicate::WellFormed(ty) => { - // WF predicates cannot themselves make - // errors. They can only block due to - // ambiguity; otherwise, they always - // degenerate into other obligations - // (which may fail). - span_bug!(span, "WF predicate not satisfied for {:?}", ty); - } - - ty::Predicate::ConstEvaluatable(..) => { - // Errors for `ConstEvaluatable` predicates show up as - // `SelectionError::ConstEvalFailure`, - // not `Unimplemented`. - span_bug!( - span, - "const-evaluatable requirement gave wrong error: `{:?}`", - obligation - ) - } - } - } - - OutputTypeParameterMismatch(ref found_trait_ref, ref expected_trait_ref, _) => { - let found_trait_ref = self.resolve_vars_if_possible(&*found_trait_ref); - let expected_trait_ref = self.resolve_vars_if_possible(&*expected_trait_ref); - - if expected_trait_ref.self_ty().references_error() { - return; - } - - let found_trait_ty = found_trait_ref.self_ty(); - - let found_did = match found_trait_ty.kind { - ty::Closure(did, _) | ty::Foreign(did) | ty::FnDef(did, _) => Some(did), - ty::Adt(def, _) => Some(def.did), - _ => None, - }; - - let found_span = found_did - .and_then(|did| self.tcx.hir().span_if_local(did)) - .map(|sp| self.tcx.sess.source_map().def_span(sp)); // the sp could be an fn def - - if self.reported_closure_mismatch.borrow().contains(&(span, found_span)) { - // We check closures twice, with obligations flowing in different directions, - // but we want to complain about them only once. - return; - } - - self.reported_closure_mismatch.borrow_mut().insert((span, found_span)); - - let found = match found_trait_ref.skip_binder().substs.type_at(1).kind { - ty::Tuple(ref tys) => vec![ArgKind::empty(); tys.len()], - _ => vec![ArgKind::empty()], - }; - - let expected_ty = expected_trait_ref.skip_binder().substs.type_at(1); - let expected = match expected_ty.kind { - ty::Tuple(ref tys) => tys - .iter() - .map(|t| ArgKind::from_expected_ty(t.expect_ty(), Some(span))) - .collect(), - _ => vec![ArgKind::Arg("_".to_owned(), expected_ty.to_string())], - }; - - if found.len() == expected.len() { - self.report_closure_arg_mismatch( - span, - found_span, - found_trait_ref, - expected_trait_ref, - ) - } else { - let (closure_span, found) = found_did - .and_then(|did| self.tcx.hir().get_if_local(did)) - .map(|node| { - let (found_span, found) = self.get_fn_like_arguments(node); - (Some(found_span), found) - }) - .unwrap_or((found_span, found)); - - self.report_arg_count_mismatch( - span, - closure_span, - expected, - found, - found_trait_ty.is_closure(), - ) - } - } - - TraitNotObjectSafe(did) => { - let violations = self.tcx.object_safety_violations(did); - report_object_safety_error(self.tcx, span, did, violations) - } - - ConstEvalFailure(ErrorHandled::TooGeneric) => { - // In this instance, we have a const expression containing an unevaluated - // generic parameter. We have no idea whether this expression is valid or - // not (e.g. it might result in an error), but we don't want to just assume - // that it's okay, because that might result in post-monomorphisation time - // errors. The onus is really on the caller to provide values that it can - // prove are well-formed. - let mut err = self - .tcx - .sess - .struct_span_err(span, "constant expression depends on a generic parameter"); - // FIXME(const_generics): we should suggest to the user how they can resolve this - // issue. However, this is currently not actually possible - // (see https://github.com/rust-lang/rust/issues/66962#issuecomment-575907083). - err.note("this may fail depending on what value the parameter takes"); - err - } - - // Already reported in the query. - ConstEvalFailure(ErrorHandled::Reported) => { - self.tcx.sess.delay_span_bug(span, "constant in type had an ignored error"); - return; - } - - Overflow => { - bug!("overflow should be handled before the `report_selection_error` path"); - } - }; - - self.note_obligation_cause(&mut err, obligation); - self.point_at_returns_when_relevant(&mut err, &obligation); - - err.emit(); - } - - /// If the `Self` type of the unsatisfied trait `trait_ref` implements a trait - /// with the same path as `trait_ref`, a help message about - /// a probable version mismatch is added to `err` - fn note_version_mismatch( - &self, - err: &mut DiagnosticBuilder<'_>, - trait_ref: &ty::PolyTraitRef<'tcx>, - ) { - let get_trait_impl = |trait_def_id| { - let mut trait_impl = None; - self.tcx.for_each_relevant_impl(trait_def_id, trait_ref.self_ty(), |impl_def_id| { - if trait_impl.is_none() { - trait_impl = Some(impl_def_id); - } - }); - trait_impl - }; - let required_trait_path = self.tcx.def_path_str(trait_ref.def_id()); - let all_traits = self.tcx.all_traits(LOCAL_CRATE); - let traits_with_same_path: std::collections::BTreeSet<_> = all_traits - .iter() - .filter(|trait_def_id| **trait_def_id != trait_ref.def_id()) - .filter(|trait_def_id| self.tcx.def_path_str(**trait_def_id) == required_trait_path) - .collect(); - for trait_with_same_path in traits_with_same_path { - if let Some(impl_def_id) = get_trait_impl(*trait_with_same_path) { - let impl_span = self.tcx.def_span(impl_def_id); - err.span_help(impl_span, "trait impl with same name found"); - let trait_crate = self.tcx.crate_name(trait_with_same_path.krate); - let crate_msg = format!( - "perhaps two different versions of crate `{}` are being used?", - trait_crate - ); - err.note(&crate_msg); - } - } - } - - fn mk_obligation_for_def_id( - &self, - def_id: DefId, - output_ty: Ty<'tcx>, - cause: ObligationCause<'tcx>, - param_env: ty::ParamEnv<'tcx>, - ) -> PredicateObligation<'tcx> { - let new_trait_ref = - ty::TraitRef { def_id, substs: self.tcx.mk_substs_trait(output_ty, &[]) }; - Obligation::new(cause, param_env, new_trait_ref.without_const().to_predicate()) - } -} - -pub fn recursive_type_with_infinite_size_error( - tcx: TyCtxt<'tcx>, - type_def_id: DefId, -) -> DiagnosticBuilder<'tcx> { - assert!(type_def_id.is_local()); - let span = tcx.hir().span_if_local(type_def_id).unwrap(); - let span = tcx.sess.source_map().def_span(span); - let mut err = struct_span_err!( - tcx.sess, - span, - E0072, - "recursive type `{}` has infinite size", - tcx.def_path_str(type_def_id) - ); - err.span_label(span, "recursive type has infinite size"); - err.help(&format!( - "insert indirection (e.g., a `Box`, `Rc`, or `&`) \ - at some point to make `{}` representable", - tcx.def_path_str(type_def_id) - )); - err } pub fn report_object_safety_error( @@ -1026,7 +46,7 @@ pub fn report_object_safety_error( hir::Node::Item(item) => Some(item.ident.span), _ => None, }); - let span = tcx.sess.source_map().def_span(span); + let span = tcx.sess.source_map().guess_head_span(span); let mut err = struct_span_err!( tcx.sess, span, @@ -1084,560 +104,3 @@ pub fn report_object_safety_error( err } - -impl<'a, 'tcx> InferCtxt<'a, 'tcx> { - fn maybe_report_ambiguity( - &self, - obligation: &PredicateObligation<'tcx>, - body_id: Option<hir::BodyId>, - ) { - // Unable to successfully determine, probably means - // insufficient type information, but could mean - // ambiguous impls. The latter *ought* to be a - // coherence violation, so we don't report it here. - - let predicate = self.resolve_vars_if_possible(&obligation.predicate); - let span = obligation.cause.span; - - debug!( - "maybe_report_ambiguity(predicate={:?}, obligation={:?} body_id={:?}, code={:?})", - predicate, obligation, body_id, obligation.cause.code, - ); - - // Ambiguity errors are often caused as fallout from earlier - // errors. So just ignore them if this infcx is tainted. - if self.is_tainted_by_errors() { - return; - } - - let mut err = match predicate { - ty::Predicate::Trait(ref data, _) => { - let trait_ref = data.to_poly_trait_ref(); - let self_ty = trait_ref.self_ty(); - debug!("self_ty {:?} {:?} trait_ref {:?}", self_ty, self_ty.kind, trait_ref); - - if predicate.references_error() { - return; - } - // Typically, this ambiguity should only happen if - // there are unresolved type inference variables - // (otherwise it would suggest a coherence - // failure). But given #21974 that is not necessarily - // the case -- we can have multiple where clauses that - // are only distinguished by a region, which results - // in an ambiguity even when all types are fully - // known, since we don't dispatch based on region - // relationships. - - // This is kind of a hack: it frequently happens that some earlier - // error prevents types from being fully inferred, and then we get - // a bunch of uninteresting errors saying something like "<generic - // #0> doesn't implement Sized". It may even be true that we - // could just skip over all checks where the self-ty is an - // inference variable, but I was afraid that there might be an - // inference variable created, registered as an obligation, and - // then never forced by writeback, and hence by skipping here we'd - // be ignoring the fact that we don't KNOW the type works - // out. Though even that would probably be harmless, given that - // we're only talking about builtin traits, which are known to be - // inhabited. We used to check for `self.tcx.sess.has_errors()` to - // avoid inundating the user with unnecessary errors, but we now - // check upstream for type errors and dont add the obligations to - // begin with in those cases. - if self - .tcx - .lang_items() - .sized_trait() - .map_or(false, |sized_id| sized_id == trait_ref.def_id()) - { - self.need_type_info_err(body_id, span, self_ty, ErrorCode::E0282).emit(); - return; - } - let mut err = self.need_type_info_err(body_id, span, self_ty, ErrorCode::E0283); - err.note(&format!("cannot resolve `{}`", predicate)); - if let ObligationCauseCode::ItemObligation(def_id) = obligation.cause.code { - self.suggest_fully_qualified_path(&mut err, def_id, span, trait_ref.def_id()); - } else if let ( - Ok(ref snippet), - ObligationCauseCode::BindingObligation(ref def_id, _), - ) = - (self.tcx.sess.source_map().span_to_snippet(span), &obligation.cause.code) - { - let generics = self.tcx.generics_of(*def_id); - if !generics.params.is_empty() && !snippet.ends_with('>') { - // FIXME: To avoid spurious suggestions in functions where type arguments - // where already supplied, we check the snippet to make sure it doesn't - // end with a turbofish. Ideally we would have access to a `PathSegment` - // instead. Otherwise we would produce the following output: - // - // error[E0283]: type annotations needed - // --> $DIR/issue-54954.rs:3:24 - // | - // LL | const ARR_LEN: usize = Tt::const_val::<[i8; 123]>(); - // | ^^^^^^^^^^^^^^^^^^^^^^^^^^ - // | | - // | cannot infer type - // | help: consider specifying the type argument - // | in the function call: - // | `Tt::const_val::<[i8; 123]>::<T>` - // ... - // LL | const fn const_val<T: Sized>() -> usize { - // | --------- - required by this bound in `Tt::const_val` - // | - // = note: cannot resolve `_: Tt` - - err.span_suggestion( - span, - &format!( - "consider specifying the type argument{} in the function call", - if generics.params.len() > 1 { "s" } else { "" }, - ), - format!( - "{}::<{}>", - snippet, - generics - .params - .iter() - .map(|p| p.name.to_string()) - .collect::<Vec<String>>() - .join(", ") - ), - Applicability::HasPlaceholders, - ); - } - } - err - } - - ty::Predicate::WellFormed(ty) => { - // Same hacky approach as above to avoid deluging user - // with error messages. - if ty.references_error() || self.tcx.sess.has_errors() { - return; - } - self.need_type_info_err(body_id, span, ty, ErrorCode::E0282) - } - - ty::Predicate::Subtype(ref data) => { - if data.references_error() || self.tcx.sess.has_errors() { - // no need to overload user in such cases - return; - } - let &SubtypePredicate { a_is_expected: _, a, b } = data.skip_binder(); - // both must be type variables, or the other would've been instantiated - assert!(a.is_ty_var() && b.is_ty_var()); - self.need_type_info_err(body_id, span, a, ErrorCode::E0282) - } - ty::Predicate::Projection(ref data) => { - let trait_ref = data.to_poly_trait_ref(self.tcx); - let self_ty = trait_ref.self_ty(); - if predicate.references_error() { - return; - } - let mut err = self.need_type_info_err(body_id, span, self_ty, ErrorCode::E0284); - err.note(&format!("cannot resolve `{}`", predicate)); - err - } - - _ => { - if self.tcx.sess.has_errors() { - return; - } - let mut err = struct_span_err!( - self.tcx.sess, - span, - E0284, - "type annotations needed: cannot resolve `{}`", - predicate, - ); - err.span_label(span, &format!("cannot resolve `{}`", predicate)); - err - } - }; - self.note_obligation_cause(&mut err, obligation); - err.emit(); - } - - /// Returns `true` if the trait predicate may apply for *some* assignment - /// to the type parameters. - fn predicate_can_apply( - &self, - param_env: ty::ParamEnv<'tcx>, - pred: ty::PolyTraitRef<'tcx>, - ) -> bool { - struct ParamToVarFolder<'a, 'tcx> { - infcx: &'a InferCtxt<'a, 'tcx>, - var_map: FxHashMap<Ty<'tcx>, Ty<'tcx>>, - } - - impl<'a, 'tcx> TypeFolder<'tcx> for ParamToVarFolder<'a, 'tcx> { - fn tcx<'b>(&'b self) -> TyCtxt<'tcx> { - self.infcx.tcx - } - - fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> { - if let ty::Param(ty::ParamTy { name, .. }) = ty.kind { - let infcx = self.infcx; - self.var_map.entry(ty).or_insert_with(|| { - infcx.next_ty_var(TypeVariableOrigin { - kind: TypeVariableOriginKind::TypeParameterDefinition(name, None), - span: DUMMY_SP, - }) - }) - } else { - ty.super_fold_with(self) - } - } - } - - self.probe(|_| { - let mut selcx = SelectionContext::new(self); - - let cleaned_pred = - pred.fold_with(&mut ParamToVarFolder { infcx: self, var_map: Default::default() }); - - let cleaned_pred = super::project::normalize( - &mut selcx, - param_env, - ObligationCause::dummy(), - &cleaned_pred, - ) - .value; - - let obligation = Obligation::new( - ObligationCause::dummy(), - param_env, - cleaned_pred.without_const().to_predicate(), - ); - - self.predicate_may_hold(&obligation) - }) - } - - fn note_obligation_cause( - &self, - err: &mut DiagnosticBuilder<'_>, - obligation: &PredicateObligation<'tcx>, - ) { - // First, attempt to add note to this error with an async-await-specific - // message, and fall back to regular note otherwise. - if !self.maybe_note_obligation_cause_for_async_await(err, obligation) { - self.note_obligation_cause_code( - err, - &obligation.predicate, - &obligation.cause.code, - &mut vec![], - ); - self.suggest_unsized_bound_if_applicable(err, obligation); - } - } - - fn suggest_unsized_bound_if_applicable( - &self, - err: &mut DiagnosticBuilder<'_>, - obligation: &PredicateObligation<'tcx>, - ) { - if let ( - ty::Predicate::Trait(pred, _), - ObligationCauseCode::BindingObligation(item_def_id, span), - ) = (&obligation.predicate, &obligation.cause.code) - { - if let (Some(generics), true) = ( - self.tcx.hir().get_if_local(*item_def_id).as_ref().and_then(|n| n.generics()), - Some(pred.def_id()) == self.tcx.lang_items().sized_trait(), - ) { - for param in generics.params { - if param.span == *span - && !param.bounds.iter().any(|bound| { - bound.trait_def_id() == self.tcx.lang_items().sized_trait() - }) - { - let (span, separator) = match param.bounds { - [] => (span.shrink_to_hi(), ":"), - [.., bound] => (bound.span().shrink_to_hi(), " + "), - }; - err.span_suggestion( - span, - "consider relaxing the implicit `Sized` restriction", - format!("{} ?Sized", separator), - Applicability::MachineApplicable, - ); - return; - } - } - } - } - } - - fn is_recursive_obligation( - &self, - obligated_types: &mut Vec<&ty::TyS<'tcx>>, - cause_code: &ObligationCauseCode<'tcx>, - ) -> bool { - if let ObligationCauseCode::BuiltinDerivedObligation(ref data) = cause_code { - let parent_trait_ref = self.resolve_vars_if_possible(&data.parent_trait_ref); - - if obligated_types.iter().any(|ot| ot == &parent_trait_ref.skip_binder().self_ty()) { - return true; - } - } - false - } -} - -/// Summarizes information -#[derive(Clone)] -pub enum ArgKind { - /// An argument of non-tuple type. Parameters are (name, ty) - Arg(String, String), - - /// An argument of tuple type. For a "found" argument, the span is - /// the locationo in the source of the pattern. For a "expected" - /// argument, it will be None. The vector is a list of (name, ty) - /// strings for the components of the tuple. - Tuple(Option<Span>, Vec<(String, String)>), -} - -impl ArgKind { - fn empty() -> ArgKind { - ArgKind::Arg("_".to_owned(), "_".to_owned()) - } - - /// Creates an `ArgKind` from the expected type of an - /// argument. It has no name (`_`) and an optional source span. - pub fn from_expected_ty(t: Ty<'_>, span: Option<Span>) -> ArgKind { - match t.kind { - ty::Tuple(ref tys) => ArgKind::Tuple( - span, - tys.iter().map(|ty| ("_".to_owned(), ty.to_string())).collect::<Vec<_>>(), - ), - _ => ArgKind::Arg("_".to_owned(), t.to_string()), - } - } -} - -/// Suggest restricting a type param with a new bound. -pub fn suggest_constraining_type_param( - tcx: TyCtxt<'_>, - generics: &hir::Generics<'_>, - err: &mut DiagnosticBuilder<'_>, - param_name: &str, - constraint: &str, - source_map: &SourceMap, - span: Span, - def_id: Option<DefId>, -) -> bool { - const MSG_RESTRICT_BOUND_FURTHER: &str = "consider further restricting this bound with"; - const MSG_RESTRICT_TYPE: &str = "consider restricting this type parameter with"; - const MSG_RESTRICT_TYPE_FURTHER: &str = "consider further restricting this type parameter with"; - - let param = generics.params.iter().find(|p| p.name.ident().as_str() == param_name); - - let param = if let Some(param) = param { - param - } else { - return false; - }; - - if def_id == tcx.lang_items().sized_trait() { - // Type parameters are already `Sized` by default. - err.span_label(param.span, &format!("this type parameter needs to be `{}`", constraint)); - return true; - } - - if param_name.starts_with("impl ") { - // If there's an `impl Trait` used in argument position, suggest - // restricting it: - // - // fn foo(t: impl Foo) { ... } - // -------- - // | - // help: consider further restricting this bound with `+ Bar` - // - // Suggestion for tools in this case is: - // - // fn foo(t: impl Foo) { ... } - // -------- - // | - // replace with: `impl Foo + Bar` - - err.span_help(param.span, &format!("{} `+ {}`", MSG_RESTRICT_BOUND_FURTHER, constraint)); - - err.tool_only_span_suggestion( - param.span, - MSG_RESTRICT_BOUND_FURTHER, - format!("{} + {}", param_name, constraint), - Applicability::MachineApplicable, - ); - - return true; - } - - if generics.where_clause.predicates.is_empty() { - if let Some(bounds_span) = param.bounds_span() { - // If user has provided some bounds, suggest restricting them: - // - // fn foo<T: Foo>(t: T) { ... } - // --- - // | - // help: consider further restricting this bound with `+ Bar` - // - // Suggestion for tools in this case is: - // - // fn foo<T: Foo>(t: T) { ... } - // -- - // | - // replace with: `T: Bar +` - - err.span_help( - bounds_span, - &format!("{} `+ {}`", MSG_RESTRICT_BOUND_FURTHER, constraint), - ); - - let span_hi = param.span.with_hi(span.hi()); - let span_with_colon = source_map.span_through_char(span_hi, ':'); - - if span_hi != param.span && span_with_colon != span_hi { - err.tool_only_span_suggestion( - span_with_colon, - MSG_RESTRICT_BOUND_FURTHER, - format!("{}: {} + ", param_name, constraint), - Applicability::MachineApplicable, - ); - } - } else { - // If user hasn't provided any bounds, suggest adding a new one: - // - // fn foo<T>(t: T) { ... } - // - help: consider restricting this type parameter with `T: Foo` - - err.span_help( - param.span, - &format!("{} `{}: {}`", MSG_RESTRICT_TYPE, param_name, constraint), - ); - - err.tool_only_span_suggestion( - param.span, - MSG_RESTRICT_TYPE, - format!("{}: {}", param_name, constraint), - Applicability::MachineApplicable, - ); - } - - true - } else { - // This part is a bit tricky, because using the `where` clause user can - // provide zero, one or many bounds for the same type parameter, so we - // have following cases to consider: - // - // 1) When the type parameter has been provided zero bounds - // - // Message: - // fn foo<X, Y>(x: X, y: Y) where Y: Foo { ... } - // - help: consider restricting this type parameter with `where X: Bar` - // - // Suggestion: - // fn foo<X, Y>(x: X, y: Y) where Y: Foo { ... } - // - insert: `, X: Bar` - // - // - // 2) When the type parameter has been provided one bound - // - // Message: - // fn foo<T>(t: T) where T: Foo { ... } - // ^^^^^^ - // | - // help: consider further restricting this bound with `+ Bar` - // - // Suggestion: - // fn foo<T>(t: T) where T: Foo { ... } - // ^^ - // | - // replace with: `T: Bar +` - // - // - // 3) When the type parameter has been provided many bounds - // - // Message: - // fn foo<T>(t: T) where T: Foo, T: Bar {... } - // - help: consider further restricting this type parameter with `where T: Zar` - // - // Suggestion: - // fn foo<T>(t: T) where T: Foo, T: Bar {... } - // - insert: `, T: Zar` - - let mut param_spans = Vec::new(); - - for predicate in generics.where_clause.predicates { - if let WherePredicate::BoundPredicate(WhereBoundPredicate { - span, bounded_ty, .. - }) = predicate - { - if let TyKind::Path(QPath::Resolved(_, path)) = &bounded_ty.kind { - if let Some(segment) = path.segments.first() { - if segment.ident.to_string() == param_name { - param_spans.push(span); - } - } - } - } - } - - let where_clause_span = - generics.where_clause.span_for_predicates_or_empty_place().shrink_to_hi(); - - match ¶m_spans[..] { - &[] => { - err.span_help( - param.span, - &format!("{} `where {}: {}`", MSG_RESTRICT_TYPE, param_name, constraint), - ); - - err.tool_only_span_suggestion( - where_clause_span, - MSG_RESTRICT_TYPE, - format!(", {}: {}", param_name, constraint), - Applicability::MachineApplicable, - ); - } - - &[¶m_span] => { - err.span_help( - param_span, - &format!("{} `+ {}`", MSG_RESTRICT_BOUND_FURTHER, constraint), - ); - - let span_hi = param_span.with_hi(span.hi()); - let span_with_colon = source_map.span_through_char(span_hi, ':'); - - if span_hi != param_span && span_with_colon != span_hi { - err.tool_only_span_suggestion( - span_with_colon, - MSG_RESTRICT_BOUND_FURTHER, - format!("{}: {} +", param_name, constraint), - Applicability::MachineApplicable, - ); - } - } - - _ => { - err.span_help( - param.span, - &format!( - "{} `where {}: {}`", - MSG_RESTRICT_TYPE_FURTHER, param_name, constraint, - ), - ); - - err.tool_only_span_suggestion( - where_clause_span, - MSG_RESTRICT_BOUND_FURTHER, - format!(", {}: {}", param_name, constraint), - Applicability::MachineApplicable, - ); - } - } - - true - } -} diff --git a/src/librustc_infer/traits/error_reporting/on_unimplemented.rs b/src/librustc_infer/traits/error_reporting/on_unimplemented.rs deleted file mode 100644 index 87c1107bd42..00000000000 --- a/src/librustc_infer/traits/error_reporting/on_unimplemented.rs +++ /dev/null @@ -1,223 +0,0 @@ -use super::{ - ObligationCauseCode, OnUnimplementedDirective, OnUnimplementedNote, PredicateObligation, -}; -use crate::infer::InferCtxt; -use rustc::ty::subst::Subst; -use rustc::ty::{self, GenericParamDefKind}; -use rustc_hir as hir; -use rustc_hir::def_id::DefId; -use rustc_span::symbol::sym; - -impl<'a, 'tcx> InferCtxt<'a, 'tcx> { - fn impl_similar_to( - &self, - trait_ref: ty::PolyTraitRef<'tcx>, - obligation: &PredicateObligation<'tcx>, - ) -> Option<DefId> { - let tcx = self.tcx; - let param_env = obligation.param_env; - let trait_ref = tcx.erase_late_bound_regions(&trait_ref); - let trait_self_ty = trait_ref.self_ty(); - - let mut self_match_impls = vec![]; - let mut fuzzy_match_impls = vec![]; - - self.tcx.for_each_relevant_impl(trait_ref.def_id, trait_self_ty, |def_id| { - let impl_substs = self.fresh_substs_for_item(obligation.cause.span, def_id); - let impl_trait_ref = tcx.impl_trait_ref(def_id).unwrap().subst(tcx, impl_substs); - - let impl_self_ty = impl_trait_ref.self_ty(); - - if let Ok(..) = self.can_eq(param_env, trait_self_ty, impl_self_ty) { - self_match_impls.push(def_id); - - if trait_ref - .substs - .types() - .skip(1) - .zip(impl_trait_ref.substs.types().skip(1)) - .all(|(u, v)| self.fuzzy_match_tys(u, v)) - { - fuzzy_match_impls.push(def_id); - } - } - }); - - let impl_def_id = if self_match_impls.len() == 1 { - self_match_impls[0] - } else if fuzzy_match_impls.len() == 1 { - fuzzy_match_impls[0] - } else { - return None; - }; - - tcx.has_attr(impl_def_id, sym::rustc_on_unimplemented).then_some(impl_def_id) - } - - /// Used to set on_unimplemented's `ItemContext` - /// to be the enclosing (async) block/function/closure - fn describe_enclosure(&self, hir_id: hir::HirId) -> Option<&'static str> { - let hir = &self.tcx.hir(); - let node = hir.find(hir_id)?; - match &node { - hir::Node::Item(hir::Item { kind: hir::ItemKind::Fn(sig, _, body_id), .. }) => { - self.describe_generator(*body_id).or_else(|| { - Some(if let hir::FnHeader { asyncness: hir::IsAsync::Async, .. } = sig.header { - "an async function" - } else { - "a function" - }) - }) - } - hir::Node::TraitItem(hir::TraitItem { - kind: hir::TraitItemKind::Method(_, hir::TraitMethod::Provided(body_id)), - .. - }) => self.describe_generator(*body_id).or_else(|| Some("a trait method")), - hir::Node::ImplItem(hir::ImplItem { - kind: hir::ImplItemKind::Method(sig, body_id), - .. - }) => self.describe_generator(*body_id).or_else(|| { - Some(if let hir::FnHeader { asyncness: hir::IsAsync::Async, .. } = sig.header { - "an async method" - } else { - "a method" - }) - }), - hir::Node::Expr(hir::Expr { - kind: hir::ExprKind::Closure(_is_move, _, body_id, _, gen_movability), - .. - }) => self.describe_generator(*body_id).or_else(|| { - Some(if gen_movability.is_some() { "an async closure" } else { "a closure" }) - }), - hir::Node::Expr(hir::Expr { .. }) => { - let parent_hid = hir.get_parent_node(hir_id); - if parent_hid != hir_id { - return self.describe_enclosure(parent_hid); - } else { - None - } - } - _ => None, - } - } - - crate fn on_unimplemented_note( - &self, - trait_ref: ty::PolyTraitRef<'tcx>, - obligation: &PredicateObligation<'tcx>, - ) -> OnUnimplementedNote { - let def_id = - self.impl_similar_to(trait_ref, obligation).unwrap_or_else(|| trait_ref.def_id()); - let trait_ref = *trait_ref.skip_binder(); - - let mut flags = vec![]; - flags.push(( - sym::item_context, - self.describe_enclosure(obligation.cause.body_id).map(|s| s.to_owned()), - )); - - match obligation.cause.code { - ObligationCauseCode::BuiltinDerivedObligation(..) - | ObligationCauseCode::ImplDerivedObligation(..) => {} - _ => { - // this is a "direct", user-specified, rather than derived, - // obligation. - flags.push((sym::direct, None)); - } - } - - if let ObligationCauseCode::ItemObligation(item) = obligation.cause.code { - // FIXME: maybe also have some way of handling methods - // from other traits? That would require name resolution, - // which we might want to be some sort of hygienic. - // - // Currently I'm leaving it for what I need for `try`. - if self.tcx.trait_of_item(item) == Some(trait_ref.def_id) { - let method = self.tcx.item_name(item); - flags.push((sym::from_method, None)); - flags.push((sym::from_method, Some(method.to_string()))); - } - } - if let Some((t, _)) = self.get_parent_trait_ref(&obligation.cause.code) { - flags.push((sym::parent_trait, Some(t))); - } - - if let Some(k) = obligation.cause.span.desugaring_kind() { - flags.push((sym::from_desugaring, None)); - flags.push((sym::from_desugaring, Some(format!("{:?}", k)))); - } - let generics = self.tcx.generics_of(def_id); - let self_ty = trait_ref.self_ty(); - // This is also included through the generics list as `Self`, - // but the parser won't allow you to use it - flags.push((sym::_Self, Some(self_ty.to_string()))); - if let Some(def) = self_ty.ty_adt_def() { - // We also want to be able to select self's original - // signature with no type arguments resolved - flags.push((sym::_Self, Some(self.tcx.type_of(def.did).to_string()))); - } - - for param in generics.params.iter() { - let value = match param.kind { - GenericParamDefKind::Type { .. } | GenericParamDefKind::Const => { - trait_ref.substs[param.index as usize].to_string() - } - GenericParamDefKind::Lifetime => continue, - }; - let name = param.name; - flags.push((name, Some(value))); - } - - if let Some(true) = self_ty.ty_adt_def().map(|def| def.did.is_local()) { - flags.push((sym::crate_local, None)); - } - - // Allow targeting all integers using `{integral}`, even if the exact type was resolved - if self_ty.is_integral() { - flags.push((sym::_Self, Some("{integral}".to_owned()))); - } - - if let ty::Array(aty, len) = self_ty.kind { - flags.push((sym::_Self, Some("[]".to_owned()))); - flags.push((sym::_Self, Some(format!("[{}]", aty)))); - if let Some(def) = aty.ty_adt_def() { - // We also want to be able to select the array's type's original - // signature with no type arguments resolved - flags.push(( - sym::_Self, - Some(format!("[{}]", self.tcx.type_of(def.did).to_string())), - )); - let tcx = self.tcx; - if let Some(len) = len.try_eval_usize(tcx, ty::ParamEnv::empty()) { - flags.push(( - sym::_Self, - Some(format!("[{}; {}]", self.tcx.type_of(def.did).to_string(), len)), - )); - } else { - flags.push(( - sym::_Self, - Some(format!("[{}; _]", self.tcx.type_of(def.did).to_string())), - )); - } - } - } - if let ty::Dynamic(traits, _) = self_ty.kind { - for t in *traits.skip_binder() { - match t { - ty::ExistentialPredicate::Trait(trait_ref) => { - flags.push((sym::_Self, Some(self.tcx.def_path_str(trait_ref.def_id)))) - } - _ => {} - } - } - } - - if let Ok(Some(command)) = - OnUnimplementedDirective::of_item(self.tcx, trait_ref.def_id, def_id) - { - command.evaluate(self.tcx, trait_ref, &flags[..]) - } else { - OnUnimplementedNote::default() - } - } -} diff --git a/src/librustc_infer/traits/error_reporting/suggestions.rs b/src/librustc_infer/traits/error_reporting/suggestions.rs deleted file mode 100644 index d05955fb858..00000000000 --- a/src/librustc_infer/traits/error_reporting/suggestions.rs +++ /dev/null @@ -1,1707 +0,0 @@ -use super::{ - ArgKind, EvaluationResult, Obligation, ObligationCause, ObligationCauseCode, - PredicateObligation, -}; - -use crate::infer::InferCtxt; -use crate::traits::error_reporting::suggest_constraining_type_param; - -use rustc::ty::TypeckTables; -use rustc::ty::{self, AdtKind, DefIdTree, ToPredicate, Ty, TyCtxt, TypeFoldable, WithConstness}; -use rustc_errors::{ - error_code, pluralize, struct_span_err, Applicability, DiagnosticBuilder, Style, -}; -use rustc_hir as hir; -use rustc_hir::def::DefKind; -use rustc_hir::def_id::DefId; -use rustc_hir::intravisit::Visitor; -use rustc_hir::Node; -use rustc_span::symbol::{kw, sym}; -use rustc_span::{MultiSpan, Span, DUMMY_SP}; -use std::fmt; - -impl<'a, 'tcx> InferCtxt<'a, 'tcx> { - crate fn suggest_restricting_param_bound( - &self, - mut err: &mut DiagnosticBuilder<'_>, - trait_ref: &ty::PolyTraitRef<'_>, - body_id: hir::HirId, - ) { - let self_ty = trait_ref.self_ty(); - let (param_ty, projection) = match &self_ty.kind { - ty::Param(_) => (true, None), - ty::Projection(projection) => (false, Some(projection)), - _ => return, - }; - - let suggest_restriction = - |generics: &hir::Generics<'_>, msg, err: &mut DiagnosticBuilder<'_>| { - let span = generics.where_clause.span_for_predicates_or_empty_place(); - if !span.from_expansion() && span.desugaring_kind().is_none() { - err.span_suggestion( - generics.where_clause.span_for_predicates_or_empty_place().shrink_to_hi(), - &format!("consider further restricting {}", msg), - format!( - "{} {} ", - if !generics.where_clause.predicates.is_empty() { - "," - } else { - " where" - }, - trait_ref.without_const().to_predicate(), - ), - Applicability::MachineApplicable, - ); - } - }; - - // FIXME: Add check for trait bound that is already present, particularly `?Sized` so we - // don't suggest `T: Sized + ?Sized`. - let mut hir_id = body_id; - while let Some(node) = self.tcx.hir().find(hir_id) { - match node { - hir::Node::TraitItem(hir::TraitItem { - generics, - kind: hir::TraitItemKind::Method(..), - .. - }) if param_ty && self_ty == self.tcx.types.self_param => { - // Restricting `Self` for a single method. - suggest_restriction(&generics, "`Self`", err); - return; - } - - hir::Node::Item(hir::Item { kind: hir::ItemKind::Fn(_, generics, _), .. }) - | hir::Node::TraitItem(hir::TraitItem { - generics, - kind: hir::TraitItemKind::Method(..), - .. - }) - | hir::Node::ImplItem(hir::ImplItem { - generics, - kind: hir::ImplItemKind::Method(..), - .. - }) - | hir::Node::Item(hir::Item { - kind: hir::ItemKind::Trait(_, _, generics, _, _), - .. - }) - | hir::Node::Item(hir::Item { - kind: hir::ItemKind::Impl { generics, .. }, .. - }) if projection.is_some() => { - // Missing associated type bound. - suggest_restriction(&generics, "the associated type", err); - return; - } - - hir::Node::Item(hir::Item { - kind: hir::ItemKind::Struct(_, generics), - span, - .. - }) - | hir::Node::Item(hir::Item { - kind: hir::ItemKind::Enum(_, generics), span, .. - }) - | hir::Node::Item(hir::Item { - kind: hir::ItemKind::Union(_, generics), - span, - .. - }) - | hir::Node::Item(hir::Item { - kind: hir::ItemKind::Trait(_, _, generics, ..), - span, - .. - }) - | hir::Node::Item(hir::Item { - kind: hir::ItemKind::Impl { generics, .. }, - span, - .. - }) - | hir::Node::Item(hir::Item { - kind: hir::ItemKind::Fn(_, generics, _), - span, - .. - }) - | hir::Node::Item(hir::Item { - kind: hir::ItemKind::TyAlias(_, generics), - span, - .. - }) - | hir::Node::Item(hir::Item { - kind: hir::ItemKind::TraitAlias(generics, _), - span, - .. - }) - | hir::Node::Item(hir::Item { - kind: hir::ItemKind::OpaqueTy(hir::OpaqueTy { generics, .. }), - span, - .. - }) - | hir::Node::TraitItem(hir::TraitItem { generics, span, .. }) - | hir::Node::ImplItem(hir::ImplItem { generics, span, .. }) - if param_ty => - { - // Missing generic type parameter bound. - let param_name = self_ty.to_string(); - let constraint = trait_ref.print_only_trait_path().to_string(); - if suggest_constraining_type_param( - self.tcx, - generics, - &mut err, - ¶m_name, - &constraint, - self.tcx.sess.source_map(), - *span, - Some(trait_ref.def_id()), - ) { - return; - } - } - - hir::Node::Crate => return, - - _ => {} - } - - hir_id = self.tcx.hir().get_parent_item(hir_id); - } - } - - /// When encountering an assignment of an unsized trait, like `let x = ""[..];`, provide a - /// suggestion to borrow the initializer in order to use have a slice instead. - crate fn suggest_borrow_on_unsized_slice( - &self, - code: &ObligationCauseCode<'tcx>, - err: &mut DiagnosticBuilder<'tcx>, - ) { - if let &ObligationCauseCode::VariableType(hir_id) = code { - let parent_node = self.tcx.hir().get_parent_node(hir_id); - if let Some(Node::Local(ref local)) = self.tcx.hir().find(parent_node) { - if let Some(ref expr) = local.init { - if let hir::ExprKind::Index(_, _) = expr.kind { - if let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(expr.span) { - err.span_suggestion( - expr.span, - "consider borrowing here", - format!("&{}", snippet), - Applicability::MachineApplicable, - ); - } - } - } - } - } - } - - /// Given a closure's `DefId`, return the given name of the closure. - /// - /// This doesn't account for reassignments, but it's only used for suggestions. - crate fn get_closure_name( - &self, - def_id: DefId, - err: &mut DiagnosticBuilder<'_>, - msg: &str, - ) -> Option<String> { - let get_name = - |err: &mut DiagnosticBuilder<'_>, kind: &hir::PatKind<'_>| -> Option<String> { - // Get the local name of this closure. This can be inaccurate because - // of the possibility of reassignment, but this should be good enough. - match &kind { - hir::PatKind::Binding(hir::BindingAnnotation::Unannotated, _, name, None) => { - Some(format!("{}", name)) - } - _ => { - err.note(&msg); - None - } - } - }; - - let hir = self.tcx.hir(); - let hir_id = hir.as_local_hir_id(def_id)?; - let parent_node = hir.get_parent_node(hir_id); - match hir.find(parent_node) { - Some(hir::Node::Stmt(hir::Stmt { kind: hir::StmtKind::Local(local), .. })) => { - get_name(err, &local.pat.kind) - } - // Different to previous arm because one is `&hir::Local` and the other - // is `P<hir::Local>`. - Some(hir::Node::Local(local)) => get_name(err, &local.pat.kind), - _ => return None, - } - } - - /// We tried to apply the bound to an `fn` or closure. Check whether calling it would - /// evaluate to a type that *would* satisfy the trait binding. If it would, suggest calling - /// it: `bar(foo)` → `bar(foo())`. This case is *very* likely to be hit if `foo` is `async`. - crate fn suggest_fn_call( - &self, - obligation: &PredicateObligation<'tcx>, - err: &mut DiagnosticBuilder<'_>, - trait_ref: &ty::Binder<ty::TraitRef<'tcx>>, - points_at_arg: bool, - ) { - let self_ty = trait_ref.self_ty(); - let (def_id, output_ty, callable) = match self_ty.kind { - ty::Closure(def_id, substs) => { - (def_id, self.closure_sig(def_id, substs).output(), "closure") - } - ty::FnDef(def_id, _) => (def_id, self_ty.fn_sig(self.tcx).output(), "function"), - _ => return, - }; - let msg = format!("use parentheses to call the {}", callable); - - let obligation = self.mk_obligation_for_def_id( - trait_ref.def_id(), - output_ty.skip_binder(), - obligation.cause.clone(), - obligation.param_env, - ); - - match self.evaluate_obligation(&obligation) { - Ok(EvaluationResult::EvaluatedToOk) - | Ok(EvaluationResult::EvaluatedToOkModuloRegions) - | Ok(EvaluationResult::EvaluatedToAmbig) => {} - _ => return, - } - let hir = self.tcx.hir(); - // Get the name of the callable and the arguments to be used in the suggestion. - let snippet = match hir.get_if_local(def_id) { - Some(hir::Node::Expr(hir::Expr { - kind: hir::ExprKind::Closure(_, decl, _, span, ..), - .. - })) => { - err.span_label(*span, "consider calling this closure"); - let name = match self.get_closure_name(def_id, err, &msg) { - Some(name) => name, - None => return, - }; - let args = decl.inputs.iter().map(|_| "_").collect::<Vec<_>>().join(", "); - format!("{}({})", name, args) - } - Some(hir::Node::Item(hir::Item { - ident, - kind: hir::ItemKind::Fn(.., body_id), - .. - })) => { - err.span_label(ident.span, "consider calling this function"); - let body = hir.body(*body_id); - let args = body - .params - .iter() - .map(|arg| match &arg.pat.kind { - hir::PatKind::Binding(_, _, ident, None) - // FIXME: provide a better suggestion when encountering `SelfLower`, it - // should suggest a method call. - if ident.name != kw::SelfLower => ident.to_string(), - _ => "_".to_string(), - }) - .collect::<Vec<_>>() - .join(", "); - format!("{}({})", ident, args) - } - _ => return, - }; - if points_at_arg { - // When the obligation error has been ensured to have been caused by - // an argument, the `obligation.cause.span` points at the expression - // of the argument, so we can provide a suggestion. This is signaled - // by `points_at_arg`. Otherwise, we give a more general note. - err.span_suggestion( - obligation.cause.span, - &msg, - snippet, - Applicability::HasPlaceholders, - ); - } else { - err.help(&format!("{}: `{}`", msg, snippet)); - } - } - - crate fn suggest_add_reference_to_arg( - &self, - obligation: &PredicateObligation<'tcx>, - err: &mut DiagnosticBuilder<'tcx>, - trait_ref: &ty::Binder<ty::TraitRef<'tcx>>, - points_at_arg: bool, - has_custom_message: bool, - ) -> bool { - if !points_at_arg { - return false; - } - - let span = obligation.cause.span; - let param_env = obligation.param_env; - let trait_ref = trait_ref.skip_binder(); - - if let ObligationCauseCode::ImplDerivedObligation(obligation) = &obligation.cause.code { - // Try to apply the original trait binding obligation by borrowing. - let self_ty = trait_ref.self_ty(); - let found = self_ty.to_string(); - let new_self_ty = self.tcx.mk_imm_ref(self.tcx.lifetimes.re_static, self_ty); - let substs = self.tcx.mk_substs_trait(new_self_ty, &[]); - let new_trait_ref = ty::TraitRef::new(obligation.parent_trait_ref.def_id(), substs); - let new_obligation = Obligation::new( - ObligationCause::dummy(), - param_env, - new_trait_ref.without_const().to_predicate(), - ); - if self.predicate_must_hold_modulo_regions(&new_obligation) { - if let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(span) { - // We have a very specific type of error, where just borrowing this argument - // might solve the problem. In cases like this, the important part is the - // original type obligation, not the last one that failed, which is arbitrary. - // Because of this, we modify the error to refer to the original obligation and - // return early in the caller. - let msg = format!( - "the trait bound `{}: {}` is not satisfied", - found, - obligation.parent_trait_ref.skip_binder().print_only_trait_path(), - ); - if has_custom_message { - err.note(&msg); - } else { - err.message = vec![(msg, Style::NoStyle)]; - } - if snippet.starts_with('&') { - // This is already a literal borrow and the obligation is failing - // somewhere else in the obligation chain. Do not suggest non-sense. - return false; - } - err.span_label( - span, - &format!( - "expected an implementor of trait `{}`", - obligation.parent_trait_ref.skip_binder().print_only_trait_path(), - ), - ); - err.span_suggestion( - span, - "consider borrowing here", - format!("&{}", snippet), - Applicability::MaybeIncorrect, - ); - return true; - } - } - } - false - } - - /// Whenever references are used by mistake, like `for (i, e) in &vec.iter().enumerate()`, - /// suggest removing these references until we reach a type that implements the trait. - crate fn suggest_remove_reference( - &self, - obligation: &PredicateObligation<'tcx>, - err: &mut DiagnosticBuilder<'tcx>, - trait_ref: &ty::Binder<ty::TraitRef<'tcx>>, - ) { - let trait_ref = trait_ref.skip_binder(); - let span = obligation.cause.span; - - if let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(span) { - let refs_number = - snippet.chars().filter(|c| !c.is_whitespace()).take_while(|c| *c == '&').count(); - if let Some('\'') = snippet.chars().filter(|c| !c.is_whitespace()).nth(refs_number) { - // Do not suggest removal of borrow from type arguments. - return; - } - - let mut trait_type = trait_ref.self_ty(); - - for refs_remaining in 0..refs_number { - if let ty::Ref(_, t_type, _) = trait_type.kind { - trait_type = t_type; - - let new_obligation = self.mk_obligation_for_def_id( - trait_ref.def_id, - trait_type, - ObligationCause::dummy(), - obligation.param_env, - ); - - if self.predicate_may_hold(&new_obligation) { - let sp = self - .tcx - .sess - .source_map() - .span_take_while(span, |c| c.is_whitespace() || *c == '&'); - - let remove_refs = refs_remaining + 1; - - let msg = if remove_refs == 1 { - "consider removing the leading `&`-reference".to_string() - } else { - format!("consider removing {} leading `&`-references", remove_refs) - }; - - err.span_suggestion_short( - sp, - &msg, - String::new(), - Applicability::MachineApplicable, - ); - break; - } - } else { - break; - } - } - } - } - - /// Check if the trait bound is implemented for a different mutability and note it in the - /// final error. - crate fn suggest_change_mut( - &self, - obligation: &PredicateObligation<'tcx>, - err: &mut DiagnosticBuilder<'tcx>, - trait_ref: &ty::Binder<ty::TraitRef<'tcx>>, - points_at_arg: bool, - ) { - let span = obligation.cause.span; - if let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(span) { - let refs_number = - snippet.chars().filter(|c| !c.is_whitespace()).take_while(|c| *c == '&').count(); - if let Some('\'') = snippet.chars().filter(|c| !c.is_whitespace()).nth(refs_number) { - // Do not suggest removal of borrow from type arguments. - return; - } - let trait_ref = self.resolve_vars_if_possible(trait_ref); - if trait_ref.has_infer_types_or_consts() { - // Do not ICE while trying to find if a reborrow would succeed on a trait with - // unresolved bindings. - return; - } - - if let ty::Ref(region, t_type, mutability) = trait_ref.skip_binder().self_ty().kind { - let trait_type = match mutability { - hir::Mutability::Mut => self.tcx.mk_imm_ref(region, t_type), - hir::Mutability::Not => self.tcx.mk_mut_ref(region, t_type), - }; - - let new_obligation = self.mk_obligation_for_def_id( - trait_ref.skip_binder().def_id, - trait_type, - ObligationCause::dummy(), - obligation.param_env, - ); - - if self.evaluate_obligation_no_overflow(&new_obligation).must_apply_modulo_regions() - { - let sp = self - .tcx - .sess - .source_map() - .span_take_while(span, |c| c.is_whitespace() || *c == '&'); - if points_at_arg && mutability == hir::Mutability::Not && refs_number > 0 { - err.span_suggestion( - sp, - "consider changing this borrow's mutability", - "&mut ".to_string(), - Applicability::MachineApplicable, - ); - } else { - err.note(&format!( - "`{}` is implemented for `{:?}`, but not for `{:?}`", - trait_ref.print_only_trait_path(), - trait_type, - trait_ref.skip_binder().self_ty(), - )); - } - } - } - } - } - - crate fn suggest_semicolon_removal( - &self, - obligation: &PredicateObligation<'tcx>, - err: &mut DiagnosticBuilder<'tcx>, - span: Span, - trait_ref: &ty::Binder<ty::TraitRef<'tcx>>, - ) { - let hir = self.tcx.hir(); - let parent_node = hir.get_parent_node(obligation.cause.body_id); - let node = hir.find(parent_node); - if let Some(hir::Node::Item(hir::Item { - kind: hir::ItemKind::Fn(sig, _, body_id), .. - })) = node - { - let body = hir.body(*body_id); - if let hir::ExprKind::Block(blk, _) = &body.value.kind { - if sig.decl.output.span().overlaps(span) - && blk.expr.is_none() - && "()" == &trait_ref.self_ty().to_string() - { - // FIXME(estebank): When encountering a method with a trait - // bound not satisfied in the return type with a body that has - // no return, suggest removal of semicolon on last statement. - // Once that is added, close #54771. - if let Some(ref stmt) = blk.stmts.last() { - let sp = self.tcx.sess.source_map().end_point(stmt.span); - err.span_label(sp, "consider removing this semicolon"); - } - } - } - } - } - - /// If all conditions are met to identify a returned `dyn Trait`, suggest using `impl Trait` if - /// applicable and signal that the error has been expanded appropriately and needs to be - /// emitted. - crate fn suggest_impl_trait( - &self, - err: &mut DiagnosticBuilder<'tcx>, - span: Span, - obligation: &PredicateObligation<'tcx>, - trait_ref: &ty::Binder<ty::TraitRef<'tcx>>, - ) -> bool { - match obligation.cause.code.peel_derives() { - // Only suggest `impl Trait` if the return type is unsized because it is `dyn Trait`. - ObligationCauseCode::SizedReturnType => {} - _ => return false, - } - - let hir = self.tcx.hir(); - let parent_node = hir.get_parent_node(obligation.cause.body_id); - let node = hir.find(parent_node); - let (sig, body_id) = if let Some(hir::Node::Item(hir::Item { - kind: hir::ItemKind::Fn(sig, _, body_id), - .. - })) = node - { - (sig, body_id) - } else { - return false; - }; - let body = hir.body(*body_id); - let trait_ref = self.resolve_vars_if_possible(trait_ref); - let ty = trait_ref.skip_binder().self_ty(); - let is_object_safe = match ty.kind { - ty::Dynamic(predicates, _) => { - // If the `dyn Trait` is not object safe, do not suggest `Box<dyn Trait>`. - predicates - .principal_def_id() - .map_or(true, |def_id| self.tcx.object_safety_violations(def_id).is_empty()) - } - // We only want to suggest `impl Trait` to `dyn Trait`s. - // For example, `fn foo() -> str` needs to be filtered out. - _ => return false, - }; - - let ret_ty = if let hir::FnRetTy::Return(ret_ty) = sig.decl.output { - ret_ty - } else { - return false; - }; - - // Use `TypeVisitor` instead of the output type directly to find the span of `ty` for - // cases like `fn foo() -> (dyn Trait, i32) {}`. - // Recursively look for `TraitObject` types and if there's only one, use that span to - // suggest `impl Trait`. - - // Visit to make sure there's a single `return` type to suggest `impl Trait`, - // otherwise suggest using `Box<dyn Trait>` or an enum. - let mut visitor = ReturnsVisitor::default(); - visitor.visit_body(&body); - - let tables = self.in_progress_tables.map(|t| t.borrow()).unwrap(); - - let mut ret_types = visitor - .returns - .iter() - .filter_map(|expr| tables.node_type_opt(expr.hir_id)) - .map(|ty| self.resolve_vars_if_possible(&ty)); - let (last_ty, all_returns_have_same_type) = ret_types.clone().fold( - (None, true), - |(last_ty, mut same): (std::option::Option<Ty<'_>>, bool), ty| { - let ty = self.resolve_vars_if_possible(&ty); - same &= last_ty.map_or(true, |last_ty| last_ty == ty) && ty.kind != ty::Error; - (Some(ty), same) - }, - ); - let all_returns_conform_to_trait = - if let Some(ty_ret_ty) = tables.node_type_opt(ret_ty.hir_id) { - match ty_ret_ty.kind { - ty::Dynamic(predicates, _) => { - let cause = ObligationCause::misc(ret_ty.span, ret_ty.hir_id); - let param_env = ty::ParamEnv::empty(); - ret_types.all(|returned_ty| { - predicates.iter().all(|predicate| { - let pred = predicate.with_self_ty(self.tcx, returned_ty); - let obl = Obligation::new(cause.clone(), param_env, pred); - self.predicate_may_hold(&obl) - }) - }) - } - _ => false, - } - } else { - true - }; - - let (snippet, last_ty) = - if let (true, hir::TyKind::TraitObject(..), Ok(snippet), true, Some(last_ty)) = ( - // Verify that we're dealing with a return `dyn Trait` - ret_ty.span.overlaps(span), - &ret_ty.kind, - self.tcx.sess.source_map().span_to_snippet(ret_ty.span), - // If any of the return types does not conform to the trait, then we can't - // suggest `impl Trait` nor trait objects, it is a type mismatch error. - all_returns_conform_to_trait, - last_ty, - ) { - (snippet, last_ty) - } else { - return false; - }; - err.code(error_code!(E0746)); - err.set_primary_message("return type cannot have an unboxed trait object"); - err.children.clear(); - let impl_trait_msg = "for information on `impl Trait`, see \ - <https://doc.rust-lang.org/book/ch10-02-traits.html\ - #returning-types-that-implement-traits>"; - let trait_obj_msg = "for information on trait objects, see \ - <https://doc.rust-lang.org/book/ch17-02-trait-objects.html\ - #using-trait-objects-that-allow-for-values-of-different-types>"; - let has_dyn = snippet.split_whitespace().next().map_or(false, |s| s == "dyn"); - let trait_obj = if has_dyn { &snippet[4..] } else { &snippet[..] }; - if all_returns_have_same_type { - // Suggest `-> impl Trait`. - err.span_suggestion( - ret_ty.span, - &format!( - "return `impl {1}` instead, as all return paths are of type `{}`, \ - which implements `{1}`", - last_ty, trait_obj, - ), - format!("impl {}", trait_obj), - Applicability::MachineApplicable, - ); - err.note(impl_trait_msg); - } else { - if is_object_safe { - // Suggest `-> Box<dyn Trait>` and `Box::new(returned_value)`. - // Get all the return values and collect their span and suggestion. - let mut suggestions = visitor - .returns - .iter() - .map(|expr| { - ( - expr.span, - format!( - "Box::new({})", - self.tcx.sess.source_map().span_to_snippet(expr.span).unwrap() - ), - ) - }) - .collect::<Vec<_>>(); - // Add the suggestion for the return type. - suggestions.push((ret_ty.span, format!("Box<dyn {}>", trait_obj))); - err.multipart_suggestion( - "return a boxed trait object instead", - suggestions, - Applicability::MaybeIncorrect, - ); - } else { - // This is currently not possible to trigger because E0038 takes precedence, but - // leave it in for completeness in case anything changes in an earlier stage. - err.note(&format!( - "if trait `{}` was object safe, you could return a trait object", - trait_obj, - )); - } - err.note(trait_obj_msg); - err.note(&format!( - "if all the returned values were of the same type you could use \ - `impl {}` as the return type", - trait_obj, - )); - err.note(impl_trait_msg); - err.note("you can create a new `enum` with a variant for each returned type"); - } - true - } - - crate fn point_at_returns_when_relevant( - &self, - err: &mut DiagnosticBuilder<'tcx>, - obligation: &PredicateObligation<'tcx>, - ) { - match obligation.cause.code.peel_derives() { - ObligationCauseCode::SizedReturnType => {} - _ => return, - } - - let hir = self.tcx.hir(); - let parent_node = hir.get_parent_node(obligation.cause.body_id); - let node = hir.find(parent_node); - if let Some(hir::Node::Item(hir::Item { kind: hir::ItemKind::Fn(_, _, body_id), .. })) = - node - { - let body = hir.body(*body_id); - // Point at all the `return`s in the function as they have failed trait bounds. - let mut visitor = ReturnsVisitor::default(); - visitor.visit_body(&body); - let tables = self.in_progress_tables.map(|t| t.borrow()).unwrap(); - for expr in &visitor.returns { - if let Some(returned_ty) = tables.node_type_opt(expr.hir_id) { - let ty = self.resolve_vars_if_possible(&returned_ty); - err.span_label(expr.span, &format!("this returned value is of type `{}`", ty)); - } - } - } - } - - /// Given some node representing a fn-like thing in the HIR map, - /// returns a span and `ArgKind` information that describes the - /// arguments it expects. This can be supplied to - /// `report_arg_count_mismatch`. - pub fn get_fn_like_arguments(&self, node: Node<'_>) -> (Span, Vec<ArgKind>) { - match node { - Node::Expr(&hir::Expr { - kind: hir::ExprKind::Closure(_, ref _decl, id, span, _), - .. - }) => ( - self.tcx.sess.source_map().def_span(span), - self.tcx - .hir() - .body(id) - .params - .iter() - .map(|arg| { - if let hir::Pat { kind: hir::PatKind::Tuple(ref args, _), span, .. } = - *arg.pat - { - ArgKind::Tuple( - Some(span), - args.iter() - .map(|pat| { - let snippet = self - .tcx - .sess - .source_map() - .span_to_snippet(pat.span) - .unwrap(); - (snippet, "_".to_owned()) - }) - .collect::<Vec<_>>(), - ) - } else { - let name = - self.tcx.sess.source_map().span_to_snippet(arg.pat.span).unwrap(); - ArgKind::Arg(name, "_".to_owned()) - } - }) - .collect::<Vec<ArgKind>>(), - ), - Node::Item(&hir::Item { span, kind: hir::ItemKind::Fn(ref sig, ..), .. }) - | Node::ImplItem(&hir::ImplItem { - span, - kind: hir::ImplItemKind::Method(ref sig, _), - .. - }) - | Node::TraitItem(&hir::TraitItem { - span, - kind: hir::TraitItemKind::Method(ref sig, _), - .. - }) => ( - self.tcx.sess.source_map().def_span(span), - sig.decl - .inputs - .iter() - .map(|arg| match arg.clone().kind { - hir::TyKind::Tup(ref tys) => ArgKind::Tuple( - Some(arg.span), - vec![("_".to_owned(), "_".to_owned()); tys.len()], - ), - _ => ArgKind::empty(), - }) - .collect::<Vec<ArgKind>>(), - ), - Node::Ctor(ref variant_data) => { - let span = variant_data - .ctor_hir_id() - .map(|hir_id| self.tcx.hir().span(hir_id)) - .unwrap_or(DUMMY_SP); - let span = self.tcx.sess.source_map().def_span(span); - - (span, vec![ArgKind::empty(); variant_data.fields().len()]) - } - _ => panic!("non-FnLike node found: {:?}", node), - } - } - - /// Reports an error when the number of arguments needed by a - /// trait match doesn't match the number that the expression - /// provides. - pub fn report_arg_count_mismatch( - &self, - span: Span, - found_span: Option<Span>, - expected_args: Vec<ArgKind>, - found_args: Vec<ArgKind>, - is_closure: bool, - ) -> DiagnosticBuilder<'tcx> { - let kind = if is_closure { "closure" } else { "function" }; - - let args_str = |arguments: &[ArgKind], other: &[ArgKind]| { - let arg_length = arguments.len(); - let distinct = match &other[..] { - &[ArgKind::Tuple(..)] => true, - _ => false, - }; - match (arg_length, arguments.get(0)) { - (1, Some(&ArgKind::Tuple(_, ref fields))) => { - format!("a single {}-tuple as argument", fields.len()) - } - _ => format!( - "{} {}argument{}", - arg_length, - if distinct && arg_length > 1 { "distinct " } else { "" }, - pluralize!(arg_length) - ), - } - }; - - let expected_str = args_str(&expected_args, &found_args); - let found_str = args_str(&found_args, &expected_args); - - let mut err = struct_span_err!( - self.tcx.sess, - span, - E0593, - "{} is expected to take {}, but it takes {}", - kind, - expected_str, - found_str, - ); - - err.span_label(span, format!("expected {} that takes {}", kind, expected_str)); - - if let Some(found_span) = found_span { - err.span_label(found_span, format!("takes {}", found_str)); - - // move |_| { ... } - // ^^^^^^^^-- def_span - // - // move |_| { ... } - // ^^^^^-- prefix - let prefix_span = self.tcx.sess.source_map().span_until_non_whitespace(found_span); - // move |_| { ... } - // ^^^-- pipe_span - let pipe_span = - if let Some(span) = found_span.trim_start(prefix_span) { span } else { found_span }; - - // Suggest to take and ignore the arguments with expected_args_length `_`s if - // found arguments is empty (assume the user just wants to ignore args in this case). - // For example, if `expected_args_length` is 2, suggest `|_, _|`. - if found_args.is_empty() && is_closure { - let underscores = vec!["_"; expected_args.len()].join(", "); - err.span_suggestion( - pipe_span, - &format!( - "consider changing the closure to take and ignore the expected argument{}", - if expected_args.len() < 2 { "" } else { "s" } - ), - format!("|{}|", underscores), - Applicability::MachineApplicable, - ); - } - - if let &[ArgKind::Tuple(_, ref fields)] = &found_args[..] { - if fields.len() == expected_args.len() { - let sugg = fields - .iter() - .map(|(name, _)| name.to_owned()) - .collect::<Vec<String>>() - .join(", "); - err.span_suggestion( - found_span, - "change the closure to take multiple arguments instead of a single tuple", - format!("|{}|", sugg), - Applicability::MachineApplicable, - ); - } - } - if let &[ArgKind::Tuple(_, ref fields)] = &expected_args[..] { - if fields.len() == found_args.len() && is_closure { - let sugg = format!( - "|({}){}|", - found_args - .iter() - .map(|arg| match arg { - ArgKind::Arg(name, _) => name.to_owned(), - _ => "_".to_owned(), - }) - .collect::<Vec<String>>() - .join(", "), - // add type annotations if available - if found_args.iter().any(|arg| match arg { - ArgKind::Arg(_, ty) => ty != "_", - _ => false, - }) { - format!( - ": ({})", - fields - .iter() - .map(|(_, ty)| ty.to_owned()) - .collect::<Vec<String>>() - .join(", ") - ) - } else { - String::new() - }, - ); - err.span_suggestion( - found_span, - "change the closure to accept a tuple instead of individual arguments", - sugg, - Applicability::MachineApplicable, - ); - } - } - } - - err - } - - crate fn report_closure_arg_mismatch( - &self, - span: Span, - found_span: Option<Span>, - expected_ref: ty::PolyTraitRef<'tcx>, - found: ty::PolyTraitRef<'tcx>, - ) -> DiagnosticBuilder<'tcx> { - crate fn build_fn_sig_string<'tcx>( - tcx: TyCtxt<'tcx>, - trait_ref: &ty::TraitRef<'tcx>, - ) -> String { - let inputs = trait_ref.substs.type_at(1); - let sig = if let ty::Tuple(inputs) = inputs.kind { - tcx.mk_fn_sig( - inputs.iter().map(|k| k.expect_ty()), - tcx.mk_ty_infer(ty::TyVar(ty::TyVid { index: 0 })), - false, - hir::Unsafety::Normal, - ::rustc_target::spec::abi::Abi::Rust, - ) - } else { - tcx.mk_fn_sig( - ::std::iter::once(inputs), - tcx.mk_ty_infer(ty::TyVar(ty::TyVid { index: 0 })), - false, - hir::Unsafety::Normal, - ::rustc_target::spec::abi::Abi::Rust, - ) - }; - ty::Binder::bind(sig).to_string() - } - - let argument_is_closure = expected_ref.skip_binder().substs.type_at(0).is_closure(); - let mut err = struct_span_err!( - self.tcx.sess, - span, - E0631, - "type mismatch in {} arguments", - if argument_is_closure { "closure" } else { "function" } - ); - - let found_str = format!( - "expected signature of `{}`", - build_fn_sig_string(self.tcx, found.skip_binder()) - ); - err.span_label(span, found_str); - - let found_span = found_span.unwrap_or(span); - let expected_str = format!( - "found signature of `{}`", - build_fn_sig_string(self.tcx, expected_ref.skip_binder()) - ); - err.span_label(found_span, expected_str); - - err - } -} - -impl<'a, 'tcx> InferCtxt<'a, 'tcx> { - crate fn suggest_fully_qualified_path( - &self, - err: &mut DiagnosticBuilder<'_>, - def_id: DefId, - span: Span, - trait_ref: DefId, - ) { - if let Some(assoc_item) = self.tcx.opt_associated_item(def_id) { - if let ty::AssocKind::Const | ty::AssocKind::Type = assoc_item.kind { - err.note(&format!( - "{}s cannot be accessed directly on a `trait`, they can only be \ - accessed through a specific `impl`", - assoc_item.kind.suggestion_descr(), - )); - err.span_suggestion( - span, - "use the fully qualified path to an implementation", - format!("<Type as {}>::{}", self.tcx.def_path_str(trait_ref), assoc_item.ident), - Applicability::HasPlaceholders, - ); - } - } - } - - /// Adds an async-await specific note to the diagnostic when the future does not implement - /// an auto trait because of a captured type. - /// - /// ```ignore (diagnostic) - /// note: future does not implement `Qux` as this value is used across an await - /// --> $DIR/issue-64130-3-other.rs:17:5 - /// | - /// LL | let x = Foo; - /// | - has type `Foo` - /// LL | baz().await; - /// | ^^^^^^^^^^^ await occurs here, with `x` maybe used later - /// LL | } - /// | - `x` is later dropped here - /// ``` - /// - /// When the diagnostic does not implement `Send` or `Sync` specifically, then the diagnostic - /// is "replaced" with a different message and a more specific error. - /// - /// ```ignore (diagnostic) - /// error: future cannot be sent between threads safely - /// --> $DIR/issue-64130-2-send.rs:21:5 - /// | - /// LL | fn is_send<T: Send>(t: T) { } - /// | ------- ---- required by this bound in `is_send` - /// ... - /// LL | is_send(bar()); - /// | ^^^^^^^ future returned by `bar` is not send - /// | - /// = help: within `impl std::future::Future`, the trait `std::marker::Send` is not - /// implemented for `Foo` - /// note: future is not send as this value is used across an await - /// --> $DIR/issue-64130-2-send.rs:15:5 - /// | - /// LL | let x = Foo; - /// | - has type `Foo` - /// LL | baz().await; - /// | ^^^^^^^^^^^ await occurs here, with `x` maybe used later - /// LL | } - /// | - `x` is later dropped here - /// ``` - /// - /// Returns `true` if an async-await specific note was added to the diagnostic. - crate fn maybe_note_obligation_cause_for_async_await( - &self, - err: &mut DiagnosticBuilder<'_>, - obligation: &PredicateObligation<'tcx>, - ) -> bool { - debug!( - "maybe_note_obligation_cause_for_async_await: obligation.predicate={:?} \ - obligation.cause.span={:?}", - obligation.predicate, obligation.cause.span - ); - let source_map = self.tcx.sess.source_map(); - - // Attempt to detect an async-await error by looking at the obligation causes, looking - // for a generator to be present. - // - // When a future does not implement a trait because of a captured type in one of the - // generators somewhere in the call stack, then the result is a chain of obligations. - // - // Given a `async fn` A that calls a `async fn` B which captures a non-send type and that - // future is passed as an argument to a function C which requires a `Send` type, then the - // chain looks something like this: - // - // - `BuiltinDerivedObligation` with a generator witness (B) - // - `BuiltinDerivedObligation` with a generator (B) - // - `BuiltinDerivedObligation` with `std::future::GenFuture` (B) - // - `BuiltinDerivedObligation` with `impl std::future::Future` (B) - // - `BuiltinDerivedObligation` with `impl std::future::Future` (B) - // - `BuiltinDerivedObligation` with a generator witness (A) - // - `BuiltinDerivedObligation` with a generator (A) - // - `BuiltinDerivedObligation` with `std::future::GenFuture` (A) - // - `BuiltinDerivedObligation` with `impl std::future::Future` (A) - // - `BuiltinDerivedObligation` with `impl std::future::Future` (A) - // - `BindingObligation` with `impl_send (Send requirement) - // - // The first obligation in the chain is the most useful and has the generator that captured - // the type. The last generator has information about where the bound was introduced. At - // least one generator should be present for this diagnostic to be modified. - let (mut trait_ref, mut target_ty) = match obligation.predicate { - ty::Predicate::Trait(p, _) => { - (Some(p.skip_binder().trait_ref), Some(p.skip_binder().self_ty())) - } - _ => (None, None), - }; - let mut generator = None; - let mut last_generator = None; - let mut next_code = Some(&obligation.cause.code); - while let Some(code) = next_code { - debug!("maybe_note_obligation_cause_for_async_await: code={:?}", code); - match code { - ObligationCauseCode::BuiltinDerivedObligation(derived_obligation) - | ObligationCauseCode::ImplDerivedObligation(derived_obligation) => { - let ty = derived_obligation.parent_trait_ref.self_ty(); - debug!( - "maybe_note_obligation_cause_for_async_await: \ - parent_trait_ref={:?} self_ty.kind={:?}", - derived_obligation.parent_trait_ref, ty.kind - ); - - match ty.kind { - ty::Generator(did, ..) => { - generator = generator.or(Some(did)); - last_generator = Some(did); - } - ty::GeneratorWitness(..) => {} - _ if generator.is_none() => { - trait_ref = Some(*derived_obligation.parent_trait_ref.skip_binder()); - target_ty = Some(ty); - } - _ => {} - } - - next_code = Some(derived_obligation.parent_code.as_ref()); - } - _ => break, - } - } - - // Only continue if a generator was found. - debug!( - "maybe_note_obligation_cause_for_async_await: generator={:?} trait_ref={:?} \ - target_ty={:?}", - generator, trait_ref, target_ty - ); - let (generator_did, trait_ref, target_ty) = match (generator, trait_ref, target_ty) { - (Some(generator_did), Some(trait_ref), Some(target_ty)) => { - (generator_did, trait_ref, target_ty) - } - _ => return false, - }; - - let span = self.tcx.def_span(generator_did); - - // Do not ICE on closure typeck (#66868). - if self.tcx.hir().as_local_hir_id(generator_did).is_none() { - return false; - } - - // Get the tables from the infcx if the generator is the function we are - // currently type-checking; otherwise, get them by performing a query. - // This is needed to avoid cycles. - let in_progress_tables = self.in_progress_tables.map(|t| t.borrow()); - let generator_did_root = self.tcx.closure_base_def_id(generator_did); - debug!( - "maybe_note_obligation_cause_for_async_await: generator_did={:?} \ - generator_did_root={:?} in_progress_tables.local_id_root={:?} span={:?}", - generator_did, - generator_did_root, - in_progress_tables.as_ref().map(|t| t.local_id_root), - span - ); - let query_tables; - let tables: &TypeckTables<'tcx> = match &in_progress_tables { - Some(t) if t.local_id_root == Some(generator_did_root) => t, - _ => { - query_tables = self.tcx.typeck_tables_of(generator_did); - &query_tables - } - }; - - // Look for a type inside the generator interior that matches the target type to get - // a span. - let target_ty_erased = self.tcx.erase_regions(&target_ty); - let target_span = tables - .generator_interior_types - .iter() - .find(|ty::GeneratorInteriorTypeCause { ty, .. }| { - // Careful: the regions for types that appear in the - // generator interior are not generally known, so we - // want to erase them when comparing (and anyway, - // `Send` and other bounds are generally unaffected by - // the choice of region). When erasing regions, we - // also have to erase late-bound regions. This is - // because the types that appear in the generator - // interior generally contain "bound regions" to - // represent regions that are part of the suspended - // generator frame. Bound regions are preserved by - // `erase_regions` and so we must also call - // `erase_late_bound_regions`. - let ty_erased = self.tcx.erase_late_bound_regions(&ty::Binder::bind(*ty)); - let ty_erased = self.tcx.erase_regions(&ty_erased); - let eq = ty::TyS::same_type(ty_erased, target_ty_erased); - debug!( - "maybe_note_obligation_cause_for_async_await: ty_erased={:?} \ - target_ty_erased={:?} eq={:?}", - ty_erased, target_ty_erased, eq - ); - eq - }) - .map(|ty::GeneratorInteriorTypeCause { span, scope_span, expr, .. }| { - (span, source_map.span_to_snippet(*span), scope_span, expr) - }); - - debug!( - "maybe_note_obligation_cause_for_async_await: target_ty={:?} \ - generator_interior_types={:?} target_span={:?}", - target_ty, tables.generator_interior_types, target_span - ); - if let Some((target_span, Ok(snippet), scope_span, expr)) = target_span { - self.note_obligation_cause_for_async_await( - err, - *target_span, - scope_span, - *expr, - snippet, - generator_did, - last_generator, - trait_ref, - target_ty, - tables, - obligation, - next_code, - ); - true - } else { - false - } - } - - /// Unconditionally adds the diagnostic note described in - /// `maybe_note_obligation_cause_for_async_await`'s documentation comment. - crate fn note_obligation_cause_for_async_await( - &self, - err: &mut DiagnosticBuilder<'_>, - target_span: Span, - scope_span: &Option<Span>, - expr: Option<hir::HirId>, - snippet: String, - first_generator: DefId, - last_generator: Option<DefId>, - trait_ref: ty::TraitRef<'_>, - target_ty: Ty<'tcx>, - tables: &ty::TypeckTables<'_>, - obligation: &PredicateObligation<'tcx>, - next_code: Option<&ObligationCauseCode<'tcx>>, - ) { - let source_map = self.tcx.sess.source_map(); - - let is_async_fn = self - .tcx - .parent(first_generator) - .map(|parent_did| self.tcx.asyncness(parent_did)) - .map(|parent_asyncness| parent_asyncness == hir::IsAsync::Async) - .unwrap_or(false); - let is_async_move = self - .tcx - .hir() - .as_local_hir_id(first_generator) - .and_then(|hir_id| self.tcx.hir().maybe_body_owned_by(hir_id)) - .map(|body_id| self.tcx.hir().body(body_id)) - .and_then(|body| body.generator_kind()) - .map(|generator_kind| match generator_kind { - hir::GeneratorKind::Async(..) => true, - _ => false, - }) - .unwrap_or(false); - let await_or_yield = if is_async_fn || is_async_move { "await" } else { "yield" }; - - // Special case the primary error message when send or sync is the trait that was - // not implemented. - let is_send = self.tcx.is_diagnostic_item(sym::send_trait, trait_ref.def_id); - let is_sync = self.tcx.is_diagnostic_item(sym::sync_trait, trait_ref.def_id); - let hir = self.tcx.hir(); - let trait_explanation = if is_send || is_sync { - let (trait_name, trait_verb) = - if is_send { ("`Send`", "sent") } else { ("`Sync`", "shared") }; - - err.clear_code(); - err.set_primary_message(format!( - "future cannot be {} between threads safely", - trait_verb - )); - - let original_span = err.span.primary_span().unwrap(); - let mut span = MultiSpan::from_span(original_span); - - let message = if let Some(name) = last_generator - .and_then(|generator_did| self.tcx.parent(generator_did)) - .and_then(|parent_did| hir.as_local_hir_id(parent_did)) - .and_then(|parent_hir_id| hir.opt_name(parent_hir_id)) - { - format!("future returned by `{}` is not {}", name, trait_name) - } else { - format!("future is not {}", trait_name) - }; - - span.push_span_label(original_span, message); - err.set_span(span); - - format!("is not {}", trait_name) - } else { - format!("does not implement `{}`", trait_ref.print_only_trait_path()) - }; - - // Look at the last interior type to get a span for the `.await`. - let await_span = tables.generator_interior_types.iter().map(|t| t.span).last().unwrap(); - let mut span = MultiSpan::from_span(await_span); - span.push_span_label( - await_span, - format!("{} occurs here, with `{}` maybe used later", await_or_yield, snippet), - ); - - span.push_span_label(target_span, format!("has type `{}`", target_ty)); - - // If available, use the scope span to annotate the drop location. - if let Some(scope_span) = scope_span { - span.push_span_label( - source_map.end_point(*scope_span), - format!("`{}` is later dropped here", snippet), - ); - } - - err.span_note( - span, - &format!( - "future {} as this value is used across an {}", - trait_explanation, await_or_yield, - ), - ); - - if let Some(expr_id) = expr { - let expr = hir.expect_expr(expr_id); - debug!("target_ty evaluated from {:?}", expr); - - let parent = hir.get_parent_node(expr_id); - if let Some(hir::Node::Expr(e)) = hir.find(parent) { - let parent_span = hir.span(parent); - let parent_did = parent.owner_def_id(); - // ```rust - // impl T { - // fn foo(&self) -> i32 {} - // } - // T.foo(); - // ^^^^^^^ a temporary `&T` created inside this method call due to `&self` - // ``` - // - let is_region_borrow = - tables.expr_adjustments(expr).iter().any(|adj| adj.is_region_borrow()); - - // ```rust - // struct Foo(*const u8); - // bar(Foo(std::ptr::null())).await; - // ^^^^^^^^^^^^^^^^^^^^^ raw-ptr `*T` created inside this struct ctor. - // ``` - debug!("parent_def_kind: {:?}", self.tcx.def_kind(parent_did)); - let is_raw_borrow_inside_fn_like_call = match self.tcx.def_kind(parent_did) { - Some(DefKind::Fn) | Some(DefKind::Ctor(..)) => target_ty.is_unsafe_ptr(), - _ => false, - }; - - if (tables.is_method_call(e) && is_region_borrow) - || is_raw_borrow_inside_fn_like_call - { - err.span_help( - parent_span, - "consider moving this into a `let` \ - binding to create a shorter lived borrow", - ); - } - } - } - - // Add a note for the item obligation that remains - normally a note pointing to the - // bound that introduced the obligation (e.g. `T: Send`). - debug!("note_obligation_cause_for_async_await: next_code={:?}", next_code); - self.note_obligation_cause_code( - err, - &obligation.predicate, - next_code.unwrap(), - &mut Vec::new(), - ); - } - - crate fn note_obligation_cause_code<T>( - &self, - err: &mut DiagnosticBuilder<'_>, - predicate: &T, - cause_code: &ObligationCauseCode<'tcx>, - obligated_types: &mut Vec<&ty::TyS<'tcx>>, - ) where - T: fmt::Display, - { - let tcx = self.tcx; - match *cause_code { - ObligationCauseCode::ExprAssignable - | ObligationCauseCode::MatchExpressionArm { .. } - | ObligationCauseCode::Pattern { .. } - | ObligationCauseCode::IfExpression { .. } - | ObligationCauseCode::IfExpressionWithNoElse - | ObligationCauseCode::MainFunctionType - | ObligationCauseCode::StartFunctionType - | ObligationCauseCode::IntrinsicType - | ObligationCauseCode::MethodReceiver - | ObligationCauseCode::ReturnNoExpression - | ObligationCauseCode::MiscObligation => {} - ObligationCauseCode::SliceOrArrayElem => { - err.note("slice and array elements must have `Sized` type"); - } - ObligationCauseCode::TupleElem => { - err.note("only the last element of a tuple may have a dynamically sized type"); - } - ObligationCauseCode::ProjectionWf(data) => { - err.note(&format!("required so that the projection `{}` is well-formed", data,)); - } - ObligationCauseCode::ReferenceOutlivesReferent(ref_ty) => { - err.note(&format!( - "required so that reference `{}` does not outlive its referent", - ref_ty, - )); - } - ObligationCauseCode::ObjectTypeBound(object_ty, region) => { - err.note(&format!( - "required so that the lifetime bound of `{}` for `{}` is satisfied", - region, object_ty, - )); - } - ObligationCauseCode::ItemObligation(item_def_id) => { - let item_name = tcx.def_path_str(item_def_id); - let msg = format!("required by `{}`", item_name); - - if let Some(sp) = tcx.hir().span_if_local(item_def_id) { - let sp = tcx.sess.source_map().def_span(sp); - err.span_label(sp, &msg); - } else { - err.note(&msg); - } - } - ObligationCauseCode::BindingObligation(item_def_id, span) => { - let item_name = tcx.def_path_str(item_def_id); - let msg = format!("required by this bound in `{}`", item_name); - if let Some(ident) = tcx.opt_item_name(item_def_id) { - err.span_label(ident.span, ""); - } - if span != DUMMY_SP { - err.span_label(span, &msg); - } else { - err.note(&msg); - } - } - ObligationCauseCode::ObjectCastObligation(object_ty) => { - err.note(&format!( - "required for the cast to the object type `{}`", - self.ty_to_string(object_ty) - )); - } - ObligationCauseCode::Coercion { source: _, target } => { - err.note(&format!("required by cast to type `{}`", self.ty_to_string(target))); - } - ObligationCauseCode::RepeatVec(suggest_const_in_array_repeat_expressions) => { - err.note( - "the `Copy` trait is required because the repeated element will be copied", - ); - if suggest_const_in_array_repeat_expressions { - err.note( - "this array initializer can be evaluated at compile-time, see issue \ - #48147 <https://github.com/rust-lang/rust/issues/49147> \ - for more information", - ); - if tcx.sess.opts.unstable_features.is_nightly_build() { - err.help( - "add `#![feature(const_in_array_repeat_expressions)]` to the \ - crate attributes to enable", - ); - } - } - } - ObligationCauseCode::VariableType(_) => { - err.note("all local variables must have a statically known size"); - if !self.tcx.features().unsized_locals { - err.help("unsized locals are gated as an unstable feature"); - } - } - ObligationCauseCode::SizedArgumentType => { - err.note("all function arguments must have a statically known size"); - if !self.tcx.features().unsized_locals { - err.help("unsized locals are gated as an unstable feature"); - } - } - ObligationCauseCode::SizedReturnType => { - err.note("the return type of a function must have a statically known size"); - } - ObligationCauseCode::SizedYieldType => { - err.note("the yield type of a generator must have a statically known size"); - } - ObligationCauseCode::AssignmentLhsSized => { - err.note("the left-hand-side of an assignment must have a statically known size"); - } - ObligationCauseCode::TupleInitializerSized => { - err.note("tuples must have a statically known size to be initialized"); - } - ObligationCauseCode::StructInitializerSized => { - err.note("structs must have a statically known size to be initialized"); - } - ObligationCauseCode::FieldSized { adt_kind: ref item, last } => match *item { - AdtKind::Struct => { - if last { - err.note( - "the last field of a packed struct may only have a \ - dynamically sized type if it does not need drop to be run", - ); - } else { - err.note( - "only the last field of a struct may have a dynamically sized type", - ); - } - } - AdtKind::Union => { - err.note("no field of a union may have a dynamically sized type"); - } - AdtKind::Enum => { - err.note("no field of an enum variant may have a dynamically sized type"); - } - }, - ObligationCauseCode::ConstSized => { - err.note("constant expressions must have a statically known size"); - } - ObligationCauseCode::ConstPatternStructural => { - err.note("constants used for pattern-matching must derive `PartialEq` and `Eq`"); - } - ObligationCauseCode::SharedStatic => { - err.note("shared static variables must have a type that implements `Sync`"); - } - ObligationCauseCode::BuiltinDerivedObligation(ref data) => { - let parent_trait_ref = self.resolve_vars_if_possible(&data.parent_trait_ref); - let ty = parent_trait_ref.skip_binder().self_ty(); - err.note(&format!("required because it appears within the type `{}`", ty)); - obligated_types.push(ty); - - let parent_predicate = parent_trait_ref.without_const().to_predicate(); - if !self.is_recursive_obligation(obligated_types, &data.parent_code) { - self.note_obligation_cause_code( - err, - &parent_predicate, - &data.parent_code, - obligated_types, - ); - } - } - ObligationCauseCode::ImplDerivedObligation(ref data) => { - let parent_trait_ref = self.resolve_vars_if_possible(&data.parent_trait_ref); - err.note(&format!( - "required because of the requirements on the impl of `{}` for `{}`", - parent_trait_ref.print_only_trait_path(), - parent_trait_ref.skip_binder().self_ty() - )); - let parent_predicate = parent_trait_ref.without_const().to_predicate(); - self.note_obligation_cause_code( - err, - &parent_predicate, - &data.parent_code, - obligated_types, - ); - } - ObligationCauseCode::CompareImplMethodObligation { .. } => { - err.note(&format!( - "the requirement `{}` appears on the impl method \ - but not on the corresponding trait method", - predicate - )); - } - ObligationCauseCode::CompareImplTypeObligation { .. } => { - err.note(&format!( - "the requirement `{}` appears on the associated impl type \ - but not on the corresponding associated trait type", - predicate - )); - } - ObligationCauseCode::ReturnType - | ObligationCauseCode::ReturnValue(_) - | ObligationCauseCode::BlockTailExpression(_) => (), - ObligationCauseCode::TrivialBound => { - err.help("see issue #48214"); - if tcx.sess.opts.unstable_features.is_nightly_build() { - err.help("add `#![feature(trivial_bounds)]` to the crate attributes to enable"); - } - } - ObligationCauseCode::AssocTypeBound(ref data) => { - err.span_label(data.original, "associated type defined here"); - if let Some(sp) = data.impl_span { - err.span_label(sp, "in this `impl` item"); - } - for sp in &data.bounds { - err.span_label(*sp, "restricted in this bound"); - } - } - } - } - - crate fn suggest_new_overflow_limit(&self, err: &mut DiagnosticBuilder<'_>) { - let current_limit = self.tcx.sess.recursion_limit.get(); - let suggested_limit = current_limit * 2; - err.help(&format!( - "consider adding a `#![recursion_limit=\"{}\"]` attribute to your crate (`{}`)", - suggested_limit, self.tcx.crate_name, - )); - } -} - -/// Collect all the returned expressions within the input expression. -/// Used to point at the return spans when we want to suggest some change to them. -#[derive(Default)] -struct ReturnsVisitor<'v> { - returns: Vec<&'v hir::Expr<'v>>, - in_block_tail: bool, -} - -impl<'v> Visitor<'v> for ReturnsVisitor<'v> { - type Map = rustc::hir::map::Map<'v>; - - fn nested_visit_map(&mut self) -> hir::intravisit::NestedVisitorMap<'_, Self::Map> { - hir::intravisit::NestedVisitorMap::None - } - - fn visit_expr(&mut self, ex: &'v hir::Expr<'v>) { - // Visit every expression to detect `return` paths, either through the function's tail - // expression or `return` statements. We walk all nodes to find `return` statements, but - // we only care about tail expressions when `in_block_tail` is `true`, which means that - // they're in the return path of the function body. - match ex.kind { - hir::ExprKind::Ret(Some(ex)) => { - self.returns.push(ex); - } - hir::ExprKind::Block(block, _) if self.in_block_tail => { - self.in_block_tail = false; - for stmt in block.stmts { - hir::intravisit::walk_stmt(self, stmt); - } - self.in_block_tail = true; - if let Some(expr) = block.expr { - self.visit_expr(expr); - } - } - hir::ExprKind::Match(_, arms, _) if self.in_block_tail => { - for arm in arms { - self.visit_expr(arm.body); - } - } - // We need to walk to find `return`s in the entire body. - _ if !self.in_block_tail => hir::intravisit::walk_expr(self, ex), - _ => self.returns.push(ex), - } - } - - fn visit_body(&mut self, body: &'v hir::Body<'v>) { - assert!(!self.in_block_tail); - if body.generator_kind().is_none() { - if let hir::ExprKind::Block(block, None) = body.value.kind { - if block.expr.is_some() { - self.in_block_tail = true; - } - } - } - hir::intravisit::walk_body(self, body); - } -} diff --git a/src/librustc_infer/traits/fulfill.rs b/src/librustc_infer/traits/fulfill.rs deleted file mode 100644 index ac9ff484a02..00000000000 --- a/src/librustc_infer/traits/fulfill.rs +++ /dev/null @@ -1,556 +0,0 @@ -use crate::infer::{InferCtxt, ShallowResolver}; -use rustc::ty::error::ExpectedFound; -use rustc::ty::{self, ToPolyTraitRef, Ty, TypeFoldable}; -use rustc_data_structures::obligation_forest::ProcessResult; -use rustc_data_structures::obligation_forest::{DoCompleted, Error, ForestObligation}; -use rustc_data_structures::obligation_forest::{ObligationForest, ObligationProcessor}; -use std::marker::PhantomData; - -use super::engine::{TraitEngine, TraitEngineExt}; -use super::project; -use super::select::SelectionContext; -use super::wf; -use super::CodeAmbiguity; -use super::CodeProjectionError; -use super::CodeSelectionError; -use super::{ConstEvalFailure, Unimplemented}; -use super::{FulfillmentError, FulfillmentErrorCode}; -use super::{ObligationCause, PredicateObligation}; - -impl<'tcx> ForestObligation for PendingPredicateObligation<'tcx> { - /// Note that we include both the `ParamEnv` and the `Predicate`, - /// as the `ParamEnv` can influence whether fulfillment succeeds - /// or fails. - type CacheKey = ty::ParamEnvAnd<'tcx, ty::Predicate<'tcx>>; - - fn as_cache_key(&self) -> Self::CacheKey { - self.obligation.param_env.and(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<PendingPredicateObligation<'tcx>>, - // 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<ty::InferTy>, -} - -// `PendingPredicateObligation` is used a lot. Make sure it doesn't unintentionally get bigger. -#[cfg(target_arch = "x86_64")] -static_assert_size!(PendingPredicateObligation<'_>, 136); - -impl<'a, '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, 'tcx>, - ) -> Result<(), Vec<FulfillmentError<'tcx>>> { - 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 `<SomeType as SomeTrait>::X` by - /// creating a fresh type variable `$0` as well as a projection - /// predicate `<SomeType as SomeTrait>::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( - &mut self, - infcx: &InferCtxt<'_, '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( - &mut self, - infcx: &InferCtxt<'_, '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_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( - &mut self, - infcx: &InferCtxt<'_, 'tcx>, - ) -> Result<(), Vec<FulfillmentError<'tcx>>> { - 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( - &mut self, - infcx: &InferCtxt<'_, 'tcx>, - ) -> Result<(), Vec<FulfillmentError<'tcx>>> { - let mut selcx = SelectionContext::new(infcx); - self.select(&mut selcx) - } - - fn pending_obligations(&self) -> Vec<PredicateObligation<'tcx>> { - self.predicates.map_pending_obligations(|o| o.obligation.clone()) - } -} - -struct FulfillProcessor<'a, 'b, 'tcx> { - selcx: &'a mut SelectionContext<'b, 'tcx>, - register_region_obligations: bool, -} - -fn mk_pending(os: Vec<PredicateObligation<'tcx>>) -> Vec<PendingPredicateObligation<'tcx>> { - os.into_iter() - .map(|o| PendingPredicateObligation { obligation: o, stalled_on: vec![] }) - .collect() -} - -impl<'a, 'b, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'b, '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<Self::Obligation, Self::Error> { - // 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. - let change = match pending_obligation.stalled_on.len() { - // Match arms are in order of frequency, which matters because this - // code is so hot. 1 and 0 dominate; 2+ is fairly rare. - 1 => { - let infer = pending_obligation.stalled_on[0]; - ShallowResolver::new(self.selcx.infcx()).shallow_resolve_changed(infer) - } - 0 => { - // In this case we haven't changed, but wish to make a change. - true - } - _ => { - // This `for` loop was once a call to `all()`, but this lower-level - // form was a perf win. See #64545 for details. - (|| { - for &infer in &pending_obligation.stalled_on { - if ShallowResolver::new(self.selcx.infcx()).shallow_resolve_changed(infer) { - return true; - } - } - false - })() - } - }; - - if !change { - debug!( - "process_predicate: pending obligation {:?} still stalled on {:?}", - self.selcx.infcx().resolve_vars_if_possible(&pending_obligation.obligation), - pending_obligation.stalled_on - ); - return ProcessResult::Unchanged; - } - - // This part of the code is much colder. - - pending_obligation.stalled_on.truncate(0); - - let obligation = &mut pending_obligation.obligation; - - if obligation.predicate.has_infer_types_or_consts() { - obligation.predicate = - self.selcx.infcx().resolve_vars_if_possible(&obligation.predicate); - } - - debug!("process_obligation: obligation = {:?} cause = {:?}", obligation, obligation.cause); - - fn infer_ty(ty: Ty<'tcx>) -> ty::InferTy { - match ty.kind { - ty::Infer(infer) => infer, - _ => panic!(), - } - } - - 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. - 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_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<OutlivesPredicate<Ty, Region>>` to `Binder<Ty>`. - 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().lifetimes.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 wf::obligations( - self.selcx.infcx(), - obligation.param_env, - obligation.cause.body_id, - ty, - obligation.cause.span, - ) { - None => { - pending_obligation.stalled_on = vec![infer_ty(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![ - infer_ty(subtype.skip_binder().a), - infer_ty(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.infcx().const_eval_resolve( - obligation.param_env, - def_id, - substs, - None, - Some(obligation.cause.span), - ) { - Ok(_) => ProcessResult::Changed(vec![]), - Err(err) => ProcessResult::Error(CodeSelectionError(ConstEvalFailure(err))), - } - } - } - } - - fn process_backedge<'c, I>( - &mut self, - cycle: I, - _marker: PhantomData<&'c PendingPredicateObligation<'tcx>>, - ) where - I: Clone + Iterator<Item = &'c PendingPredicateObligation<'tcx>>, - { - 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, 'tcx>( - selcx: &mut SelectionContext<'a, 'tcx>, - t: ty::PolyTraitRef<'tcx>, -) -> Vec<ty::InferTy> { - t.skip_binder() // ok b/c this check doesn't care about regions - .input_types() - .map(|t| selcx.infcx().resolve_vars_if_possible(&t)) - .filter(|t| t.has_infer_types()) - .flat_map(|t| t.walk()) - .filter_map(|t| match t.kind { - ty::Infer(infer) => Some(infer), - _ => None, - }) - .collect() -} - -fn to_fulfillment_error<'tcx>( - error: Error<PendingPredicateObligation<'tcx>, FulfillmentErrorCode<'tcx>>, -) -> FulfillmentError<'tcx> { - let obligation = error.backtrace.into_iter().next().unwrap().obligation; - FulfillmentError::new(obligation, error.error) -} diff --git a/src/librustc_infer/traits/misc.rs b/src/librustc_infer/traits/misc.rs deleted file mode 100644 index 7ab918c159e..00000000000 --- a/src/librustc_infer/traits/misc.rs +++ /dev/null @@ -1,71 +0,0 @@ -//! Miscellaneous type-system utilities that are too small to deserve their own modules. - -use crate::infer::TyCtxtInferExt; -use crate::traits::{self, ObligationCause}; - -use rustc::ty::{self, Ty, TyCtxt, TypeFoldable}; -use rustc_hir as hir; - -#[derive(Clone)] -pub enum CopyImplementationError<'tcx> { - InfrigingFields(Vec<&'tcx ty::FieldDef>), - NotAnAdt, - HasDestructor, -} - -pub fn can_type_implement_copy( - tcx: TyCtxt<'tcx>, - param_env: ty::ParamEnv<'tcx>, - self_type: Ty<'tcx>, -) -> Result<(), CopyImplementationError<'tcx>> { - // FIXME: (@jroesch) float this code up - tcx.infer_ctxt().enter(|infcx| { - let (adt, substs) = match self_type.kind { - // These types used to have a builtin impl. - // Now libcore provides that impl. - ty::Uint(_) - | ty::Int(_) - | ty::Bool - | ty::Float(_) - | ty::Char - | ty::RawPtr(..) - | ty::Never - | ty::Ref(_, _, hir::Mutability::Not) => return Ok(()), - - ty::Adt(adt, substs) => (adt, substs), - - _ => return Err(CopyImplementationError::NotAnAdt), - }; - - let mut infringing = Vec::new(); - for variant in &adt.variants { - for field in &variant.fields { - let ty = field.ty(tcx, substs); - if ty.references_error() { - continue; - } - let span = tcx.def_span(field.did); - let cause = ObligationCause { span, ..ObligationCause::dummy() }; - let ctx = traits::FulfillmentContext::new(); - match traits::fully_normalize(&infcx, ctx, cause, param_env, &ty) { - Ok(ty) => { - if !infcx.type_is_copy_modulo_regions(param_env, ty, span) { - infringing.push(field); - } - } - Err(errors) => { - infcx.report_fulfillment_errors(&errors, None, false); - } - }; - } - } - if !infringing.is_empty() { - return Err(CopyImplementationError::InfrigingFields(infringing)); - } - if adt.has_dtor(tcx) { - return Err(CopyImplementationError::HasDestructor); - } - - Ok(()) - }) -} diff --git a/src/librustc_infer/traits/mod.rs b/src/librustc_infer/traits/mod.rs index 61702d74f1a..758a0b39d43 100644 --- a/src/librustc_infer/traits/mod.rs +++ b/src/librustc_infer/traits/mod.rs @@ -2,113 +2,31 @@ //! //! [rustc guide]: https://rust-lang.github.io/rustc-guide/traits/resolution.html -#[allow(dead_code)] -pub mod auto_trait; -pub mod codegen; -mod coherence; mod engine; pub mod error_reporting; -mod fulfill; -pub mod misc; -mod object_safety; -mod on_unimplemented; mod project; -pub mod query; -mod select; -mod specialize; mod structural_impls; -mod structural_match; -mod util; -pub mod wf; +pub mod util; -use crate::infer::outlives::env::OutlivesEnvironment; -use crate::infer::{InferCtxt, SuppressRegionErrors, TyCtxtInferExt}; -use rustc::middle::region; -use rustc::ty::error::{ExpectedFound, TypeError}; -use rustc::ty::fold::TypeFoldable; -use rustc::ty::subst::{InternalSubsts, SubstsRef}; -use rustc::ty::{self, GenericParamDefKind, ToPredicate, Ty, TyCtxt, WithConstness}; -use rustc::util::common::ErrorReported; use rustc_hir as hir; -use rustc_hir::def_id::DefId; -use rustc_span::{Span, DUMMY_SP}; - -use std::fmt::Debug; +use rustc_middle::ty::error::{ExpectedFound, TypeError}; +use rustc_middle::ty::{self, Ty}; +use rustc_span::Span; pub use self::FulfillmentErrorCode::*; pub use self::ObligationCauseCode::*; pub use self::SelectionError::*; pub use self::Vtable::*; -pub use self::coherence::{add_placeholder_note, orphan_check, overlapping_impls}; -pub use self::coherence::{OrphanCheckErr, OverlapResult}; pub use self::engine::{TraitEngine, TraitEngineExt}; -pub use self::fulfill::{FulfillmentContext, PendingPredicateObligation}; -pub use self::object_safety::astconv_object_safety_violations; -pub use self::object_safety::is_vtable_safe_method; -pub use self::object_safety::MethodViolationCode; -pub use self::object_safety::ObjectSafetyViolation; -pub use self::on_unimplemented::{OnUnimplementedDirective, OnUnimplementedNote}; pub use self::project::MismatchedProjectionTypes; pub use self::project::{ - normalize, normalize_projection_type, normalize_to, poly_project_and_unify_type, -}; -pub use self::project::{Normalized, ProjectionCache, ProjectionCacheSnapshot, Reveal}; -pub use self::select::{EvaluationCache, SelectionCache, SelectionContext}; -pub use self::select::{EvaluationResult, IntercrateAmbiguityCause, OverflowError}; -pub use self::specialize::find_associated_item; -pub use self::specialize::specialization_graph::FutureCompatOverlapError; -pub use self::specialize::specialization_graph::FutureCompatOverlapErrorKind; -pub use self::specialize::{specialization_graph, translate_substs, OverlapError}; -pub use self::structural_match::search_for_structural_match_violation; -pub use self::structural_match::type_marked_structural; -pub use self::structural_match::NonStructuralMatchTy; -pub use self::util::{elaborate_predicates, elaborate_trait_ref, elaborate_trait_refs}; -pub use self::util::{expand_trait_aliases, TraitAliasExpander}; -pub use self::util::{ - get_vtable_index_of_object_method, impl_is_default, impl_item_is_final, - predicate_for_trait_def, upcast_choices, -}; -pub use self::util::{ - supertrait_def_ids, supertraits, transitive_bounds, SupertraitDefIds, Supertraits, + Normalized, NormalizedTy, ProjectionCache, ProjectionCacheEntry, ProjectionCacheKey, + ProjectionCacheSnapshot, Reveal, }; +crate use self::util::elaborate_predicates; -pub use rustc::traits::*; - -/// Whether to skip the leak check, as part of a future compatibility warning step. -#[derive(Copy, Clone, PartialEq, Eq, Debug)] -pub enum SkipLeakCheck { - Yes, - No, -} - -impl SkipLeakCheck { - fn is_yes(self) -> bool { - self == SkipLeakCheck::Yes - } -} - -/// The "default" for skip-leak-check corresponds to the current -/// behavior (do not skip the leak check) -- not the behavior we are -/// transitioning into. -impl Default for SkipLeakCheck { - fn default() -> Self { - SkipLeakCheck::No - } -} - -/// The mode that trait queries run in. -#[derive(Copy, Clone, PartialEq, Eq, Debug)] -pub enum TraitQueryMode { - // Standard/un-canonicalized queries get accurate - // spans etc. passed in and hence can do reasonable - // error reporting on their own. - Standard, - // Canonicalized queries get dummy spans and hence - // must generally propagate errors to - // pre-canonicalization callsites. - Canonical, -} +pub use rustc_middle::traits::*; /// An `Obligation` represents some trait reference (e.g., `int: Eq`) for /// which the vtable must be found. The process of finding a vtable is @@ -165,418 +83,6 @@ pub enum FulfillmentErrorCode<'tcx> { CodeAmbiguity, } -/// Creates predicate obligations from the generic bounds. -pub fn predicates_for_generics<'tcx>( - cause: ObligationCause<'tcx>, - param_env: ty::ParamEnv<'tcx>, - generic_bounds: &ty::InstantiatedPredicates<'tcx>, -) -> PredicateObligations<'tcx> { - util::predicates_for_generics(cause, 0, param_env, generic_bounds) -} - -/// Determines whether the type `ty` is known to meet `bound` and -/// returns true if so. Returns false if `ty` either does not meet -/// `bound` or is not known to meet bound (note that this is -/// conservative towards *no impl*, which is the opposite of the -/// `evaluate` methods). -pub fn type_known_to_meet_bound_modulo_regions<'a, 'tcx>( - infcx: &InferCtxt<'a, 'tcx>, - param_env: ty::ParamEnv<'tcx>, - ty: Ty<'tcx>, - def_id: DefId, - span: Span, -) -> bool { - debug!( - "type_known_to_meet_bound_modulo_regions(ty={:?}, bound={:?})", - ty, - infcx.tcx.def_path_str(def_id) - ); - - let trait_ref = ty::TraitRef { def_id, substs: infcx.tcx.mk_substs_trait(ty, &[]) }; - let obligation = Obligation { - param_env, - cause: ObligationCause::misc(span, hir::DUMMY_HIR_ID), - recursion_depth: 0, - predicate: trait_ref.without_const().to_predicate(), - }; - - let result = infcx.predicate_must_hold_modulo_regions(&obligation); - debug!( - "type_known_to_meet_ty={:?} bound={} => {:?}", - ty, - infcx.tcx.def_path_str(def_id), - result - ); - - if result && ty.has_infer_types_or_consts() { - // Because of inference "guessing", selection can sometimes claim - // to succeed while the success requires a guess. To ensure - // this function's result remains infallible, we must confirm - // that guess. While imperfect, I believe this is sound. - - // The handling of regions in this area of the code is terrible, - // see issue #29149. We should be able to improve on this with - // NLL. - let mut fulfill_cx = FulfillmentContext::new_ignoring_regions(); - - // We can use a dummy node-id here because we won't pay any mind - // to region obligations that arise (there shouldn't really be any - // anyhow). - let cause = ObligationCause::misc(span, hir::DUMMY_HIR_ID); - - fulfill_cx.register_bound(infcx, param_env, ty, def_id, cause); - - // Note: we only assume something is `Copy` if we can - // *definitively* show that it implements `Copy`. Otherwise, - // assume it is move; linear is always ok. - match fulfill_cx.select_all_or_error(infcx) { - Ok(()) => { - debug!( - "type_known_to_meet_bound_modulo_regions: ty={:?} bound={} success", - ty, - infcx.tcx.def_path_str(def_id) - ); - true - } - Err(e) => { - debug!( - "type_known_to_meet_bound_modulo_regions: ty={:?} bound={} errors={:?}", - ty, - infcx.tcx.def_path_str(def_id), - e - ); - false - } - } - } else { - result - } -} - -fn do_normalize_predicates<'tcx>( - tcx: TyCtxt<'tcx>, - region_context: DefId, - cause: ObligationCause<'tcx>, - elaborated_env: ty::ParamEnv<'tcx>, - predicates: Vec<ty::Predicate<'tcx>>, -) -> Result<Vec<ty::Predicate<'tcx>>, ErrorReported> { - debug!( - "do_normalize_predicates(predicates={:?}, region_context={:?}, cause={:?})", - predicates, region_context, cause, - ); - let span = cause.span; - tcx.infer_ctxt().enter(|infcx| { - // FIXME. We should really... do something with these region - // obligations. But this call just continues the older - // behavior (i.e., doesn't cause any new bugs), and it would - // take some further refactoring to actually solve them. In - // particular, we would have to handle implied bounds - // properly, and that code is currently largely confined to - // regionck (though I made some efforts to extract it - // out). -nmatsakis - // - // @arielby: In any case, these obligations are checked - // by wfcheck anyway, so I'm not sure we have to check - // them here too, and we will remove this function when - // we move over to lazy normalization *anyway*. - let fulfill_cx = FulfillmentContext::new_ignoring_regions(); - let predicates = - match fully_normalize(&infcx, fulfill_cx, cause, elaborated_env, &predicates) { - Ok(predicates) => predicates, - Err(errors) => { - infcx.report_fulfillment_errors(&errors, None, false); - return Err(ErrorReported); - } - }; - - debug!("do_normalize_predictes: normalized predicates = {:?}", predicates); - - let region_scope_tree = region::ScopeTree::default(); - - // We can use the `elaborated_env` here; the region code only - // cares about declarations like `'a: 'b`. - let outlives_env = OutlivesEnvironment::new(elaborated_env); - - infcx.resolve_regions_and_report_errors( - region_context, - ®ion_scope_tree, - &outlives_env, - SuppressRegionErrors::default(), - ); - - let predicates = match infcx.fully_resolve(&predicates) { - Ok(predicates) => predicates, - Err(fixup_err) => { - // If we encounter a fixup error, it means that some type - // variable wound up unconstrained. I actually don't know - // if this can happen, and I certainly don't expect it to - // happen often, but if it did happen it probably - // represents a legitimate failure due to some kind of - // unconstrained variable, and it seems better not to ICE, - // all things considered. - tcx.sess.span_err(span, &fixup_err.to_string()); - return Err(ErrorReported); - } - }; - if predicates.has_local_value() { - // FIXME: shouldn't we, you know, actually report an error here? or an ICE? - Err(ErrorReported) - } else { - Ok(predicates) - } - }) -} - -// FIXME: this is gonna need to be removed ... -/// Normalizes the parameter environment, reporting errors if they occur. -pub fn normalize_param_env_or_error<'tcx>( - tcx: TyCtxt<'tcx>, - region_context: DefId, - unnormalized_env: ty::ParamEnv<'tcx>, - cause: ObligationCause<'tcx>, -) -> ty::ParamEnv<'tcx> { - // I'm not wild about reporting errors here; I'd prefer to - // have the errors get reported at a defined place (e.g., - // during typeck). Instead I have all parameter - // environments, in effect, going through this function - // and hence potentially reporting errors. This ensures of - // course that we never forget to normalize (the - // alternative seemed like it would involve a lot of - // manual invocations of this fn -- and then we'd have to - // deal with the errors at each of those sites). - // - // In any case, in practice, typeck constructs all the - // parameter environments once for every fn as it goes, - // and errors will get reported then; so after typeck we - // can be sure that no errors should occur. - - debug!( - "normalize_param_env_or_error(region_context={:?}, unnormalized_env={:?}, cause={:?})", - region_context, unnormalized_env, cause - ); - - let mut predicates: Vec<_> = - util::elaborate_predicates(tcx, unnormalized_env.caller_bounds.to_vec()).collect(); - - debug!("normalize_param_env_or_error: elaborated-predicates={:?}", predicates); - - let elaborated_env = ty::ParamEnv::new( - tcx.intern_predicates(&predicates), - unnormalized_env.reveal, - unnormalized_env.def_id, - ); - - // HACK: we are trying to normalize the param-env inside *itself*. The problem is that - // normalization expects its param-env to be already normalized, which means we have - // a circularity. - // - // The way we handle this is by normalizing the param-env inside an unnormalized version - // of the param-env, which means that if the param-env contains unnormalized projections, - // we'll have some normalization failures. This is unfortunate. - // - // Lazy normalization would basically handle this by treating just the - // normalizing-a-trait-ref-requires-itself cycles as evaluation failures. - // - // Inferred outlives bounds can create a lot of `TypeOutlives` predicates for associated - // types, so to make the situation less bad, we normalize all the predicates *but* - // the `TypeOutlives` predicates first inside the unnormalized parameter environment, and - // then we normalize the `TypeOutlives` bounds inside the normalized parameter environment. - // - // This works fairly well because trait matching does not actually care about param-env - // TypeOutlives predicates - these are normally used by regionck. - let outlives_predicates: Vec<_> = predicates - .drain_filter(|predicate| match predicate { - ty::Predicate::TypeOutlives(..) => true, - _ => false, - }) - .collect(); - - debug!( - "normalize_param_env_or_error: predicates=(non-outlives={:?}, outlives={:?})", - predicates, outlives_predicates - ); - let non_outlives_predicates = match do_normalize_predicates( - tcx, - region_context, - cause.clone(), - elaborated_env, - predicates, - ) { - Ok(predicates) => predicates, - // An unnormalized env is better than nothing. - Err(ErrorReported) => { - debug!("normalize_param_env_or_error: errored resolving non-outlives predicates"); - return elaborated_env; - } - }; - - debug!("normalize_param_env_or_error: non-outlives predicates={:?}", non_outlives_predicates); - - // Not sure whether it is better to include the unnormalized TypeOutlives predicates - // here. I believe they should not matter, because we are ignoring TypeOutlives param-env - // predicates here anyway. Keeping them here anyway because it seems safer. - let outlives_env: Vec<_> = - non_outlives_predicates.iter().chain(&outlives_predicates).cloned().collect(); - let outlives_env = - ty::ParamEnv::new(tcx.intern_predicates(&outlives_env), unnormalized_env.reveal, None); - let outlives_predicates = match do_normalize_predicates( - tcx, - region_context, - cause, - outlives_env, - outlives_predicates, - ) { - Ok(predicates) => predicates, - // An unnormalized env is better than nothing. - Err(ErrorReported) => { - debug!("normalize_param_env_or_error: errored resolving outlives predicates"); - return elaborated_env; - } - }; - debug!("normalize_param_env_or_error: outlives predicates={:?}", outlives_predicates); - - let mut predicates = non_outlives_predicates; - predicates.extend(outlives_predicates); - debug!("normalize_param_env_or_error: final predicates={:?}", predicates); - ty::ParamEnv::new( - tcx.intern_predicates(&predicates), - unnormalized_env.reveal, - unnormalized_env.def_id, - ) -} - -pub fn fully_normalize<'a, 'tcx, T>( - infcx: &InferCtxt<'a, 'tcx>, - mut fulfill_cx: FulfillmentContext<'tcx>, - cause: ObligationCause<'tcx>, - param_env: ty::ParamEnv<'tcx>, - value: &T, -) -> Result<T, Vec<FulfillmentError<'tcx>>> -where - T: TypeFoldable<'tcx>, -{ - debug!("fully_normalize_with_fulfillcx(value={:?})", value); - let selcx = &mut SelectionContext::new(infcx); - let Normalized { value: normalized_value, obligations } = - project::normalize(selcx, param_env, cause, value); - debug!( - "fully_normalize: normalized_value={:?} obligations={:?}", - normalized_value, obligations - ); - for obligation in obligations { - fulfill_cx.register_predicate_obligation(selcx.infcx(), obligation); - } - - debug!("fully_normalize: select_all_or_error start"); - fulfill_cx.select_all_or_error(infcx)?; - debug!("fully_normalize: select_all_or_error complete"); - let resolved_value = infcx.resolve_vars_if_possible(&normalized_value); - debug!("fully_normalize: resolved_value={:?}", resolved_value); - Ok(resolved_value) -} - -/// Normalizes the predicates and checks whether they hold in an empty -/// environment. If this returns false, then either normalize -/// encountered an error or one of the predicates did not hold. Used -/// when creating vtables to check for unsatisfiable methods. -pub fn normalize_and_test_predicates<'tcx>( - tcx: TyCtxt<'tcx>, - predicates: Vec<ty::Predicate<'tcx>>, -) -> bool { - debug!("normalize_and_test_predicates(predicates={:?})", predicates); - - let result = tcx.infer_ctxt().enter(|infcx| { - let param_env = ty::ParamEnv::reveal_all(); - let mut selcx = SelectionContext::new(&infcx); - let mut fulfill_cx = FulfillmentContext::new(); - let cause = ObligationCause::dummy(); - let Normalized { value: predicates, obligations } = - normalize(&mut selcx, param_env, cause.clone(), &predicates); - for obligation in obligations { - fulfill_cx.register_predicate_obligation(&infcx, obligation); - } - for predicate in predicates { - let obligation = Obligation::new(cause.clone(), param_env, predicate); - fulfill_cx.register_predicate_obligation(&infcx, obligation); - } - - fulfill_cx.select_all_or_error(&infcx).is_ok() - }); - debug!("normalize_and_test_predicates(predicates={:?}) = {:?}", predicates, result); - result -} - -fn substitute_normalize_and_test_predicates<'tcx>( - tcx: TyCtxt<'tcx>, - key: (DefId, SubstsRef<'tcx>), -) -> bool { - debug!("substitute_normalize_and_test_predicates(key={:?})", key); - - let predicates = tcx.predicates_of(key.0).instantiate(tcx, key.1).predicates; - let result = normalize_and_test_predicates(tcx, predicates); - - debug!("substitute_normalize_and_test_predicates(key={:?}) = {:?}", key, result); - result -} - -/// Given a trait `trait_ref`, iterates the vtable entries -/// that come from `trait_ref`, including its supertraits. -#[inline] // FIXME(#35870): avoid closures being unexported due to `impl Trait`. -fn vtable_methods<'tcx>( - tcx: TyCtxt<'tcx>, - trait_ref: ty::PolyTraitRef<'tcx>, -) -> &'tcx [Option<(DefId, SubstsRef<'tcx>)>] { - debug!("vtable_methods({:?})", trait_ref); - - tcx.arena.alloc_from_iter(supertraits(tcx, trait_ref).flat_map(move |trait_ref| { - let trait_methods = tcx - .associated_items(trait_ref.def_id()) - .in_definition_order() - .filter(|item| item.kind == ty::AssocKind::Method); - - // Now list each method's DefId and InternalSubsts (for within its trait). - // If the method can never be called from this object, produce None. - trait_methods.map(move |trait_method| { - debug!("vtable_methods: trait_method={:?}", trait_method); - let def_id = trait_method.def_id; - - // Some methods cannot be called on an object; skip those. - if !is_vtable_safe_method(tcx, trait_ref.def_id(), &trait_method) { - debug!("vtable_methods: not vtable safe"); - return None; - } - - // The method may have some early-bound lifetimes; add regions for those. - let substs = trait_ref.map_bound(|trait_ref| { - InternalSubsts::for_item(tcx, def_id, |param, _| match param.kind { - GenericParamDefKind::Lifetime => tcx.lifetimes.re_erased.into(), - GenericParamDefKind::Type { .. } | GenericParamDefKind::Const => { - trait_ref.substs[param.index as usize] - } - }) - }); - - // The trait type may have higher-ranked lifetimes in it; - // erase them if they appear, so that we get the type - // at some particular call site. - let substs = - tcx.normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), &substs); - - // It's possible that the method relies on where-clauses that - // do not hold for this particular set of type parameters. - // Note that this method could then never be called, so we - // do not want to try and codegen it, in that case (see #23435). - let predicates = tcx.predicates_of(def_id).instantiate_own(tcx, substs); - if !normalize_and_test_predicates(tcx, predicates.predicates) { - debug!("vtable_methods: predicates do not hold"); - return None; - } - - Some((def_id, substs)) - }) - })) -} - impl<'tcx, O> Obligation<'tcx, O> { pub fn new( cause: ObligationCause<'tcx>, @@ -586,7 +92,7 @@ impl<'tcx, O> Obligation<'tcx, O> { Obligation { cause, param_env, recursion_depth: 0, predicate } } - fn with_depth( + pub fn with_depth( cause: ObligationCause<'tcx>, recursion_depth: usize, param_env: ty::ParamEnv<'tcx>, @@ -615,28 +121,16 @@ impl<'tcx, O> Obligation<'tcx, O> { } impl<'tcx> FulfillmentError<'tcx> { - fn new( + pub fn new( obligation: PredicateObligation<'tcx>, code: FulfillmentErrorCode<'tcx>, ) -> FulfillmentError<'tcx> { - FulfillmentError { obligation: obligation, code: code, points_at_arg_span: false } + FulfillmentError { obligation, code, points_at_arg_span: false } } } impl<'tcx> TraitObligation<'tcx> { - fn self_ty(&self) -> ty::Binder<Ty<'tcx>> { + pub fn self_ty(&self) -> ty::Binder<Ty<'tcx>> { self.predicate.map_bound(|p| p.self_ty()) } } - -pub fn provide(providers: &mut ty::query::Providers<'_>) { - object_safety::provide(providers); - *providers = ty::query::Providers { - specialization_graph_of: specialize::specialization_graph_provider, - specializes: specialize::specializes, - codegen_fulfill_obligation: codegen::codegen_fulfill_obligation, - vtable_methods, - substitute_normalize_and_test_predicates, - ..*providers - }; -} diff --git a/src/librustc_infer/traits/object_safety.rs b/src/librustc_infer/traits/object_safety.rs deleted file mode 100644 index f5bab7cfac9..00000000000 --- a/src/librustc_infer/traits/object_safety.rs +++ /dev/null @@ -1,777 +0,0 @@ -//! "Object safety" refers to the ability for a trait to be converted -//! to an object. In general, traits may only be converted to an -//! object if all of their methods meet certain criteria. In particular, -//! they must: -//! -//! - have a suitable receiver from which we can extract a vtable and coerce to a "thin" version -//! that doesn't contain the vtable; -//! - not reference the erased type `Self` except for in this receiver; -//! - not have generic type parameters. - -use super::elaborate_predicates; - -use crate::infer::TyCtxtInferExt; -use crate::traits::{self, Obligation, ObligationCause}; -use rustc::ty::subst::{InternalSubsts, Subst}; -use rustc::ty::{self, Predicate, ToPredicate, Ty, TyCtxt, TypeFoldable, WithConstness}; -use rustc_errors::Applicability; -use rustc_hir as hir; -use rustc_hir::def_id::DefId; -use rustc_session::lint::builtin::WHERE_CLAUSES_OBJECT_SAFETY; -use rustc_span::symbol::Symbol; -use rustc_span::Span; -use smallvec::SmallVec; - -use std::iter; - -pub use crate::traits::{MethodViolationCode, ObjectSafetyViolation}; - -/// Returns the object safety violations that affect -/// astconv -- currently, `Self` in supertraits. This is needed -/// because `object_safety_violations` can't be used during -/// type collection. -pub fn astconv_object_safety_violations( - tcx: TyCtxt<'_>, - trait_def_id: DefId, -) -> Vec<ObjectSafetyViolation> { - debug_assert!(tcx.generics_of(trait_def_id).has_self); - let violations = traits::supertrait_def_ids(tcx, trait_def_id) - .map(|def_id| predicates_reference_self(tcx, def_id, true)) - .filter(|spans| !spans.is_empty()) - .map(|spans| ObjectSafetyViolation::SupertraitSelf(spans)) - .collect(); - - debug!("astconv_object_safety_violations(trait_def_id={:?}) = {:?}", trait_def_id, violations); - - violations -} - -fn object_safety_violations(tcx: TyCtxt<'_>, trait_def_id: DefId) -> Vec<ObjectSafetyViolation> { - debug_assert!(tcx.generics_of(trait_def_id).has_self); - debug!("object_safety_violations: {:?}", trait_def_id); - - traits::supertrait_def_ids(tcx, trait_def_id) - .flat_map(|def_id| object_safety_violations_for_trait(tcx, def_id)) - .collect() -} - -/// We say a method is *vtable safe* if it can be invoked on a trait -/// object. Note that object-safe traits can have some -/// non-vtable-safe methods, so long as they require `Self: Sized` or -/// otherwise ensure that they cannot be used when `Self = Trait`. -pub fn is_vtable_safe_method(tcx: TyCtxt<'_>, trait_def_id: DefId, method: &ty::AssocItem) -> bool { - debug_assert!(tcx.generics_of(trait_def_id).has_self); - debug!("is_vtable_safe_method({:?}, {:?})", trait_def_id, method); - // Any method that has a `Self: Sized` bound cannot be called. - if generics_require_sized_self(tcx, method.def_id) { - return false; - } - - match virtual_call_violation_for_method(tcx, trait_def_id, method) { - None | Some(MethodViolationCode::WhereClauseReferencesSelf) => true, - Some(_) => false, - } -} - -fn object_safety_violations_for_trait( - tcx: TyCtxt<'_>, - trait_def_id: DefId, -) -> Vec<ObjectSafetyViolation> { - // Check methods for violations. - let mut violations: Vec<_> = tcx - .associated_items(trait_def_id) - .in_definition_order() - .filter(|item| item.kind == ty::AssocKind::Method) - .filter_map(|item| { - object_safety_violation_for_method(tcx, trait_def_id, &item) - .map(|(code, span)| ObjectSafetyViolation::Method(item.ident.name, code, span)) - }) - .filter(|violation| { - if let ObjectSafetyViolation::Method( - _, - MethodViolationCode::WhereClauseReferencesSelf, - span, - ) = violation - { - // Using `CRATE_NODE_ID` is wrong, but it's hard to get a more precise id. - // It's also hard to get a use site span, so we use the method definition span. - tcx.struct_span_lint_hir( - WHERE_CLAUSES_OBJECT_SAFETY, - hir::CRATE_HIR_ID, - *span, - |lint| { - let mut err = lint.build(&format!( - "the trait `{}` cannot be made into an object", - tcx.def_path_str(trait_def_id) - )); - let node = tcx.hir().get_if_local(trait_def_id); - let msg = if let Some(hir::Node::Item(item)) = node { - err.span_label( - item.ident.span, - "this trait cannot be made into an object...", - ); - format!("...because {}", violation.error_msg()) - } else { - format!( - "the trait cannot be made into an object because {}", - violation.error_msg() - ) - }; - err.span_label(*span, &msg); - match (node, violation.solution()) { - (Some(_), Some((note, None))) => { - err.help(¬e); - } - (Some(_), Some((note, Some((sugg, span))))) => { - err.span_suggestion( - span, - ¬e, - sugg, - Applicability::MachineApplicable, - ); - } - // Only provide the help if its a local trait, otherwise it's not actionable. - _ => {} - } - err.emit(); - }, - ); - false - } else { - true - } - }) - .collect(); - - // Check the trait itself. - if trait_has_sized_self(tcx, trait_def_id) { - // We don't want to include the requirement from `Sized` itself to be `Sized` in the list. - let spans = get_sized_bounds(tcx, trait_def_id); - violations.push(ObjectSafetyViolation::SizedSelf(spans)); - } - let spans = predicates_reference_self(tcx, trait_def_id, false); - if !spans.is_empty() { - violations.push(ObjectSafetyViolation::SupertraitSelf(spans)); - } - - violations.extend( - tcx.associated_items(trait_def_id) - .in_definition_order() - .filter(|item| item.kind == ty::AssocKind::Const) - .map(|item| ObjectSafetyViolation::AssocConst(item.ident.name, item.ident.span)), - ); - - debug!( - "object_safety_violations_for_trait(trait_def_id={:?}) = {:?}", - trait_def_id, violations - ); - - violations -} - -fn get_sized_bounds(tcx: TyCtxt<'_>, trait_def_id: DefId) -> SmallVec<[Span; 1]> { - tcx.hir() - .get_if_local(trait_def_id) - .and_then(|node| match node { - hir::Node::Item(hir::Item { - kind: hir::ItemKind::Trait(.., generics, bounds, _), - .. - }) => Some( - generics - .where_clause - .predicates - .iter() - .filter_map(|pred| { - match pred { - hir::WherePredicate::BoundPredicate(pred) - if pred.bounded_ty.hir_id.owner_def_id() == trait_def_id => - { - // Fetch spans for trait bounds that are Sized: - // `trait T where Self: Pred` - Some(pred.bounds.iter().filter_map(|b| match b { - hir::GenericBound::Trait( - trait_ref, - hir::TraitBoundModifier::None, - ) if trait_has_sized_self( - tcx, - trait_ref.trait_ref.trait_def_id(), - ) => - { - Some(trait_ref.span) - } - _ => None, - })) - } - _ => None, - } - }) - .flatten() - .chain(bounds.iter().filter_map(|b| match b { - hir::GenericBound::Trait(trait_ref, hir::TraitBoundModifier::None) - if trait_has_sized_self(tcx, trait_ref.trait_ref.trait_def_id()) => - { - // Fetch spans for supertraits that are `Sized`: `trait T: Super` - Some(trait_ref.span) - } - _ => None, - })) - .collect::<SmallVec<[Span; 1]>>(), - ), - _ => None, - }) - .unwrap_or_else(SmallVec::new) -} - -fn predicates_reference_self( - tcx: TyCtxt<'_>, - trait_def_id: DefId, - supertraits_only: bool, -) -> SmallVec<[Span; 1]> { - let trait_ref = ty::Binder::dummy(ty::TraitRef::identity(tcx, trait_def_id)); - let predicates = if supertraits_only { - tcx.super_predicates_of(trait_def_id) - } else { - tcx.predicates_of(trait_def_id) - }; - let self_ty = tcx.types.self_param; - let has_self_ty = |t: Ty<'_>| t.walk().any(|t| t == self_ty); - predicates - .predicates - .iter() - .map(|(predicate, sp)| (predicate.subst_supertrait(tcx, &trait_ref), sp)) - .filter_map(|(predicate, &sp)| { - match predicate { - ty::Predicate::Trait(ref data, _) => { - // In the case of a trait predicate, we can skip the "self" type. - if data.skip_binder().input_types().skip(1).any(has_self_ty) { - Some(sp) - } else { - None - } - } - ty::Predicate::Projection(ref data) => { - // And similarly for projections. This should be redundant with - // the previous check because any projection should have a - // matching `Trait` predicate with the same inputs, but we do - // the check to be safe. - // - // Note that we *do* allow projection *outputs* to contain - // `self` (i.e., `trait Foo: Bar<Output=Self::Result> { type Result; }`), - // we just require the user to specify *both* outputs - // in the object type (i.e., `dyn Foo<Output=(), Result=()>`). - // - // This is ALT2 in issue #56288, see that for discussion of the - // possible alternatives. - if data - .skip_binder() - .projection_ty - .trait_ref(tcx) - .input_types() - .skip(1) - .any(has_self_ty) - { - Some(sp) - } else { - None - } - } - ty::Predicate::WellFormed(..) - | ty::Predicate::ObjectSafe(..) - | ty::Predicate::TypeOutlives(..) - | ty::Predicate::RegionOutlives(..) - | ty::Predicate::ClosureKind(..) - | ty::Predicate::Subtype(..) - | ty::Predicate::ConstEvaluatable(..) => None, - } - }) - .collect() -} - -fn trait_has_sized_self(tcx: TyCtxt<'_>, trait_def_id: DefId) -> bool { - generics_require_sized_self(tcx, trait_def_id) -} - -fn generics_require_sized_self(tcx: TyCtxt<'_>, def_id: DefId) -> bool { - let sized_def_id = match tcx.lang_items().sized_trait() { - Some(def_id) => def_id, - None => { - return false; /* No Sized trait, can't require it! */ - } - }; - - // Search for a predicate like `Self : Sized` amongst the trait bounds. - let predicates = tcx.predicates_of(def_id); - let predicates = predicates.instantiate_identity(tcx).predicates; - elaborate_predicates(tcx, predicates).any(|predicate| match predicate { - ty::Predicate::Trait(ref trait_pred, _) => { - trait_pred.def_id() == sized_def_id && trait_pred.skip_binder().self_ty().is_param(0) - } - ty::Predicate::Projection(..) - | ty::Predicate::Subtype(..) - | ty::Predicate::RegionOutlives(..) - | ty::Predicate::WellFormed(..) - | ty::Predicate::ObjectSafe(..) - | ty::Predicate::ClosureKind(..) - | ty::Predicate::TypeOutlives(..) - | ty::Predicate::ConstEvaluatable(..) => false, - }) -} - -/// Returns `Some(_)` if this method makes the containing trait not object safe. -fn object_safety_violation_for_method( - tcx: TyCtxt<'_>, - trait_def_id: DefId, - method: &ty::AssocItem, -) -> Option<(MethodViolationCode, Span)> { - debug!("object_safety_violation_for_method({:?}, {:?})", trait_def_id, method); - // Any method that has a `Self : Sized` requisite is otherwise - // exempt from the regulations. - if generics_require_sized_self(tcx, method.def_id) { - return None; - } - - let violation = virtual_call_violation_for_method(tcx, trait_def_id, method); - // Get an accurate span depending on the violation. - violation.map(|v| { - let node = tcx.hir().get_if_local(method.def_id); - let span = match (v, node) { - (MethodViolationCode::ReferencesSelfInput(arg), Some(node)) => node - .fn_decl() - .and_then(|decl| decl.inputs.get(arg + 1)) - .map_or(method.ident.span, |arg| arg.span), - (MethodViolationCode::UndispatchableReceiver, Some(node)) => node - .fn_decl() - .and_then(|decl| decl.inputs.get(0)) - .map_or(method.ident.span, |arg| arg.span), - (MethodViolationCode::ReferencesSelfOutput, Some(node)) => { - node.fn_decl().map_or(method.ident.span, |decl| decl.output.span()) - } - _ => method.ident.span, - }; - (v, span) - }) -} - -/// Returns `Some(_)` if this method cannot be called on a trait -/// object; this does not necessarily imply that the enclosing trait -/// is not object safe, because the method might have a where clause -/// `Self:Sized`. -fn virtual_call_violation_for_method<'tcx>( - tcx: TyCtxt<'tcx>, - trait_def_id: DefId, - method: &ty::AssocItem, -) -> Option<MethodViolationCode> { - // The method's first parameter must be named `self` - if !method.method_has_self_argument { - // We'll attempt to provide a structured suggestion for `Self: Sized`. - let sugg = - tcx.hir().get_if_local(method.def_id).as_ref().and_then(|node| node.generics()).map( - |generics| match generics.where_clause.predicates { - [] => (" where Self: Sized", generics.where_clause.span), - [.., pred] => (", Self: Sized", pred.span().shrink_to_hi()), - }, - ); - return Some(MethodViolationCode::StaticMethod(sugg)); - } - - let sig = tcx.fn_sig(method.def_id); - - for (i, input_ty) in sig.skip_binder().inputs()[1..].iter().enumerate() { - if contains_illegal_self_type_reference(tcx, trait_def_id, input_ty) { - return Some(MethodViolationCode::ReferencesSelfInput(i)); - } - } - if contains_illegal_self_type_reference(tcx, trait_def_id, sig.output().skip_binder()) { - return Some(MethodViolationCode::ReferencesSelfOutput); - } - - // We can't monomorphize things like `fn foo<A>(...)`. - let own_counts = tcx.generics_of(method.def_id).own_counts(); - if own_counts.types + own_counts.consts != 0 { - return Some(MethodViolationCode::Generic); - } - - if tcx - .predicates_of(method.def_id) - .predicates - .iter() - // A trait object can't claim to live more than the concrete type, - // so outlives predicates will always hold. - .cloned() - .filter(|(p, _)| p.to_opt_type_outlives().is_none()) - .collect::<Vec<_>>() - // Do a shallow visit so that `contains_illegal_self_type_reference` - // may apply it's custom visiting. - .visit_tys_shallow(|t| contains_illegal_self_type_reference(tcx, trait_def_id, t)) - { - return Some(MethodViolationCode::WhereClauseReferencesSelf); - } - - let receiver_ty = - tcx.liberate_late_bound_regions(method.def_id, &sig.map_bound(|sig| sig.inputs()[0])); - - // Until `unsized_locals` is fully implemented, `self: Self` can't be dispatched on. - // However, this is already considered object-safe. We allow it as a special case here. - // FIXME(mikeyhew) get rid of this `if` statement once `receiver_is_dispatchable` allows - // `Receiver: Unsize<Receiver[Self => dyn Trait]>`. - if receiver_ty != tcx.types.self_param { - if !receiver_is_dispatchable(tcx, method, receiver_ty) { - return Some(MethodViolationCode::UndispatchableReceiver); - } else { - // Do sanity check to make sure the receiver actually has the layout of a pointer. - - use rustc::ty::layout::Abi; - - let param_env = tcx.param_env(method.def_id); - - let abi_of_ty = |ty: Ty<'tcx>| -> &Abi { - match tcx.layout_of(param_env.and(ty)) { - Ok(layout) => &layout.abi, - Err(err) => bug!("error: {}\n while computing layout for type {:?}", err, ty), - } - }; - - // e.g., `Rc<()>` - let unit_receiver_ty = - receiver_for_self_ty(tcx, receiver_ty, tcx.mk_unit(), method.def_id); - - match abi_of_ty(unit_receiver_ty) { - &Abi::Scalar(..) => (), - abi => { - tcx.sess.delay_span_bug( - tcx.def_span(method.def_id), - &format!( - "receiver when `Self = ()` should have a Scalar ABI; found {:?}", - abi - ), - ); - } - } - - let trait_object_ty = - object_ty_for_trait(tcx, trait_def_id, tcx.mk_region(ty::ReStatic)); - - // e.g., `Rc<dyn Trait>` - let trait_object_receiver = - receiver_for_self_ty(tcx, receiver_ty, trait_object_ty, method.def_id); - - match abi_of_ty(trait_object_receiver) { - &Abi::ScalarPair(..) => (), - abi => { - tcx.sess.delay_span_bug( - tcx.def_span(method.def_id), - &format!( - "receiver when `Self = {}` should have a ScalarPair ABI; \ - found {:?}", - trait_object_ty, abi - ), - ); - } - } - } - } - - None -} - -/// Performs a type substitution to produce the version of `receiver_ty` when `Self = self_ty`. -/// For example, for `receiver_ty = Rc<Self>` and `self_ty = Foo`, returns `Rc<Foo>`. -fn receiver_for_self_ty<'tcx>( - tcx: TyCtxt<'tcx>, - receiver_ty: Ty<'tcx>, - self_ty: Ty<'tcx>, - method_def_id: DefId, -) -> Ty<'tcx> { - debug!("receiver_for_self_ty({:?}, {:?}, {:?})", receiver_ty, self_ty, method_def_id); - let substs = InternalSubsts::for_item(tcx, method_def_id, |param, _| { - if param.index == 0 { self_ty.into() } else { tcx.mk_param_from_def(param) } - }); - - let result = receiver_ty.subst(tcx, substs); - debug!( - "receiver_for_self_ty({:?}, {:?}, {:?}) = {:?}", - receiver_ty, self_ty, method_def_id, result - ); - result -} - -/// Creates the object type for the current trait. For example, -/// if the current trait is `Deref`, then this will be -/// `dyn Deref<Target = Self::Target> + 'static`. -fn object_ty_for_trait<'tcx>( - tcx: TyCtxt<'tcx>, - trait_def_id: DefId, - lifetime: ty::Region<'tcx>, -) -> Ty<'tcx> { - debug!("object_ty_for_trait: trait_def_id={:?}", trait_def_id); - - let trait_ref = ty::TraitRef::identity(tcx, trait_def_id); - - let trait_predicate = - ty::ExistentialPredicate::Trait(ty::ExistentialTraitRef::erase_self_ty(tcx, trait_ref)); - - let mut associated_types = traits::supertraits(tcx, ty::Binder::dummy(trait_ref)) - .flat_map(|super_trait_ref| { - tcx.associated_items(super_trait_ref.def_id()) - .in_definition_order() - .map(move |item| (super_trait_ref, item)) - }) - .filter(|(_, item)| item.kind == ty::AssocKind::Type) - .collect::<Vec<_>>(); - - // existential predicates need to be in a specific order - associated_types.sort_by_cached_key(|(_, item)| tcx.def_path_hash(item.def_id)); - - let projection_predicates = associated_types.into_iter().map(|(super_trait_ref, item)| { - // We *can* get bound lifetimes here in cases like - // `trait MyTrait: for<'s> OtherTrait<&'s T, Output=bool>`. - // - // binder moved to (*)... - let super_trait_ref = super_trait_ref.skip_binder(); - ty::ExistentialPredicate::Projection(ty::ExistentialProjection { - ty: tcx.mk_projection(item.def_id, super_trait_ref.substs), - item_def_id: item.def_id, - substs: super_trait_ref.substs, - }) - }); - - let existential_predicates = - tcx.mk_existential_predicates(iter::once(trait_predicate).chain(projection_predicates)); - - let object_ty = tcx.mk_dynamic( - // (*) ... binder re-introduced here - ty::Binder::bind(existential_predicates), - lifetime, - ); - - debug!("object_ty_for_trait: object_ty=`{}`", object_ty); - - object_ty -} - -/// Checks the method's receiver (the `self` argument) can be dispatched on when `Self` is a -/// trait object. We require that `DispatchableFromDyn` be implemented for the receiver type -/// in the following way: -/// - let `Receiver` be the type of the `self` argument, i.e `Self`, `&Self`, `Rc<Self>`, -/// - require the following bound: -/// -/// ``` -/// Receiver[Self => T]: DispatchFromDyn<Receiver[Self => dyn Trait]> -/// ``` -/// -/// where `Foo[X => Y]` means "the same type as `Foo`, but with `X` replaced with `Y`" -/// (substitution notation). -/// -/// Some examples of receiver types and their required obligation: -/// - `&'a mut self` requires `&'a mut Self: DispatchFromDyn<&'a mut dyn Trait>`, -/// - `self: Rc<Self>` requires `Rc<Self>: DispatchFromDyn<Rc<dyn Trait>>`, -/// - `self: Pin<Box<Self>>` requires `Pin<Box<Self>>: DispatchFromDyn<Pin<Box<dyn Trait>>>`. -/// -/// The only case where the receiver is not dispatchable, but is still a valid receiver -/// type (just not object-safe), is when there is more than one level of pointer indirection. -/// E.g., `self: &&Self`, `self: &Rc<Self>`, `self: Box<Box<Self>>`. In these cases, there -/// is no way, or at least no inexpensive way, to coerce the receiver from the version where -/// `Self = dyn Trait` to the version where `Self = T`, where `T` is the unknown erased type -/// contained by the trait object, because the object that needs to be coerced is behind -/// a pointer. -/// -/// In practice, we cannot use `dyn Trait` explicitly in the obligation because it would result -/// in a new check that `Trait` is object safe, creating a cycle (until object_safe_for_dispatch -/// is stabilized, see tracking issue https://github.com/rust-lang/rust/issues/43561). -/// Instead, we fudge a little by introducing a new type parameter `U` such that -/// `Self: Unsize<U>` and `U: Trait + ?Sized`, and use `U` in place of `dyn Trait`. -/// Written as a chalk-style query: -/// -/// forall (U: Trait + ?Sized) { -/// if (Self: Unsize<U>) { -/// Receiver: DispatchFromDyn<Receiver[Self => U]> -/// } -/// } -/// -/// for `self: &'a mut Self`, this means `&'a mut Self: DispatchFromDyn<&'a mut U>` -/// for `self: Rc<Self>`, this means `Rc<Self>: DispatchFromDyn<Rc<U>>` -/// for `self: Pin<Box<Self>>`, this means `Pin<Box<Self>>: DispatchFromDyn<Pin<Box<U>>>` -// -// FIXME(mikeyhew) when unsized receivers are implemented as part of unsized rvalues, add this -// fallback query: `Receiver: Unsize<Receiver[Self => U]>` to support receivers like -// `self: Wrapper<Self>`. -#[allow(dead_code)] -fn receiver_is_dispatchable<'tcx>( - tcx: TyCtxt<'tcx>, - method: &ty::AssocItem, - receiver_ty: Ty<'tcx>, -) -> bool { - debug!("receiver_is_dispatchable: method = {:?}, receiver_ty = {:?}", method, receiver_ty); - - let traits = (tcx.lang_items().unsize_trait(), tcx.lang_items().dispatch_from_dyn_trait()); - let (unsize_did, dispatch_from_dyn_did) = if let (Some(u), Some(cu)) = traits { - (u, cu) - } else { - debug!("receiver_is_dispatchable: Missing Unsize or DispatchFromDyn traits"); - return false; - }; - - // the type `U` in the query - // use a bogus type parameter to mimick a forall(U) query using u32::MAX for now. - // FIXME(mikeyhew) this is a total hack. Once object_safe_for_dispatch is stabilized, we can - // replace this with `dyn Trait` - let unsized_self_ty: Ty<'tcx> = - tcx.mk_ty_param(::std::u32::MAX, Symbol::intern("RustaceansAreAwesome")); - - // `Receiver[Self => U]` - let unsized_receiver_ty = - receiver_for_self_ty(tcx, receiver_ty, unsized_self_ty, method.def_id); - - // create a modified param env, with `Self: Unsize<U>` and `U: Trait` added to caller bounds - // `U: ?Sized` is already implied here - let param_env = { - let mut param_env = tcx.param_env(method.def_id); - - // Self: Unsize<U> - let unsize_predicate = ty::TraitRef { - def_id: unsize_did, - substs: tcx.mk_substs_trait(tcx.types.self_param, &[unsized_self_ty.into()]), - } - .without_const() - .to_predicate(); - - // U: Trait<Arg1, ..., ArgN> - let trait_predicate = { - let substs = - InternalSubsts::for_item(tcx, method.container.assert_trait(), |param, _| { - if param.index == 0 { - unsized_self_ty.into() - } else { - tcx.mk_param_from_def(param) - } - }); - - ty::TraitRef { def_id: unsize_did, substs }.without_const().to_predicate() - }; - - let caller_bounds: Vec<Predicate<'tcx>> = param_env - .caller_bounds - .iter() - .cloned() - .chain(iter::once(unsize_predicate)) - .chain(iter::once(trait_predicate)) - .collect(); - - param_env.caller_bounds = tcx.intern_predicates(&caller_bounds); - - param_env - }; - - // Receiver: DispatchFromDyn<Receiver[Self => U]> - let obligation = { - let predicate = ty::TraitRef { - def_id: dispatch_from_dyn_did, - substs: tcx.mk_substs_trait(receiver_ty, &[unsized_receiver_ty.into()]), - } - .without_const() - .to_predicate(); - - Obligation::new(ObligationCause::dummy(), param_env, predicate) - }; - - tcx.infer_ctxt().enter(|ref infcx| { - // the receiver is dispatchable iff the obligation holds - infcx.predicate_must_hold_modulo_regions(&obligation) - }) -} - -fn contains_illegal_self_type_reference<'tcx>( - tcx: TyCtxt<'tcx>, - trait_def_id: DefId, - ty: Ty<'tcx>, -) -> bool { - // This is somewhat subtle. In general, we want to forbid - // references to `Self` in the argument and return types, - // since the value of `Self` is erased. However, there is one - // exception: it is ok to reference `Self` in order to access - // an associated type of the current trait, since we retain - // the value of those associated types in the object type - // itself. - // - // ```rust - // trait SuperTrait { - // type X; - // } - // - // trait Trait : SuperTrait { - // type Y; - // fn foo(&self, x: Self) // bad - // fn foo(&self) -> Self // bad - // fn foo(&self) -> Option<Self> // bad - // fn foo(&self) -> Self::Y // OK, desugars to next example - // fn foo(&self) -> <Self as Trait>::Y // OK - // fn foo(&self) -> Self::X // OK, desugars to next example - // fn foo(&self) -> <Self as SuperTrait>::X // OK - // } - // ``` - // - // However, it is not as simple as allowing `Self` in a projected - // type, because there are illegal ways to use `Self` as well: - // - // ```rust - // trait Trait : SuperTrait { - // ... - // fn foo(&self) -> <Self as SomeOtherTrait>::X; - // } - // ``` - // - // Here we will not have the type of `X` recorded in the - // object type, and we cannot resolve `Self as SomeOtherTrait` - // without knowing what `Self` is. - - let mut supertraits: Option<Vec<ty::PolyTraitRef<'tcx>>> = None; - let mut error = false; - let self_ty = tcx.types.self_param; - ty.maybe_walk(|ty| { - match ty.kind { - ty::Param(_) => { - if ty == self_ty { - error = true; - } - - false // no contained types to walk - } - - ty::Projection(ref data) => { - // This is a projected type `<Foo as SomeTrait>::X`. - - // Compute supertraits of current trait lazily. - if supertraits.is_none() { - let trait_ref = ty::Binder::bind(ty::TraitRef::identity(tcx, trait_def_id)); - supertraits = Some(traits::supertraits(tcx, trait_ref).collect()); - } - - // Determine whether the trait reference `Foo as - // SomeTrait` is in fact a supertrait of the - // current trait. In that case, this type is - // legal, because the type `X` will be specified - // in the object type. Note that we can just use - // direct equality here because all of these types - // are part of the formal parameter listing, and - // hence there should be no inference variables. - let projection_trait_ref = ty::Binder::bind(data.trait_ref(tcx)); - let is_supertrait_of_current_trait = - supertraits.as_ref().unwrap().contains(&projection_trait_ref); - - if is_supertrait_of_current_trait { - false // do not walk contained types, do not report error, do collect $200 - } else { - true // DO walk contained types, POSSIBLY reporting an error - } - } - - _ => true, // walk contained types, if any - } - }); - - error -} - -pub fn provide(providers: &mut ty::query::Providers<'_>) { - *providers = ty::query::Providers { object_safety_violations, ..*providers }; -} diff --git a/src/librustc_infer/traits/on_unimplemented.rs b/src/librustc_infer/traits/on_unimplemented.rs deleted file mode 100644 index 19260293ee6..00000000000 --- a/src/librustc_infer/traits/on_unimplemented.rs +++ /dev/null @@ -1,383 +0,0 @@ -use fmt_macros::{Parser, Piece, Position}; - -use rustc::ty::{self, GenericParamDefKind, TyCtxt}; -use rustc::util::common::ErrorReported; - -use rustc_ast::ast::{MetaItem, NestedMetaItem}; -use rustc_attr as attr; -use rustc_data_structures::fx::FxHashMap; -use rustc_errors::struct_span_err; -use rustc_hir::def_id::DefId; -use rustc_span::symbol::{kw, sym, Symbol}; -use rustc_span::Span; - -#[derive(Clone, Debug)] -pub struct OnUnimplementedFormatString(Symbol); - -#[derive(Debug)] -pub struct OnUnimplementedDirective { - pub condition: Option<MetaItem>, - pub subcommands: Vec<OnUnimplementedDirective>, - pub message: Option<OnUnimplementedFormatString>, - pub label: Option<OnUnimplementedFormatString>, - pub note: Option<OnUnimplementedFormatString>, - pub enclosing_scope: Option<OnUnimplementedFormatString>, -} - -#[derive(Default)] -pub struct OnUnimplementedNote { - pub message: Option<String>, - pub label: Option<String>, - pub note: Option<String>, - pub enclosing_scope: Option<String>, -} - -fn parse_error( - tcx: TyCtxt<'_>, - span: Span, - message: &str, - label: &str, - note: Option<&str>, -) -> ErrorReported { - let mut diag = struct_span_err!(tcx.sess, span, E0232, "{}", message); - diag.span_label(span, label); - if let Some(note) = note { - diag.note(note); - } - diag.emit(); - ErrorReported -} - -impl<'tcx> OnUnimplementedDirective { - fn parse( - tcx: TyCtxt<'tcx>, - trait_def_id: DefId, - items: &[NestedMetaItem], - span: Span, - is_root: bool, - ) -> Result<Self, ErrorReported> { - let mut errored = false; - let mut item_iter = items.iter(); - - let condition = if is_root { - None - } else { - let cond = item_iter - .next() - .ok_or_else(|| { - parse_error( - tcx, - span, - "empty `on`-clause in `#[rustc_on_unimplemented]`", - "empty on-clause here", - None, - ) - })? - .meta_item() - .ok_or_else(|| { - parse_error( - tcx, - span, - "invalid `on`-clause in `#[rustc_on_unimplemented]`", - "invalid on-clause here", - None, - ) - })?; - attr::eval_condition(cond, &tcx.sess.parse_sess, &mut |_| true); - Some(cond.clone()) - }; - - let mut message = None; - let mut label = None; - let mut note = None; - let mut enclosing_scope = None; - let mut subcommands = vec![]; - - let parse_value = |value_str| { - OnUnimplementedFormatString::try_parse(tcx, trait_def_id, value_str, span).map(Some) - }; - - for item in item_iter { - if item.check_name(sym::message) && message.is_none() { - if let Some(message_) = item.value_str() { - message = parse_value(message_)?; - continue; - } - } else if item.check_name(sym::label) && label.is_none() { - if let Some(label_) = item.value_str() { - label = parse_value(label_)?; - continue; - } - } else if item.check_name(sym::note) && note.is_none() { - if let Some(note_) = item.value_str() { - note = parse_value(note_)?; - continue; - } - } else if item.check_name(sym::enclosing_scope) && enclosing_scope.is_none() { - if let Some(enclosing_scope_) = item.value_str() { - enclosing_scope = parse_value(enclosing_scope_)?; - continue; - } - } else if item.check_name(sym::on) - && is_root - && message.is_none() - && label.is_none() - && note.is_none() - { - if let Some(items) = item.meta_item_list() { - if let Ok(subcommand) = - Self::parse(tcx, trait_def_id, &items, item.span(), false) - { - subcommands.push(subcommand); - } else { - errored = true; - } - continue; - } - } - - // nothing found - parse_error( - tcx, - item.span(), - "this attribute must have a valid value", - "expected value here", - Some(r#"eg `#[rustc_on_unimplemented(message="foo")]`"#), - ); - } - - if errored { - Err(ErrorReported) - } else { - Ok(OnUnimplementedDirective { - condition, - subcommands, - message, - label, - note, - enclosing_scope, - }) - } - } - - pub fn of_item( - tcx: TyCtxt<'tcx>, - trait_def_id: DefId, - impl_def_id: DefId, - ) -> Result<Option<Self>, ErrorReported> { - let attrs = tcx.get_attrs(impl_def_id); - - let attr = if let Some(item) = attr::find_by_name(&attrs, sym::rustc_on_unimplemented) { - item - } else { - return Ok(None); - }; - - let result = if let Some(items) = attr.meta_item_list() { - Self::parse(tcx, trait_def_id, &items, attr.span, true).map(Some) - } else if let Some(value) = attr.value_str() { - Ok(Some(OnUnimplementedDirective { - condition: None, - message: None, - subcommands: vec![], - label: Some(OnUnimplementedFormatString::try_parse( - tcx, - trait_def_id, - value, - attr.span, - )?), - note: None, - enclosing_scope: None, - })) - } else { - return Err(ErrorReported); - }; - debug!("of_item({:?}/{:?}) = {:?}", trait_def_id, impl_def_id, result); - result - } - - pub fn evaluate( - &self, - tcx: TyCtxt<'tcx>, - trait_ref: ty::TraitRef<'tcx>, - options: &[(Symbol, Option<String>)], - ) -> OnUnimplementedNote { - let mut message = None; - let mut label = None; - let mut note = None; - let mut enclosing_scope = None; - info!("evaluate({:?}, trait_ref={:?}, options={:?})", self, trait_ref, options); - - for command in self.subcommands.iter().chain(Some(self)).rev() { - if let Some(ref condition) = command.condition { - if !attr::eval_condition(condition, &tcx.sess.parse_sess, &mut |c| { - c.ident().map_or(false, |ident| { - options.contains(&(ident.name, c.value_str().map(|s| s.to_string()))) - }) - }) { - debug!("evaluate: skipping {:?} due to condition", command); - continue; - } - } - debug!("evaluate: {:?} succeeded", command); - if let Some(ref message_) = command.message { - message = Some(message_.clone()); - } - - if let Some(ref label_) = command.label { - label = Some(label_.clone()); - } - - if let Some(ref note_) = command.note { - note = Some(note_.clone()); - } - - if let Some(ref enclosing_scope_) = command.enclosing_scope { - enclosing_scope = Some(enclosing_scope_.clone()); - } - } - - let options: FxHashMap<Symbol, String> = - options.iter().filter_map(|(k, v)| v.as_ref().map(|v| (*k, v.to_owned()))).collect(); - OnUnimplementedNote { - label: label.map(|l| l.format(tcx, trait_ref, &options)), - message: message.map(|m| m.format(tcx, trait_ref, &options)), - note: note.map(|n| n.format(tcx, trait_ref, &options)), - enclosing_scope: enclosing_scope.map(|e_s| e_s.format(tcx, trait_ref, &options)), - } - } -} - -impl<'tcx> OnUnimplementedFormatString { - fn try_parse( - tcx: TyCtxt<'tcx>, - trait_def_id: DefId, - from: Symbol, - err_sp: Span, - ) -> Result<Self, ErrorReported> { - let result = OnUnimplementedFormatString(from); - result.verify(tcx, trait_def_id, err_sp)?; - Ok(result) - } - - fn verify( - &self, - tcx: TyCtxt<'tcx>, - trait_def_id: DefId, - span: Span, - ) -> Result<(), ErrorReported> { - let name = tcx.item_name(trait_def_id); - let generics = tcx.generics_of(trait_def_id); - let s = self.0.as_str(); - let parser = Parser::new(&s, None, vec![], false); - let mut result = Ok(()); - for token in parser { - match token { - Piece::String(_) => (), // Normal string, no need to check it - Piece::NextArgument(a) => match a.position { - // `{Self}` is allowed - Position::ArgumentNamed(s) if s == kw::SelfUpper => (), - // `{ThisTraitsName}` is allowed - Position::ArgumentNamed(s) if s == name => (), - // `{from_method}` is allowed - Position::ArgumentNamed(s) if s == sym::from_method => (), - // `{from_desugaring}` is allowed - Position::ArgumentNamed(s) if s == sym::from_desugaring => (), - // `{ItemContext}` is allowed - Position::ArgumentNamed(s) if s == sym::item_context => (), - // So is `{A}` if A is a type parameter - Position::ArgumentNamed(s) => { - match generics.params.iter().find(|param| param.name == s) { - Some(_) => (), - None => { - struct_span_err!( - tcx.sess, - span, - E0230, - "there is no parameter `{}` on trait `{}`", - s, - name - ) - .emit(); - result = Err(ErrorReported); - } - } - } - // `{:1}` and `{}` are not to be used - Position::ArgumentIs(_) | Position::ArgumentImplicitlyIs(_) => { - struct_span_err!( - tcx.sess, - span, - E0231, - "only named substitution parameters are allowed" - ) - .emit(); - result = Err(ErrorReported); - } - }, - } - } - - result - } - - pub fn format( - &self, - tcx: TyCtxt<'tcx>, - trait_ref: ty::TraitRef<'tcx>, - options: &FxHashMap<Symbol, String>, - ) -> String { - let name = tcx.item_name(trait_ref.def_id); - let trait_str = tcx.def_path_str(trait_ref.def_id); - let generics = tcx.generics_of(trait_ref.def_id); - let generic_map = generics - .params - .iter() - .filter_map(|param| { - let value = match param.kind { - GenericParamDefKind::Type { .. } | GenericParamDefKind::Const => { - trait_ref.substs[param.index as usize].to_string() - } - GenericParamDefKind::Lifetime => return None, - }; - let name = param.name; - Some((name, value)) - }) - .collect::<FxHashMap<Symbol, String>>(); - let empty_string = String::new(); - - let s = self.0.as_str(); - let parser = Parser::new(&s, None, vec![], false); - let item_context = (options.get(&sym::item_context)).unwrap_or(&empty_string); - parser - .map(|p| match p { - Piece::String(s) => s, - Piece::NextArgument(a) => match a.position { - Position::ArgumentNamed(s) => match generic_map.get(&s) { - Some(val) => val, - None if s == name => &trait_str, - None => { - if let Some(val) = options.get(&s) { - val - } else if s == sym::from_desugaring || s == sym::from_method { - // don't break messages using these two arguments incorrectly - &empty_string - } else if s == sym::item_context { - &item_context - } else { - bug!( - "broken on_unimplemented {:?} for {:?}: \ - no argument matching {:?}", - self.0, - trait_ref, - s - ) - } - } - }, - _ => bug!("broken on_unimplemented {:?} - bad format arg", self.0), - }, - }) - .collect() - } -} diff --git a/src/librustc_infer/traits/project.rs b/src/librustc_infer/traits/project.rs index 34889c6984b..48375a9ddf4 100644 --- a/src/librustc_infer/traits/project.rs +++ b/src/librustc_infer/traits/project.rs @@ -1,398 +1,18 @@ //! Code for projecting associated types out of trait references. -use super::elaborate_predicates; -use super::specialization_graph; -use super::translate_substs; -use super::util; -use super::Obligation; -use super::ObligationCause; use super::PredicateObligation; -use super::Selection; -use super::SelectionContext; -use super::SelectionError; -use super::{VtableClosureData, VtableFnPointerData, VtableGeneratorData, VtableImplData}; -use crate::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; -use crate::infer::{InferCtxt, InferOk, LateBoundRegionConversionTime}; -use rustc::ty::fold::{TypeFoldable, TypeFolder}; -use rustc::ty::subst::{InternalSubsts, Subst}; -use rustc::ty::{self, ToPolyTraitRef, ToPredicate, Ty, TyCtxt, WithConstness}; -use rustc_ast::ast::Ident; use rustc_data_structures::snapshot_map::{Snapshot, SnapshotMap}; -use rustc_hir::def_id::DefId; -use rustc_span::symbol::sym; -use rustc_span::DUMMY_SP; +use rustc_middle::ty::fold::TypeFoldable; +use rustc_middle::ty::{self, Ty}; -pub use rustc::traits::Reveal; - -pub type PolyProjectionObligation<'tcx> = Obligation<'tcx, ty::PolyProjectionPredicate<'tcx>>; - -pub type ProjectionObligation<'tcx> = Obligation<'tcx, ty::ProjectionPredicate<'tcx>>; - -pub type ProjectionTyObligation<'tcx> = Obligation<'tcx, ty::ProjectionTy<'tcx>>; - -/// When attempting to resolve `<T as TraitRef>::Name` ... -#[derive(Debug)] -pub enum ProjectionTyError<'tcx> { - /// ...we found multiple sources of information and couldn't resolve the ambiguity. - TooManyCandidates, - - /// ...an error occurred matching `T : TraitRef` - TraitSelectionError(SelectionError<'tcx>), -} +pub use rustc_middle::traits::Reveal; #[derive(Clone)] pub struct MismatchedProjectionTypes<'tcx> { pub err: ty::error::TypeError<'tcx>, } -#[derive(PartialEq, Eq, Debug)] -enum ProjectionTyCandidate<'tcx> { - // from a where-clause in the env or object type - ParamEnv(ty::PolyProjectionPredicate<'tcx>), - - // from the definition of `Trait` when you have something like <<A as Trait>::B as Trait2>::C - TraitDef(ty::PolyProjectionPredicate<'tcx>), - - // from a "impl" (or a "pseudo-impl" returned by select) - Select(Selection<'tcx>), -} - -enum ProjectionTyCandidateSet<'tcx> { - None, - Single(ProjectionTyCandidate<'tcx>), - Ambiguous, - Error(SelectionError<'tcx>), -} - -impl<'tcx> ProjectionTyCandidateSet<'tcx> { - fn mark_ambiguous(&mut self) { - *self = ProjectionTyCandidateSet::Ambiguous; - } - - fn mark_error(&mut self, err: SelectionError<'tcx>) { - *self = ProjectionTyCandidateSet::Error(err); - } - - // Returns true if the push was successful, or false if the candidate - // was discarded -- this could be because of ambiguity, or because - // a higher-priority candidate is already there. - fn push_candidate(&mut self, candidate: ProjectionTyCandidate<'tcx>) -> bool { - use self::ProjectionTyCandidate::*; - use self::ProjectionTyCandidateSet::*; - - // This wacky variable is just used to try and - // make code readable and avoid confusing paths. - // It is assigned a "value" of `()` only on those - // paths in which we wish to convert `*self` to - // ambiguous (and return false, because the candidate - // was not used). On other paths, it is not assigned, - // and hence if those paths *could* reach the code that - // comes after the match, this fn would not compile. - let convert_to_ambiguous; - - match self { - None => { - *self = Single(candidate); - return true; - } - - Single(current) => { - // Duplicates can happen inside ParamEnv. In the case, we - // perform a lazy deduplication. - if current == &candidate { - return false; - } - - // Prefer where-clauses. As in select, if there are multiple - // candidates, we prefer where-clause candidates over impls. This - // may seem a bit surprising, since impls are the source of - // "truth" in some sense, but in fact some of the impls that SEEM - // applicable are not, because of nested obligations. Where - // clauses are the safer choice. See the comment on - // `select::SelectionCandidate` and #21974 for more details. - match (current, candidate) { - (ParamEnv(..), ParamEnv(..)) => convert_to_ambiguous = (), - (ParamEnv(..), _) => return false, - (_, ParamEnv(..)) => unreachable!(), - (_, _) => convert_to_ambiguous = (), - } - } - - Ambiguous | Error(..) => { - return false; - } - } - - // We only ever get here when we moved from a single candidate - // to ambiguous. - let () = convert_to_ambiguous; - *self = Ambiguous; - false - } -} - -/// Evaluates constraints of the form: -/// -/// for<...> <T as Trait>::U == V -/// -/// If successful, this may result in additional obligations. Also returns -/// the projection cache key used to track these additional obligations. -pub fn poly_project_and_unify_type<'cx, 'tcx>( - selcx: &mut SelectionContext<'cx, 'tcx>, - obligation: &PolyProjectionObligation<'tcx>, -) -> Result<Option<Vec<PredicateObligation<'tcx>>>, MismatchedProjectionTypes<'tcx>> { - debug!("poly_project_and_unify_type(obligation={:?})", obligation); - - let infcx = selcx.infcx(); - infcx.commit_if_ok(|snapshot| { - let (placeholder_predicate, placeholder_map) = - infcx.replace_bound_vars_with_placeholders(&obligation.predicate); - - let placeholder_obligation = obligation.with(placeholder_predicate); - let result = project_and_unify_type(selcx, &placeholder_obligation)?; - infcx - .leak_check(false, &placeholder_map, snapshot) - .map_err(|err| MismatchedProjectionTypes { err })?; - Ok(result) - }) -} - -/// Evaluates constraints of the form: -/// -/// <T as Trait>::U == V -/// -/// If successful, this may result in additional obligations. -fn project_and_unify_type<'cx, 'tcx>( - selcx: &mut SelectionContext<'cx, 'tcx>, - obligation: &ProjectionObligation<'tcx>, -) -> Result<Option<Vec<PredicateObligation<'tcx>>>, MismatchedProjectionTypes<'tcx>> { - debug!("project_and_unify_type(obligation={:?})", obligation); - - let mut obligations = vec![]; - let normalized_ty = match opt_normalize_projection_type( - selcx, - obligation.param_env, - obligation.predicate.projection_ty, - obligation.cause.clone(), - obligation.recursion_depth, - &mut obligations, - ) { - Some(n) => n, - None => return Ok(None), - }; - - debug!( - "project_and_unify_type: normalized_ty={:?} obligations={:?}", - normalized_ty, obligations - ); - - let infcx = selcx.infcx(); - match infcx - .at(&obligation.cause, obligation.param_env) - .eq(normalized_ty, obligation.predicate.ty) - { - Ok(InferOk { obligations: inferred_obligations, value: () }) => { - obligations.extend(inferred_obligations); - Ok(Some(obligations)) - } - Err(err) => { - debug!("project_and_unify_type: equating types encountered error {:?}", err); - Err(MismatchedProjectionTypes { err }) - } - } -} - -/// Normalizes any associated type projections in `value`, replacing -/// them with a fully resolved type where possible. The return value -/// combines the normalized result and any additional obligations that -/// were incurred as result. -pub fn normalize<'a, 'b, 'tcx, T>( - selcx: &'a mut SelectionContext<'b, 'tcx>, - param_env: ty::ParamEnv<'tcx>, - cause: ObligationCause<'tcx>, - value: &T, -) -> Normalized<'tcx, T> -where - T: TypeFoldable<'tcx>, -{ - let mut obligations = Vec::new(); - let value = normalize_to(selcx, param_env, cause, value, &mut obligations); - Normalized { value, obligations } -} - -pub fn normalize_to<'a, 'b, 'tcx, T>( - selcx: &'a mut SelectionContext<'b, 'tcx>, - param_env: ty::ParamEnv<'tcx>, - cause: ObligationCause<'tcx>, - value: &T, - obligations: &mut Vec<PredicateObligation<'tcx>>, -) -> T -where - T: TypeFoldable<'tcx>, -{ - normalize_with_depth_to(selcx, param_env, cause, 0, value, obligations) -} - -/// As `normalize`, but with a custom depth. -pub fn normalize_with_depth<'a, 'b, 'tcx, T>( - selcx: &'a mut SelectionContext<'b, 'tcx>, - param_env: ty::ParamEnv<'tcx>, - cause: ObligationCause<'tcx>, - depth: usize, - value: &T, -) -> Normalized<'tcx, T> -where - T: TypeFoldable<'tcx>, -{ - let mut obligations = Vec::new(); - let value = normalize_with_depth_to(selcx, param_env, cause, depth, value, &mut obligations); - Normalized { value, obligations } -} - -pub fn normalize_with_depth_to<'a, 'b, 'tcx, T>( - selcx: &'a mut SelectionContext<'b, 'tcx>, - param_env: ty::ParamEnv<'tcx>, - cause: ObligationCause<'tcx>, - depth: usize, - value: &T, - obligations: &mut Vec<PredicateObligation<'tcx>>, -) -> T -where - T: TypeFoldable<'tcx>, -{ - debug!("normalize_with_depth(depth={}, value={:?})", depth, value); - let mut normalizer = AssocTypeNormalizer::new(selcx, param_env, cause, depth, obligations); - let result = normalizer.fold(value); - debug!( - "normalize_with_depth: depth={} result={:?} with {} obligations", - depth, - result, - normalizer.obligations.len() - ); - debug!("normalize_with_depth: depth={} obligations={:?}", depth, normalizer.obligations); - result -} - -struct AssocTypeNormalizer<'a, 'b, 'tcx> { - selcx: &'a mut SelectionContext<'b, 'tcx>, - param_env: ty::ParamEnv<'tcx>, - cause: ObligationCause<'tcx>, - obligations: &'a mut Vec<PredicateObligation<'tcx>>, - depth: usize, -} - -impl<'a, 'b, 'tcx> AssocTypeNormalizer<'a, 'b, 'tcx> { - fn new( - selcx: &'a mut SelectionContext<'b, 'tcx>, - param_env: ty::ParamEnv<'tcx>, - cause: ObligationCause<'tcx>, - depth: usize, - obligations: &'a mut Vec<PredicateObligation<'tcx>>, - ) -> AssocTypeNormalizer<'a, 'b, 'tcx> { - AssocTypeNormalizer { selcx, param_env, cause, obligations, depth } - } - - fn fold<T: TypeFoldable<'tcx>>(&mut self, value: &T) -> T { - let value = self.selcx.infcx().resolve_vars_if_possible(value); - - if !value.has_projections() { value } else { value.fold_with(self) } - } -} - -impl<'a, 'b, 'tcx> TypeFolder<'tcx> for AssocTypeNormalizer<'a, 'b, 'tcx> { - fn tcx<'c>(&'c self) -> TyCtxt<'tcx> { - self.selcx.tcx() - } - - fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> { - if !ty.has_projections() { - return ty; - } - // We don't want to normalize associated types that occur inside of region - // binders, because they may contain bound regions, and we can't cope with that. - // - // Example: - // - // for<'a> fn(<T as Foo<&'a>>::A) - // - // Instead of normalizing `<T as Foo<&'a>>::A` here, we'll - // normalize it when we instantiate those bound regions (which - // should occur eventually). - - let ty = ty.super_fold_with(self); - match ty.kind { - ty::Opaque(def_id, substs) if !substs.has_escaping_bound_vars() => { - // (*) - // Only normalize `impl Trait` after type-checking, usually in codegen. - match self.param_env.reveal { - Reveal::UserFacing => ty, - - Reveal::All => { - let recursion_limit = *self.tcx().sess.recursion_limit.get(); - if self.depth >= recursion_limit { - let obligation = Obligation::with_depth( - self.cause.clone(), - recursion_limit, - self.param_env, - ty, - ); - self.selcx.infcx().report_overflow_error(&obligation, true); - } - - let generic_ty = self.tcx().type_of(def_id); - let concrete_ty = generic_ty.subst(self.tcx(), substs); - self.depth += 1; - let folded_ty = self.fold_ty(concrete_ty); - self.depth -= 1; - folded_ty - } - } - } - - ty::Projection(ref data) if !data.has_escaping_bound_vars() => { - // (*) - - // (*) This is kind of hacky -- we need to be able to - // handle normalization within binders because - // otherwise we wind up a need to normalize when doing - // trait matching (since you can have a trait - // obligation like `for<'a> T::B : Fn(&'a int)`), but - // we can't normalize with bound regions in scope. So - // far now we just ignore binders but only normalize - // if all bound regions are gone (and then we still - // have to renormalize whenever we instantiate a - // binder). It would be better to normalize in a - // binding-aware fashion. - - let normalized_ty = normalize_projection_type( - self.selcx, - self.param_env, - *data, - self.cause.clone(), - self.depth, - &mut self.obligations, - ); - debug!( - "AssocTypeNormalizer: depth={} normalized {:?} to {:?}, \ - now with {} obligations", - self.depth, - ty, - normalized_ty, - self.obligations.len() - ); - normalized_ty - } - - _ => ty, - } - } - - fn fold_const(&mut self, constant: &'tcx ty::Const<'tcx>) -> &'tcx ty::Const<'tcx> { - constant.eval(self.selcx.tcx(), self.param_env) - } -} - #[derive(Clone, TypeFoldable)] pub struct Normalized<'tcx, T> { pub value: T, @@ -403,1100 +23,7 @@ pub type NormalizedTy<'tcx> = Normalized<'tcx, Ty<'tcx>>; impl<'tcx, T> Normalized<'tcx, T> { pub fn with<U>(self, value: U) -> Normalized<'tcx, U> { - Normalized { value: value, obligations: self.obligations } - } -} - -/// The guts of `normalize`: normalize a specific projection like `<T -/// as Trait>::Item`. The result is always a type (and possibly -/// additional obligations). If ambiguity arises, which implies that -/// there are unresolved type variables in the projection, we will -/// substitute a fresh type variable `$X` and generate a new -/// obligation `<T as Trait>::Item == $X` for later. -pub fn normalize_projection_type<'a, 'b, 'tcx>( - selcx: &'a mut SelectionContext<'b, 'tcx>, - param_env: ty::ParamEnv<'tcx>, - projection_ty: ty::ProjectionTy<'tcx>, - cause: ObligationCause<'tcx>, - depth: usize, - obligations: &mut Vec<PredicateObligation<'tcx>>, -) -> Ty<'tcx> { - opt_normalize_projection_type( - selcx, - param_env, - projection_ty, - cause.clone(), - depth, - obligations, - ) - .unwrap_or_else(move || { - // if we bottom out in ambiguity, create a type variable - // and a deferred predicate to resolve this when more type - // information is available. - - let tcx = selcx.infcx().tcx; - let def_id = projection_ty.item_def_id; - let ty_var = selcx.infcx().next_ty_var(TypeVariableOrigin { - kind: TypeVariableOriginKind::NormalizeProjectionType, - span: tcx.def_span(def_id), - }); - let projection = ty::Binder::dummy(ty::ProjectionPredicate { projection_ty, ty: ty_var }); - let obligation = - Obligation::with_depth(cause, depth + 1, param_env, projection.to_predicate()); - obligations.push(obligation); - ty_var - }) -} - -/// The guts of `normalize`: normalize a specific projection like `<T -/// as Trait>::Item`. The result is always a type (and possibly -/// additional obligations). Returns `None` in the case of ambiguity, -/// which indicates that there are unbound type variables. -/// -/// This function used to return `Option<NormalizedTy<'tcx>>`, which contains a -/// `Ty<'tcx>` and an obligations vector. But that obligation vector was very -/// often immediately appended to another obligations vector. So now this -/// function takes an obligations vector and appends to it directly, which is -/// slightly uglier but avoids the need for an extra short-lived allocation. -fn opt_normalize_projection_type<'a, 'b, 'tcx>( - selcx: &'a mut SelectionContext<'b, 'tcx>, - param_env: ty::ParamEnv<'tcx>, - projection_ty: ty::ProjectionTy<'tcx>, - cause: ObligationCause<'tcx>, - depth: usize, - obligations: &mut Vec<PredicateObligation<'tcx>>, -) -> Option<Ty<'tcx>> { - let infcx = selcx.infcx(); - - let projection_ty = infcx.resolve_vars_if_possible(&projection_ty); - let cache_key = ProjectionCacheKey { ty: projection_ty }; - - debug!( - "opt_normalize_projection_type(\ - projection_ty={:?}, \ - depth={})", - projection_ty, depth - ); - - // FIXME(#20304) For now, I am caching here, which is good, but it - // means we don't capture the type variables that are created in - // the case of ambiguity. Which means we may create a large stream - // of such variables. OTOH, if we move the caching up a level, we - // would not benefit from caching when proving `T: Trait<U=Foo>` - // bounds. It might be the case that we want two distinct caches, - // or else another kind of cache entry. - - let cache_result = infcx.inner.borrow_mut().projection_cache.try_start(cache_key); - match cache_result { - Ok(()) => {} - Err(ProjectionCacheEntry::Ambiguous) => { - // If we found ambiguity the last time, that means we will continue - // to do so until some type in the key changes (and we know it - // hasn't, because we just fully resolved it). - debug!( - "opt_normalize_projection_type: \ - found cache entry: ambiguous" - ); - return None; - } - Err(ProjectionCacheEntry::InProgress) => { - // If while normalized A::B, we are asked to normalize - // A::B, just return A::B itself. This is a conservative - // answer, in the sense that A::B *is* clearly equivalent - // to A::B, though there may be a better value we can - // find. - - // Under lazy normalization, this can arise when - // bootstrapping. That is, imagine an environment with a - // where-clause like `A::B == u32`. Now, if we are asked - // to normalize `A::B`, we will want to check the - // where-clauses in scope. So we will try to unify `A::B` - // with `A::B`, which can trigger a recursive - // normalization. In that case, I think we will want this code: - // - // ``` - // let ty = selcx.tcx().mk_projection(projection_ty.item_def_id, - // projection_ty.substs; - // return Some(NormalizedTy { value: v, obligations: vec![] }); - // ``` - - debug!( - "opt_normalize_projection_type: \ - found cache entry: in-progress" - ); - - // But for now, let's classify this as an overflow: - let recursion_limit = *selcx.tcx().sess.recursion_limit.get(); - let obligation = - Obligation::with_depth(cause, recursion_limit, param_env, projection_ty); - selcx.infcx().report_overflow_error(&obligation, false); - } - Err(ProjectionCacheEntry::NormalizedTy(ty)) => { - // This is the hottest path in this function. - // - // If we find the value in the cache, then return it along - // with the obligations that went along with it. Note - // that, when using a fulfillment context, these - // obligations could in principle be ignored: they have - // already been registered when the cache entry was - // created (and hence the new ones will quickly be - // discarded as duplicated). But when doing trait - // evaluation this is not the case, and dropping the trait - // evaluations can causes ICEs (e.g., #43132). - debug!( - "opt_normalize_projection_type: \ - found normalized ty `{:?}`", - ty - ); - - // Once we have inferred everything we need to know, we - // can ignore the `obligations` from that point on. - if infcx.unresolved_type_vars(&ty.value).is_none() { - infcx.inner.borrow_mut().projection_cache.complete_normalized(cache_key, &ty); - // No need to extend `obligations`. - } else { - obligations.extend(ty.obligations); - } - - obligations.push(get_paranoid_cache_value_obligation( - infcx, - param_env, - projection_ty, - cause, - depth, - )); - return Some(ty.value); - } - Err(ProjectionCacheEntry::Error) => { - debug!( - "opt_normalize_projection_type: \ - found error" - ); - let result = normalize_to_error(selcx, param_env, projection_ty, cause, depth); - obligations.extend(result.obligations); - return Some(result.value); - } - } - - let obligation = Obligation::with_depth(cause.clone(), depth, param_env, projection_ty); - match project_type(selcx, &obligation) { - Ok(ProjectedTy::Progress(Progress { - ty: projected_ty, - obligations: mut projected_obligations, - })) => { - // if projection succeeded, then what we get out of this - // is also non-normalized (consider: it was derived from - // an impl, where-clause etc) and hence we must - // re-normalize it - - debug!( - "opt_normalize_projection_type: \ - projected_ty={:?} \ - depth={} \ - projected_obligations={:?}", - projected_ty, depth, projected_obligations - ); - - let result = if projected_ty.has_projections() { - let mut normalizer = AssocTypeNormalizer::new( - selcx, - param_env, - cause, - depth + 1, - &mut projected_obligations, - ); - let normalized_ty = normalizer.fold(&projected_ty); - - debug!( - "opt_normalize_projection_type: \ - normalized_ty={:?} depth={}", - normalized_ty, depth - ); - - Normalized { value: normalized_ty, obligations: projected_obligations } - } else { - Normalized { value: projected_ty, obligations: projected_obligations } - }; - - let cache_value = prune_cache_value_obligations(infcx, &result); - infcx.inner.borrow_mut().projection_cache.insert_ty(cache_key, cache_value); - obligations.extend(result.obligations); - Some(result.value) - } - Ok(ProjectedTy::NoProgress(projected_ty)) => { - debug!( - "opt_normalize_projection_type: \ - projected_ty={:?} no progress", - projected_ty - ); - let result = Normalized { value: projected_ty, obligations: vec![] }; - infcx.inner.borrow_mut().projection_cache.insert_ty(cache_key, result.clone()); - // No need to extend `obligations`. - Some(result.value) - } - Err(ProjectionTyError::TooManyCandidates) => { - debug!( - "opt_normalize_projection_type: \ - too many candidates" - ); - infcx.inner.borrow_mut().projection_cache.ambiguous(cache_key); - None - } - Err(ProjectionTyError::TraitSelectionError(_)) => { - debug!("opt_normalize_projection_type: ERROR"); - // if we got an error processing the `T as Trait` part, - // just return `ty::err` but add the obligation `T : - // Trait`, which when processed will cause the error to be - // reported later - - infcx.inner.borrow_mut().projection_cache.error(cache_key); - let result = normalize_to_error(selcx, param_env, projection_ty, cause, depth); - obligations.extend(result.obligations); - Some(result.value) - } - } -} - -/// If there are unresolved type variables, then we need to include -/// any subobligations that bind them, at least until those type -/// variables are fully resolved. -fn prune_cache_value_obligations<'a, 'tcx>( - infcx: &'a InferCtxt<'a, 'tcx>, - result: &NormalizedTy<'tcx>, -) -> NormalizedTy<'tcx> { - if infcx.unresolved_type_vars(&result.value).is_none() { - return NormalizedTy { value: result.value, obligations: vec![] }; - } - - let mut obligations: Vec<_> = result - .obligations - .iter() - .filter(|obligation| match obligation.predicate { - // We found a `T: Foo<X = U>` predicate, let's check - // if `U` references any unresolved type - // variables. In principle, we only care if this - // projection can help resolve any of the type - // variables found in `result.value` -- but we just - // check for any type variables here, for fear of - // indirect obligations (e.g., we project to `?0`, - // but we have `T: Foo<X = ?1>` and `?1: Bar<X = - // ?0>`). - ty::Predicate::Projection(ref data) => infcx.unresolved_type_vars(&data.ty()).is_some(), - - // We are only interested in `T: Foo<X = U>` predicates, whre - // `U` references one of `unresolved_type_vars`. =) - _ => false, - }) - .cloned() - .collect(); - - obligations.shrink_to_fit(); - - NormalizedTy { value: result.value, obligations } -} - -/// Whenever we give back a cache result for a projection like `<T as -/// Trait>::Item ==> X`, we *always* include the obligation to prove -/// that `T: Trait` (we may also include some other obligations). This -/// may or may not be necessary -- in principle, all the obligations -/// that must be proven to show that `T: Trait` were also returned -/// when the cache was first populated. But there are some vague concerns, -/// and so we take the precautionary measure of including `T: Trait` in -/// the result: -/// -/// Concern #1. The current setup is fragile. Perhaps someone could -/// have failed to prove the concerns from when the cache was -/// populated, but also not have used a snapshot, in which case the -/// cache could remain populated even though `T: Trait` has not been -/// shown. In this case, the "other code" is at fault -- when you -/// project something, you are supposed to either have a snapshot or -/// else prove all the resulting obligations -- but it's still easy to -/// get wrong. -/// -/// Concern #2. Even within the snapshot, if those original -/// obligations are not yet proven, then we are able to do projections -/// that may yet turn out to be wrong. This *may* lead to some sort -/// of trouble, though we don't have a concrete example of how that -/// can occur yet. But it seems risky at best. -fn get_paranoid_cache_value_obligation<'a, 'tcx>( - infcx: &'a InferCtxt<'a, 'tcx>, - param_env: ty::ParamEnv<'tcx>, - projection_ty: ty::ProjectionTy<'tcx>, - cause: ObligationCause<'tcx>, - depth: usize, -) -> PredicateObligation<'tcx> { - let trait_ref = projection_ty.trait_ref(infcx.tcx).to_poly_trait_ref(); - Obligation { - cause, - recursion_depth: depth, - param_env, - predicate: trait_ref.without_const().to_predicate(), - } -} - -/// If we are projecting `<T as Trait>::Item`, but `T: Trait` does not -/// hold. In various error cases, we cannot generate a valid -/// normalized projection. Therefore, we create an inference variable -/// return an associated obligation that, when fulfilled, will lead to -/// an error. -/// -/// Note that we used to return `Error` here, but that was quite -/// dubious -- the premise was that an error would *eventually* be -/// reported, when the obligation was processed. But in general once -/// you see a `Error` you are supposed to be able to assume that an -/// error *has been* reported, so that you can take whatever heuristic -/// paths you want to take. To make things worse, it was possible for -/// cycles to arise, where you basically had a setup like `<MyType<$0> -/// as Trait>::Foo == $0`. Here, normalizing `<MyType<$0> as -/// Trait>::Foo> to `[type error]` would lead to an obligation of -/// `<MyType<[type error]> as Trait>::Foo`. We are supposed to report -/// an error for this obligation, but we legitimately should not, -/// because it contains `[type error]`. Yuck! (See issue #29857 for -/// one case where this arose.) -fn normalize_to_error<'a, 'tcx>( - selcx: &mut SelectionContext<'a, 'tcx>, - param_env: ty::ParamEnv<'tcx>, - projection_ty: ty::ProjectionTy<'tcx>, - cause: ObligationCause<'tcx>, - depth: usize, -) -> NormalizedTy<'tcx> { - let trait_ref = projection_ty.trait_ref(selcx.tcx()).to_poly_trait_ref(); - let trait_obligation = Obligation { - cause, - recursion_depth: depth, - param_env, - predicate: trait_ref.without_const().to_predicate(), - }; - let tcx = selcx.infcx().tcx; - let def_id = projection_ty.item_def_id; - let new_value = selcx.infcx().next_ty_var(TypeVariableOrigin { - kind: TypeVariableOriginKind::NormalizeProjectionType, - span: tcx.def_span(def_id), - }); - Normalized { value: new_value, obligations: vec![trait_obligation] } -} - -enum ProjectedTy<'tcx> { - Progress(Progress<'tcx>), - NoProgress(Ty<'tcx>), -} - -struct Progress<'tcx> { - ty: Ty<'tcx>, - obligations: Vec<PredicateObligation<'tcx>>, -} - -impl<'tcx> Progress<'tcx> { - fn error(tcx: TyCtxt<'tcx>) -> Self { - Progress { ty: tcx.types.err, obligations: vec![] } - } - - fn with_addl_obligations(mut self, mut obligations: Vec<PredicateObligation<'tcx>>) -> Self { - debug!( - "with_addl_obligations: self.obligations.len={} obligations.len={}", - self.obligations.len(), - obligations.len() - ); - - debug!( - "with_addl_obligations: self.obligations={:?} obligations={:?}", - self.obligations, obligations - ); - - self.obligations.append(&mut obligations); - self - } -} - -/// Computes the result of a projection type (if we can). -/// -/// IMPORTANT: -/// - `obligation` must be fully normalized -fn project_type<'cx, 'tcx>( - selcx: &mut SelectionContext<'cx, 'tcx>, - obligation: &ProjectionTyObligation<'tcx>, -) -> Result<ProjectedTy<'tcx>, ProjectionTyError<'tcx>> { - debug!("project(obligation={:?})", obligation); - - let recursion_limit = *selcx.tcx().sess.recursion_limit.get(); - if obligation.recursion_depth >= recursion_limit { - debug!("project: overflow!"); - return Err(ProjectionTyError::TraitSelectionError(SelectionError::Overflow)); - } - - let obligation_trait_ref = &obligation.predicate.trait_ref(selcx.tcx()); - - debug!("project: obligation_trait_ref={:?}", obligation_trait_ref); - - if obligation_trait_ref.references_error() { - return Ok(ProjectedTy::Progress(Progress::error(selcx.tcx()))); - } - - let mut candidates = ProjectionTyCandidateSet::None; - - // Make sure that the following procedures are kept in order. ParamEnv - // needs to be first because it has highest priority, and Select checks - // the return value of push_candidate which assumes it's ran at last. - assemble_candidates_from_param_env(selcx, obligation, &obligation_trait_ref, &mut candidates); - - assemble_candidates_from_trait_def(selcx, obligation, &obligation_trait_ref, &mut candidates); - - assemble_candidates_from_impls(selcx, obligation, &obligation_trait_ref, &mut candidates); - - match candidates { - ProjectionTyCandidateSet::Single(candidate) => Ok(ProjectedTy::Progress( - confirm_candidate(selcx, obligation, &obligation_trait_ref, candidate), - )), - ProjectionTyCandidateSet::None => Ok(ProjectedTy::NoProgress( - selcx - .tcx() - .mk_projection(obligation.predicate.item_def_id, obligation.predicate.substs), - )), - // Error occurred while trying to processing impls. - ProjectionTyCandidateSet::Error(e) => Err(ProjectionTyError::TraitSelectionError(e)), - // Inherent ambiguity that prevents us from even enumerating the - // candidates. - ProjectionTyCandidateSet::Ambiguous => Err(ProjectionTyError::TooManyCandidates), - } -} - -/// The first thing we have to do is scan through the parameter -/// environment to see whether there are any projection predicates -/// there that can answer this question. -fn assemble_candidates_from_param_env<'cx, 'tcx>( - selcx: &mut SelectionContext<'cx, 'tcx>, - obligation: &ProjectionTyObligation<'tcx>, - obligation_trait_ref: &ty::TraitRef<'tcx>, - candidate_set: &mut ProjectionTyCandidateSet<'tcx>, -) { - debug!("assemble_candidates_from_param_env(..)"); - assemble_candidates_from_predicates( - selcx, - obligation, - obligation_trait_ref, - candidate_set, - ProjectionTyCandidate::ParamEnv, - obligation.param_env.caller_bounds.iter().cloned(), - ); -} - -/// In the case of a nested projection like <<A as Foo>::FooT as Bar>::BarT, we may find -/// that the definition of `Foo` has some clues: -/// -/// ``` -/// trait Foo { -/// type FooT : Bar<BarT=i32> -/// } -/// ``` -/// -/// Here, for example, we could conclude that the result is `i32`. -fn assemble_candidates_from_trait_def<'cx, 'tcx>( - selcx: &mut SelectionContext<'cx, 'tcx>, - obligation: &ProjectionTyObligation<'tcx>, - obligation_trait_ref: &ty::TraitRef<'tcx>, - candidate_set: &mut ProjectionTyCandidateSet<'tcx>, -) { - debug!("assemble_candidates_from_trait_def(..)"); - - let tcx = selcx.tcx(); - // Check whether the self-type is itself a projection. - let (def_id, substs) = match obligation_trait_ref.self_ty().kind { - ty::Projection(ref data) => (data.trait_ref(tcx).def_id, data.substs), - ty::Opaque(def_id, substs) => (def_id, substs), - ty::Infer(ty::TyVar(_)) => { - // If the self-type is an inference variable, then it MAY wind up - // being a projected type, so induce an ambiguity. - candidate_set.mark_ambiguous(); - return; - } - _ => return, - }; - - // If so, extract what we know from the trait and try to come up with a good answer. - let trait_predicates = tcx.predicates_of(def_id); - let bounds = trait_predicates.instantiate(tcx, substs); - let bounds = elaborate_predicates(tcx, bounds.predicates); - assemble_candidates_from_predicates( - selcx, - obligation, - obligation_trait_ref, - candidate_set, - ProjectionTyCandidate::TraitDef, - bounds, - ) -} - -fn assemble_candidates_from_predicates<'cx, 'tcx, I>( - selcx: &mut SelectionContext<'cx, 'tcx>, - obligation: &ProjectionTyObligation<'tcx>, - obligation_trait_ref: &ty::TraitRef<'tcx>, - candidate_set: &mut ProjectionTyCandidateSet<'tcx>, - ctor: fn(ty::PolyProjectionPredicate<'tcx>) -> ProjectionTyCandidate<'tcx>, - env_predicates: I, -) where - I: IntoIterator<Item = ty::Predicate<'tcx>>, -{ - debug!("assemble_candidates_from_predicates(obligation={:?})", obligation); - let infcx = selcx.infcx(); - for predicate in env_predicates { - debug!("assemble_candidates_from_predicates: predicate={:?}", predicate); - if let ty::Predicate::Projection(data) = predicate { - let same_def_id = data.projection_def_id() == obligation.predicate.item_def_id; - - let is_match = same_def_id - && infcx.probe(|_| { - let data_poly_trait_ref = data.to_poly_trait_ref(infcx.tcx); - let obligation_poly_trait_ref = obligation_trait_ref.to_poly_trait_ref(); - infcx - .at(&obligation.cause, obligation.param_env) - .sup(obligation_poly_trait_ref, data_poly_trait_ref) - .map(|InferOk { obligations: _, value: () }| { - // FIXME(#32730) -- do we need to take obligations - // into account in any way? At the moment, no. - }) - .is_ok() - }); - - debug!( - "assemble_candidates_from_predicates: candidate={:?} \ - is_match={} same_def_id={}", - data, is_match, same_def_id - ); - - if is_match { - candidate_set.push_candidate(ctor(data)); - } - } - } -} - -fn assemble_candidates_from_impls<'cx, 'tcx>( - selcx: &mut SelectionContext<'cx, 'tcx>, - obligation: &ProjectionTyObligation<'tcx>, - obligation_trait_ref: &ty::TraitRef<'tcx>, - candidate_set: &mut ProjectionTyCandidateSet<'tcx>, -) { - // If we are resolving `<T as TraitRef<...>>::Item == Type`, - // start out by selecting the predicate `T as TraitRef<...>`: - let poly_trait_ref = obligation_trait_ref.to_poly_trait_ref(); - let trait_obligation = obligation.with(poly_trait_ref.to_poly_trait_predicate()); - let _ = selcx.infcx().commit_if_ok(|_| { - let vtable = match selcx.select(&trait_obligation) { - Ok(Some(vtable)) => vtable, - Ok(None) => { - candidate_set.mark_ambiguous(); - return Err(()); - } - Err(e) => { - debug!("assemble_candidates_from_impls: selection error {:?}", e); - candidate_set.mark_error(e); - return Err(()); - } - }; - - let eligible = match &vtable { - super::VtableClosure(_) - | super::VtableGenerator(_) - | super::VtableFnPointer(_) - | super::VtableObject(_) - | super::VtableTraitAlias(_) => { - debug!("assemble_candidates_from_impls: vtable={:?}", vtable); - true - } - super::VtableImpl(impl_data) => { - // We have to be careful when projecting out of an - // impl because of specialization. If we are not in - // codegen (i.e., projection mode is not "any"), and the - // impl's type is declared as default, then we disable - // projection (even if the trait ref is fully - // monomorphic). In the case where trait ref is not - // fully monomorphic (i.e., includes type parameters), - // this is because those type parameters may - // ultimately be bound to types from other crates that - // may have specialized impls we can't see. In the - // case where the trait ref IS fully monomorphic, this - // is a policy decision that we made in the RFC in - // order to preserve flexibility for the crate that - // defined the specializable impl to specialize later - // for existing types. - // - // In either case, we handle this by not adding a - // candidate for an impl if it contains a `default` - // type. - // - // NOTE: This should be kept in sync with the similar code in - // `rustc::ty::instance::resolve_associated_item()`. - let node_item = - assoc_ty_def(selcx, impl_data.impl_def_id, obligation.predicate.item_def_id); - - let is_default = if node_item.node.is_from_trait() { - // If true, the impl inherited a `type Foo = Bar` - // given in the trait, which is implicitly default. - // Otherwise, the impl did not specify `type` and - // neither did the trait: - // - // ```rust - // trait Foo { type T; } - // impl Foo for Bar { } - // ``` - // - // This is an error, but it will be - // reported in `check_impl_items_against_trait`. - // We accept it here but will flag it as - // an error when we confirm the candidate - // (which will ultimately lead to `normalize_to_error` - // being invoked). - false - } else { - // If we're looking at a trait *impl*, the item is - // specializable if the impl or the item are marked - // `default`. - node_item.item.defaultness.is_default() - || super::util::impl_is_default(selcx.tcx(), node_item.node.def_id()) - }; - - match is_default { - // Non-specializable items are always projectable - false => true, - - // Only reveal a specializable default if we're past type-checking - // and the obligation is monomorphic, otherwise passes such as - // transmute checking and polymorphic MIR optimizations could - // get a result which isn't correct for all monomorphizations. - true if obligation.param_env.reveal == Reveal::All => { - // NOTE(eddyb) inference variables can resolve to parameters, so - // assume `poly_trait_ref` isn't monomorphic, if it contains any. - let poly_trait_ref = - selcx.infcx().resolve_vars_if_possible(&poly_trait_ref); - !poly_trait_ref.needs_infer() && !poly_trait_ref.needs_subst() - } - - true => { - debug!( - "assemble_candidates_from_impls: not eligible due to default: \ - assoc_ty={} predicate={}", - selcx.tcx().def_path_str(node_item.item.def_id), - obligation.predicate, - ); - false - } - } - } - super::VtableParam(..) => { - // This case tell us nothing about the value of an - // associated type. Consider: - // - // ``` - // trait SomeTrait { type Foo; } - // fn foo<T:SomeTrait>(...) { } - // ``` - // - // If the user writes `<T as SomeTrait>::Foo`, then the `T - // : SomeTrait` binding does not help us decide what the - // type `Foo` is (at least, not more specifically than - // what we already knew). - // - // But wait, you say! What about an example like this: - // - // ``` - // fn bar<T:SomeTrait<Foo=usize>>(...) { ... } - // ``` - // - // Doesn't the `T : Sometrait<Foo=usize>` predicate help - // resolve `T::Foo`? And of course it does, but in fact - // that single predicate is desugared into two predicates - // in the compiler: a trait predicate (`T : SomeTrait`) and a - // projection. And the projection where clause is handled - // in `assemble_candidates_from_param_env`. - false - } - super::VtableAutoImpl(..) | super::VtableBuiltin(..) => { - // These traits have no associated types. - span_bug!( - obligation.cause.span, - "Cannot project an associated type from `{:?}`", - vtable - ); - } - }; - - if eligible { - if candidate_set.push_candidate(ProjectionTyCandidate::Select(vtable)) { - Ok(()) - } else { - Err(()) - } - } else { - Err(()) - } - }); -} - -fn confirm_candidate<'cx, 'tcx>( - selcx: &mut SelectionContext<'cx, 'tcx>, - obligation: &ProjectionTyObligation<'tcx>, - obligation_trait_ref: &ty::TraitRef<'tcx>, - candidate: ProjectionTyCandidate<'tcx>, -) -> Progress<'tcx> { - debug!("confirm_candidate(candidate={:?}, obligation={:?})", candidate, obligation); - - match candidate { - ProjectionTyCandidate::ParamEnv(poly_projection) - | ProjectionTyCandidate::TraitDef(poly_projection) => { - confirm_param_env_candidate(selcx, obligation, poly_projection) - } - - ProjectionTyCandidate::Select(vtable) => { - confirm_select_candidate(selcx, obligation, obligation_trait_ref, vtable) - } - } -} - -fn confirm_select_candidate<'cx, 'tcx>( - selcx: &mut SelectionContext<'cx, 'tcx>, - obligation: &ProjectionTyObligation<'tcx>, - obligation_trait_ref: &ty::TraitRef<'tcx>, - vtable: Selection<'tcx>, -) -> Progress<'tcx> { - match vtable { - super::VtableImpl(data) => confirm_impl_candidate(selcx, obligation, data), - super::VtableGenerator(data) => confirm_generator_candidate(selcx, obligation, data), - super::VtableClosure(data) => confirm_closure_candidate(selcx, obligation, data), - super::VtableFnPointer(data) => confirm_fn_pointer_candidate(selcx, obligation, data), - super::VtableObject(_) => confirm_object_candidate(selcx, obligation, obligation_trait_ref), - super::VtableAutoImpl(..) - | super::VtableParam(..) - | super::VtableBuiltin(..) - | super::VtableTraitAlias(..) => - // we don't create Select candidates with this kind of resolution - { - span_bug!( - obligation.cause.span, - "Cannot project an associated type from `{:?}`", - vtable - ) - } - } -} - -fn confirm_object_candidate<'cx, 'tcx>( - selcx: &mut SelectionContext<'cx, 'tcx>, - obligation: &ProjectionTyObligation<'tcx>, - obligation_trait_ref: &ty::TraitRef<'tcx>, -) -> Progress<'tcx> { - let self_ty = obligation_trait_ref.self_ty(); - let object_ty = selcx.infcx().shallow_resolve(self_ty); - debug!("confirm_object_candidate(object_ty={:?})", object_ty); - let data = match object_ty.kind { - ty::Dynamic(ref data, ..) => data, - _ => span_bug!( - obligation.cause.span, - "confirm_object_candidate called with non-object: {:?}", - object_ty - ), - }; - let env_predicates = data - .projection_bounds() - .map(|p| p.with_self_ty(selcx.tcx(), object_ty).to_predicate()) - .collect(); - let env_predicate = { - let env_predicates = elaborate_predicates(selcx.tcx(), env_predicates); - - // select only those projections that are actually projecting an - // item with the correct name - let env_predicates = env_predicates.filter_map(|p| match p { - ty::Predicate::Projection(data) => { - if data.projection_def_id() == obligation.predicate.item_def_id { - Some(data) - } else { - None - } - } - _ => None, - }); - - // select those with a relevant trait-ref - let mut env_predicates = env_predicates.filter(|data| { - let data_poly_trait_ref = data.to_poly_trait_ref(selcx.tcx()); - let obligation_poly_trait_ref = obligation_trait_ref.to_poly_trait_ref(); - selcx.infcx().probe(|_| { - selcx - .infcx() - .at(&obligation.cause, obligation.param_env) - .sup(obligation_poly_trait_ref, data_poly_trait_ref) - .is_ok() - }) - }); - - // select the first matching one; there really ought to be one or - // else the object type is not WF, since an object type should - // include all of its projections explicitly - match env_predicates.next() { - Some(env_predicate) => env_predicate, - None => { - debug!( - "confirm_object_candidate: no env-predicate \ - found in object type `{:?}`; ill-formed", - object_ty - ); - return Progress::error(selcx.tcx()); - } - } - }; - - confirm_param_env_candidate(selcx, obligation, env_predicate) -} - -fn confirm_generator_candidate<'cx, 'tcx>( - selcx: &mut SelectionContext<'cx, 'tcx>, - obligation: &ProjectionTyObligation<'tcx>, - vtable: VtableGeneratorData<'tcx, PredicateObligation<'tcx>>, -) -> Progress<'tcx> { - let gen_sig = vtable.substs.as_generator().poly_sig(vtable.generator_def_id, selcx.tcx()); - let Normalized { value: gen_sig, obligations } = normalize_with_depth( - selcx, - obligation.param_env, - obligation.cause.clone(), - obligation.recursion_depth + 1, - &gen_sig, - ); - - debug!( - "confirm_generator_candidate: obligation={:?},gen_sig={:?},obligations={:?}", - obligation, gen_sig, obligations - ); - - let tcx = selcx.tcx(); - - let gen_def_id = tcx.lang_items().gen_trait().unwrap(); - - let predicate = super::util::generator_trait_ref_and_outputs( - tcx, - gen_def_id, - obligation.predicate.self_ty(), - gen_sig, - ) - .map_bound(|(trait_ref, yield_ty, return_ty)| { - let name = tcx.associated_item(obligation.predicate.item_def_id).ident.name; - let ty = if name == sym::Return { - return_ty - } else if name == sym::Yield { - yield_ty - } else { - bug!() - }; - - ty::ProjectionPredicate { - projection_ty: ty::ProjectionTy { - substs: trait_ref.substs, - item_def_id: obligation.predicate.item_def_id, - }, - ty: ty, - } - }); - - confirm_param_env_candidate(selcx, obligation, predicate) - .with_addl_obligations(vtable.nested) - .with_addl_obligations(obligations) -} - -fn confirm_fn_pointer_candidate<'cx, 'tcx>( - selcx: &mut SelectionContext<'cx, 'tcx>, - obligation: &ProjectionTyObligation<'tcx>, - fn_pointer_vtable: VtableFnPointerData<'tcx, PredicateObligation<'tcx>>, -) -> Progress<'tcx> { - let fn_type = selcx.infcx().shallow_resolve(fn_pointer_vtable.fn_ty); - let sig = fn_type.fn_sig(selcx.tcx()); - let Normalized { value: sig, obligations } = normalize_with_depth( - selcx, - obligation.param_env, - obligation.cause.clone(), - obligation.recursion_depth + 1, - &sig, - ); - - confirm_callable_candidate(selcx, obligation, sig, util::TupleArgumentsFlag::Yes) - .with_addl_obligations(fn_pointer_vtable.nested) - .with_addl_obligations(obligations) -} - -fn confirm_closure_candidate<'cx, 'tcx>( - selcx: &mut SelectionContext<'cx, 'tcx>, - obligation: &ProjectionTyObligation<'tcx>, - vtable: VtableClosureData<'tcx, PredicateObligation<'tcx>>, -) -> Progress<'tcx> { - let tcx = selcx.tcx(); - let infcx = selcx.infcx(); - let closure_sig_ty = vtable.substs.as_closure().sig_ty(vtable.closure_def_id, tcx); - let closure_sig = infcx.shallow_resolve(closure_sig_ty).fn_sig(tcx); - let Normalized { value: closure_sig, obligations } = normalize_with_depth( - selcx, - obligation.param_env, - obligation.cause.clone(), - obligation.recursion_depth + 1, - &closure_sig, - ); - - debug!( - "confirm_closure_candidate: obligation={:?},closure_sig={:?},obligations={:?}", - obligation, closure_sig, obligations - ); - - confirm_callable_candidate(selcx, obligation, closure_sig, util::TupleArgumentsFlag::No) - .with_addl_obligations(vtable.nested) - .with_addl_obligations(obligations) -} - -fn confirm_callable_candidate<'cx, 'tcx>( - selcx: &mut SelectionContext<'cx, 'tcx>, - obligation: &ProjectionTyObligation<'tcx>, - fn_sig: ty::PolyFnSig<'tcx>, - flag: util::TupleArgumentsFlag, -) -> Progress<'tcx> { - let tcx = selcx.tcx(); - - debug!("confirm_callable_candidate({:?},{:?})", obligation, fn_sig); - - // the `Output` associated type is declared on `FnOnce` - let fn_once_def_id = tcx.lang_items().fn_once_trait().unwrap(); - - let predicate = super::util::closure_trait_ref_and_return_type( - tcx, - fn_once_def_id, - obligation.predicate.self_ty(), - fn_sig, - flag, - ) - .map_bound(|(trait_ref, ret_type)| ty::ProjectionPredicate { - projection_ty: ty::ProjectionTy::from_ref_and_name( - tcx, - trait_ref, - Ident::with_dummy_span(rustc_hir::FN_OUTPUT_NAME), - ), - ty: ret_type, - }); - - confirm_param_env_candidate(selcx, obligation, predicate) -} - -fn confirm_param_env_candidate<'cx, 'tcx>( - selcx: &mut SelectionContext<'cx, 'tcx>, - obligation: &ProjectionTyObligation<'tcx>, - poly_cache_entry: ty::PolyProjectionPredicate<'tcx>, -) -> Progress<'tcx> { - let infcx = selcx.infcx(); - let cause = &obligation.cause; - let param_env = obligation.param_env; - - let (cache_entry, _) = infcx.replace_bound_vars_with_fresh_vars( - cause.span, - LateBoundRegionConversionTime::HigherRankedType, - &poly_cache_entry, - ); - - let cache_trait_ref = cache_entry.projection_ty.trait_ref(infcx.tcx); - let obligation_trait_ref = obligation.predicate.trait_ref(infcx.tcx); - match infcx.at(cause, param_env).eq(cache_trait_ref, obligation_trait_ref) { - Ok(InferOk { value: _, obligations }) => Progress { ty: cache_entry.ty, obligations }, - Err(e) => { - let msg = format!( - "Failed to unify obligation `{:?}` with poly_projection `{:?}`: {:?}", - obligation, poly_cache_entry, e, - ); - debug!("confirm_param_env_candidate: {}", msg); - infcx.tcx.sess.delay_span_bug(obligation.cause.span, &msg); - Progress { ty: infcx.tcx.types.err, obligations: vec![] } - } - } -} - -fn confirm_impl_candidate<'cx, 'tcx>( - selcx: &mut SelectionContext<'cx, 'tcx>, - obligation: &ProjectionTyObligation<'tcx>, - impl_vtable: VtableImplData<'tcx, PredicateObligation<'tcx>>, -) -> Progress<'tcx> { - let tcx = selcx.tcx(); - - let VtableImplData { impl_def_id, substs, nested } = impl_vtable; - let assoc_item_id = obligation.predicate.item_def_id; - let trait_def_id = tcx.trait_id_of_impl(impl_def_id).unwrap(); - - let param_env = obligation.param_env; - let assoc_ty = assoc_ty_def(selcx, impl_def_id, assoc_item_id); - - if !assoc_ty.item.defaultness.has_value() { - // This means that the impl is missing a definition for the - // associated type. This error will be reported by the type - // checker method `check_impl_items_against_trait`, so here we - // just return Error. - debug!( - "confirm_impl_candidate: no associated type {:?} for {:?}", - assoc_ty.item.ident, obligation.predicate - ); - return Progress { ty: tcx.types.err, obligations: nested }; - } - let substs = obligation.predicate.substs.rebase_onto(tcx, trait_def_id, substs); - let substs = translate_substs(selcx.infcx(), param_env, impl_def_id, substs, assoc_ty.node); - let ty = if let ty::AssocKind::OpaqueTy = assoc_ty.item.kind { - let item_substs = InternalSubsts::identity_for_item(tcx, assoc_ty.item.def_id); - tcx.mk_opaque(assoc_ty.item.def_id, item_substs) - } else { - tcx.type_of(assoc_ty.item.def_id) - }; - if substs.len() != tcx.generics_of(assoc_ty.item.def_id).count() { - tcx.sess - .delay_span_bug(DUMMY_SP, "impl item and trait item have different parameter counts"); - Progress { ty: tcx.types.err, obligations: nested } - } else { - Progress { ty: ty.subst(tcx, substs), obligations: nested } - } -} - -/// Locate the definition of an associated type in the specialization hierarchy, -/// starting from the given impl. -/// -/// Based on the "projection mode", this lookup may in fact only examine the -/// topmost impl. See the comments for `Reveal` for more details. -fn assoc_ty_def( - selcx: &SelectionContext<'_, '_>, - impl_def_id: DefId, - assoc_ty_def_id: DefId, -) -> specialization_graph::NodeItem<ty::AssocItem> { - let tcx = selcx.tcx(); - let assoc_ty_name = tcx.associated_item(assoc_ty_def_id).ident; - let trait_def_id = tcx.impl_trait_ref(impl_def_id).unwrap().def_id; - let trait_def = tcx.trait_def(trait_def_id); - - // This function may be called while we are still building the - // specialization graph that is queried below (via TraidDef::ancestors()), - // so, in order to avoid unnecessary infinite recursion, we manually look - // for the associated item at the given impl. - // If there is no such item in that impl, this function will fail with a - // cycle error if the specialization graph is currently being built. - let impl_node = specialization_graph::Node::Impl(impl_def_id); - for item in impl_node.items(tcx) { - if matches!(item.kind, ty::AssocKind::Type | ty::AssocKind::OpaqueTy) - && tcx.hygienic_eq(item.ident, assoc_ty_name, trait_def_id) - { - return specialization_graph::NodeItem { - node: specialization_graph::Node::Impl(impl_def_id), - item: *item, - }; - } - } - - if let Some(assoc_item) = - trait_def.ancestors(tcx, impl_def_id).leaf_def(tcx, assoc_ty_name, ty::AssocKind::Type) - { - assoc_item - } else { - // This is saying that neither the trait nor - // the impl contain a definition for this - // associated type. Normally this situation - // could only arise through a compiler bug -- - // if the user wrote a bad item name, it - // should have failed in astconv. - bug!("No associated type `{}` for {}", assoc_ty_name, tcx.def_path_str(impl_def_id)) + Normalized { value, obligations: self.obligations } } } @@ -1541,26 +68,14 @@ pub struct ProjectionCacheKey<'tcx> { ty: ty::ProjectionTy<'tcx>, } -impl<'cx, 'tcx> ProjectionCacheKey<'tcx> { - pub fn from_poly_projection_predicate( - selcx: &mut SelectionContext<'cx, 'tcx>, - predicate: &ty::PolyProjectionPredicate<'tcx>, - ) -> Option<Self> { - let infcx = selcx.infcx(); - // We don't do cross-snapshot caching of obligations with escaping regions, - // so there's no cache key to use - predicate.no_bound_vars().map(|predicate| ProjectionCacheKey { - // We don't attempt to match up with a specific type-variable state - // from a specific call to `opt_normalize_projection_type` - if - // there's no precise match, the original cache entry is "stranded" - // anyway. - ty: infcx.resolve_vars_if_possible(&predicate.projection_ty), - }) +impl ProjectionCacheKey<'tcx> { + pub fn new(ty: ty::ProjectionTy<'tcx>) -> Self { + Self { ty } } } #[derive(Clone, Debug)] -enum ProjectionCacheEntry<'tcx> { +pub enum ProjectionCacheEntry<'tcx> { InProgress, Ambiguous, Error, @@ -1596,7 +111,7 @@ impl<'tcx> ProjectionCache<'tcx> { /// Try to start normalize `key`; returns an error if /// normalization already occurred (this error corresponds to a /// cache hit, so it's actually a good thing). - fn try_start( + pub fn try_start( &mut self, key: ProjectionCacheKey<'tcx>, ) -> Result<(), ProjectionCacheEntry<'tcx>> { @@ -1609,7 +124,7 @@ impl<'tcx> ProjectionCache<'tcx> { } /// Indicates that `key` was normalized to `value`. - fn insert_ty(&mut self, key: ProjectionCacheKey<'tcx>, value: NormalizedTy<'tcx>) { + pub fn insert_ty(&mut self, key: ProjectionCacheKey<'tcx>, value: NormalizedTy<'tcx>) { debug!( "ProjectionCacheEntry::insert_ty: adding cache entry: key={:?}, value={:?}", key, value @@ -1662,14 +177,14 @@ impl<'tcx> ProjectionCache<'tcx> { /// ambiguity. No point in trying it again then until we gain more /// type information (in which case, the "fully resolved" key will /// be different). - fn ambiguous(&mut self, key: ProjectionCacheKey<'tcx>) { + pub fn ambiguous(&mut self, key: ProjectionCacheKey<'tcx>) { let fresh = self.map.insert(key, ProjectionCacheEntry::Ambiguous); assert!(!fresh, "never started projecting `{:?}`", key); } /// Indicates that trying to normalize `key` resulted in /// error. - fn error(&mut self, key: ProjectionCacheKey<'tcx>) { + pub fn error(&mut self, key: ProjectionCacheKey<'tcx>) { let fresh = self.map.insert(key, ProjectionCacheEntry::Error); assert!(!fresh, "never started projecting `{:?}`", key); } diff --git a/src/librustc_infer/traits/query/dropck_outlives.rs b/src/librustc_infer/traits/query/dropck_outlives.rs deleted file mode 100644 index a1d7a2836e4..00000000000 --- a/src/librustc_infer/traits/query/dropck_outlives.rs +++ /dev/null @@ -1,137 +0,0 @@ -use crate::infer::at::At; -use crate::infer::canonical::OriginalQueryValues; -use crate::infer::InferOk; - -use rustc::ty::subst::GenericArg; -use rustc::ty::{self, Ty, TyCtxt}; - -pub use rustc::traits::query::{DropckOutlivesResult, DtorckConstraint}; - -impl<'cx, 'tcx> At<'cx, 'tcx> { - /// Given a type `ty` of some value being dropped, computes a set - /// of "kinds" (types, regions) that must be outlive the execution - /// of the destructor. These basically correspond to data that the - /// destructor might access. This is used during regionck to - /// impose "outlives" constraints on any lifetimes referenced - /// within. - /// - /// The rules here are given by the "dropck" RFCs, notably [#1238] - /// and [#1327]. This is a fixed-point computation, where we - /// explore all the data that will be dropped (transitively) when - /// a value of type `ty` is dropped. For each type T that will be - /// dropped and which has a destructor, we must assume that all - /// the types/regions of T are live during the destructor, unless - /// they are marked with a special attribute (`#[may_dangle]`). - /// - /// [#1238]: https://github.com/rust-lang/rfcs/blob/master/text/1238-nonparametric-dropck.md - /// [#1327]: https://github.com/rust-lang/rfcs/blob/master/text/1327-dropck-param-eyepatch.md - pub fn dropck_outlives(&self, ty: Ty<'tcx>) -> InferOk<'tcx, Vec<GenericArg<'tcx>>> { - debug!("dropck_outlives(ty={:?}, param_env={:?})", ty, self.param_env,); - - // Quick check: there are a number of cases that we know do not require - // any destructor. - let tcx = self.infcx.tcx; - if trivial_dropck_outlives(tcx, ty) { - return InferOk { value: vec![], obligations: vec![] }; - } - - let mut orig_values = OriginalQueryValues::default(); - let c_ty = self.infcx.canonicalize_query(&self.param_env.and(ty), &mut orig_values); - let span = self.cause.span; - debug!("c_ty = {:?}", c_ty); - if let Ok(result) = &tcx.dropck_outlives(c_ty) { - if result.is_proven() { - if let Ok(InferOk { value, obligations }) = - self.infcx.instantiate_query_response_and_region_obligations( - self.cause, - self.param_env, - &orig_values, - result, - ) - { - let ty = self.infcx.resolve_vars_if_possible(&ty); - let kinds = value.into_kinds_reporting_overflows(tcx, span, ty); - return InferOk { value: kinds, obligations }; - } - } - } - - // Errors and ambiuity in dropck occur in two cases: - // - unresolved inference variables at the end of typeck - // - non well-formed types where projections cannot be resolved - // Either of these should have created an error before. - tcx.sess.delay_span_bug(span, "dtorck encountered internal error"); - - InferOk { value: vec![], obligations: vec![] } - } -} - -/// This returns true if the type `ty` is "trivial" for -/// dropck-outlives -- that is, if it doesn't require any types to -/// outlive. This is similar but not *quite* the same as the -/// `needs_drop` test in the compiler already -- that is, for every -/// type T for which this function return true, needs-drop would -/// return `false`. But the reverse does not hold: in particular, -/// `needs_drop` returns false for `PhantomData`, but it is not -/// trivial for dropck-outlives. -/// -/// Note also that `needs_drop` requires a "global" type (i.e., one -/// with erased regions), but this function does not. -pub fn trivial_dropck_outlives<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> bool { - match ty.kind { - // None of these types have a destructor and hence they do not - // require anything in particular to outlive the dtor's - // execution. - ty::Infer(ty::FreshIntTy(_)) - | ty::Infer(ty::FreshFloatTy(_)) - | ty::Bool - | ty::Int(_) - | ty::Uint(_) - | ty::Float(_) - | ty::Never - | ty::FnDef(..) - | ty::FnPtr(_) - | ty::Char - | ty::GeneratorWitness(..) - | ty::RawPtr(_) - | ty::Ref(..) - | ty::Str - | ty::Foreign(..) - | ty::Error => true, - - // [T; N] and [T] have same properties as T. - ty::Array(ty, _) | ty::Slice(ty) => trivial_dropck_outlives(tcx, ty), - - // (T1..Tn) and closures have same properties as T1..Tn -- - // check if *any* of those are trivial. - ty::Tuple(ref tys) => tys.iter().all(|t| trivial_dropck_outlives(tcx, t.expect_ty())), - ty::Closure(def_id, ref substs) => { - substs.as_closure().upvar_tys(def_id, tcx).all(|t| trivial_dropck_outlives(tcx, t)) - } - - ty::Adt(def, _) => { - if Some(def.did) == tcx.lang_items().manually_drop() { - // `ManuallyDrop` never has a dtor. - true - } else { - // Other types might. Moreover, PhantomData doesn't - // have a dtor, but it is considered to own its - // content, so it is non-trivial. Unions can have `impl Drop`, - // and hence are non-trivial as well. - false - } - } - - // The following *might* require a destructor: needs deeper inspection. - ty::Dynamic(..) - | ty::Projection(..) - | ty::Param(_) - | ty::Opaque(..) - | ty::Placeholder(..) - | ty::Infer(_) - | ty::Bound(..) - | ty::Generator(..) => false, - - ty::UnnormalizedProjection(..) => bug!("only used with chalk-engine"), - } -} diff --git a/src/librustc_infer/traits/query/evaluate_obligation.rs b/src/librustc_infer/traits/query/evaluate_obligation.rs deleted file mode 100644 index b9ce3ccff27..00000000000 --- a/src/librustc_infer/traits/query/evaluate_obligation.rs +++ /dev/null @@ -1,75 +0,0 @@ -use crate::infer::canonical::OriginalQueryValues; -use crate::infer::InferCtxt; -use crate::traits::{ - EvaluationResult, OverflowError, PredicateObligation, SelectionContext, TraitQueryMode, -}; - -impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> { - /// Evaluates whether the predicate can be satisfied (by any means) - /// in the given `ParamEnv`. - pub fn predicate_may_hold(&self, obligation: &PredicateObligation<'tcx>) -> bool { - self.evaluate_obligation_no_overflow(obligation).may_apply() - } - - /// Evaluates whether the predicate can be satisfied in the given - /// `ParamEnv`, and returns `false` if not certain. However, this is - /// not entirely accurate if inference variables are involved. - /// - /// This version may conservatively fail when outlives obligations - /// are required. - pub fn predicate_must_hold_considering_regions( - &self, - obligation: &PredicateObligation<'tcx>, - ) -> bool { - self.evaluate_obligation_no_overflow(obligation).must_apply_considering_regions() - } - - /// Evaluates whether the predicate can be satisfied in the given - /// `ParamEnv`, and returns `false` if not certain. However, this is - /// not entirely accurate if inference variables are involved. - /// - /// This version ignores all outlives constraints. - pub fn predicate_must_hold_modulo_regions( - &self, - obligation: &PredicateObligation<'tcx>, - ) -> bool { - self.evaluate_obligation_no_overflow(obligation).must_apply_modulo_regions() - } - - /// Evaluate a given predicate, capturing overflow and propagating it back. - pub fn evaluate_obligation( - &self, - obligation: &PredicateObligation<'tcx>, - ) -> Result<EvaluationResult, OverflowError> { - let mut _orig_values = OriginalQueryValues::default(); - let c_pred = self - .canonicalize_query(&obligation.param_env.and(obligation.predicate), &mut _orig_values); - // Run canonical query. If overflow occurs, rerun from scratch but this time - // in standard trait query mode so that overflow is handled appropriately - // within `SelectionContext`. - self.tcx.evaluate_obligation(c_pred) - } - - // Helper function that canonicalizes and runs the query. If an - // overflow results, we re-run it in the local context so we can - // report a nice error. - crate fn evaluate_obligation_no_overflow( - &self, - obligation: &PredicateObligation<'tcx>, - ) -> EvaluationResult { - match self.evaluate_obligation(obligation) { - Ok(result) => result, - Err(OverflowError) => { - let mut selcx = SelectionContext::with_query_mode(&self, TraitQueryMode::Standard); - selcx.evaluate_root_obligation(obligation).unwrap_or_else(|r| { - span_bug!( - obligation.cause.span, - "Overflow should be caught earlier in standard query mode: {:?}, {:?}", - obligation, - r, - ) - }) - } - } - } -} diff --git a/src/librustc_infer/traits/query/method_autoderef.rs b/src/librustc_infer/traits/query/method_autoderef.rs deleted file mode 100644 index 80748c5ef38..00000000000 --- a/src/librustc_infer/traits/query/method_autoderef.rs +++ /dev/null @@ -1 +0,0 @@ -pub use rustc::traits::query::{CandidateStep, MethodAutoderefBadTy, MethodAutoderefStepsResult}; diff --git a/src/librustc_infer/traits/query/mod.rs b/src/librustc_infer/traits/query/mod.rs deleted file mode 100644 index 77b5ec669a0..00000000000 --- a/src/librustc_infer/traits/query/mod.rs +++ /dev/null @@ -1,15 +0,0 @@ -//! Experimental types for the trait query interface. The methods -//! defined in this module are all based on **canonicalization**, -//! which makes a canonical query by replacing unbound inference -//! variables and regions, so that results can be reused more broadly. -//! The providers for the queries defined here can be found in -//! `librustc_traits`. - -pub mod dropck_outlives; -pub mod evaluate_obligation; -pub mod method_autoderef; -pub mod normalize; -pub mod outlives_bounds; -pub mod type_op; - -pub use rustc::traits::query::*; diff --git a/src/librustc_infer/traits/query/normalize.rs b/src/librustc_infer/traits/query/normalize.rs deleted file mode 100644 index 4577e3d2e1c..00000000000 --- a/src/librustc_infer/traits/query/normalize.rs +++ /dev/null @@ -1,189 +0,0 @@ -//! Code for the 'normalization' query. This consists of a wrapper -//! which folds deeply, invoking the underlying -//! `normalize_projection_ty` query when it encounters projections. - -use crate::infer::at::At; -use crate::infer::canonical::OriginalQueryValues; -use crate::infer::{InferCtxt, InferOk}; -use crate::traits::project::Normalized; -use crate::traits::{Obligation, ObligationCause, PredicateObligation, Reveal}; -use rustc::ty::fold::{TypeFoldable, TypeFolder}; -use rustc::ty::subst::Subst; -use rustc::ty::{self, Ty, TyCtxt}; - -use super::NoSolution; - -pub use rustc::traits::query::NormalizationResult; - -impl<'cx, 'tcx> At<'cx, 'tcx> { - /// Normalize `value` in the context of the inference context, - /// yielding a resulting type, or an error if `value` cannot be - /// normalized. If you don't care about regions, you should prefer - /// `normalize_erasing_regions`, which is more efficient. - /// - /// If the normalization succeeds and is unambiguous, returns back - /// the normalized value along with various outlives relations (in - /// the form of obligations that must be discharged). - /// - /// N.B., this will *eventually* be the main means of - /// normalizing, but for now should be used only when we actually - /// know that normalization will succeed, since error reporting - /// and other details are still "under development". - pub fn normalize<T>(&self, value: &T) -> Result<Normalized<'tcx, T>, NoSolution> - where - T: TypeFoldable<'tcx>, - { - debug!( - "normalize::<{}>(value={:?}, param_env={:?})", - ::std::any::type_name::<T>(), - value, - self.param_env, - ); - if !value.has_projections() { - return Ok(Normalized { value: value.clone(), obligations: vec![] }); - } - - let mut normalizer = QueryNormalizer { - infcx: self.infcx, - cause: self.cause, - param_env: self.param_env, - obligations: vec![], - error: false, - anon_depth: 0, - }; - - let value1 = value.fold_with(&mut normalizer); - if normalizer.error { - Err(NoSolution) - } else { - Ok(Normalized { value: value1, obligations: normalizer.obligations }) - } - } -} - -struct QueryNormalizer<'cx, 'tcx> { - infcx: &'cx InferCtxt<'cx, 'tcx>, - cause: &'cx ObligationCause<'tcx>, - param_env: ty::ParamEnv<'tcx>, - obligations: Vec<PredicateObligation<'tcx>>, - error: bool, - anon_depth: usize, -} - -impl<'cx, 'tcx> TypeFolder<'tcx> for QueryNormalizer<'cx, 'tcx> { - fn tcx<'c>(&'c self) -> TyCtxt<'tcx> { - self.infcx.tcx - } - - fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> { - if !ty.has_projections() { - return ty; - } - - let ty = ty.super_fold_with(self); - match ty.kind { - ty::Opaque(def_id, substs) if !substs.has_escaping_bound_vars() => { - // (*) - // Only normalize `impl Trait` after type-checking, usually in codegen. - match self.param_env.reveal { - Reveal::UserFacing => ty, - - Reveal::All => { - let recursion_limit = *self.tcx().sess.recursion_limit.get(); - if self.anon_depth >= recursion_limit { - let obligation = Obligation::with_depth( - self.cause.clone(), - recursion_limit, - self.param_env, - ty, - ); - self.infcx.report_overflow_error(&obligation, true); - } - - let generic_ty = self.tcx().type_of(def_id); - let concrete_ty = generic_ty.subst(self.tcx(), substs); - self.anon_depth += 1; - if concrete_ty == ty { - bug!( - "infinite recursion generic_ty: {:#?}, substs: {:#?}, \ - concrete_ty: {:#?}, ty: {:#?}", - generic_ty, - substs, - concrete_ty, - ty - ); - } - let folded_ty = self.fold_ty(concrete_ty); - self.anon_depth -= 1; - folded_ty - } - } - } - - ty::Projection(ref data) if !data.has_escaping_bound_vars() => { - // (*) - // (*) This is kind of hacky -- we need to be able to - // handle normalization within binders because - // otherwise we wind up a need to normalize when doing - // trait matching (since you can have a trait - // obligation like `for<'a> T::B : Fn(&'a int)`), but - // we can't normalize with bound regions in scope. So - // far now we just ignore binders but only normalize - // if all bound regions are gone (and then we still - // have to renormalize whenever we instantiate a - // binder). It would be better to normalize in a - // binding-aware fashion. - - let tcx = self.infcx.tcx; - - let mut orig_values = OriginalQueryValues::default(); - // HACK(matthewjasper) `'static` is special-cased in selection, - // so we cannot canonicalize it. - let c_data = self - .infcx - .canonicalize_hr_query_hack(&self.param_env.and(*data), &mut orig_values); - debug!("QueryNormalizer: c_data = {:#?}", c_data); - debug!("QueryNormalizer: orig_values = {:#?}", orig_values); - match tcx.normalize_projection_ty(c_data) { - Ok(result) => { - // We don't expect ambiguity. - if result.is_ambiguous() { - self.error = true; - return ty; - } - - match self.infcx.instantiate_query_response_and_region_obligations( - self.cause, - self.param_env, - &orig_values, - &result, - ) { - Ok(InferOk { value: result, obligations }) => { - debug!("QueryNormalizer: result = {:#?}", result); - debug!("QueryNormalizer: obligations = {:#?}", obligations); - self.obligations.extend(obligations); - return result.normalized_ty; - } - - Err(_) => { - self.error = true; - return ty; - } - } - } - - Err(NoSolution) => { - self.error = true; - ty - } - } - } - - _ => ty, - } - } - - fn fold_const(&mut self, constant: &'tcx ty::Const<'tcx>) -> &'tcx ty::Const<'tcx> { - constant.eval(self.infcx.tcx, self.param_env) - } -} diff --git a/src/librustc_infer/traits/query/outlives_bounds.rs b/src/librustc_infer/traits/query/outlives_bounds.rs deleted file mode 100644 index eb32ebf5c4d..00000000000 --- a/src/librustc_infer/traits/query/outlives_bounds.rs +++ /dev/null @@ -1,103 +0,0 @@ -use crate::infer::canonical::OriginalQueryValues; -use crate::infer::InferCtxt; -use crate::traits::query::NoSolution; -use crate::traits::{FulfillmentContext, ObligationCause, TraitEngine, TraitEngineExt}; -use rustc::ty::{self, Ty}; -use rustc_hir as hir; -use rustc_span::source_map::Span; - -pub use rustc::traits::query::OutlivesBound; - -impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> { - /// Implied bounds are region relationships that we deduce - /// automatically. The idea is that (e.g.) a caller must check that a - /// function's argument types are well-formed immediately before - /// calling that fn, and hence the *callee* can assume that its - /// argument types are well-formed. This may imply certain relationships - /// between generic parameters. For example: - /// - /// fn foo<'a,T>(x: &'a T) - /// - /// can only be called with a `'a` and `T` such that `&'a T` is WF. - /// For `&'a T` to be WF, `T: 'a` must hold. So we can assume `T: 'a`. - /// - /// # Parameters - /// - /// - `param_env`, the where-clauses in scope - /// - `body_id`, the body-id to use when normalizing assoc types. - /// Note that this may cause outlives obligations to be injected - /// into the inference context with this body-id. - /// - `ty`, the type that we are supposed to assume is WF. - /// - `span`, a span to use when normalizing, hopefully not important, - /// might be useful if a `bug!` occurs. - pub fn implied_outlives_bounds( - &self, - param_env: ty::ParamEnv<'tcx>, - body_id: hir::HirId, - ty: Ty<'tcx>, - span: Span, - ) -> Vec<OutlivesBound<'tcx>> { - debug!("implied_outlives_bounds(ty = {:?})", ty); - - let mut orig_values = OriginalQueryValues::default(); - let key = self.canonicalize_query(¶m_env.and(ty), &mut orig_values); - let result = match self.tcx.implied_outlives_bounds(key) { - Ok(r) => r, - Err(NoSolution) => { - self.tcx.sess.delay_span_bug( - span, - "implied_outlives_bounds failed to solve all obligations", - ); - return vec![]; - } - }; - assert!(result.value.is_proven()); - - let result = self.instantiate_query_response_and_region_obligations( - &ObligationCause::misc(span, body_id), - param_env, - &orig_values, - &result, - ); - debug!("implied_outlives_bounds for {:?}: {:#?}", ty, result); - let result = match result { - Ok(v) => v, - Err(_) => { - self.tcx.sess.delay_span_bug(span, "implied_outlives_bounds failed to instantiate"); - return vec![]; - } - }; - - // Instantiation may have produced new inference variables and constraints on those - // variables. Process these constraints. - let mut fulfill_cx = FulfillmentContext::new(); - fulfill_cx.register_predicate_obligations(self, result.obligations); - if fulfill_cx.select_all_or_error(self).is_err() { - self.tcx.sess.delay_span_bug( - span, - "implied_outlives_bounds failed to solve obligations from instantiation", - ); - } - - result.value - } -} - -pub fn explicit_outlives_bounds<'tcx>( - param_env: ty::ParamEnv<'tcx>, -) -> impl Iterator<Item = OutlivesBound<'tcx>> + 'tcx { - debug!("explicit_outlives_bounds()"); - param_env.caller_bounds.into_iter().filter_map(move |predicate| match predicate { - ty::Predicate::Projection(..) - | ty::Predicate::Trait(..) - | ty::Predicate::Subtype(..) - | ty::Predicate::WellFormed(..) - | ty::Predicate::ObjectSafe(..) - | ty::Predicate::ClosureKind(..) - | ty::Predicate::TypeOutlives(..) - | ty::Predicate::ConstEvaluatable(..) => None, - ty::Predicate::RegionOutlives(ref data) => data - .no_bound_vars() - .map(|ty::OutlivesPredicate(r_a, r_b)| OutlivesBound::RegionSubRegion(r_b, r_a)), - }) -} diff --git a/src/librustc_infer/traits/query/type_op/ascribe_user_type.rs b/src/librustc_infer/traits/query/type_op/ascribe_user_type.rs deleted file mode 100644 index b14b79f0907..00000000000 --- a/src/librustc_infer/traits/query/type_op/ascribe_user_type.rs +++ /dev/null @@ -1,23 +0,0 @@ -use crate::infer::canonical::{Canonicalized, CanonicalizedQueryResponse}; -use crate::traits::query::Fallible; -use rustc::ty::{ParamEnvAnd, TyCtxt}; - -pub use rustc::traits::query::type_op::AscribeUserType; - -impl<'tcx> super::QueryTypeOp<'tcx> for AscribeUserType<'tcx> { - type QueryResponse = (); - - fn try_fast_path( - _tcx: TyCtxt<'tcx>, - _key: &ParamEnvAnd<'tcx, Self>, - ) -> Option<Self::QueryResponse> { - None - } - - fn perform_query( - tcx: TyCtxt<'tcx>, - canonicalized: Canonicalized<'tcx, ParamEnvAnd<'tcx, Self>>, - ) -> Fallible<CanonicalizedQueryResponse<'tcx, ()>> { - tcx.type_op_ascribe_user_type(canonicalized) - } -} diff --git a/src/librustc_infer/traits/query/type_op/custom.rs b/src/librustc_infer/traits/query/type_op/custom.rs deleted file mode 100644 index c1c9030b888..00000000000 --- a/src/librustc_infer/traits/query/type_op/custom.rs +++ /dev/null @@ -1,106 +0,0 @@ -use crate::infer::{InferCtxt, InferOk}; -use crate::traits::query::Fallible; -use std::fmt; - -use crate::infer::canonical::query_response; -use crate::infer::canonical::QueryRegionConstraints; -use crate::traits::{ObligationCause, TraitEngine, TraitEngineExt}; -use rustc_span::source_map::DUMMY_SP; -use std::rc::Rc; - -pub struct CustomTypeOp<F, G> { - closure: F, - description: G, -} - -impl<F, G> CustomTypeOp<F, G> { - pub fn new<'tcx, R>(closure: F, description: G) -> Self - where - F: FnOnce(&InferCtxt<'_, 'tcx>) -> Fallible<InferOk<'tcx, R>>, - G: Fn() -> String, - { - CustomTypeOp { closure, description } - } -} - -impl<'tcx, F, R, G> super::TypeOp<'tcx> for CustomTypeOp<F, G> -where - F: for<'a, 'cx> FnOnce(&'a InferCtxt<'cx, 'tcx>) -> Fallible<InferOk<'tcx, R>>, - G: Fn() -> String, -{ - type Output = R; - - /// Processes the operation and all resulting obligations, - /// returning the final result along with any region constraints - /// (they will be given over to the NLL region solver). - fn fully_perform( - self, - infcx: &InferCtxt<'_, 'tcx>, - ) -> Fallible<(Self::Output, Option<Rc<QueryRegionConstraints<'tcx>>>)> { - if cfg!(debug_assertions) { - info!("fully_perform({:?})", self); - } - - scrape_region_constraints(infcx, || Ok((self.closure)(infcx)?)) - } -} - -impl<F, G> fmt::Debug for CustomTypeOp<F, G> -where - G: Fn() -> String, -{ - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{}", (self.description)()) - } -} - -/// Executes `op` and then scrapes out all the "old style" region -/// constraints that result, creating query-region-constraints. -fn scrape_region_constraints<'tcx, R>( - infcx: &InferCtxt<'_, 'tcx>, - op: impl FnOnce() -> Fallible<InferOk<'tcx, R>>, -) -> Fallible<(R, Option<Rc<QueryRegionConstraints<'tcx>>>)> { - let mut fulfill_cx = TraitEngine::new(infcx.tcx); - let dummy_body_id = ObligationCause::dummy().body_id; - - // During NLL, we expect that nobody will register region - // obligations **except** as part of a custom type op (and, at the - // end of each custom type op, we scrape out the region - // obligations that resulted). So this vector should be empty on - // entry. - let pre_obligations = infcx.take_registered_region_obligations(); - assert!( - pre_obligations.is_empty(), - "scrape_region_constraints: incoming region obligations = {:#?}", - pre_obligations, - ); - - let InferOk { value, obligations } = infcx.commit_if_ok(|_| op())?; - debug_assert!(obligations.iter().all(|o| o.cause.body_id == dummy_body_id)); - fulfill_cx.register_predicate_obligations(infcx, obligations); - if let Err(e) = fulfill_cx.select_all_or_error(infcx) { - infcx.tcx.sess.diagnostic().delay_span_bug( - DUMMY_SP, - &format!("errors selecting obligation during MIR typeck: {:?}", e), - ); - } - - let region_obligations = infcx.take_registered_region_obligations(); - - let region_constraint_data = infcx.take_and_reset_region_constraints(); - - let region_constraints = query_response::make_query_region_constraints( - infcx.tcx, - region_obligations - .iter() - .map(|(_, r_o)| (r_o.sup_type, r_o.sub_region)) - .map(|(ty, r)| (infcx.resolve_vars_if_possible(&ty), r)), - ®ion_constraint_data, - ); - - if region_constraints.is_empty() { - Ok((value, None)) - } else { - Ok((value, Some(Rc::new(region_constraints)))) - } -} diff --git a/src/librustc_infer/traits/query/type_op/eq.rs b/src/librustc_infer/traits/query/type_op/eq.rs deleted file mode 100644 index 3b6fbc7d8dd..00000000000 --- a/src/librustc_infer/traits/query/type_op/eq.rs +++ /dev/null @@ -1,23 +0,0 @@ -use crate::infer::canonical::{Canonicalized, CanonicalizedQueryResponse}; -use crate::traits::query::Fallible; -use rustc::ty::{ParamEnvAnd, TyCtxt}; - -pub use rustc::traits::query::type_op::Eq; - -impl<'tcx> super::QueryTypeOp<'tcx> for Eq<'tcx> { - type QueryResponse = (); - - fn try_fast_path( - _tcx: TyCtxt<'tcx>, - key: &ParamEnvAnd<'tcx, Eq<'tcx>>, - ) -> Option<Self::QueryResponse> { - if key.value.a == key.value.b { Some(()) } else { None } - } - - fn perform_query( - tcx: TyCtxt<'tcx>, - canonicalized: Canonicalized<'tcx, ParamEnvAnd<'tcx, Self>>, - ) -> Fallible<CanonicalizedQueryResponse<'tcx, ()>> { - tcx.type_op_eq(canonicalized) - } -} diff --git a/src/librustc_infer/traits/query/type_op/implied_outlives_bounds.rs b/src/librustc_infer/traits/query/type_op/implied_outlives_bounds.rs deleted file mode 100644 index 3dad546872e..00000000000 --- a/src/librustc_infer/traits/query/type_op/implied_outlives_bounds.rs +++ /dev/null @@ -1,41 +0,0 @@ -use crate::infer::canonical::{Canonicalized, CanonicalizedQueryResponse}; -use crate::traits::query::outlives_bounds::OutlivesBound; -use crate::traits::query::Fallible; -use rustc::ty::{ParamEnvAnd, Ty, TyCtxt}; - -#[derive(Clone, Debug, HashStable, TypeFoldable, Lift)] -pub struct ImpliedOutlivesBounds<'tcx> { - pub ty: Ty<'tcx>, -} - -impl<'tcx> ImpliedOutlivesBounds<'tcx> { - pub fn new(ty: Ty<'tcx>) -> Self { - ImpliedOutlivesBounds { ty } - } -} - -impl<'tcx> super::QueryTypeOp<'tcx> for ImpliedOutlivesBounds<'tcx> { - type QueryResponse = Vec<OutlivesBound<'tcx>>; - - fn try_fast_path( - _tcx: TyCtxt<'tcx>, - _key: &ParamEnvAnd<'tcx, Self>, - ) -> Option<Self::QueryResponse> { - None - } - - fn perform_query( - tcx: TyCtxt<'tcx>, - canonicalized: Canonicalized<'tcx, ParamEnvAnd<'tcx, Self>>, - ) -> Fallible<CanonicalizedQueryResponse<'tcx, Self::QueryResponse>> { - // FIXME this `unchecked_map` is only necessary because the - // query is defined as taking a `ParamEnvAnd<Ty>`; it should - // take a `ImpliedOutlivesBounds` instead - let canonicalized = canonicalized.unchecked_map(|ParamEnvAnd { param_env, value }| { - let ImpliedOutlivesBounds { ty } = value; - param_env.and(ty) - }); - - tcx.implied_outlives_bounds(canonicalized) - } -} diff --git a/src/librustc_infer/traits/query/type_op/mod.rs b/src/librustc_infer/traits/query/type_op/mod.rs deleted file mode 100644 index eb4c0a029e1..00000000000 --- a/src/librustc_infer/traits/query/type_op/mod.rs +++ /dev/null @@ -1,136 +0,0 @@ -use crate::infer::canonical::{ - Canonicalized, CanonicalizedQueryResponse, OriginalQueryValues, QueryRegionConstraints, -}; -use crate::infer::{InferCtxt, InferOk}; -use crate::traits::query::Fallible; -use crate::traits::ObligationCause; -use rustc::ty::fold::TypeFoldable; -use rustc::ty::{ParamEnvAnd, TyCtxt}; -use std::fmt; -use std::rc::Rc; - -pub mod ascribe_user_type; -pub mod custom; -pub mod eq; -pub mod implied_outlives_bounds; -pub mod normalize; -pub mod outlives; -pub mod prove_predicate; -use self::prove_predicate::ProvePredicate; -pub mod subtype; - -pub use rustc::traits::query::type_op::*; - -/// "Type ops" are used in NLL to perform some particular action and -/// extract out the resulting region constraints (or an error if it -/// cannot be completed). -pub trait TypeOp<'tcx>: Sized + fmt::Debug { - type Output; - - /// Processes the operation and all resulting obligations, - /// returning the final result along with any region constraints - /// (they will be given over to the NLL region solver). - fn fully_perform( - self, - infcx: &InferCtxt<'_, 'tcx>, - ) -> Fallible<(Self::Output, Option<Rc<QueryRegionConstraints<'tcx>>>)>; -} - -/// "Query type ops" are type ops that are implemented using a -/// [canonical query][c]. The `Self` type here contains the kernel of -/// information needed to do the operation -- `TypeOp` is actually -/// implemented for `ParamEnvAnd<Self>`, since we always need to bring -/// along a parameter environment as well. For query type-ops, we will -/// first canonicalize the key and then invoke the query on the tcx, -/// which produces the resulting query region constraints. -/// -/// [c]: https://rust-lang.github.io/rustc-guide/traits/canonicalization.html -pub trait QueryTypeOp<'tcx>: fmt::Debug + Sized + TypeFoldable<'tcx> + 'tcx { - type QueryResponse: TypeFoldable<'tcx>; - - /// Give query the option for a simple fast path that never - /// actually hits the tcx cache lookup etc. Return `Some(r)` with - /// a final result or `None` to do the full path. - fn try_fast_path( - tcx: TyCtxt<'tcx>, - key: &ParamEnvAnd<'tcx, Self>, - ) -> Option<Self::QueryResponse>; - - /// Performs the actual query with the canonicalized key -- the - /// real work happens here. This method is not given an `infcx` - /// because it shouldn't need one -- and if it had access to one, - /// it might do things like invoke `sub_regions`, which would be - /// bad, because it would create subregion relationships that are - /// not captured in the return value. - fn perform_query( - tcx: TyCtxt<'tcx>, - canonicalized: Canonicalized<'tcx, ParamEnvAnd<'tcx, Self>>, - ) -> Fallible<CanonicalizedQueryResponse<'tcx, Self::QueryResponse>>; - - fn fully_perform_into( - query_key: ParamEnvAnd<'tcx, Self>, - infcx: &InferCtxt<'_, 'tcx>, - output_query_region_constraints: &mut QueryRegionConstraints<'tcx>, - ) -> Fallible<Self::QueryResponse> { - if let Some(result) = QueryTypeOp::try_fast_path(infcx.tcx, &query_key) { - return Ok(result); - } - - // FIXME(#33684) -- We need to use - // `canonicalize_hr_query_hack` here because of things - // like the subtype query, which go awry around - // `'static` otherwise. - let mut canonical_var_values = OriginalQueryValues::default(); - let canonical_self = - infcx.canonicalize_hr_query_hack(&query_key, &mut canonical_var_values); - let canonical_result = Self::perform_query(infcx.tcx, canonical_self)?; - - let param_env = query_key.param_env; - - let InferOk { value, obligations } = infcx - .instantiate_nll_query_response_and_region_obligations( - &ObligationCause::dummy(), - param_env, - &canonical_var_values, - canonical_result, - output_query_region_constraints, - )?; - - // Typically, instantiating NLL query results does not - // create obligations. However, in some cases there - // are unresolved type variables, and unify them *can* - // create obligations. In that case, we have to go - // fulfill them. We do this via a (recursive) query. - for obligation in obligations { - let () = ProvePredicate::fully_perform_into( - obligation.param_env.and(ProvePredicate::new(obligation.predicate)), - infcx, - output_query_region_constraints, - )?; - } - - Ok(value) - } -} - -impl<'tcx, Q> TypeOp<'tcx> for ParamEnvAnd<'tcx, Q> -where - Q: QueryTypeOp<'tcx>, -{ - type Output = Q::QueryResponse; - - fn fully_perform( - self, - infcx: &InferCtxt<'_, 'tcx>, - ) -> Fallible<(Self::Output, Option<Rc<QueryRegionConstraints<'tcx>>>)> { - let mut region_constraints = QueryRegionConstraints::default(); - let r = Q::fully_perform_into(self, infcx, &mut region_constraints)?; - - // Promote the final query-region-constraints into a - // (optional) ref-counted vector: - let opt_qrc = - if region_constraints.is_empty() { None } else { Some(Rc::new(region_constraints)) }; - - Ok((r, opt_qrc)) - } -} diff --git a/src/librustc_infer/traits/query/type_op/normalize.rs b/src/librustc_infer/traits/query/type_op/normalize.rs deleted file mode 100644 index d2eec53bf80..00000000000 --- a/src/librustc_infer/traits/query/type_op/normalize.rs +++ /dev/null @@ -1,68 +0,0 @@ -use crate::infer::canonical::{Canonicalized, CanonicalizedQueryResponse}; -use crate::traits::query::Fallible; -use rustc::ty::fold::TypeFoldable; -use rustc::ty::{self, Lift, ParamEnvAnd, Ty, TyCtxt}; -use std::fmt; - -pub use rustc::traits::query::type_op::Normalize; - -impl<'tcx, T> super::QueryTypeOp<'tcx> for Normalize<T> -where - T: Normalizable<'tcx> + 'tcx, -{ - type QueryResponse = T; - - fn try_fast_path(_tcx: TyCtxt<'tcx>, key: &ParamEnvAnd<'tcx, Self>) -> Option<T> { - if !key.value.value.has_projections() { Some(key.value.value) } else { None } - } - - fn perform_query( - tcx: TyCtxt<'tcx>, - canonicalized: Canonicalized<'tcx, ParamEnvAnd<'tcx, Self>>, - ) -> Fallible<CanonicalizedQueryResponse<'tcx, Self::QueryResponse>> { - T::type_op_method(tcx, canonicalized) - } -} - -pub trait Normalizable<'tcx>: fmt::Debug + TypeFoldable<'tcx> + Lift<'tcx> + Copy { - fn type_op_method( - tcx: TyCtxt<'tcx>, - canonicalized: Canonicalized<'tcx, ParamEnvAnd<'tcx, Normalize<Self>>>, - ) -> Fallible<CanonicalizedQueryResponse<'tcx, Self>>; -} - -impl Normalizable<'tcx> for Ty<'tcx> { - fn type_op_method( - tcx: TyCtxt<'tcx>, - canonicalized: Canonicalized<'tcx, ParamEnvAnd<'tcx, Normalize<Self>>>, - ) -> Fallible<CanonicalizedQueryResponse<'tcx, Self>> { - tcx.type_op_normalize_ty(canonicalized) - } -} - -impl Normalizable<'tcx> for ty::Predicate<'tcx> { - fn type_op_method( - tcx: TyCtxt<'tcx>, - canonicalized: Canonicalized<'tcx, ParamEnvAnd<'tcx, Normalize<Self>>>, - ) -> Fallible<CanonicalizedQueryResponse<'tcx, Self>> { - tcx.type_op_normalize_predicate(canonicalized) - } -} - -impl Normalizable<'tcx> for ty::PolyFnSig<'tcx> { - fn type_op_method( - tcx: TyCtxt<'tcx>, - canonicalized: Canonicalized<'tcx, ParamEnvAnd<'tcx, Normalize<Self>>>, - ) -> Fallible<CanonicalizedQueryResponse<'tcx, Self>> { - tcx.type_op_normalize_poly_fn_sig(canonicalized) - } -} - -impl Normalizable<'tcx> for ty::FnSig<'tcx> { - fn type_op_method( - tcx: TyCtxt<'tcx>, - canonicalized: Canonicalized<'tcx, ParamEnvAnd<'tcx, Normalize<Self>>>, - ) -> Fallible<CanonicalizedQueryResponse<'tcx, Self>> { - tcx.type_op_normalize_fn_sig(canonicalized) - } -} diff --git a/src/librustc_infer/traits/query/type_op/outlives.rs b/src/librustc_infer/traits/query/type_op/outlives.rs deleted file mode 100644 index b94948cffd6..00000000000 --- a/src/librustc_infer/traits/query/type_op/outlives.rs +++ /dev/null @@ -1,55 +0,0 @@ -use crate::infer::canonical::{Canonicalized, CanonicalizedQueryResponse}; -use crate::traits::query::dropck_outlives::{trivial_dropck_outlives, DropckOutlivesResult}; -use crate::traits::query::Fallible; -use rustc::ty::{ParamEnvAnd, Ty, TyCtxt}; - -#[derive(Copy, Clone, Debug, HashStable, TypeFoldable, Lift)] -pub struct DropckOutlives<'tcx> { - dropped_ty: Ty<'tcx>, -} - -impl<'tcx> DropckOutlives<'tcx> { - pub fn new(dropped_ty: Ty<'tcx>) -> Self { - DropckOutlives { dropped_ty } - } -} - -impl super::QueryTypeOp<'tcx> for DropckOutlives<'tcx> { - type QueryResponse = DropckOutlivesResult<'tcx>; - - fn try_fast_path( - tcx: TyCtxt<'tcx>, - key: &ParamEnvAnd<'tcx, Self>, - ) -> Option<Self::QueryResponse> { - if trivial_dropck_outlives(tcx, key.value.dropped_ty) { - Some(DropckOutlivesResult::default()) - } else { - None - } - } - - fn perform_query( - tcx: TyCtxt<'tcx>, - canonicalized: Canonicalized<'tcx, ParamEnvAnd<'tcx, Self>>, - ) -> Fallible<CanonicalizedQueryResponse<'tcx, Self::QueryResponse>> { - // Subtle: note that we are not invoking - // `infcx.at(...).dropck_outlives(...)` here, but rather the - // underlying `dropck_outlives` query. This same underlying - // query is also used by the - // `infcx.at(...).dropck_outlives(...)` fn. Avoiding the - // wrapper means we don't need an infcx in this code, which is - // good because the interface doesn't give us one (so that we - // know we are not registering any subregion relations or - // other things). - - // FIXME convert to the type expected by the `dropck_outlives` - // query. This should eventually be fixed by changing the - // *underlying query*. - let canonicalized = canonicalized.unchecked_map(|ParamEnvAnd { param_env, value }| { - let DropckOutlives { dropped_ty } = value; - param_env.and(dropped_ty) - }); - - tcx.dropck_outlives(canonicalized) - } -} diff --git a/src/librustc_infer/traits/query/type_op/prove_predicate.rs b/src/librustc_infer/traits/query/type_op/prove_predicate.rs deleted file mode 100644 index 8c68f7db9e5..00000000000 --- a/src/librustc_infer/traits/query/type_op/prove_predicate.rs +++ /dev/null @@ -1,37 +0,0 @@ -use crate::infer::canonical::{Canonicalized, CanonicalizedQueryResponse}; -use crate::traits::query::Fallible; -use rustc::ty::{ParamEnvAnd, Predicate, TyCtxt}; - -pub use rustc::traits::query::type_op::ProvePredicate; - -impl<'tcx> super::QueryTypeOp<'tcx> for ProvePredicate<'tcx> { - type QueryResponse = (); - - fn try_fast_path( - tcx: TyCtxt<'tcx>, - key: &ParamEnvAnd<'tcx, Self>, - ) -> Option<Self::QueryResponse> { - // Proving Sized, very often on "obviously sized" types like - // `&T`, accounts for about 60% percentage of the predicates - // we have to prove. No need to canonicalize and all that for - // such cases. - if let Predicate::Trait(trait_ref, _) = key.value.predicate { - if let Some(sized_def_id) = tcx.lang_items().sized_trait() { - if trait_ref.def_id() == sized_def_id { - if trait_ref.skip_binder().self_ty().is_trivially_sized(tcx) { - return Some(()); - } - } - } - } - - None - } - - fn perform_query( - tcx: TyCtxt<'tcx>, - canonicalized: Canonicalized<'tcx, ParamEnvAnd<'tcx, Self>>, - ) -> Fallible<CanonicalizedQueryResponse<'tcx, ()>> { - tcx.type_op_prove_predicate(canonicalized) - } -} diff --git a/src/librustc_infer/traits/query/type_op/subtype.rs b/src/librustc_infer/traits/query/type_op/subtype.rs deleted file mode 100644 index 053411b0cac..00000000000 --- a/src/librustc_infer/traits/query/type_op/subtype.rs +++ /dev/null @@ -1,20 +0,0 @@ -use crate::infer::canonical::{Canonicalized, CanonicalizedQueryResponse}; -use crate::traits::query::Fallible; -use rustc::ty::{ParamEnvAnd, TyCtxt}; - -pub use rustc::traits::query::type_op::Subtype; - -impl<'tcx> super::QueryTypeOp<'tcx> for Subtype<'tcx> { - type QueryResponse = (); - - fn try_fast_path(_tcx: TyCtxt<'tcx>, key: &ParamEnvAnd<'tcx, Self>) -> Option<()> { - if key.value.sub == key.value.sup { Some(()) } else { None } - } - - fn perform_query( - tcx: TyCtxt<'tcx>, - canonicalized: Canonicalized<'tcx, ParamEnvAnd<'tcx, Self>>, - ) -> Fallible<CanonicalizedQueryResponse<'tcx, ()>> { - tcx.type_op_subtype(canonicalized) - } -} diff --git a/src/librustc_infer/traits/select.rs b/src/librustc_infer/traits/select.rs deleted file mode 100644 index 4c312c9fce2..00000000000 --- a/src/librustc_infer/traits/select.rs +++ /dev/null @@ -1,3823 +0,0 @@ -// ignore-tidy-filelength - -//! Candidate selection. See the [rustc guide] for more information on how this works. -//! -//! [rustc guide]: https://rust-lang.github.io/rustc-guide/traits/resolution.html#selection - -use self::EvaluationResult::*; -use self::SelectionCandidate::*; - -use super::coherence::{self, Conflict}; -use super::project; -use super::project::{ - normalize_with_depth, normalize_with_depth_to, Normalized, ProjectionCacheKey, -}; -use super::util; -use super::util::{closure_trait_ref_and_return_type, predicate_for_trait_def}; -use super::wf; -use super::DerivedObligationCause; -use super::Selection; -use super::SelectionResult; -use super::TraitNotObjectSafe; -use super::TraitQueryMode; -use super::{BuiltinDerivedObligation, ImplDerivedObligation, ObligationCauseCode}; -use super::{ObjectCastObligation, Obligation}; -use super::{ObligationCause, PredicateObligation, TraitObligation}; -use super::{OutputTypeParameterMismatch, Overflow, SelectionError, Unimplemented}; -use super::{ - VtableAutoImpl, VtableBuiltin, VtableClosure, VtableFnPointer, VtableGenerator, VtableImpl, - VtableObject, VtableParam, VtableTraitAlias, -}; -use super::{ - VtableAutoImplData, VtableBuiltinData, VtableClosureData, VtableFnPointerData, - VtableGeneratorData, VtableImplData, VtableObjectData, VtableTraitAliasData, -}; - -use crate::infer::{CombinedSnapshot, InferCtxt, InferOk, PlaceholderMap, TypeFreshener}; -use rustc::dep_graph::{DepKind, DepNodeIndex}; -use rustc::middle::lang_items; -use rustc::ty::fast_reject; -use rustc::ty::relate::TypeRelation; -use rustc::ty::subst::{Subst, SubstsRef}; -use rustc::ty::{self, ToPolyTraitRef, ToPredicate, Ty, TyCtxt, TypeFoldable, WithConstness}; -use rustc_ast::attr; -use rustc_data_structures::fx::{FxHashMap, FxHashSet}; -use rustc_hir as hir; -use rustc_hir::def_id::DefId; -use rustc_index::bit_set::GrowableBitSet; -use rustc_span::symbol::sym; -use rustc_target::spec::abi::Abi; - -use std::cell::{Cell, RefCell}; -use std::cmp; -use std::fmt::{self, Display}; -use std::iter; -use std::rc::Rc; - -pub use rustc::traits::select::*; - -pub struct SelectionContext<'cx, 'tcx> { - infcx: &'cx InferCtxt<'cx, 'tcx>, - - /// Freshener used specifically for entries on the obligation - /// stack. This ensures that all entries on the stack at one time - /// will have the same set of placeholder entries, which is - /// important for checking for trait bounds that recursively - /// require themselves. - freshener: TypeFreshener<'cx, 'tcx>, - - /// If `true`, indicates that the evaluation should be conservative - /// and consider the possibility of types outside this crate. - /// This comes up primarily when resolving ambiguity. Imagine - /// there is some trait reference `$0: Bar` where `$0` is an - /// inference variable. If `intercrate` is true, then we can never - /// say for sure that this reference is not implemented, even if - /// there are *no impls at all for `Bar`*, because `$0` could be - /// bound to some type that in a downstream crate that implements - /// `Bar`. This is the suitable mode for coherence. Elsewhere, - /// though, we set this to false, because we are only interested - /// in types that the user could actually have written --- in - /// other words, we consider `$0: Bar` to be unimplemented if - /// there is no type that the user could *actually name* that - /// would satisfy it. This avoids crippling inference, basically. - intercrate: bool, - - intercrate_ambiguity_causes: Option<Vec<IntercrateAmbiguityCause>>, - - /// Controls whether or not to filter out negative impls when selecting. - /// This is used in librustdoc to distinguish between the lack of an impl - /// and a negative impl - allow_negative_impls: bool, - - /// The mode that trait queries run in, which informs our error handling - /// policy. In essence, canonicalized queries need their errors propagated - /// rather than immediately reported because we do not have accurate spans. - query_mode: TraitQueryMode, -} - -#[derive(Clone, Debug)] -pub enum IntercrateAmbiguityCause { - DownstreamCrate { trait_desc: String, self_desc: Option<String> }, - UpstreamCrateUpdate { trait_desc: String, self_desc: Option<String> }, - ReservationImpl { message: String }, -} - -impl IntercrateAmbiguityCause { - /// Emits notes when the overlap is caused by complex intercrate ambiguities. - /// See #23980 for details. - pub fn add_intercrate_ambiguity_hint(&self, err: &mut rustc_errors::DiagnosticBuilder<'_>) { - err.note(&self.intercrate_ambiguity_hint()); - } - - pub fn intercrate_ambiguity_hint(&self) -> String { - match self { - &IntercrateAmbiguityCause::DownstreamCrate { ref trait_desc, ref self_desc } => { - let self_desc = if let &Some(ref ty) = self_desc { - format!(" for type `{}`", ty) - } else { - String::new() - }; - format!("downstream crates may implement trait `{}`{}", trait_desc, self_desc) - } - &IntercrateAmbiguityCause::UpstreamCrateUpdate { ref trait_desc, ref self_desc } => { - let self_desc = if let &Some(ref ty) = self_desc { - format!(" for type `{}`", ty) - } else { - String::new() - }; - format!( - "upstream crates may add a new impl of trait `{}`{} \ - in future versions", - trait_desc, self_desc - ) - } - &IntercrateAmbiguityCause::ReservationImpl { ref message } => message.clone(), - } - } -} - -// A stack that walks back up the stack frame. -struct TraitObligationStack<'prev, 'tcx> { - obligation: &'prev TraitObligation<'tcx>, - - /// The trait ref from `obligation` but "freshened" with the - /// selection-context's freshener. Used to check for recursion. - fresh_trait_ref: ty::PolyTraitRef<'tcx>, - - /// Starts out equal to `depth` -- if, during evaluation, we - /// encounter a cycle, then we will set this flag to the minimum - /// depth of that cycle for all participants in the cycle. These - /// participants will then forego caching their results. This is - /// not the most efficient solution, but it addresses #60010. The - /// problem we are trying to prevent: - /// - /// - If you have `A: AutoTrait` requires `B: AutoTrait` and `C: NonAutoTrait` - /// - `B: AutoTrait` requires `A: AutoTrait` (coinductive cycle, ok) - /// - `C: NonAutoTrait` requires `A: AutoTrait` (non-coinductive cycle, not ok) - /// - /// you don't want to cache that `B: AutoTrait` or `A: AutoTrait` - /// is `EvaluatedToOk`; this is because they were only considered - /// ok on the premise that if `A: AutoTrait` held, but we indeed - /// encountered a problem (later on) with `A: AutoTrait. So we - /// currently set a flag on the stack node for `B: AutoTrait` (as - /// well as the second instance of `A: AutoTrait`) to suppress - /// caching. - /// - /// This is a simple, targeted fix. A more-performant fix requires - /// deeper changes, but would permit more caching: we could - /// basically defer caching until we have fully evaluated the - /// tree, and then cache the entire tree at once. In any case, the - /// performance impact here shouldn't be so horrible: every time - /// this is hit, we do cache at least one trait, so we only - /// evaluate each member of a cycle up to N times, where N is the - /// length of the cycle. This means the performance impact is - /// bounded and we shouldn't have any terrible worst-cases. - reached_depth: Cell<usize>, - - previous: TraitObligationStackList<'prev, 'tcx>, - - /// The number of parent frames plus one (thus, the topmost frame has depth 1). - depth: usize, - - /// The depth-first number of this node in the search graph -- a - /// pre-order index. Basically, a freshly incremented counter. - dfn: usize, -} - -struct SelectionCandidateSet<'tcx> { - // A list of candidates that definitely apply to the current - // obligation (meaning: types unify). - vec: Vec<SelectionCandidate<'tcx>>, - - // If `true`, then there were candidates that might or might - // not have applied, but we couldn't tell. This occurs when some - // of the input types are type variables, in which case there are - // various "builtin" rules that might or might not trigger. - ambiguous: bool, -} - -#[derive(PartialEq, Eq, Debug, Clone)] -struct EvaluatedCandidate<'tcx> { - candidate: SelectionCandidate<'tcx>, - evaluation: EvaluationResult, -} - -/// When does the builtin impl for `T: Trait` apply? -enum BuiltinImplConditions<'tcx> { - /// The impl is conditional on `T1, T2, ...: Trait`. - Where(ty::Binder<Vec<Ty<'tcx>>>), - /// There is no built-in impl. There may be some other - /// candidate (a where-clause or user-defined impl). - None, - /// It is unknown whether there is an impl. - Ambiguous, -} - -impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { - pub fn new(infcx: &'cx InferCtxt<'cx, 'tcx>) -> SelectionContext<'cx, 'tcx> { - SelectionContext { - infcx, - freshener: infcx.freshener(), - intercrate: false, - intercrate_ambiguity_causes: None, - allow_negative_impls: false, - query_mode: TraitQueryMode::Standard, - } - } - - pub fn intercrate(infcx: &'cx InferCtxt<'cx, 'tcx>) -> SelectionContext<'cx, 'tcx> { - SelectionContext { - infcx, - freshener: infcx.freshener(), - intercrate: true, - intercrate_ambiguity_causes: None, - allow_negative_impls: false, - query_mode: TraitQueryMode::Standard, - } - } - - pub fn with_negative( - infcx: &'cx InferCtxt<'cx, 'tcx>, - allow_negative_impls: bool, - ) -> SelectionContext<'cx, 'tcx> { - debug!("with_negative({:?})", allow_negative_impls); - SelectionContext { - infcx, - freshener: infcx.freshener(), - intercrate: false, - intercrate_ambiguity_causes: None, - allow_negative_impls, - query_mode: TraitQueryMode::Standard, - } - } - - pub fn with_query_mode( - infcx: &'cx InferCtxt<'cx, 'tcx>, - query_mode: TraitQueryMode, - ) -> SelectionContext<'cx, 'tcx> { - debug!("with_query_mode({:?})", query_mode); - SelectionContext { - infcx, - freshener: infcx.freshener(), - intercrate: false, - intercrate_ambiguity_causes: None, - allow_negative_impls: false, - query_mode, - } - } - - /// Enables tracking of intercrate ambiguity causes. These are - /// used in coherence to give improved diagnostics. We don't do - /// this until we detect a coherence error because it can lead to - /// false overflow results (#47139) and because it costs - /// computation time. - pub fn enable_tracking_intercrate_ambiguity_causes(&mut self) { - assert!(self.intercrate); - assert!(self.intercrate_ambiguity_causes.is_none()); - self.intercrate_ambiguity_causes = Some(vec![]); - debug!("selcx: enable_tracking_intercrate_ambiguity_causes"); - } - - /// Gets the intercrate ambiguity causes collected since tracking - /// was enabled and disables tracking at the same time. If - /// tracking is not enabled, just returns an empty vector. - pub fn take_intercrate_ambiguity_causes(&mut self) -> Vec<IntercrateAmbiguityCause> { - assert!(self.intercrate); - self.intercrate_ambiguity_causes.take().unwrap_or(vec![]) - } - - pub fn infcx(&self) -> &'cx InferCtxt<'cx, 'tcx> { - self.infcx - } - - pub fn tcx(&self) -> TyCtxt<'tcx> { - self.infcx.tcx - } - - pub fn closure_typer(&self) -> &'cx InferCtxt<'cx, 'tcx> { - self.infcx - } - - /////////////////////////////////////////////////////////////////////////// - // Selection - // - // The selection phase tries to identify *how* an obligation will - // be resolved. For example, it will identify which impl or - // parameter bound is to be used. The process can be inconclusive - // if the self type in the obligation is not fully inferred. Selection - // can result in an error in one of two ways: - // - // 1. If no applicable impl or parameter bound can be found. - // 2. If the output type parameters in the obligation do not match - // those specified by the impl/bound. For example, if the obligation - // is `Vec<Foo>: Iterable<Bar>`, but the impl specifies - // `impl<T> Iterable<T> for Vec<T>`, than an error would result. - - /// Attempts to satisfy the obligation. If successful, this will affect the surrounding - /// type environment by performing unification. - pub fn select( - &mut self, - obligation: &TraitObligation<'tcx>, - ) -> SelectionResult<'tcx, Selection<'tcx>> { - debug!("select({:?})", obligation); - debug_assert!(!obligation.predicate.has_escaping_bound_vars()); - - let pec = &ProvisionalEvaluationCache::default(); - let stack = self.push_stack(TraitObligationStackList::empty(pec), obligation); - - let candidate = match self.candidate_from_obligation(&stack) { - Err(SelectionError::Overflow) => { - // In standard mode, overflow must have been caught and reported - // earlier. - assert!(self.query_mode == TraitQueryMode::Canonical); - return Err(SelectionError::Overflow); - } - Err(e) => { - return Err(e); - } - Ok(None) => { - return Ok(None); - } - Ok(Some(candidate)) => candidate, - }; - - match self.confirm_candidate(obligation, candidate) { - Err(SelectionError::Overflow) => { - assert!(self.query_mode == TraitQueryMode::Canonical); - Err(SelectionError::Overflow) - } - Err(e) => Err(e), - Ok(candidate) => Ok(Some(candidate)), - } - } - - /////////////////////////////////////////////////////////////////////////// - // EVALUATION - // - // Tests whether an obligation can be selected or whether an impl - // can be applied to particular types. It skips the "confirmation" - // step and hence completely ignores output type parameters. - // - // The result is "true" if the obligation *may* hold and "false" if - // we can be sure it does not. - - /// Evaluates whether the obligation `obligation` can be satisfied (by any means). - pub fn predicate_may_hold_fatal(&mut self, obligation: &PredicateObligation<'tcx>) -> bool { - debug!("predicate_may_hold_fatal({:?})", obligation); - - // This fatal query is a stopgap that should only be used in standard mode, - // where we do not expect overflow to be propagated. - assert!(self.query_mode == TraitQueryMode::Standard); - - self.evaluate_root_obligation(obligation) - .expect("Overflow should be caught earlier in standard query mode") - .may_apply() - } - - /// Evaluates whether the obligation `obligation` can be satisfied - /// and returns an `EvaluationResult`. This is meant for the - /// *initial* call. - pub fn evaluate_root_obligation( - &mut self, - obligation: &PredicateObligation<'tcx>, - ) -> Result<EvaluationResult, OverflowError> { - self.evaluation_probe(|this| { - this.evaluate_predicate_recursively( - TraitObligationStackList::empty(&ProvisionalEvaluationCache::default()), - obligation.clone(), - ) - }) - } - - fn evaluation_probe( - &mut self, - op: impl FnOnce(&mut Self) -> Result<EvaluationResult, OverflowError>, - ) -> Result<EvaluationResult, OverflowError> { - self.infcx.probe(|snapshot| -> Result<EvaluationResult, OverflowError> { - let result = op(self)?; - match self.infcx.region_constraints_added_in_snapshot(snapshot) { - None => Ok(result), - Some(_) => Ok(result.max(EvaluatedToOkModuloRegions)), - } - }) - } - - /// Evaluates the predicates in `predicates` recursively. Note that - /// this applies projections in the predicates, and therefore - /// is run within an inference probe. - fn evaluate_predicates_recursively<'o, I>( - &mut self, - stack: TraitObligationStackList<'o, 'tcx>, - predicates: I, - ) -> Result<EvaluationResult, OverflowError> - where - I: IntoIterator<Item = PredicateObligation<'tcx>>, - { - let mut result = EvaluatedToOk; - for obligation in predicates { - let eval = self.evaluate_predicate_recursively(stack, obligation.clone())?; - debug!("evaluate_predicate_recursively({:?}) = {:?}", obligation, eval); - if let EvaluatedToErr = eval { - // fast-path - EvaluatedToErr is the top of the lattice, - // so we don't need to look on the other predicates. - return Ok(EvaluatedToErr); - } else { - result = cmp::max(result, eval); - } - } - Ok(result) - } - - fn evaluate_predicate_recursively<'o>( - &mut self, - previous_stack: TraitObligationStackList<'o, 'tcx>, - obligation: PredicateObligation<'tcx>, - ) -> Result<EvaluationResult, OverflowError> { - debug!( - "evaluate_predicate_recursively(previous_stack={:?}, obligation={:?})", - previous_stack.head(), - obligation - ); - - // `previous_stack` stores a `TraitObligatiom`, while `obligation` is - // a `PredicateObligation`. These are distinct types, so we can't - // use any `Option` combinator method that would force them to be - // the same. - match previous_stack.head() { - Some(h) => self.check_recursion_limit(&obligation, h.obligation)?, - None => self.check_recursion_limit(&obligation, &obligation)?, - } - - match obligation.predicate { - ty::Predicate::Trait(ref t, _) => { - debug_assert!(!t.has_escaping_bound_vars()); - let obligation = obligation.with(t.clone()); - self.evaluate_trait_predicate_recursively(previous_stack, obligation) - } - - ty::Predicate::Subtype(ref p) => { - // Does this code ever run? - match self.infcx.subtype_predicate(&obligation.cause, obligation.param_env, p) { - Some(Ok(InferOk { mut obligations, .. })) => { - self.add_depth(obligations.iter_mut(), obligation.recursion_depth); - self.evaluate_predicates_recursively( - previous_stack, - obligations.into_iter(), - ) - } - Some(Err(_)) => Ok(EvaluatedToErr), - None => Ok(EvaluatedToAmbig), - } - } - - ty::Predicate::WellFormed(ty) => match wf::obligations( - self.infcx, - obligation.param_env, - obligation.cause.body_id, - ty, - obligation.cause.span, - ) { - Some(mut obligations) => { - self.add_depth(obligations.iter_mut(), obligation.recursion_depth); - self.evaluate_predicates_recursively(previous_stack, obligations.into_iter()) - } - None => Ok(EvaluatedToAmbig), - }, - - ty::Predicate::TypeOutlives(..) | ty::Predicate::RegionOutlives(..) => { - // We do not consider region relationships when evaluating trait matches. - Ok(EvaluatedToOkModuloRegions) - } - - ty::Predicate::ObjectSafe(trait_def_id) => { - if self.tcx().is_object_safe(trait_def_id) { - Ok(EvaluatedToOk) - } else { - Ok(EvaluatedToErr) - } - } - - ty::Predicate::Projection(ref data) => { - let project_obligation = obligation.with(data.clone()); - match project::poly_project_and_unify_type(self, &project_obligation) { - Ok(Some(mut subobligations)) => { - self.add_depth(subobligations.iter_mut(), obligation.recursion_depth); - let result = self.evaluate_predicates_recursively( - previous_stack, - subobligations.into_iter(), - ); - if let Some(key) = - ProjectionCacheKey::from_poly_projection_predicate(self, data) - { - self.infcx.inner.borrow_mut().projection_cache.complete(key); - } - result - } - Ok(None) => Ok(EvaluatedToAmbig), - Err(_) => Ok(EvaluatedToErr), - } - } - - ty::Predicate::ClosureKind(closure_def_id, closure_substs, kind) => { - match self.infcx.closure_kind(closure_def_id, closure_substs) { - Some(closure_kind) => { - if closure_kind.extends(kind) { - Ok(EvaluatedToOk) - } else { - Ok(EvaluatedToErr) - } - } - None => Ok(EvaluatedToAmbig), - } - } - - ty::Predicate::ConstEvaluatable(def_id, substs) => { - match self.tcx().const_eval_resolve( - obligation.param_env, - def_id, - substs, - None, - None, - ) { - Ok(_) => Ok(EvaluatedToOk), - Err(_) => Ok(EvaluatedToErr), - } - } - } - } - - fn evaluate_trait_predicate_recursively<'o>( - &mut self, - previous_stack: TraitObligationStackList<'o, 'tcx>, - mut obligation: TraitObligation<'tcx>, - ) -> Result<EvaluationResult, OverflowError> { - debug!("evaluate_trait_predicate_recursively({:?})", obligation); - - if !self.intercrate - && obligation.is_global() - && obligation.param_env.caller_bounds.iter().all(|bound| bound.needs_subst()) - { - // If a param env has no global bounds, global obligations do not - // depend on its particular value in order to work, so we can clear - // out the param env and get better caching. - debug!("evaluate_trait_predicate_recursively({:?}) - in global", obligation); - obligation.param_env = obligation.param_env.without_caller_bounds(); - } - - let stack = self.push_stack(previous_stack, &obligation); - let fresh_trait_ref = stack.fresh_trait_ref; - if let Some(result) = self.check_evaluation_cache(obligation.param_env, fresh_trait_ref) { - debug!("CACHE HIT: EVAL({:?})={:?}", fresh_trait_ref, result); - return Ok(result); - } - - if let Some(result) = stack.cache().get_provisional(fresh_trait_ref) { - debug!("PROVISIONAL CACHE HIT: EVAL({:?})={:?}", fresh_trait_ref, result); - stack.update_reached_depth(stack.cache().current_reached_depth()); - return Ok(result); - } - - // Check if this is a match for something already on the - // stack. If so, we don't want to insert the result into the - // main cache (it is cycle dependent) nor the provisional - // cache (which is meant for things that have completed but - // for a "backedge" -- this result *is* the backedge). - if let Some(cycle_result) = self.check_evaluation_cycle(&stack) { - return Ok(cycle_result); - } - - let (result, dep_node) = self.in_task(|this| this.evaluate_stack(&stack)); - let result = result?; - - if !result.must_apply_modulo_regions() { - stack.cache().on_failure(stack.dfn); - } - - let reached_depth = stack.reached_depth.get(); - if reached_depth >= stack.depth { - debug!("CACHE MISS: EVAL({:?})={:?}", fresh_trait_ref, result); - self.insert_evaluation_cache(obligation.param_env, fresh_trait_ref, dep_node, result); - - stack.cache().on_completion(stack.depth, |fresh_trait_ref, provisional_result| { - self.insert_evaluation_cache( - obligation.param_env, - fresh_trait_ref, - dep_node, - provisional_result.max(result), - ); - }); - } else { - debug!("PROVISIONAL: {:?}={:?}", fresh_trait_ref, result); - debug!( - "evaluate_trait_predicate_recursively: caching provisionally because {:?} \ - is a cycle participant (at depth {}, reached depth {})", - fresh_trait_ref, stack.depth, reached_depth, - ); - - stack.cache().insert_provisional(stack.dfn, reached_depth, fresh_trait_ref, result); - } - - Ok(result) - } - - /// If there is any previous entry on the stack that precisely - /// matches this obligation, then we can assume that the - /// obligation is satisfied for now (still all other conditions - /// must be met of course). One obvious case this comes up is - /// marker traits like `Send`. Think of a linked list: - /// - /// struct List<T> { data: T, next: Option<Box<List<T>>> } - /// - /// `Box<List<T>>` will be `Send` if `T` is `Send` and - /// `Option<Box<List<T>>>` is `Send`, and in turn - /// `Option<Box<List<T>>>` is `Send` if `Box<List<T>>` is - /// `Send`. - /// - /// Note that we do this comparison using the `fresh_trait_ref` - /// fields. Because these have all been freshened using - /// `self.freshener`, we can be sure that (a) this will not - /// affect the inferencer state and (b) that if we see two - /// fresh regions with the same index, they refer to the same - /// unbound type variable. - fn check_evaluation_cycle( - &mut self, - stack: &TraitObligationStack<'_, 'tcx>, - ) -> Option<EvaluationResult> { - if let Some(cycle_depth) = stack - .iter() - .skip(1) // Skip top-most frame. - .find(|prev| { - stack.obligation.param_env == prev.obligation.param_env - && stack.fresh_trait_ref == prev.fresh_trait_ref - }) - .map(|stack| stack.depth) - { - debug!( - "evaluate_stack({:?}) --> recursive at depth {}", - stack.fresh_trait_ref, cycle_depth, - ); - - // If we have a stack like `A B C D E A`, where the top of - // the stack is the final `A`, then this will iterate over - // `A, E, D, C, B` -- i.e., all the participants apart - // from the cycle head. We mark them as participating in a - // cycle. This suppresses caching for those nodes. See - // `in_cycle` field for more details. - stack.update_reached_depth(cycle_depth); - - // Subtle: when checking for a coinductive cycle, we do - // not compare using the "freshened trait refs" (which - // have erased regions) but rather the fully explicit - // trait refs. This is important because it's only a cycle - // if the regions match exactly. - let cycle = stack.iter().skip(1).take_while(|s| s.depth >= cycle_depth); - let cycle = cycle.map(|stack| { - ty::Predicate::Trait(stack.obligation.predicate, hir::Constness::NotConst) - }); - if self.coinductive_match(cycle) { - debug!("evaluate_stack({:?}) --> recursive, coinductive", stack.fresh_trait_ref); - Some(EvaluatedToOk) - } else { - debug!("evaluate_stack({:?}) --> recursive, inductive", stack.fresh_trait_ref); - Some(EvaluatedToRecur) - } - } else { - None - } - } - - fn evaluate_stack<'o>( - &mut self, - stack: &TraitObligationStack<'o, 'tcx>, - ) -> Result<EvaluationResult, OverflowError> { - // In intercrate mode, whenever any of the types are unbound, - // there can always be an impl. Even if there are no impls in - // this crate, perhaps the type would be unified with - // something from another crate that does provide an impl. - // - // In intra mode, we must still be conservative. The reason is - // that we want to avoid cycles. Imagine an impl like: - // - // impl<T:Eq> Eq for Vec<T> - // - // and a trait reference like `$0 : Eq` where `$0` is an - // unbound variable. When we evaluate this trait-reference, we - // will unify `$0` with `Vec<$1>` (for some fresh variable - // `$1`), on the condition that `$1 : Eq`. We will then wind - // up with many candidates (since that are other `Eq` impls - // that apply) and try to winnow things down. This results in - // a recursive evaluation that `$1 : Eq` -- as you can - // imagine, this is just where we started. To avoid that, we - // check for unbound variables and return an ambiguous (hence possible) - // match if we've seen this trait before. - // - // This suffices to allow chains like `FnMut` implemented in - // terms of `Fn` etc, but we could probably make this more - // precise still. - let unbound_input_types = - stack.fresh_trait_ref.skip_binder().input_types().any(|ty| ty.is_fresh()); - // This check was an imperfect workaround for a bug in the old - // intercrate mode; it should be removed when that goes away. - if unbound_input_types && self.intercrate { - debug!( - "evaluate_stack({:?}) --> unbound argument, intercrate --> ambiguous", - stack.fresh_trait_ref - ); - // Heuristics: show the diagnostics when there are no candidates in crate. - if self.intercrate_ambiguity_causes.is_some() { - debug!("evaluate_stack: intercrate_ambiguity_causes is some"); - if let Ok(candidate_set) = self.assemble_candidates(stack) { - if !candidate_set.ambiguous && candidate_set.vec.is_empty() { - let trait_ref = stack.obligation.predicate.skip_binder().trait_ref; - let self_ty = trait_ref.self_ty(); - let cause = IntercrateAmbiguityCause::DownstreamCrate { - trait_desc: trait_ref.print_only_trait_path().to_string(), - self_desc: if self_ty.has_concrete_skeleton() { - Some(self_ty.to_string()) - } else { - None - }, - }; - debug!("evaluate_stack: pushing cause = {:?}", cause); - self.intercrate_ambiguity_causes.as_mut().unwrap().push(cause); - } - } - } - return Ok(EvaluatedToAmbig); - } - if unbound_input_types - && stack.iter().skip(1).any(|prev| { - stack.obligation.param_env == prev.obligation.param_env - && self.match_fresh_trait_refs( - &stack.fresh_trait_ref, - &prev.fresh_trait_ref, - prev.obligation.param_env, - ) - }) - { - debug!( - "evaluate_stack({:?}) --> unbound argument, recursive --> giving up", - stack.fresh_trait_ref - ); - return Ok(EvaluatedToUnknown); - } - - match self.candidate_from_obligation(stack) { - Ok(Some(c)) => self.evaluate_candidate(stack, &c), - Ok(None) => Ok(EvaluatedToAmbig), - Err(Overflow) => Err(OverflowError), - Err(..) => Ok(EvaluatedToErr), - } - } - - /// 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, - /// - it also appears in the backtrace at some position `X`, - /// - all the predicates at positions `X..` between `X` and the top are - /// also defaulted traits. - pub fn coinductive_match<I>(&mut self, cycle: I) -> bool - where - I: Iterator<Item = ty::Predicate<'tcx>>, - { - let mut cycle = cycle; - cycle.all(|predicate| self.coinductive_predicate(predicate)) - } - - fn coinductive_predicate(&self, predicate: ty::Predicate<'tcx>) -> bool { - let result = match predicate { - ty::Predicate::Trait(ref data, _) => self.tcx().trait_is_auto(data.def_id()), - _ => false, - }; - debug!("coinductive_predicate({:?}) = {:?}", predicate, result); - result - } - - /// Further evaluates `candidate` to decide whether all type parameters match and whether nested - /// obligations are met. Returns whether `candidate` remains viable after this further - /// scrutiny. - fn evaluate_candidate<'o>( - &mut self, - stack: &TraitObligationStack<'o, 'tcx>, - candidate: &SelectionCandidate<'tcx>, - ) -> Result<EvaluationResult, OverflowError> { - debug!( - "evaluate_candidate: depth={} candidate={:?}", - stack.obligation.recursion_depth, candidate - ); - let result = self.evaluation_probe(|this| { - let candidate = (*candidate).clone(); - match this.confirm_candidate(stack.obligation, candidate) { - Ok(selection) => this.evaluate_predicates_recursively( - stack.list(), - selection.nested_obligations().into_iter(), - ), - Err(..) => Ok(EvaluatedToErr), - } - })?; - debug!( - "evaluate_candidate: depth={} result={:?}", - stack.obligation.recursion_depth, result - ); - Ok(result) - } - - fn check_evaluation_cache( - &self, - param_env: ty::ParamEnv<'tcx>, - trait_ref: ty::PolyTraitRef<'tcx>, - ) -> Option<EvaluationResult> { - let tcx = self.tcx(); - if self.can_use_global_caches(param_env) { - let cache = tcx.evaluation_cache.hashmap.borrow(); - if let Some(cached) = cache.get(¶m_env.and(trait_ref)) { - return Some(cached.get(tcx)); - } - } - self.infcx - .evaluation_cache - .hashmap - .borrow() - .get(¶m_env.and(trait_ref)) - .map(|v| v.get(tcx)) - } - - fn insert_evaluation_cache( - &mut self, - param_env: ty::ParamEnv<'tcx>, - trait_ref: ty::PolyTraitRef<'tcx>, - dep_node: DepNodeIndex, - result: EvaluationResult, - ) { - // Avoid caching results that depend on more than just the trait-ref - // - the stack can create recursion. - if result.is_stack_dependent() { - return; - } - - if self.can_use_global_caches(param_env) { - if !trait_ref.has_local_value() { - debug!( - "insert_evaluation_cache(trait_ref={:?}, candidate={:?}) global", - trait_ref, result, - ); - // This may overwrite the cache with the same value - // FIXME: Due to #50507 this overwrites the different values - // This should be changed to use HashMapExt::insert_same - // when that is fixed - self.tcx() - .evaluation_cache - .hashmap - .borrow_mut() - .insert(param_env.and(trait_ref), WithDepNode::new(dep_node, result)); - return; - } - } - - debug!("insert_evaluation_cache(trait_ref={:?}, candidate={:?})", trait_ref, result,); - self.infcx - .evaluation_cache - .hashmap - .borrow_mut() - .insert(param_env.and(trait_ref), WithDepNode::new(dep_node, result)); - } - - /// For various reasons, it's possible for a subobligation - /// to have a *lower* recursion_depth than the obligation used to create it. - /// Projection sub-obligations may be returned from the projection cache, - /// which results in obligations with an 'old' `recursion_depth`. - /// Additionally, methods like `wf::obligations` and - /// `InferCtxt.subtype_predicate` produce subobligations without - /// taking in a 'parent' depth, causing the generated subobligations - /// to have a `recursion_depth` of `0`. - /// - /// To ensure that obligation_depth never decreasees, we force all subobligations - /// to have at least the depth of the original obligation. - fn add_depth<T: 'cx, I: Iterator<Item = &'cx mut Obligation<'tcx, T>>>( - &self, - it: I, - min_depth: usize, - ) { - it.for_each(|o| o.recursion_depth = cmp::max(min_depth, o.recursion_depth) + 1); - } - - /// Checks that the recursion limit has not been exceeded. - /// - /// The weird return type of this function allows it to be used with the `try` (`?`) - /// operator within certain functions. - fn check_recursion_limit<T: Display + TypeFoldable<'tcx>, V: Display + TypeFoldable<'tcx>>( - &self, - obligation: &Obligation<'tcx, T>, - error_obligation: &Obligation<'tcx, V>, - ) -> Result<(), OverflowError> { - let recursion_limit = *self.infcx.tcx.sess.recursion_limit.get(); - if obligation.recursion_depth >= recursion_limit { - match self.query_mode { - TraitQueryMode::Standard => { - self.infcx().report_overflow_error(error_obligation, true); - } - TraitQueryMode::Canonical => { - return Err(OverflowError); - } - } - } - Ok(()) - } - - /////////////////////////////////////////////////////////////////////////// - // CANDIDATE ASSEMBLY - // - // The selection process begins by examining all in-scope impls, - // caller obligations, and so forth and assembling a list of - // candidates. See the [rustc guide] for more details. - // - // [rustc guide]: - // https://rust-lang.github.io/rustc-guide/traits/resolution.html#candidate-assembly - - fn candidate_from_obligation<'o>( - &mut self, - stack: &TraitObligationStack<'o, 'tcx>, - ) -> SelectionResult<'tcx, SelectionCandidate<'tcx>> { - // Watch out for overflow. This intentionally bypasses (and does - // not update) the cache. - self.check_recursion_limit(&stack.obligation, &stack.obligation)?; - - // Check the cache. Note that we freshen the trait-ref - // separately rather than using `stack.fresh_trait_ref` -- - // this is because we want the unbound variables to be - // replaced with fresh types starting from index 0. - let cache_fresh_trait_pred = self.infcx.freshen(stack.obligation.predicate.clone()); - debug!( - "candidate_from_obligation(cache_fresh_trait_pred={:?}, obligation={:?})", - cache_fresh_trait_pred, stack - ); - debug_assert!(!stack.obligation.predicate.has_escaping_bound_vars()); - - if let Some(c) = - self.check_candidate_cache(stack.obligation.param_env, &cache_fresh_trait_pred) - { - debug!("CACHE HIT: SELECT({:?})={:?}", cache_fresh_trait_pred, c); - return c; - } - - // If no match, compute result and insert into cache. - // - // FIXME(nikomatsakis) -- this cache is not taking into - // account cycles that may have occurred in forming the - // candidate. I don't know of any specific problems that - // result but it seems awfully suspicious. - let (candidate, dep_node) = - self.in_task(|this| this.candidate_from_obligation_no_cache(stack)); - - debug!("CACHE MISS: SELECT({:?})={:?}", cache_fresh_trait_pred, candidate); - self.insert_candidate_cache( - stack.obligation.param_env, - cache_fresh_trait_pred, - dep_node, - candidate.clone(), - ); - candidate - } - - fn in_task<OP, R>(&mut self, op: OP) -> (R, DepNodeIndex) - where - OP: FnOnce(&mut Self) -> R, - { - let (result, dep_node) = - self.tcx().dep_graph.with_anon_task(DepKind::TraitSelect, || op(self)); - self.tcx().dep_graph.read_index(dep_node); - (result, dep_node) - } - - // Treat negative impls as unimplemented, and reservation impls as ambiguity. - fn filter_negative_and_reservation_impls( - &mut self, - candidate: SelectionCandidate<'tcx>, - ) -> SelectionResult<'tcx, SelectionCandidate<'tcx>> { - if let ImplCandidate(def_id) = candidate { - let tcx = self.tcx(); - match tcx.impl_polarity(def_id) { - ty::ImplPolarity::Negative if !self.allow_negative_impls => { - return Err(Unimplemented); - } - ty::ImplPolarity::Reservation => { - if let Some(intercrate_ambiguity_clauses) = - &mut self.intercrate_ambiguity_causes - { - let attrs = tcx.get_attrs(def_id); - let attr = attr::find_by_name(&attrs, sym::rustc_reservation_impl); - let value = attr.and_then(|a| a.value_str()); - if let Some(value) = value { - debug!( - "filter_negative_and_reservation_impls: \ - reservation impl ambiguity on {:?}", - def_id - ); - intercrate_ambiguity_clauses.push( - IntercrateAmbiguityCause::ReservationImpl { - message: value.to_string(), - }, - ); - } - } - return Ok(None); - } - _ => {} - }; - } - Ok(Some(candidate)) - } - - fn candidate_from_obligation_no_cache<'o>( - &mut self, - stack: &TraitObligationStack<'o, 'tcx>, - ) -> SelectionResult<'tcx, SelectionCandidate<'tcx>> { - if stack.obligation.predicate.references_error() { - // If we encounter a `Error`, we generally prefer the - // most "optimistic" result in response -- that is, the - // one least likely to report downstream errors. But - // because this routine is shared by coherence and by - // trait selection, there isn't an obvious "right" choice - // here in that respect, so we opt to just return - // ambiguity and let the upstream clients sort it out. - return Ok(None); - } - - if let Some(conflict) = self.is_knowable(stack) { - debug!("coherence stage: not knowable"); - if self.intercrate_ambiguity_causes.is_some() { - debug!("evaluate_stack: intercrate_ambiguity_causes is some"); - // Heuristics: show the diagnostics when there are no candidates in crate. - if let Ok(candidate_set) = self.assemble_candidates(stack) { - let mut no_candidates_apply = true; - { - let evaluated_candidates = - candidate_set.vec.iter().map(|c| self.evaluate_candidate(stack, &c)); - - for ec in evaluated_candidates { - match ec { - Ok(c) => { - if c.may_apply() { - no_candidates_apply = false; - break; - } - } - Err(e) => return Err(e.into()), - } - } - } - - if !candidate_set.ambiguous && no_candidates_apply { - let trait_ref = stack.obligation.predicate.skip_binder().trait_ref; - let self_ty = trait_ref.self_ty(); - let trait_desc = trait_ref.print_only_trait_path().to_string(); - let self_desc = if self_ty.has_concrete_skeleton() { - Some(self_ty.to_string()) - } else { - None - }; - let cause = if let Conflict::Upstream = conflict { - IntercrateAmbiguityCause::UpstreamCrateUpdate { trait_desc, self_desc } - } else { - IntercrateAmbiguityCause::DownstreamCrate { trait_desc, self_desc } - }; - debug!("evaluate_stack: pushing cause = {:?}", cause); - self.intercrate_ambiguity_causes.as_mut().unwrap().push(cause); - } - } - } - return Ok(None); - } - - let candidate_set = self.assemble_candidates(stack)?; - - if candidate_set.ambiguous { - debug!("candidate set contains ambig"); - return Ok(None); - } - - let mut candidates = candidate_set.vec; - - debug!("assembled {} candidates for {:?}: {:?}", candidates.len(), stack, candidates); - - // At this point, we know that each of the entries in the - // candidate set is *individually* applicable. Now we have to - // figure out if they contain mutual incompatibilities. This - // frequently arises if we have an unconstrained input type -- - // for example, we are looking for `$0: Eq` where `$0` is some - // unconstrained type variable. In that case, we'll get a - // candidate which assumes $0 == int, one that assumes `$0 == - // usize`, etc. This spells an ambiguity. - - // If there is more than one candidate, first winnow them down - // by considering extra conditions (nested obligations and so - // forth). We don't winnow if there is exactly one - // candidate. This is a relatively minor distinction but it - // can lead to better inference and error-reporting. An - // example would be if there was an impl: - // - // impl<T:Clone> Vec<T> { fn push_clone(...) { ... } } - // - // and we were to see some code `foo.push_clone()` where `boo` - // is a `Vec<Bar>` and `Bar` does not implement `Clone`. If - // we were to winnow, we'd wind up with zero candidates. - // Instead, we select the right impl now but report "`Bar` does - // not implement `Clone`". - if candidates.len() == 1 { - return self.filter_negative_and_reservation_impls(candidates.pop().unwrap()); - } - - // Winnow, but record the exact outcome of evaluation, which - // is needed for specialization. Propagate overflow if it occurs. - let mut candidates = candidates - .into_iter() - .map(|c| match self.evaluate_candidate(stack, &c) { - Ok(eval) if eval.may_apply() => { - Ok(Some(EvaluatedCandidate { candidate: c, evaluation: eval })) - } - Ok(_) => Ok(None), - Err(OverflowError) => Err(Overflow), - }) - .flat_map(Result::transpose) - .collect::<Result<Vec<_>, _>>()?; - - debug!("winnowed to {} candidates for {:?}: {:?}", candidates.len(), stack, candidates); - - let needs_infer = stack.obligation.predicate.needs_infer(); - - // If there are STILL multiple candidates, we can further - // reduce the list by dropping duplicates -- including - // resolving specializations. - if candidates.len() > 1 { - let mut i = 0; - while i < candidates.len() { - let is_dup = (0..candidates.len()).filter(|&j| i != j).any(|j| { - self.candidate_should_be_dropped_in_favor_of( - &candidates[i], - &candidates[j], - needs_infer, - ) - }); - if is_dup { - debug!("Dropping candidate #{}/{}: {:?}", i, candidates.len(), candidates[i]); - candidates.swap_remove(i); - } else { - debug!("Retaining candidate #{}/{}: {:?}", i, candidates.len(), candidates[i]); - i += 1; - - // If there are *STILL* multiple candidates, give up - // and report ambiguity. - if i > 1 { - debug!("multiple matches, ambig"); - return Ok(None); - } - } - } - } - - // If there are *NO* candidates, then there are no impls -- - // that we know of, anyway. Note that in the case where there - // are unbound type variables within the obligation, it might - // be the case that you could still satisfy the obligation - // from another crate by instantiating the type variables with - // a type from another crate that does have an impl. This case - // is checked for in `evaluate_stack` (and hence users - // who might care about this case, like coherence, should use - // that function). - if candidates.is_empty() { - return Err(Unimplemented); - } - - // Just one candidate left. - self.filter_negative_and_reservation_impls(candidates.pop().unwrap().candidate) - } - - fn is_knowable<'o>(&mut self, stack: &TraitObligationStack<'o, 'tcx>) -> Option<Conflict> { - debug!("is_knowable(intercrate={:?})", self.intercrate); - - if !self.intercrate { - return None; - } - - let obligation = &stack.obligation; - let predicate = self.infcx().resolve_vars_if_possible(&obligation.predicate); - - // Okay to skip binder because of the nature of the - // trait-ref-is-knowable check, which does not care about - // bound regions. - let trait_ref = predicate.skip_binder().trait_ref; - - coherence::trait_ref_is_knowable(self.tcx(), trait_ref) - } - - /// Returns `true` if the global caches can be used. - /// Do note that if the type itself is not in the - /// global tcx, the local caches will be used. - fn can_use_global_caches(&self, param_env: ty::ParamEnv<'tcx>) -> bool { - // If there are any e.g. inference variables in the `ParamEnv`, then we - // always use a cache local to this particular scope. Otherwise, we - // switch to a global cache. - if param_env.has_local_value() { - return false; - } - - // Avoid using the master cache during coherence and just rely - // on the local cache. This effectively disables caching - // during coherence. It is really just a simplification to - // avoid us having to fear that coherence results "pollute" - // the master cache. Since coherence executes pretty quickly, - // it's not worth going to more trouble to increase the - // hit-rate, I don't think. - if self.intercrate { - return false; - } - - // Otherwise, we can use the global cache. - true - } - - fn check_candidate_cache( - &mut self, - param_env: ty::ParamEnv<'tcx>, - cache_fresh_trait_pred: &ty::PolyTraitPredicate<'tcx>, - ) -> Option<SelectionResult<'tcx, SelectionCandidate<'tcx>>> { - let tcx = self.tcx(); - let trait_ref = &cache_fresh_trait_pred.skip_binder().trait_ref; - if self.can_use_global_caches(param_env) { - let cache = tcx.selection_cache.hashmap.borrow(); - if let Some(cached) = cache.get(¶m_env.and(*trait_ref)) { - return Some(cached.get(tcx)); - } - } - self.infcx - .selection_cache - .hashmap - .borrow() - .get(¶m_env.and(*trait_ref)) - .map(|v| v.get(tcx)) - } - - /// Determines whether can we safely cache the result - /// of selecting an obligation. This is almost always `true`, - /// except when dealing with certain `ParamCandidate`s. - /// - /// Ordinarily, a `ParamCandidate` will contain no inference variables, - /// since it was usually produced directly from a `DefId`. However, - /// certain cases (currently only librustdoc's blanket impl finder), - /// a `ParamEnv` may be explicitly constructed with inference types. - /// When this is the case, we do *not* want to cache the resulting selection - /// candidate. This is due to the fact that it might not always be possible - /// to equate the obligation's trait ref and the candidate's trait ref, - /// if more constraints end up getting added to an inference variable. - /// - /// Because of this, we always want to re-run the full selection - /// process for our obligation the next time we see it, since - /// we might end up picking a different `SelectionCandidate` (or none at all). - fn can_cache_candidate( - &self, - result: &SelectionResult<'tcx, SelectionCandidate<'tcx>>, - ) -> bool { - match result { - Ok(Some(SelectionCandidate::ParamCandidate(trait_ref))) => { - !trait_ref.skip_binder().input_types().any(|t| t.walk().any(|t_| t_.is_ty_infer())) - } - _ => true, - } - } - - fn insert_candidate_cache( - &mut self, - param_env: ty::ParamEnv<'tcx>, - cache_fresh_trait_pred: ty::PolyTraitPredicate<'tcx>, - dep_node: DepNodeIndex, - candidate: SelectionResult<'tcx, SelectionCandidate<'tcx>>, - ) { - let tcx = self.tcx(); - let trait_ref = cache_fresh_trait_pred.skip_binder().trait_ref; - - if !self.can_cache_candidate(&candidate) { - debug!( - "insert_candidate_cache(trait_ref={:?}, candidate={:?} -\ - candidate is not cacheable", - trait_ref, candidate - ); - return; - } - - if self.can_use_global_caches(param_env) { - if let Err(Overflow) = candidate { - // Don't cache overflow globally; we only produce this in certain modes. - } else if !trait_ref.has_local_value() { - if !candidate.has_local_value() { - debug!( - "insert_candidate_cache(trait_ref={:?}, candidate={:?}) global", - trait_ref, candidate, - ); - // This may overwrite the cache with the same value. - tcx.selection_cache - .hashmap - .borrow_mut() - .insert(param_env.and(trait_ref), WithDepNode::new(dep_node, candidate)); - return; - } - } - } - - debug!( - "insert_candidate_cache(trait_ref={:?}, candidate={:?}) local", - trait_ref, candidate, - ); - self.infcx - .selection_cache - .hashmap - .borrow_mut() - .insert(param_env.and(trait_ref), WithDepNode::new(dep_node, candidate)); - } - - fn assemble_candidates<'o>( - &mut self, - stack: &TraitObligationStack<'o, 'tcx>, - ) -> Result<SelectionCandidateSet<'tcx>, SelectionError<'tcx>> { - let TraitObligationStack { obligation, .. } = *stack; - let ref obligation = Obligation { - param_env: obligation.param_env, - cause: obligation.cause.clone(), - recursion_depth: obligation.recursion_depth, - predicate: self.infcx().resolve_vars_if_possible(&obligation.predicate), - }; - - if obligation.predicate.skip_binder().self_ty().is_ty_var() { - // Self is a type variable (e.g., `_: AsRef<str>`). - // - // This is somewhat problematic, as the current scheme can't really - // handle it turning to be a projection. This does end up as truly - // ambiguous in most cases anyway. - // - // Take the fast path out - this also improves - // performance by preventing assemble_candidates_from_impls from - // matching every impl for this trait. - return Ok(SelectionCandidateSet { vec: vec![], ambiguous: true }); - } - - let mut candidates = SelectionCandidateSet { vec: Vec::new(), ambiguous: false }; - - self.assemble_candidates_for_trait_alias(obligation, &mut candidates)?; - - // Other bounds. Consider both in-scope bounds from fn decl - // and applicable impls. There is a certain set of precedence rules here. - let def_id = obligation.predicate.def_id(); - let lang_items = self.tcx().lang_items(); - - if lang_items.copy_trait() == Some(def_id) { - debug!("obligation self ty is {:?}", obligation.predicate.skip_binder().self_ty()); - - // User-defined copy impls are permitted, but only for - // structs and enums. - self.assemble_candidates_from_impls(obligation, &mut candidates)?; - - // For other types, we'll use the builtin rules. - let copy_conditions = self.copy_clone_conditions(obligation); - self.assemble_builtin_bound_candidates(copy_conditions, &mut candidates)?; - } else if lang_items.sized_trait() == Some(def_id) { - // Sized is never implementable by end-users, it is - // always automatically computed. - let sized_conditions = self.sized_conditions(obligation); - self.assemble_builtin_bound_candidates(sized_conditions, &mut candidates)?; - } else if lang_items.unsize_trait() == Some(def_id) { - self.assemble_candidates_for_unsizing(obligation, &mut candidates); - } else { - if lang_items.clone_trait() == Some(def_id) { - // Same builtin conditions as `Copy`, i.e., every type which has builtin support - // for `Copy` also has builtin support for `Clone`, and tuples/arrays of `Clone` - // types have builtin support for `Clone`. - let clone_conditions = self.copy_clone_conditions(obligation); - self.assemble_builtin_bound_candidates(clone_conditions, &mut candidates)?; - } - - self.assemble_generator_candidates(obligation, &mut candidates)?; - self.assemble_closure_candidates(obligation, &mut candidates)?; - self.assemble_fn_pointer_candidates(obligation, &mut candidates)?; - self.assemble_candidates_from_impls(obligation, &mut candidates)?; - self.assemble_candidates_from_object_ty(obligation, &mut candidates); - } - - self.assemble_candidates_from_projected_tys(obligation, &mut candidates); - self.assemble_candidates_from_caller_bounds(stack, &mut candidates)?; - // Auto implementations have lower priority, so we only - // consider triggering a default if there is no other impl that can apply. - if candidates.vec.is_empty() { - self.assemble_candidates_from_auto_impls(obligation, &mut candidates)?; - } - debug!("candidate list size: {}", candidates.vec.len()); - Ok(candidates) - } - - fn assemble_candidates_from_projected_tys( - &mut self, - obligation: &TraitObligation<'tcx>, - candidates: &mut SelectionCandidateSet<'tcx>, - ) { - debug!("assemble_candidates_for_projected_tys({:?})", obligation); - - // Before we go into the whole placeholder thing, just - // quickly check if the self-type is a projection at all. - match obligation.predicate.skip_binder().trait_ref.self_ty().kind { - ty::Projection(_) | ty::Opaque(..) => {} - ty::Infer(ty::TyVar(_)) => { - span_bug!( - obligation.cause.span, - "Self=_ should have been handled by assemble_candidates" - ); - } - _ => return, - } - - let result = self.infcx.probe(|snapshot| { - self.match_projection_obligation_against_definition_bounds(obligation, snapshot) - }); - - if result { - candidates.vec.push(ProjectionCandidate); - } - } - - fn match_projection_obligation_against_definition_bounds( - &mut self, - obligation: &TraitObligation<'tcx>, - snapshot: &CombinedSnapshot<'_, 'tcx>, - ) -> bool { - let poly_trait_predicate = self.infcx().resolve_vars_if_possible(&obligation.predicate); - let (placeholder_trait_predicate, placeholder_map) = - self.infcx().replace_bound_vars_with_placeholders(&poly_trait_predicate); - debug!( - "match_projection_obligation_against_definition_bounds: \ - placeholder_trait_predicate={:?}", - placeholder_trait_predicate, - ); - - let (def_id, substs) = match placeholder_trait_predicate.trait_ref.self_ty().kind { - ty::Projection(ref data) => (data.trait_ref(self.tcx()).def_id, data.substs), - ty::Opaque(def_id, substs) => (def_id, substs), - _ => { - span_bug!( - obligation.cause.span, - "match_projection_obligation_against_definition_bounds() called \ - but self-ty is not a projection: {:?}", - placeholder_trait_predicate.trait_ref.self_ty() - ); - } - }; - debug!( - "match_projection_obligation_against_definition_bounds: \ - def_id={:?}, substs={:?}", - def_id, substs - ); - - let predicates_of = self.tcx().predicates_of(def_id); - let bounds = predicates_of.instantiate(self.tcx(), substs); - debug!( - "match_projection_obligation_against_definition_bounds: \ - bounds={:?}", - bounds - ); - - let elaborated_predicates = util::elaborate_predicates(self.tcx(), bounds.predicates); - let matching_bound = elaborated_predicates.filter_to_traits().find(|bound| { - self.infcx.probe(|_| { - self.match_projection( - obligation, - bound.clone(), - placeholder_trait_predicate.trait_ref.clone(), - &placeholder_map, - snapshot, - ) - }) - }); - - debug!( - "match_projection_obligation_against_definition_bounds: \ - matching_bound={:?}", - matching_bound - ); - match matching_bound { - None => false, - Some(bound) => { - // Repeat the successful match, if any, this time outside of a probe. - let result = self.match_projection( - obligation, - bound, - placeholder_trait_predicate.trait_ref.clone(), - &placeholder_map, - snapshot, - ); - - assert!(result); - true - } - } - } - - fn match_projection( - &mut self, - obligation: &TraitObligation<'tcx>, - trait_bound: ty::PolyTraitRef<'tcx>, - placeholder_trait_ref: ty::TraitRef<'tcx>, - placeholder_map: &PlaceholderMap<'tcx>, - snapshot: &CombinedSnapshot<'_, 'tcx>, - ) -> bool { - debug_assert!(!placeholder_trait_ref.has_escaping_bound_vars()); - self.infcx - .at(&obligation.cause, obligation.param_env) - .sup(ty::Binder::dummy(placeholder_trait_ref), trait_bound) - .is_ok() - && self.infcx.leak_check(false, placeholder_map, snapshot).is_ok() - } - - /// Given an obligation like `<SomeTrait for T>`, searches the obligations that the caller - /// supplied to find out whether it is listed among them. - /// - /// Never affects the inference environment. - fn assemble_candidates_from_caller_bounds<'o>( - &mut self, - stack: &TraitObligationStack<'o, 'tcx>, - candidates: &mut SelectionCandidateSet<'tcx>, - ) -> Result<(), SelectionError<'tcx>> { - debug!("assemble_candidates_from_caller_bounds({:?})", stack.obligation); - - let all_bounds = stack - .obligation - .param_env - .caller_bounds - .iter() - .filter_map(|o| o.to_opt_poly_trait_ref()); - - // Micro-optimization: filter out predicates relating to different traits. - let matching_bounds = - all_bounds.filter(|p| p.def_id() == stack.obligation.predicate.def_id()); - - // Keep only those bounds which may apply, and propagate overflow if it occurs. - let mut param_candidates = vec![]; - for bound in matching_bounds { - let wc = self.evaluate_where_clause(stack, bound.clone())?; - if wc.may_apply() { - param_candidates.push(ParamCandidate(bound)); - } - } - - candidates.vec.extend(param_candidates); - - Ok(()) - } - - fn evaluate_where_clause<'o>( - &mut self, - stack: &TraitObligationStack<'o, 'tcx>, - where_clause_trait_ref: ty::PolyTraitRef<'tcx>, - ) -> Result<EvaluationResult, OverflowError> { - self.evaluation_probe(|this| { - match this.match_where_clause_trait_ref(stack.obligation, where_clause_trait_ref) { - Ok(obligations) => { - this.evaluate_predicates_recursively(stack.list(), obligations.into_iter()) - } - Err(()) => Ok(EvaluatedToErr), - } - }) - } - - fn assemble_generator_candidates( - &mut self, - obligation: &TraitObligation<'tcx>, - candidates: &mut SelectionCandidateSet<'tcx>, - ) -> Result<(), SelectionError<'tcx>> { - if self.tcx().lang_items().gen_trait() != Some(obligation.predicate.def_id()) { - return Ok(()); - } - - // Okay to skip binder because the substs on generator types never - // touch bound regions, they just capture the in-scope - // type/region parameters. - let self_ty = *obligation.self_ty().skip_binder(); - match self_ty.kind { - ty::Generator(..) => { - debug!( - "assemble_generator_candidates: self_ty={:?} obligation={:?}", - self_ty, obligation - ); - - candidates.vec.push(GeneratorCandidate); - } - ty::Infer(ty::TyVar(_)) => { - debug!("assemble_generator_candidates: ambiguous self-type"); - candidates.ambiguous = true; - } - _ => {} - } - - Ok(()) - } - - /// Checks for the artificial impl that the compiler will create for an obligation like `X : - /// FnMut<..>` where `X` is a closure type. - /// - /// Note: the type parameters on a closure candidate are modeled as *output* type - /// parameters and hence do not affect whether this trait is a match or not. They will be - /// unified during the confirmation step. - fn assemble_closure_candidates( - &mut self, - obligation: &TraitObligation<'tcx>, - candidates: &mut SelectionCandidateSet<'tcx>, - ) -> Result<(), SelectionError<'tcx>> { - let kind = match self.tcx().fn_trait_kind_from_lang_item(obligation.predicate.def_id()) { - Some(k) => k, - None => { - return Ok(()); - } - }; - - // Okay to skip binder because the substs on closure types never - // touch bound regions, they just capture the in-scope - // type/region parameters - match obligation.self_ty().skip_binder().kind { - ty::Closure(closure_def_id, closure_substs) => { - debug!("assemble_unboxed_candidates: kind={:?} obligation={:?}", kind, obligation); - match self.infcx.closure_kind(closure_def_id, closure_substs) { - Some(closure_kind) => { - debug!("assemble_unboxed_candidates: closure_kind = {:?}", closure_kind); - if closure_kind.extends(kind) { - candidates.vec.push(ClosureCandidate); - } - } - None => { - debug!("assemble_unboxed_candidates: closure_kind not yet known"); - candidates.vec.push(ClosureCandidate); - } - } - } - ty::Infer(ty::TyVar(_)) => { - debug!("assemble_unboxed_closure_candidates: ambiguous self-type"); - candidates.ambiguous = true; - } - _ => {} - } - - Ok(()) - } - - /// Implements one of the `Fn()` family for a fn pointer. - fn assemble_fn_pointer_candidates( - &mut self, - obligation: &TraitObligation<'tcx>, - candidates: &mut SelectionCandidateSet<'tcx>, - ) -> Result<(), SelectionError<'tcx>> { - // We provide impl of all fn traits for fn pointers. - if self.tcx().fn_trait_kind_from_lang_item(obligation.predicate.def_id()).is_none() { - return Ok(()); - } - - // Okay to skip binder because what we are inspecting doesn't involve bound regions. - let self_ty = *obligation.self_ty().skip_binder(); - match self_ty.kind { - ty::Infer(ty::TyVar(_)) => { - debug!("assemble_fn_pointer_candidates: ambiguous self-type"); - candidates.ambiguous = true; // Could wind up being a fn() type. - } - // Provide an impl, but only for suitable `fn` pointers. - ty::FnDef(..) | ty::FnPtr(_) => { - if let ty::FnSig { - unsafety: hir::Unsafety::Normal, - abi: Abi::Rust, - c_variadic: false, - .. - } = self_ty.fn_sig(self.tcx()).skip_binder() - { - candidates.vec.push(FnPointerCandidate); - } - } - _ => {} - } - - Ok(()) - } - - /// Searches for impls that might apply to `obligation`. - fn assemble_candidates_from_impls( - &mut self, - obligation: &TraitObligation<'tcx>, - candidates: &mut SelectionCandidateSet<'tcx>, - ) -> Result<(), SelectionError<'tcx>> { - debug!("assemble_candidates_from_impls(obligation={:?})", obligation); - - self.tcx().for_each_relevant_impl( - obligation.predicate.def_id(), - obligation.predicate.skip_binder().trait_ref.self_ty(), - |impl_def_id| { - self.infcx.probe(|snapshot| { - if let Ok(_substs) = self.match_impl(impl_def_id, obligation, snapshot) { - candidates.vec.push(ImplCandidate(impl_def_id)); - } - }); - }, - ); - - Ok(()) - } - - fn assemble_candidates_from_auto_impls( - &mut self, - obligation: &TraitObligation<'tcx>, - candidates: &mut SelectionCandidateSet<'tcx>, - ) -> Result<(), SelectionError<'tcx>> { - // Okay to skip binder here because the tests we do below do not involve bound regions. - let self_ty = *obligation.self_ty().skip_binder(); - debug!("assemble_candidates_from_auto_impls(self_ty={:?})", self_ty); - - let def_id = obligation.predicate.def_id(); - - if self.tcx().trait_is_auto(def_id) { - match self_ty.kind { - ty::Dynamic(..) => { - // For object types, we don't know what the closed - // over types are. This means we conservatively - // say nothing; a candidate may be added by - // `assemble_candidates_from_object_ty`. - } - ty::Foreign(..) => { - // Since the contents of foreign types is unknown, - // we don't add any `..` impl. Default traits could - // still be provided by a manual implementation for - // this trait and type. - } - ty::Param(..) | ty::Projection(..) => { - // In these cases, we don't know what the actual - // type is. Therefore, we cannot break it down - // into its constituent types. So we don't - // consider the `..` impl but instead just add no - // candidates: this means that typeck will only - // succeed if there is another reason to believe - // that this obligation holds. That could be a - // where-clause or, in the case of an object type, - // it could be that the object type lists the - // trait (e.g., `Foo+Send : Send`). See - // `compile-fail/typeck-default-trait-impl-send-param.rs` - // for an example of a test case that exercises - // this path. - } - ty::Infer(ty::TyVar(_)) => { - // The auto impl might apply; we don't know. - candidates.ambiguous = true; - } - ty::Generator(_, _, movability) - if self.tcx().lang_items().unpin_trait() == Some(def_id) => - { - match movability { - hir::Movability::Static => { - // Immovable generators are never `Unpin`, so - // suppress the normal auto-impl candidate for it. - } - hir::Movability::Movable => { - // Movable generators are always `Unpin`, so add an - // unconditional builtin candidate. - candidates.vec.push(BuiltinCandidate { has_nested: false }); - } - } - } - - _ => candidates.vec.push(AutoImplCandidate(def_id)), - } - } - - Ok(()) - } - - /// Searches for impls that might apply to `obligation`. - fn assemble_candidates_from_object_ty( - &mut self, - obligation: &TraitObligation<'tcx>, - candidates: &mut SelectionCandidateSet<'tcx>, - ) { - debug!( - "assemble_candidates_from_object_ty(self_ty={:?})", - obligation.self_ty().skip_binder() - ); - - self.infcx.probe(|_snapshot| { - // The code below doesn't care about regions, and the - // self-ty here doesn't escape this probe, so just erase - // any LBR. - let self_ty = self.tcx().erase_late_bound_regions(&obligation.self_ty()); - let poly_trait_ref = match self_ty.kind { - ty::Dynamic(ref data, ..) => { - if data.auto_traits().any(|did| did == obligation.predicate.def_id()) { - debug!( - "assemble_candidates_from_object_ty: matched builtin bound, \ - pushing candidate" - ); - candidates.vec.push(BuiltinObjectCandidate); - return; - } - - if let Some(principal) = data.principal() { - if !self.infcx.tcx.features().object_safe_for_dispatch { - principal.with_self_ty(self.tcx(), self_ty) - } else if self.tcx().is_object_safe(principal.def_id()) { - principal.with_self_ty(self.tcx(), self_ty) - } else { - return; - } - } else { - // Only auto trait bounds exist. - return; - } - } - ty::Infer(ty::TyVar(_)) => { - debug!("assemble_candidates_from_object_ty: ambiguous"); - candidates.ambiguous = true; // could wind up being an object type - return; - } - _ => return, - }; - - debug!("assemble_candidates_from_object_ty: poly_trait_ref={:?}", poly_trait_ref); - - // Count only those upcast versions that match the trait-ref - // we are looking for. Specifically, do not only check for the - // correct trait, but also the correct type parameters. - // For example, we may be trying to upcast `Foo` to `Bar<i32>`, - // but `Foo` is declared as `trait Foo: Bar<u32>`. - let upcast_trait_refs = util::supertraits(self.tcx(), poly_trait_ref) - .filter(|upcast_trait_ref| { - self.infcx - .probe(|_| self.match_poly_trait_ref(obligation, *upcast_trait_ref).is_ok()) - }) - .count(); - - if upcast_trait_refs > 1 { - // Can be upcast in many ways; need more type information. - candidates.ambiguous = true; - } else if upcast_trait_refs == 1 { - candidates.vec.push(ObjectCandidate); - } - }) - } - - /// Searches for unsizing that might apply to `obligation`. - fn assemble_candidates_for_unsizing( - &mut self, - obligation: &TraitObligation<'tcx>, - candidates: &mut SelectionCandidateSet<'tcx>, - ) { - // We currently never consider higher-ranked obligations e.g. - // `for<'a> &'a T: Unsize<Trait+'a>` to be implemented. This is not - // because they are a priori invalid, and we could potentially add support - // for them later, it's just that there isn't really a strong need for it. - // A `T: Unsize<U>` obligation is always used as part of a `T: CoerceUnsize<U>` - // impl, and those are generally applied to concrete types. - // - // That said, one might try to write a fn with a where clause like - // for<'a> Foo<'a, T>: Unsize<Foo<'a, Trait>> - // where the `'a` is kind of orthogonal to the relevant part of the `Unsize`. - // Still, you'd be more likely to write that where clause as - // T: Trait - // so it seems ok if we (conservatively) fail to accept that `Unsize` - // obligation above. Should be possible to extend this in the future. - let source = match obligation.self_ty().no_bound_vars() { - Some(t) => t, - None => { - // Don't add any candidates if there are bound regions. - return; - } - }; - let target = obligation.predicate.skip_binder().trait_ref.substs.type_at(1); - - debug!("assemble_candidates_for_unsizing(source={:?}, target={:?})", source, target); - - let may_apply = match (&source.kind, &target.kind) { - // Trait+Kx+'a -> Trait+Ky+'b (upcasts). - (&ty::Dynamic(ref data_a, ..), &ty::Dynamic(ref data_b, ..)) => { - // Upcasts permit two things: - // - // 1. Dropping auto traits, e.g., `Foo + Send` to `Foo` - // 2. Tightening the region bound, e.g., `Foo + 'a` to `Foo + 'b` if `'a: 'b` - // - // Note that neither of these changes requires any - // change at runtime. Eventually this will be - // generalized. - // - // We always upcast when we can because of reason - // #2 (region bounds). - data_a.principal_def_id() == data_b.principal_def_id() - && data_b - .auto_traits() - // All of a's auto traits need to be in b's auto traits. - .all(|b| data_a.auto_traits().any(|a| a == b)) - } - - // `T` -> `Trait` - (_, &ty::Dynamic(..)) => true, - - // Ambiguous handling is below `T` -> `Trait`, because inference - // variables can still implement `Unsize<Trait>` and nested - // obligations will have the final say (likely deferred). - (&ty::Infer(ty::TyVar(_)), _) | (_, &ty::Infer(ty::TyVar(_))) => { - debug!("assemble_candidates_for_unsizing: ambiguous"); - candidates.ambiguous = true; - false - } - - // `[T; n]` -> `[T]` - (&ty::Array(..), &ty::Slice(_)) => true, - - // `Struct<T>` -> `Struct<U>` - (&ty::Adt(def_id_a, _), &ty::Adt(def_id_b, _)) if def_id_a.is_struct() => { - def_id_a == def_id_b - } - - // `(.., T)` -> `(.., U)` - (&ty::Tuple(tys_a), &ty::Tuple(tys_b)) => tys_a.len() == tys_b.len(), - - _ => false, - }; - - if may_apply { - candidates.vec.push(BuiltinUnsizeCandidate); - } - } - - fn assemble_candidates_for_trait_alias( - &mut self, - obligation: &TraitObligation<'tcx>, - candidates: &mut SelectionCandidateSet<'tcx>, - ) -> Result<(), SelectionError<'tcx>> { - // Okay to skip binder here because the tests we do below do not involve bound regions. - let self_ty = *obligation.self_ty().skip_binder(); - debug!("assemble_candidates_for_trait_alias(self_ty={:?})", self_ty); - - let def_id = obligation.predicate.def_id(); - - if self.tcx().is_trait_alias(def_id) { - candidates.vec.push(TraitAliasCandidate(def_id)); - } - - Ok(()) - } - - /////////////////////////////////////////////////////////////////////////// - // WINNOW - // - // Winnowing is the process of attempting to resolve ambiguity by - // probing further. During the winnowing process, we unify all - // type variables and then we also attempt to evaluate recursive - // bounds to see if they are satisfied. - - /// Returns `true` if `victim` should be dropped in favor of - /// `other`. Generally speaking we will drop duplicate - /// candidates and prefer where-clause candidates. - /// - /// See the comment for "SelectionCandidate" for more details. - fn candidate_should_be_dropped_in_favor_of( - &mut self, - victim: &EvaluatedCandidate<'tcx>, - other: &EvaluatedCandidate<'tcx>, - needs_infer: bool, - ) -> bool { - if victim.candidate == other.candidate { - return true; - } - - // Check if a bound would previously have been removed when normalizing - // the param_env so that it can be given the lowest priority. See - // #50825 for the motivation for this. - let is_global = - |cand: &ty::PolyTraitRef<'_>| cand.is_global() && !cand.has_late_bound_regions(); - - match other.candidate { - // Prefer `BuiltinCandidate { has_nested: false }` to anything else. - // This is a fix for #53123 and prevents winnowing from accidentally extending the - // lifetime of a variable. - BuiltinCandidate { has_nested: false } => true, - ParamCandidate(ref cand) => match victim.candidate { - AutoImplCandidate(..) => { - bug!( - "default implementations shouldn't be recorded \ - when there are other valid candidates" - ); - } - // Prefer `BuiltinCandidate { has_nested: false }` to anything else. - // This is a fix for #53123 and prevents winnowing from accidentally extending the - // lifetime of a variable. - BuiltinCandidate { has_nested: false } => false, - ImplCandidate(..) - | ClosureCandidate - | GeneratorCandidate - | FnPointerCandidate - | BuiltinObjectCandidate - | BuiltinUnsizeCandidate - | BuiltinCandidate { .. } - | TraitAliasCandidate(..) => { - // Global bounds from the where clause should be ignored - // here (see issue #50825). Otherwise, we have a where - // clause so don't go around looking for impls. - !is_global(cand) - } - ObjectCandidate | ProjectionCandidate => { - // Arbitrarily give param candidates priority - // over projection and object candidates. - !is_global(cand) - } - ParamCandidate(..) => false, - }, - ObjectCandidate | ProjectionCandidate => match victim.candidate { - AutoImplCandidate(..) => { - bug!( - "default implementations shouldn't be recorded \ - when there are other valid candidates" - ); - } - // Prefer `BuiltinCandidate { has_nested: false }` to anything else. - // This is a fix for #53123 and prevents winnowing from accidentally extending the - // lifetime of a variable. - BuiltinCandidate { has_nested: false } => false, - ImplCandidate(..) - | ClosureCandidate - | GeneratorCandidate - | FnPointerCandidate - | BuiltinObjectCandidate - | BuiltinUnsizeCandidate - | BuiltinCandidate { .. } - | TraitAliasCandidate(..) => true, - ObjectCandidate | ProjectionCandidate => { - // Arbitrarily give param candidates priority - // over projection and object candidates. - true - } - ParamCandidate(ref cand) => is_global(cand), - }, - ImplCandidate(other_def) => { - // See if we can toss out `victim` based on specialization. - // This requires us to know *for sure* that the `other` impl applies - // i.e., `EvaluatedToOk`. - if other.evaluation.must_apply_modulo_regions() { - match victim.candidate { - ImplCandidate(victim_def) => { - let tcx = self.tcx(); - if tcx.specializes((other_def, victim_def)) { - return true; - } - return match tcx.impls_are_allowed_to_overlap(other_def, victim_def) { - Some(ty::ImplOverlapKind::Permitted { marker: true }) => { - // Subtle: If the predicate we are evaluating has inference - // variables, do *not* allow discarding candidates due to - // marker trait impls. - // - // Without this restriction, we could end up accidentally - // constrainting inference variables based on an arbitrarily - // chosen trait impl. - // - // Imagine we have the following code: - // - // ```rust - // #[marker] trait MyTrait {} - // impl MyTrait for u8 {} - // impl MyTrait for bool {} - // ``` - // - // And we are evaluating the predicate `<_#0t as MyTrait>`. - // - // During selection, we will end up with one candidate for each - // impl of `MyTrait`. If we were to discard one impl in favor - // of the other, we would be left with one candidate, causing - // us to "successfully" select the predicate, unifying - // _#0t with (for example) `u8`. - // - // However, we have no reason to believe that this unification - // is correct - we've essentially just picked an arbitrary - // *possibility* for _#0t, and required that this be the *only* - // possibility. - // - // Eventually, we will either: - // 1) Unify all inference variables in the predicate through - // some other means (e.g. type-checking of a function). We will - // then be in a position to drop marker trait candidates - // without constraining inference variables (since there are - // none left to constrin) - // 2) Be left with some unconstrained inference variables. We - // will then correctly report an inference error, since the - // existence of multiple marker trait impls tells us nothing - // about which one should actually apply. - !needs_infer - } - Some(_) => true, - None => false, - }; - } - ParamCandidate(ref cand) => { - // Prefer the impl to a global where clause candidate. - return is_global(cand); - } - _ => (), - } - } - - false - } - ClosureCandidate - | GeneratorCandidate - | FnPointerCandidate - | BuiltinObjectCandidate - | BuiltinUnsizeCandidate - | BuiltinCandidate { has_nested: true } => { - match victim.candidate { - ParamCandidate(ref cand) => { - // Prefer these to a global where-clause bound - // (see issue #50825). - is_global(cand) && other.evaluation.must_apply_modulo_regions() - } - _ => false, - } - } - _ => false, - } - } - - /////////////////////////////////////////////////////////////////////////// - // BUILTIN BOUNDS - // - // These cover the traits that are built-in to the language - // itself: `Copy`, `Clone` and `Sized`. - - fn assemble_builtin_bound_candidates( - &mut self, - conditions: BuiltinImplConditions<'tcx>, - candidates: &mut SelectionCandidateSet<'tcx>, - ) -> Result<(), SelectionError<'tcx>> { - match conditions { - BuiltinImplConditions::Where(nested) => { - debug!("builtin_bound: nested={:?}", nested); - candidates - .vec - .push(BuiltinCandidate { has_nested: !nested.skip_binder().is_empty() }); - } - BuiltinImplConditions::None => {} - BuiltinImplConditions::Ambiguous => { - debug!("assemble_builtin_bound_candidates: ambiguous builtin"); - candidates.ambiguous = true; - } - } - - Ok(()) - } - - fn sized_conditions( - &mut self, - obligation: &TraitObligation<'tcx>, - ) -> BuiltinImplConditions<'tcx> { - use self::BuiltinImplConditions::{Ambiguous, None, Where}; - - // NOTE: binder moved to (*) - let self_ty = self.infcx.shallow_resolve(obligation.predicate.skip_binder().self_ty()); - - match self_ty.kind { - ty::Infer(ty::IntVar(_)) - | ty::Infer(ty::FloatVar(_)) - | ty::Uint(_) - | ty::Int(_) - | ty::Bool - | ty::Float(_) - | ty::FnDef(..) - | ty::FnPtr(_) - | ty::RawPtr(..) - | ty::Char - | ty::Ref(..) - | ty::Generator(..) - | ty::GeneratorWitness(..) - | ty::Array(..) - | ty::Closure(..) - | ty::Never - | ty::Error => { - // safe for everything - Where(ty::Binder::dummy(Vec::new())) - } - - ty::Str | ty::Slice(_) | ty::Dynamic(..) | ty::Foreign(..) => None, - - ty::Tuple(tys) => { - Where(ty::Binder::bind(tys.last().into_iter().map(|k| k.expect_ty()).collect())) - } - - ty::Adt(def, substs) => { - let sized_crit = def.sized_constraint(self.tcx()); - // (*) binder moved here - Where(ty::Binder::bind( - sized_crit.iter().map(|ty| ty.subst(self.tcx(), substs)).collect(), - )) - } - - ty::Projection(_) | ty::Param(_) | ty::Opaque(..) => None, - ty::Infer(ty::TyVar(_)) => Ambiguous, - - ty::UnnormalizedProjection(..) - | ty::Placeholder(..) - | ty::Bound(..) - | ty::Infer(ty::FreshTy(_)) - | ty::Infer(ty::FreshIntTy(_)) - | ty::Infer(ty::FreshFloatTy(_)) => { - bug!("asked to assemble builtin bounds of unexpected type: {:?}", self_ty); - } - } - } - - fn copy_clone_conditions( - &mut self, - obligation: &TraitObligation<'tcx>, - ) -> BuiltinImplConditions<'tcx> { - // NOTE: binder moved to (*) - let self_ty = self.infcx.shallow_resolve(obligation.predicate.skip_binder().self_ty()); - - use self::BuiltinImplConditions::{Ambiguous, None, Where}; - - match self_ty.kind { - ty::Infer(ty::IntVar(_)) - | ty::Infer(ty::FloatVar(_)) - | ty::FnDef(..) - | ty::FnPtr(_) - | ty::Error => Where(ty::Binder::dummy(Vec::new())), - - ty::Uint(_) - | ty::Int(_) - | ty::Bool - | ty::Float(_) - | ty::Char - | ty::RawPtr(..) - | ty::Never - | ty::Ref(_, _, hir::Mutability::Not) => { - // Implementations provided in libcore - None - } - - ty::Dynamic(..) - | ty::Str - | ty::Slice(..) - | ty::Generator(..) - | ty::GeneratorWitness(..) - | ty::Foreign(..) - | ty::Ref(_, _, hir::Mutability::Mut) => None, - - ty::Array(element_ty, _) => { - // (*) binder moved here - Where(ty::Binder::bind(vec![element_ty])) - } - - ty::Tuple(tys) => { - // (*) binder moved here - Where(ty::Binder::bind(tys.iter().map(|k| k.expect_ty()).collect())) - } - - ty::Closure(def_id, substs) => { - // (*) binder moved here - Where(ty::Binder::bind(substs.as_closure().upvar_tys(def_id, self.tcx()).collect())) - } - - ty::Adt(..) | ty::Projection(..) | ty::Param(..) | ty::Opaque(..) => { - // Fallback to whatever user-defined impls exist in this case. - None - } - - ty::Infer(ty::TyVar(_)) => { - // Unbound type variable. Might or might not have - // applicable impls and so forth, depending on what - // those type variables wind up being bound to. - Ambiguous - } - - ty::UnnormalizedProjection(..) - | ty::Placeholder(..) - | ty::Bound(..) - | ty::Infer(ty::FreshTy(_)) - | ty::Infer(ty::FreshIntTy(_)) - | ty::Infer(ty::FreshFloatTy(_)) => { - bug!("asked to assemble builtin bounds of unexpected type: {:?}", self_ty); - } - } - } - - /// For default impls, we need to break apart a type into its - /// "constituent types" -- meaning, the types that it contains. - /// - /// Here are some (simple) examples: - /// - /// ``` - /// (i32, u32) -> [i32, u32] - /// Foo where struct Foo { x: i32, y: u32 } -> [i32, u32] - /// Bar<i32> where struct Bar<T> { x: T, y: u32 } -> [i32, u32] - /// Zed<i32> where enum Zed { A(T), B(u32) } -> [i32, u32] - /// ``` - fn constituent_types_for_ty(&self, t: Ty<'tcx>) -> Vec<Ty<'tcx>> { - match t.kind { - ty::Uint(_) - | ty::Int(_) - | ty::Bool - | ty::Float(_) - | ty::FnDef(..) - | ty::FnPtr(_) - | ty::Str - | ty::Error - | ty::Infer(ty::IntVar(_)) - | ty::Infer(ty::FloatVar(_)) - | ty::Never - | ty::Char => Vec::new(), - - ty::UnnormalizedProjection(..) - | ty::Placeholder(..) - | ty::Dynamic(..) - | ty::Param(..) - | ty::Foreign(..) - | ty::Projection(..) - | ty::Bound(..) - | ty::Infer(ty::TyVar(_)) - | ty::Infer(ty::FreshTy(_)) - | ty::Infer(ty::FreshIntTy(_)) - | ty::Infer(ty::FreshFloatTy(_)) => { - bug!("asked to assemble constituent types of unexpected type: {:?}", t); - } - - ty::RawPtr(ty::TypeAndMut { ty: element_ty, .. }) | ty::Ref(_, element_ty, _) => { - vec![element_ty] - } - - ty::Array(element_ty, _) | ty::Slice(element_ty) => vec![element_ty], - - ty::Tuple(ref tys) => { - // (T1, ..., Tn) -- meets any bound that all of T1...Tn meet - tys.iter().map(|k| k.expect_ty()).collect() - } - - ty::Closure(def_id, ref substs) => { - substs.as_closure().upvar_tys(def_id, self.tcx()).collect() - } - - ty::Generator(def_id, ref substs, _) => { - let witness = substs.as_generator().witness(def_id, self.tcx()); - substs - .as_generator() - .upvar_tys(def_id, self.tcx()) - .chain(iter::once(witness)) - .collect() - } - - ty::GeneratorWitness(types) => { - // This is sound because no regions in the witness can refer to - // the binder outside the witness. So we'll effectivly reuse - // the implicit binder around the witness. - types.skip_binder().to_vec() - } - - // For `PhantomData<T>`, we pass `T`. - ty::Adt(def, substs) if def.is_phantom_data() => substs.types().collect(), - - ty::Adt(def, substs) => def.all_fields().map(|f| f.ty(self.tcx(), substs)).collect(), - - ty::Opaque(def_id, substs) => { - // We can resolve the `impl Trait` to its concrete type, - // which enforces a DAG between the functions requiring - // the auto trait bounds in question. - vec![self.tcx().type_of(def_id).subst(self.tcx(), substs)] - } - } - } - - fn collect_predicates_for_types( - &mut self, - param_env: ty::ParamEnv<'tcx>, - cause: ObligationCause<'tcx>, - recursion_depth: usize, - trait_def_id: DefId, - types: ty::Binder<Vec<Ty<'tcx>>>, - ) -> Vec<PredicateObligation<'tcx>> { - // Because the types were potentially derived from - // higher-ranked obligations they may reference late-bound - // regions. For example, `for<'a> Foo<&'a int> : Copy` would - // yield a type like `for<'a> &'a int`. In general, we - // maintain the invariant that we never manipulate bound - // regions, so we have to process these bound regions somehow. - // - // The strategy is to: - // - // 1. Instantiate those regions to placeholder regions (e.g., - // `for<'a> &'a int` becomes `&0 int`. - // 2. Produce something like `&'0 int : Copy` - // 3. Re-bind the regions back to `for<'a> &'a int : Copy` - - types - .skip_binder() - .iter() - .flat_map(|ty| { - // binder moved -\ - let ty: ty::Binder<Ty<'tcx>> = ty::Binder::bind(ty); // <----/ - - self.infcx.commit_unconditionally(|_| { - let (skol_ty, _) = self.infcx.replace_bound_vars_with_placeholders(&ty); - let Normalized { value: normalized_ty, mut obligations } = - project::normalize_with_depth( - self, - param_env, - cause.clone(), - recursion_depth, - &skol_ty, - ); - let skol_obligation = predicate_for_trait_def( - self.tcx(), - param_env, - cause.clone(), - trait_def_id, - recursion_depth, - normalized_ty, - &[], - ); - obligations.push(skol_obligation); - obligations - }) - }) - .collect() - } - - /////////////////////////////////////////////////////////////////////////// - // CONFIRMATION - // - // Confirmation unifies the output type parameters of the trait - // with the values found in the obligation, possibly yielding a - // type error. See the [rustc guide] for more details. - // - // [rustc guide]: - // https://rust-lang.github.io/rustc-guide/traits/resolution.html#confirmation - - fn confirm_candidate( - &mut self, - obligation: &TraitObligation<'tcx>, - candidate: SelectionCandidate<'tcx>, - ) -> Result<Selection<'tcx>, SelectionError<'tcx>> { - debug!("confirm_candidate({:?}, {:?})", obligation, candidate); - - match candidate { - BuiltinCandidate { has_nested } => { - let data = self.confirm_builtin_candidate(obligation, has_nested); - Ok(VtableBuiltin(data)) - } - - ParamCandidate(param) => { - let obligations = self.confirm_param_candidate(obligation, param); - Ok(VtableParam(obligations)) - } - - ImplCandidate(impl_def_id) => { - Ok(VtableImpl(self.confirm_impl_candidate(obligation, impl_def_id))) - } - - AutoImplCandidate(trait_def_id) => { - let data = self.confirm_auto_impl_candidate(obligation, trait_def_id); - Ok(VtableAutoImpl(data)) - } - - ProjectionCandidate => { - self.confirm_projection_candidate(obligation); - Ok(VtableParam(Vec::new())) - } - - ClosureCandidate => { - let vtable_closure = self.confirm_closure_candidate(obligation)?; - Ok(VtableClosure(vtable_closure)) - } - - GeneratorCandidate => { - let vtable_generator = self.confirm_generator_candidate(obligation)?; - Ok(VtableGenerator(vtable_generator)) - } - - FnPointerCandidate => { - let data = self.confirm_fn_pointer_candidate(obligation)?; - Ok(VtableFnPointer(data)) - } - - TraitAliasCandidate(alias_def_id) => { - let data = self.confirm_trait_alias_candidate(obligation, alias_def_id); - Ok(VtableTraitAlias(data)) - } - - ObjectCandidate => { - let data = self.confirm_object_candidate(obligation); - Ok(VtableObject(data)) - } - - BuiltinObjectCandidate => { - // This indicates something like `Trait + Send: Send`. In this case, we know that - // this holds because that's what the object type is telling us, and there's really - // no additional obligations to prove and no types in particular to unify, etc. - Ok(VtableParam(Vec::new())) - } - - BuiltinUnsizeCandidate => { - let data = self.confirm_builtin_unsize_candidate(obligation)?; - Ok(VtableBuiltin(data)) - } - } - } - - fn confirm_projection_candidate(&mut self, obligation: &TraitObligation<'tcx>) { - self.infcx.commit_unconditionally(|snapshot| { - let result = - self.match_projection_obligation_against_definition_bounds(obligation, snapshot); - assert!(result); - }) - } - - fn confirm_param_candidate( - &mut self, - obligation: &TraitObligation<'tcx>, - param: ty::PolyTraitRef<'tcx>, - ) -> Vec<PredicateObligation<'tcx>> { - debug!("confirm_param_candidate({:?},{:?})", obligation, param); - - // During evaluation, we already checked that this - // where-clause trait-ref could be unified with the obligation - // trait-ref. Repeat that unification now without any - // transactional boundary; it should not fail. - match self.match_where_clause_trait_ref(obligation, param.clone()) { - Ok(obligations) => obligations, - Err(()) => { - bug!( - "Where clause `{:?}` was applicable to `{:?}` but now is not", - param, - obligation - ); - } - } - } - - fn confirm_builtin_candidate( - &mut self, - obligation: &TraitObligation<'tcx>, - has_nested: bool, - ) -> VtableBuiltinData<PredicateObligation<'tcx>> { - debug!("confirm_builtin_candidate({:?}, {:?})", obligation, has_nested); - - let lang_items = self.tcx().lang_items(); - let obligations = if has_nested { - let trait_def = obligation.predicate.def_id(); - let conditions = if Some(trait_def) == lang_items.sized_trait() { - self.sized_conditions(obligation) - } else if Some(trait_def) == lang_items.copy_trait() { - self.copy_clone_conditions(obligation) - } else if Some(trait_def) == lang_items.clone_trait() { - self.copy_clone_conditions(obligation) - } else { - bug!("unexpected builtin trait {:?}", trait_def) - }; - let nested = match conditions { - BuiltinImplConditions::Where(nested) => nested, - _ => bug!("obligation {:?} had matched a builtin impl but now doesn't", obligation), - }; - - let cause = obligation.derived_cause(BuiltinDerivedObligation); - self.collect_predicates_for_types( - obligation.param_env, - cause, - obligation.recursion_depth + 1, - trait_def, - nested, - ) - } else { - vec![] - }; - - debug!("confirm_builtin_candidate: obligations={:?}", obligations); - - VtableBuiltinData { nested: obligations } - } - - /// This handles the case where a `auto trait Foo` impl is being used. - /// The idea is that the impl applies to `X : Foo` if the following conditions are met: - /// - /// 1. For each constituent type `Y` in `X`, `Y : Foo` holds - /// 2. For each where-clause `C` declared on `Foo`, `[Self => X] C` holds. - fn confirm_auto_impl_candidate( - &mut self, - obligation: &TraitObligation<'tcx>, - trait_def_id: DefId, - ) -> VtableAutoImplData<PredicateObligation<'tcx>> { - debug!("confirm_auto_impl_candidate({:?}, {:?})", obligation, trait_def_id); - - let types = obligation.predicate.map_bound(|inner| { - let self_ty = self.infcx.shallow_resolve(inner.self_ty()); - self.constituent_types_for_ty(self_ty) - }); - self.vtable_auto_impl(obligation, trait_def_id, types) - } - - /// See `confirm_auto_impl_candidate`. - fn vtable_auto_impl( - &mut self, - obligation: &TraitObligation<'tcx>, - trait_def_id: DefId, - nested: ty::Binder<Vec<Ty<'tcx>>>, - ) -> VtableAutoImplData<PredicateObligation<'tcx>> { - debug!("vtable_auto_impl: nested={:?}", nested); - - let cause = obligation.derived_cause(BuiltinDerivedObligation); - let mut obligations = self.collect_predicates_for_types( - obligation.param_env, - cause, - obligation.recursion_depth + 1, - trait_def_id, - nested, - ); - - let trait_obligations: Vec<PredicateObligation<'_>> = - self.infcx.commit_unconditionally(|_| { - let poly_trait_ref = obligation.predicate.to_poly_trait_ref(); - let (trait_ref, _) = - self.infcx.replace_bound_vars_with_placeholders(&poly_trait_ref); - let cause = obligation.derived_cause(ImplDerivedObligation); - self.impl_or_trait_obligations( - cause, - obligation.recursion_depth + 1, - obligation.param_env, - trait_def_id, - &trait_ref.substs, - ) - }); - - // Adds the predicates from the trait. Note that this contains a `Self: Trait` - // predicate as usual. It won't have any effect since auto traits are coinductive. - obligations.extend(trait_obligations); - - debug!("vtable_auto_impl: obligations={:?}", obligations); - - VtableAutoImplData { trait_def_id, nested: obligations } - } - - fn confirm_impl_candidate( - &mut self, - obligation: &TraitObligation<'tcx>, - impl_def_id: DefId, - ) -> VtableImplData<'tcx, PredicateObligation<'tcx>> { - debug!("confirm_impl_candidate({:?},{:?})", obligation, impl_def_id); - - // First, create the substitutions by matching the impl again, - // this time not in a probe. - self.infcx.commit_unconditionally(|snapshot| { - let substs = self.rematch_impl(impl_def_id, obligation, snapshot); - debug!("confirm_impl_candidate: substs={:?}", substs); - let cause = obligation.derived_cause(ImplDerivedObligation); - self.vtable_impl( - impl_def_id, - substs, - cause, - obligation.recursion_depth + 1, - obligation.param_env, - ) - }) - } - - fn vtable_impl( - &mut self, - impl_def_id: DefId, - mut substs: Normalized<'tcx, SubstsRef<'tcx>>, - cause: ObligationCause<'tcx>, - recursion_depth: usize, - param_env: ty::ParamEnv<'tcx>, - ) -> VtableImplData<'tcx, PredicateObligation<'tcx>> { - debug!( - "vtable_impl(impl_def_id={:?}, substs={:?}, recursion_depth={})", - impl_def_id, substs, recursion_depth, - ); - - let mut impl_obligations = self.impl_or_trait_obligations( - cause, - recursion_depth, - param_env, - impl_def_id, - &substs.value, - ); - - debug!( - "vtable_impl: impl_def_id={:?} impl_obligations={:?}", - impl_def_id, impl_obligations - ); - - // Because of RFC447, the impl-trait-ref and obligations - // are sufficient to determine the impl substs, without - // relying on projections in the impl-trait-ref. - // - // e.g., `impl<U: Tr, V: Iterator<Item=U>> Foo<<U as Tr>::T> for V` - impl_obligations.append(&mut substs.obligations); - - VtableImplData { impl_def_id, substs: substs.value, nested: impl_obligations } - } - - fn confirm_object_candidate( - &mut self, - obligation: &TraitObligation<'tcx>, - ) -> VtableObjectData<'tcx, PredicateObligation<'tcx>> { - debug!("confirm_object_candidate({:?})", obligation); - - // FIXME(nmatsakis) skipping binder here seems wrong -- we should - // probably flatten the binder from the obligation and the binder - // from the object. Have to try to make a broken test case that - // results. - let self_ty = self.infcx.shallow_resolve(*obligation.self_ty().skip_binder()); - let poly_trait_ref = match self_ty.kind { - ty::Dynamic(ref data, ..) => data - .principal() - .unwrap_or_else(|| { - span_bug!(obligation.cause.span, "object candidate with no principal") - }) - .with_self_ty(self.tcx(), self_ty), - _ => span_bug!(obligation.cause.span, "object candidate with non-object"), - }; - - let mut upcast_trait_ref = None; - let mut nested = vec![]; - let vtable_base; - - { - let tcx = self.tcx(); - - // We want to find the first supertrait in the list of - // supertraits that we can unify with, and do that - // unification. We know that there is exactly one in the list - // where we can unify, because otherwise select would have - // reported an ambiguity. (When we do find a match, also - // record it for later.) - let nonmatching = util::supertraits(tcx, poly_trait_ref).take_while(|&t| { - match self.infcx.commit_if_ok(|_| self.match_poly_trait_ref(obligation, t)) { - Ok(obligations) => { - upcast_trait_ref = Some(t); - nested.extend(obligations); - false - } - Err(_) => true, - } - }); - - // Additionally, for each of the non-matching predicates that - // we pass over, we sum up the set of number of vtable - // entries, so that we can compute the offset for the selected - // trait. - vtable_base = nonmatching.map(|t| super::util::count_own_vtable_entries(tcx, t)).sum(); - } - - VtableObjectData { upcast_trait_ref: upcast_trait_ref.unwrap(), vtable_base, nested } - } - - fn confirm_fn_pointer_candidate( - &mut self, - obligation: &TraitObligation<'tcx>, - ) -> Result<VtableFnPointerData<'tcx, PredicateObligation<'tcx>>, SelectionError<'tcx>> { - debug!("confirm_fn_pointer_candidate({:?})", obligation); - - // Okay to skip binder; it is reintroduced below. - let self_ty = self.infcx.shallow_resolve(*obligation.self_ty().skip_binder()); - let sig = self_ty.fn_sig(self.tcx()); - let trait_ref = closure_trait_ref_and_return_type( - self.tcx(), - obligation.predicate.def_id(), - self_ty, - sig, - util::TupleArgumentsFlag::Yes, - ) - .map_bound(|(trait_ref, _)| trait_ref); - - let Normalized { value: trait_ref, obligations } = project::normalize_with_depth( - self, - obligation.param_env, - obligation.cause.clone(), - obligation.recursion_depth + 1, - &trait_ref, - ); - - self.confirm_poly_trait_refs( - obligation.cause.clone(), - obligation.param_env, - obligation.predicate.to_poly_trait_ref(), - trait_ref, - )?; - Ok(VtableFnPointerData { fn_ty: self_ty, nested: obligations }) - } - - fn confirm_trait_alias_candidate( - &mut self, - obligation: &TraitObligation<'tcx>, - alias_def_id: DefId, - ) -> VtableTraitAliasData<'tcx, PredicateObligation<'tcx>> { - debug!("confirm_trait_alias_candidate({:?}, {:?})", obligation, alias_def_id); - - self.infcx.commit_unconditionally(|_| { - let (predicate, _) = - self.infcx().replace_bound_vars_with_placeholders(&obligation.predicate); - let trait_ref = predicate.trait_ref; - let trait_def_id = trait_ref.def_id; - let substs = trait_ref.substs; - - let trait_obligations = self.impl_or_trait_obligations( - obligation.cause.clone(), - obligation.recursion_depth, - obligation.param_env, - trait_def_id, - &substs, - ); - - debug!( - "confirm_trait_alias_candidate: trait_def_id={:?} trait_obligations={:?}", - trait_def_id, trait_obligations - ); - - VtableTraitAliasData { alias_def_id, substs: substs, nested: trait_obligations } - }) - } - - fn confirm_generator_candidate( - &mut self, - obligation: &TraitObligation<'tcx>, - ) -> Result<VtableGeneratorData<'tcx, PredicateObligation<'tcx>>, SelectionError<'tcx>> { - // Okay to skip binder because the substs on generator types never - // touch bound regions, they just capture the in-scope - // type/region parameters. - let self_ty = self.infcx.shallow_resolve(*obligation.self_ty().skip_binder()); - let (generator_def_id, substs) = match self_ty.kind { - ty::Generator(id, substs, _) => (id, substs), - _ => bug!("closure candidate for non-closure {:?}", obligation), - }; - - debug!("confirm_generator_candidate({:?},{:?},{:?})", obligation, generator_def_id, substs); - - let trait_ref = self.generator_trait_ref_unnormalized(obligation, generator_def_id, substs); - let Normalized { value: trait_ref, mut obligations } = normalize_with_depth( - self, - obligation.param_env, - obligation.cause.clone(), - obligation.recursion_depth + 1, - &trait_ref, - ); - - debug!( - "confirm_generator_candidate(generator_def_id={:?}, \ - trait_ref={:?}, obligations={:?})", - generator_def_id, trait_ref, obligations - ); - - obligations.extend(self.confirm_poly_trait_refs( - obligation.cause.clone(), - obligation.param_env, - obligation.predicate.to_poly_trait_ref(), - trait_ref, - )?); - - Ok(VtableGeneratorData { generator_def_id, substs, nested: obligations }) - } - - fn confirm_closure_candidate( - &mut self, - obligation: &TraitObligation<'tcx>, - ) -> Result<VtableClosureData<'tcx, PredicateObligation<'tcx>>, SelectionError<'tcx>> { - debug!("confirm_closure_candidate({:?})", obligation); - - let kind = self - .tcx() - .fn_trait_kind_from_lang_item(obligation.predicate.def_id()) - .unwrap_or_else(|| bug!("closure candidate for non-fn trait {:?}", obligation)); - - // Okay to skip binder because the substs on closure types never - // touch bound regions, they just capture the in-scope - // type/region parameters. - let self_ty = self.infcx.shallow_resolve(*obligation.self_ty().skip_binder()); - let (closure_def_id, substs) = match self_ty.kind { - ty::Closure(id, substs) => (id, substs), - _ => bug!("closure candidate for non-closure {:?}", obligation), - }; - - let trait_ref = self.closure_trait_ref_unnormalized(obligation, closure_def_id, substs); - let Normalized { value: trait_ref, mut obligations } = normalize_with_depth( - self, - obligation.param_env, - obligation.cause.clone(), - obligation.recursion_depth + 1, - &trait_ref, - ); - - debug!( - "confirm_closure_candidate(closure_def_id={:?}, trait_ref={:?}, obligations={:?})", - closure_def_id, trait_ref, obligations - ); - - obligations.extend(self.confirm_poly_trait_refs( - obligation.cause.clone(), - obligation.param_env, - obligation.predicate.to_poly_trait_ref(), - trait_ref, - )?); - - obligations.push(Obligation::new( - obligation.cause.clone(), - obligation.param_env, - ty::Predicate::ClosureKind(closure_def_id, substs, kind), - )); - - Ok(VtableClosureData { closure_def_id, substs: substs, nested: obligations }) - } - - /// In the case of closure types and fn pointers, - /// we currently treat the input type parameters on the trait as - /// outputs. This means that when we have a match we have only - /// considered the self type, so we have to go back and make sure - /// to relate the argument types too. This is kind of wrong, but - /// since we control the full set of impls, also not that wrong, - /// and it DOES yield better error messages (since we don't report - /// errors as if there is no applicable impl, but rather report - /// errors are about mismatched argument types. - /// - /// Here is an example. Imagine we have a closure expression - /// and we desugared it so that the type of the expression is - /// `Closure`, and `Closure` expects an int as argument. Then it - /// is "as if" the compiler generated this impl: - /// - /// impl Fn(int) for Closure { ... } - /// - /// Now imagine our obligation is `Fn(usize) for Closure`. So far - /// we have matched the self type `Closure`. At this point we'll - /// compare the `int` to `usize` and generate an error. - /// - /// Note that this checking occurs *after* the impl has selected, - /// because these output type parameters should not affect the - /// selection of the impl. Therefore, if there is a mismatch, we - /// report an error to the user. - fn confirm_poly_trait_refs( - &mut self, - obligation_cause: ObligationCause<'tcx>, - obligation_param_env: ty::ParamEnv<'tcx>, - obligation_trait_ref: ty::PolyTraitRef<'tcx>, - expected_trait_ref: ty::PolyTraitRef<'tcx>, - ) -> Result<Vec<PredicateObligation<'tcx>>, SelectionError<'tcx>> { - self.infcx - .at(&obligation_cause, obligation_param_env) - .sup(obligation_trait_ref, expected_trait_ref) - .map(|InferOk { obligations, .. }| obligations) - .map_err(|e| OutputTypeParameterMismatch(expected_trait_ref, obligation_trait_ref, e)) - } - - fn confirm_builtin_unsize_candidate( - &mut self, - obligation: &TraitObligation<'tcx>, - ) -> Result<VtableBuiltinData<PredicateObligation<'tcx>>, SelectionError<'tcx>> { - let tcx = self.tcx(); - - // `assemble_candidates_for_unsizing` should ensure there are no late-bound - // regions here. See the comment there for more details. - let source = self.infcx.shallow_resolve(obligation.self_ty().no_bound_vars().unwrap()); - let target = obligation.predicate.skip_binder().trait_ref.substs.type_at(1); - let target = self.infcx.shallow_resolve(target); - - debug!("confirm_builtin_unsize_candidate(source={:?}, target={:?})", source, target); - - let mut nested = vec![]; - match (&source.kind, &target.kind) { - // Trait+Kx+'a -> Trait+Ky+'b (upcasts). - (&ty::Dynamic(ref data_a, r_a), &ty::Dynamic(ref data_b, r_b)) => { - // See `assemble_candidates_for_unsizing` for more info. - let existential_predicates = data_a.map_bound(|data_a| { - let iter = data_a - .principal() - .map(|x| ty::ExistentialPredicate::Trait(x)) - .into_iter() - .chain( - data_a - .projection_bounds() - .map(|x| ty::ExistentialPredicate::Projection(x)), - ) - .chain(data_b.auto_traits().map(ty::ExistentialPredicate::AutoTrait)); - tcx.mk_existential_predicates(iter) - }); - let source_trait = tcx.mk_dynamic(existential_predicates, r_b); - - // Require that the traits involved in this upcast are **equal**; - // only the **lifetime bound** is changed. - // - // FIXME: This condition is arguably too strong -- it would - // suffice for the source trait to be a *subtype* of the target - // trait. In particular, changing from something like - // `for<'a, 'b> Foo<'a, 'b>` to `for<'a> Foo<'a, 'a>` should be - // permitted. And, indeed, in the in commit - // 904a0bde93f0348f69914ee90b1f8b6e4e0d7cbc, this - // condition was loosened. However, when the leak check was - // added back, using subtype here actually guides the coercion - // code in such a way that it accepts `old-lub-glb-object.rs`. - // This is probably a good thing, but I've modified this to `.eq` - // because I want to continue rejecting that test (as we have - // done for quite some time) before we are firmly comfortable - // with what our behavior should be there. -nikomatsakis - let InferOk { obligations, .. } = self - .infcx - .at(&obligation.cause, obligation.param_env) - .eq(target, source_trait) // FIXME -- see below - .map_err(|_| Unimplemented)?; - nested.extend(obligations); - - // Register one obligation for 'a: 'b. - let cause = ObligationCause::new( - obligation.cause.span, - obligation.cause.body_id, - ObjectCastObligation(target), - ); - let outlives = ty::OutlivesPredicate(r_a, r_b); - nested.push(Obligation::with_depth( - cause, - obligation.recursion_depth + 1, - obligation.param_env, - ty::Binder::bind(outlives).to_predicate(), - )); - } - - // `T` -> `Trait` - (_, &ty::Dynamic(ref data, r)) => { - let mut object_dids = data.auto_traits().chain(data.principal_def_id()); - if let Some(did) = object_dids.find(|did| !tcx.is_object_safe(*did)) { - return Err(TraitNotObjectSafe(did)); - } - - let cause = ObligationCause::new( - obligation.cause.span, - obligation.cause.body_id, - ObjectCastObligation(target), - ); - - let predicate_to_obligation = |predicate| { - Obligation::with_depth( - cause.clone(), - obligation.recursion_depth + 1, - obligation.param_env, - predicate, - ) - }; - - // Create obligations: - // - Casting `T` to `Trait` - // - For all the various builtin bounds attached to the object cast. (In other - // words, if the object type is `Foo + Send`, this would create an obligation for - // the `Send` check.) - // - Projection predicates - nested.extend( - data.iter().map(|predicate| { - predicate_to_obligation(predicate.with_self_ty(tcx, source)) - }), - ); - - // We can only make objects from sized types. - let tr = ty::TraitRef::new( - tcx.require_lang_item(lang_items::SizedTraitLangItem, None), - tcx.mk_substs_trait(source, &[]), - ); - nested.push(predicate_to_obligation(tr.without_const().to_predicate())); - - // If the type is `Foo + 'a`, ensure that the type - // being cast to `Foo + 'a` outlives `'a`: - let outlives = ty::OutlivesPredicate(source, r); - nested.push(predicate_to_obligation(ty::Binder::dummy(outlives).to_predicate())); - } - - // `[T; n]` -> `[T]` - (&ty::Array(a, _), &ty::Slice(b)) => { - let InferOk { obligations, .. } = self - .infcx - .at(&obligation.cause, obligation.param_env) - .eq(b, a) - .map_err(|_| Unimplemented)?; - nested.extend(obligations); - } - - // `Struct<T>` -> `Struct<U>` - (&ty::Adt(def, substs_a), &ty::Adt(_, substs_b)) => { - let fields = - def.all_fields().map(|field| tcx.type_of(field.did)).collect::<Vec<_>>(); - - // The last field of the structure has to exist and contain type parameters. - let field = if let Some(&field) = fields.last() { - field - } else { - return Err(Unimplemented); - }; - let mut ty_params = GrowableBitSet::new_empty(); - let mut found = false; - for ty in field.walk() { - if let ty::Param(p) = ty.kind { - ty_params.insert(p.index as usize); - found = true; - } - } - if !found { - return Err(Unimplemented); - } - - // Replace type parameters used in unsizing with - // Error and ensure they do not affect any other fields. - // This could be checked after type collection for any struct - // with a potentially unsized trailing field. - let params = substs_a - .iter() - .enumerate() - .map(|(i, &k)| if ty_params.contains(i) { tcx.types.err.into() } else { k }); - let substs = tcx.mk_substs(params); - for &ty in fields.split_last().unwrap().1 { - if ty.subst(tcx, substs).references_error() { - return Err(Unimplemented); - } - } - - // Extract `Field<T>` and `Field<U>` from `Struct<T>` and `Struct<U>`. - let inner_source = field.subst(tcx, substs_a); - let inner_target = field.subst(tcx, substs_b); - - // Check that the source struct with the target's - // unsized parameters is equal to the target. - let params = substs_a.iter().enumerate().map(|(i, &k)| { - if ty_params.contains(i) { substs_b.type_at(i).into() } else { k } - }); - let new_struct = tcx.mk_adt(def, tcx.mk_substs(params)); - let InferOk { obligations, .. } = self - .infcx - .at(&obligation.cause, obligation.param_env) - .eq(target, new_struct) - .map_err(|_| Unimplemented)?; - nested.extend(obligations); - - // Construct the nested `Field<T>: Unsize<Field<U>>` predicate. - nested.push(predicate_for_trait_def( - tcx, - obligation.param_env, - obligation.cause.clone(), - obligation.predicate.def_id(), - obligation.recursion_depth + 1, - inner_source, - &[inner_target.into()], - )); - } - - // `(.., T)` -> `(.., U)` - (&ty::Tuple(tys_a), &ty::Tuple(tys_b)) => { - assert_eq!(tys_a.len(), tys_b.len()); - - // The last field of the tuple has to exist. - let (&a_last, a_mid) = if let Some(x) = tys_a.split_last() { - x - } else { - return Err(Unimplemented); - }; - let &b_last = tys_b.last().unwrap(); - - // Check that the source tuple with the target's - // last element is equal to the target. - let new_tuple = tcx.mk_tup( - a_mid.iter().map(|k| k.expect_ty()).chain(iter::once(b_last.expect_ty())), - ); - let InferOk { obligations, .. } = self - .infcx - .at(&obligation.cause, obligation.param_env) - .eq(target, new_tuple) - .map_err(|_| Unimplemented)?; - nested.extend(obligations); - - // Construct the nested `T: Unsize<U>` predicate. - nested.push(predicate_for_trait_def( - tcx, - obligation.param_env, - obligation.cause.clone(), - obligation.predicate.def_id(), - obligation.recursion_depth + 1, - a_last.expect_ty(), - &[b_last], - )); - } - - _ => bug!(), - }; - - Ok(VtableBuiltinData { nested }) - } - - /////////////////////////////////////////////////////////////////////////// - // Matching - // - // Matching is a common path used for both evaluation and - // confirmation. It basically unifies types that appear in impls - // and traits. This does affect the surrounding environment; - // therefore, when used during evaluation, match routines must be - // run inside of a `probe()` so that their side-effects are - // contained. - - fn rematch_impl( - &mut self, - impl_def_id: DefId, - obligation: &TraitObligation<'tcx>, - snapshot: &CombinedSnapshot<'_, 'tcx>, - ) -> Normalized<'tcx, SubstsRef<'tcx>> { - match self.match_impl(impl_def_id, obligation, snapshot) { - Ok(substs) => substs, - Err(()) => { - bug!( - "Impl {:?} was matchable against {:?} but now is not", - impl_def_id, - obligation - ); - } - } - } - - fn match_impl( - &mut self, - impl_def_id: DefId, - obligation: &TraitObligation<'tcx>, - snapshot: &CombinedSnapshot<'_, 'tcx>, - ) -> Result<Normalized<'tcx, SubstsRef<'tcx>>, ()> { - let impl_trait_ref = self.tcx().impl_trait_ref(impl_def_id).unwrap(); - - // Before we create the substitutions and everything, first - // consider a "quick reject". This avoids creating more types - // and so forth that we need to. - if self.fast_reject_trait_refs(obligation, &impl_trait_ref) { - return Err(()); - } - - let (skol_obligation, placeholder_map) = - self.infcx().replace_bound_vars_with_placeholders(&obligation.predicate); - let skol_obligation_trait_ref = skol_obligation.trait_ref; - - let impl_substs = self.infcx.fresh_substs_for_item(obligation.cause.span, impl_def_id); - - let impl_trait_ref = impl_trait_ref.subst(self.tcx(), impl_substs); - - let Normalized { value: impl_trait_ref, obligations: mut nested_obligations } = - project::normalize_with_depth( - self, - obligation.param_env, - obligation.cause.clone(), - obligation.recursion_depth + 1, - &impl_trait_ref, - ); - - debug!( - "match_impl(impl_def_id={:?}, obligation={:?}, \ - impl_trait_ref={:?}, skol_obligation_trait_ref={:?})", - impl_def_id, obligation, impl_trait_ref, skol_obligation_trait_ref - ); - - let InferOk { obligations, .. } = self - .infcx - .at(&obligation.cause, obligation.param_env) - .eq(skol_obligation_trait_ref, impl_trait_ref) - .map_err(|e| debug!("match_impl: failed eq_trait_refs due to `{}`", e))?; - nested_obligations.extend(obligations); - - if let Err(e) = self.infcx.leak_check(false, &placeholder_map, snapshot) { - debug!("match_impl: failed leak check due to `{}`", e); - return Err(()); - } - - if !self.intercrate - && self.tcx().impl_polarity(impl_def_id) == ty::ImplPolarity::Reservation - { - debug!("match_impl: reservation impls only apply in intercrate mode"); - return Err(()); - } - - debug!("match_impl: success impl_substs={:?}", impl_substs); - Ok(Normalized { value: impl_substs, obligations: nested_obligations }) - } - - fn fast_reject_trait_refs( - &mut self, - obligation: &TraitObligation<'_>, - impl_trait_ref: &ty::TraitRef<'_>, - ) -> bool { - // We can avoid creating type variables and doing the full - // substitution if we find that any of the input types, when - // simplified, do not match. - - obligation.predicate.skip_binder().input_types().zip(impl_trait_ref.input_types()).any( - |(obligation_ty, impl_ty)| { - let simplified_obligation_ty = - fast_reject::simplify_type(self.tcx(), obligation_ty, true); - let simplified_impl_ty = fast_reject::simplify_type(self.tcx(), impl_ty, false); - - simplified_obligation_ty.is_some() - && simplified_impl_ty.is_some() - && simplified_obligation_ty != simplified_impl_ty - }, - ) - } - - /// Normalize `where_clause_trait_ref` and try to match it against - /// `obligation`. If successful, return any predicates that - /// result from the normalization. Normalization is necessary - /// because where-clauses are stored in the parameter environment - /// unnormalized. - fn match_where_clause_trait_ref( - &mut self, - obligation: &TraitObligation<'tcx>, - where_clause_trait_ref: ty::PolyTraitRef<'tcx>, - ) -> Result<Vec<PredicateObligation<'tcx>>, ()> { - self.match_poly_trait_ref(obligation, where_clause_trait_ref) - } - - /// Returns `Ok` if `poly_trait_ref` being true implies that the - /// obligation is satisfied. - fn match_poly_trait_ref( - &mut self, - obligation: &TraitObligation<'tcx>, - poly_trait_ref: ty::PolyTraitRef<'tcx>, - ) -> Result<Vec<PredicateObligation<'tcx>>, ()> { - debug!( - "match_poly_trait_ref: obligation={:?} poly_trait_ref={:?}", - obligation, poly_trait_ref - ); - - self.infcx - .at(&obligation.cause, obligation.param_env) - .sup(obligation.predicate.to_poly_trait_ref(), poly_trait_ref) - .map(|InferOk { obligations, .. }| obligations) - .map_err(|_| ()) - } - - /////////////////////////////////////////////////////////////////////////// - // Miscellany - - fn match_fresh_trait_refs( - &self, - previous: &ty::PolyTraitRef<'tcx>, - current: &ty::PolyTraitRef<'tcx>, - param_env: ty::ParamEnv<'tcx>, - ) -> bool { - let mut matcher = ty::_match::Match::new(self.tcx(), param_env); - matcher.relate(previous, current).is_ok() - } - - fn push_stack<'o>( - &mut self, - previous_stack: TraitObligationStackList<'o, 'tcx>, - obligation: &'o TraitObligation<'tcx>, - ) -> TraitObligationStack<'o, 'tcx> { - let fresh_trait_ref = - obligation.predicate.to_poly_trait_ref().fold_with(&mut self.freshener); - - let dfn = previous_stack.cache.next_dfn(); - let depth = previous_stack.depth() + 1; - TraitObligationStack { - obligation, - fresh_trait_ref, - reached_depth: Cell::new(depth), - previous: previous_stack, - dfn, - depth, - } - } - - fn closure_trait_ref_unnormalized( - &mut self, - obligation: &TraitObligation<'tcx>, - closure_def_id: DefId, - substs: SubstsRef<'tcx>, - ) -> ty::PolyTraitRef<'tcx> { - debug!( - "closure_trait_ref_unnormalized(obligation={:?}, closure_def_id={:?}, substs={:?})", - obligation, closure_def_id, substs, - ); - let closure_type = self.infcx.closure_sig(closure_def_id, substs); - - debug!("closure_trait_ref_unnormalized: closure_type = {:?}", closure_type); - - // (1) Feels icky to skip the binder here, but OTOH we know - // that the self-type is an unboxed closure type and hence is - // in fact unparameterized (or at least does not reference any - // regions bound in the obligation). Still probably some - // refactoring could make this nicer. - closure_trait_ref_and_return_type( - self.tcx(), - obligation.predicate.def_id(), - obligation.predicate.skip_binder().self_ty(), // (1) - closure_type, - util::TupleArgumentsFlag::No, - ) - .map_bound(|(trait_ref, _)| trait_ref) - } - - fn generator_trait_ref_unnormalized( - &mut self, - obligation: &TraitObligation<'tcx>, - closure_def_id: DefId, - substs: SubstsRef<'tcx>, - ) -> ty::PolyTraitRef<'tcx> { - let gen_sig = substs.as_generator().poly_sig(closure_def_id, self.tcx()); - - // (1) Feels icky to skip the binder here, but OTOH we know - // that the self-type is an generator type and hence is - // in fact unparameterized (or at least does not reference any - // regions bound in the obligation). Still probably some - // refactoring could make this nicer. - - super::util::generator_trait_ref_and_outputs( - self.tcx(), - obligation.predicate.def_id(), - obligation.predicate.skip_binder().self_ty(), // (1) - gen_sig, - ) - .map_bound(|(trait_ref, ..)| trait_ref) - } - - /// Returns the obligations that are implied by instantiating an - /// impl or trait. The obligations are substituted and fully - /// normalized. This is used when confirming an impl or default - /// impl. - fn impl_or_trait_obligations( - &mut self, - cause: ObligationCause<'tcx>, - recursion_depth: usize, - param_env: ty::ParamEnv<'tcx>, - def_id: DefId, // of impl or trait - substs: SubstsRef<'tcx>, // for impl or trait - ) -> Vec<PredicateObligation<'tcx>> { - debug!("impl_or_trait_obligations(def_id={:?})", def_id); - let tcx = self.tcx(); - - // To allow for one-pass evaluation of the nested obligation, - // each predicate must be preceded by the obligations required - // to normalize it. - // for example, if we have: - // impl<U: Iterator<Item: Copy>, V: Iterator<Item = U>> Foo for V - // the impl will have the following predicates: - // <V as Iterator>::Item = U, - // U: Iterator, U: Sized, - // V: Iterator, V: Sized, - // <U as Iterator>::Item: Copy - // When we substitute, say, `V => IntoIter<u32>, U => $0`, the last - // obligation will normalize to `<$0 as Iterator>::Item = $1` and - // `$1: Copy`, so we must ensure the obligations are emitted in - // that order. - let predicates = tcx.predicates_of(def_id); - assert_eq!(predicates.parent, None); - let mut obligations = Vec::with_capacity(predicates.predicates.len()); - for (predicate, _) in predicates.predicates { - let predicate = normalize_with_depth_to( - self, - param_env, - cause.clone(), - recursion_depth, - &predicate.subst(tcx, substs), - &mut obligations, - ); - obligations.push(Obligation { - cause: cause.clone(), - recursion_depth, - param_env, - predicate, - }); - } - - // We are performing deduplication here to avoid exponential blowups - // (#38528) from happening, but the real cause of the duplication is - // unknown. What we know is that the deduplication avoids exponential - // amount of predicates being propagated when processing deeply nested - // types. - // - // This code is hot enough that it's worth avoiding the allocation - // required for the FxHashSet when possible. Special-casing lengths 0, - // 1 and 2 covers roughly 75-80% of the cases. - if obligations.len() <= 1 { - // No possibility of duplicates. - } else if obligations.len() == 2 { - // Only two elements. Drop the second if they are equal. - if obligations[0] == obligations[1] { - obligations.truncate(1); - } - } else { - // Three or more elements. Use a general deduplication process. - let mut seen = FxHashSet::default(); - obligations.retain(|i| seen.insert(i.clone())); - } - - obligations - } -} - -impl<'tcx> TraitObligation<'tcx> { - #[allow(unused_comparisons)] - pub fn derived_cause( - &self, - variant: fn(DerivedObligationCause<'tcx>) -> ObligationCauseCode<'tcx>, - ) -> ObligationCause<'tcx> { - /*! - * Creates a cause for obligations that are derived from - * `obligation` by a recursive search (e.g., for a builtin - * bound, or eventually a `auto trait Foo`). If `obligation` - * is itself a derived obligation, this is just a clone, but - * otherwise we create a "derived obligation" cause so as to - * keep track of the original root obligation for error - * reporting. - */ - - let obligation = self; - - // NOTE(flaper87): As of now, it keeps track of the whole error - // chain. Ideally, we should have a way to configure this either - // by using -Z verbose or just a CLI argument. - let derived_cause = DerivedObligationCause { - parent_trait_ref: obligation.predicate.to_poly_trait_ref(), - parent_code: Rc::new(obligation.cause.code.clone()), - }; - let derived_code = variant(derived_cause); - ObligationCause::new(obligation.cause.span, obligation.cause.body_id, derived_code) - } -} - -impl<'o, 'tcx> TraitObligationStack<'o, 'tcx> { - fn list(&'o self) -> TraitObligationStackList<'o, 'tcx> { - TraitObligationStackList::with(self) - } - - fn cache(&self) -> &'o ProvisionalEvaluationCache<'tcx> { - self.previous.cache - } - - fn iter(&'o self) -> TraitObligationStackList<'o, 'tcx> { - self.list() - } - - /// Indicates that attempting to evaluate this stack entry - /// required accessing something from the stack at depth `reached_depth`. - fn update_reached_depth(&self, reached_depth: usize) { - assert!( - self.depth > reached_depth, - "invoked `update_reached_depth` with something under this stack: \ - self.depth={} reached_depth={}", - self.depth, - reached_depth, - ); - debug!("update_reached_depth(reached_depth={})", reached_depth); - let mut p = self; - while reached_depth < p.depth { - debug!("update_reached_depth: marking {:?} as cycle participant", p.fresh_trait_ref); - p.reached_depth.set(p.reached_depth.get().min(reached_depth)); - p = p.previous.head.unwrap(); - } - } -} - -/// The "provisional evaluation cache" is used to store intermediate cache results -/// when solving auto traits. Auto traits are unusual in that they can support -/// cycles. So, for example, a "proof tree" like this would be ok: -/// -/// - `Foo<T>: Send` :- -/// - `Bar<T>: Send` :- -/// - `Foo<T>: Send` -- cycle, but ok -/// - `Baz<T>: Send` -/// -/// Here, to prove `Foo<T>: Send`, we have to prove `Bar<T>: Send` and -/// `Baz<T>: Send`. Proving `Bar<T>: Send` in turn required `Foo<T>: Send`. -/// For non-auto traits, this cycle would be an error, but for auto traits (because -/// they are coinductive) it is considered ok. -/// -/// However, there is a complication: at the point where we have -/// "proven" `Bar<T>: Send`, we have in fact only proven it -/// *provisionally*. In particular, we proved that `Bar<T>: Send` -/// *under the assumption* that `Foo<T>: Send`. But what if we later -/// find out this assumption is wrong? Specifically, we could -/// encounter some kind of error proving `Baz<T>: Send`. In that case, -/// `Bar<T>: Send` didn't turn out to be true. -/// -/// In Issue #60010, we found a bug in rustc where it would cache -/// these intermediate results. This was fixed in #60444 by disabling -/// *all* caching for things involved in a cycle -- in our example, -/// that would mean we don't cache that `Bar<T>: Send`. But this led -/// to large slowdowns. -/// -/// Specifically, imagine this scenario, where proving `Baz<T>: Send` -/// first requires proving `Bar<T>: Send` (which is true: -/// -/// - `Foo<T>: Send` :- -/// - `Bar<T>: Send` :- -/// - `Foo<T>: Send` -- cycle, but ok -/// - `Baz<T>: Send` -/// - `Bar<T>: Send` -- would be nice for this to be a cache hit! -/// - `*const T: Send` -- but what if we later encounter an error? -/// -/// The *provisional evaluation cache* resolves this issue. It stores -/// cache results that we've proven but which were involved in a cycle -/// in some way. We track the minimal stack depth (i.e., the -/// farthest from the top of the stack) that we are dependent on. -/// The idea is that the cache results within are all valid -- so long as -/// none of the nodes in between the current node and the node at that minimum -/// depth result in an error (in which case the cached results are just thrown away). -/// -/// During evaluation, we consult this provisional cache and rely on -/// it. Accessing a cached value is considered equivalent to accessing -/// a result at `reached_depth`, so it marks the *current* solution as -/// provisional as well. If an error is encountered, we toss out any -/// provisional results added from the subtree that encountered the -/// error. When we pop the node at `reached_depth` from the stack, we -/// can commit all the things that remain in the provisional cache. -struct ProvisionalEvaluationCache<'tcx> { - /// next "depth first number" to issue -- just a counter - dfn: Cell<usize>, - - /// Stores the "coldest" depth (bottom of stack) reached by any of - /// the evaluation entries. The idea here is that all things in the provisional - /// cache are always dependent on *something* that is colder in the stack: - /// therefore, if we add a new entry that is dependent on something *colder still*, - /// we have to modify the depth for all entries at once. - /// - /// Example: - /// - /// Imagine we have a stack `A B C D E` (with `E` being the top of - /// the stack). We cache something with depth 2, which means that - /// it was dependent on C. Then we pop E but go on and process a - /// new node F: A B C D F. Now F adds something to the cache with - /// depth 1, meaning it is dependent on B. Our original cache - /// entry is also dependent on B, because there is a path from E - /// to C and then from C to F and from F to B. - reached_depth: Cell<usize>, - - /// Map from cache key to the provisionally evaluated thing. - /// The cache entries contain the result but also the DFN in which they - /// were added. The DFN is used to clear out values on failure. - /// - /// Imagine we have a stack like: - /// - /// - `A B C` and we add a cache for the result of C (DFN 2) - /// - Then we have a stack `A B D` where `D` has DFN 3 - /// - We try to solve D by evaluating E: `A B D E` (DFN 4) - /// - `E` generates various cache entries which have cyclic dependices on `B` - /// - `A B D E F` and so forth - /// - the DFN of `F` for example would be 5 - /// - then we determine that `E` is in error -- we will then clear - /// all cache values whose DFN is >= 4 -- in this case, that - /// means the cached value for `F`. - map: RefCell<FxHashMap<ty::PolyTraitRef<'tcx>, ProvisionalEvaluation>>, -} - -/// A cache value for the provisional cache: contains the depth-first -/// number (DFN) and result. -#[derive(Copy, Clone, Debug)] -struct ProvisionalEvaluation { - from_dfn: usize, - result: EvaluationResult, -} - -impl<'tcx> Default for ProvisionalEvaluationCache<'tcx> { - fn default() -> Self { - Self { - dfn: Cell::new(0), - reached_depth: Cell::new(std::usize::MAX), - map: Default::default(), - } - } -} - -impl<'tcx> ProvisionalEvaluationCache<'tcx> { - /// Get the next DFN in sequence (basically a counter). - fn next_dfn(&self) -> usize { - let result = self.dfn.get(); - self.dfn.set(result + 1); - result - } - - /// Check the provisional cache for any result for - /// `fresh_trait_ref`. If there is a hit, then you must consider - /// it an access to the stack slots at depth - /// `self.current_reached_depth()` and above. - fn get_provisional(&self, fresh_trait_ref: ty::PolyTraitRef<'tcx>) -> Option<EvaluationResult> { - debug!( - "get_provisional(fresh_trait_ref={:?}) = {:#?} with reached-depth {}", - fresh_trait_ref, - self.map.borrow().get(&fresh_trait_ref), - self.reached_depth.get(), - ); - Some(self.map.borrow().get(&fresh_trait_ref)?.result) - } - - /// Current value of the `reached_depth` counter -- all the - /// provisional cache entries are dependent on the item at this - /// depth. - fn current_reached_depth(&self) -> usize { - self.reached_depth.get() - } - - /// Insert a provisional result into the cache. The result came - /// from the node with the given DFN. It accessed a minimum depth - /// of `reached_depth` to compute. It evaluated `fresh_trait_ref` - /// and resulted in `result`. - fn insert_provisional( - &self, - from_dfn: usize, - reached_depth: usize, - fresh_trait_ref: ty::PolyTraitRef<'tcx>, - result: EvaluationResult, - ) { - debug!( - "insert_provisional(from_dfn={}, reached_depth={}, fresh_trait_ref={:?}, result={:?})", - from_dfn, reached_depth, fresh_trait_ref, result, - ); - let r_d = self.reached_depth.get(); - self.reached_depth.set(r_d.min(reached_depth)); - - debug!("insert_provisional: reached_depth={:?}", self.reached_depth.get()); - - self.map.borrow_mut().insert(fresh_trait_ref, ProvisionalEvaluation { from_dfn, result }); - } - - /// Invoked when the node with dfn `dfn` does not get a successful - /// result. This will clear out any provisional cache entries - /// that were added since `dfn` was created. This is because the - /// provisional entries are things which must assume that the - /// things on the stack at the time of their creation succeeded -- - /// since the failing node is presently at the top of the stack, - /// these provisional entries must either depend on it or some - /// ancestor of it. - fn on_failure(&self, dfn: usize) { - debug!("on_failure(dfn={:?})", dfn,); - self.map.borrow_mut().retain(|key, eval| { - if !eval.from_dfn >= dfn { - debug!("on_failure: removing {:?}", key); - false - } else { - true - } - }); - } - - /// Invoked when the node at depth `depth` completed without - /// depending on anything higher in the stack (if that completion - /// was a failure, then `on_failure` should have been invoked - /// already). The callback `op` will be invoked for each - /// provisional entry that we can now confirm. - fn on_completion( - &self, - depth: usize, - mut op: impl FnMut(ty::PolyTraitRef<'tcx>, EvaluationResult), - ) { - debug!("on_completion(depth={}, reached_depth={})", depth, self.reached_depth.get(),); - - if self.reached_depth.get() < depth { - debug!("on_completion: did not yet reach depth to complete"); - return; - } - - for (fresh_trait_ref, eval) in self.map.borrow_mut().drain() { - debug!("on_completion: fresh_trait_ref={:?} eval={:?}", fresh_trait_ref, eval,); - - op(fresh_trait_ref, eval.result); - } - - self.reached_depth.set(std::usize::MAX); - } -} - -#[derive(Copy, Clone)] -struct TraitObligationStackList<'o, 'tcx> { - cache: &'o ProvisionalEvaluationCache<'tcx>, - head: Option<&'o TraitObligationStack<'o, 'tcx>>, -} - -impl<'o, 'tcx> TraitObligationStackList<'o, 'tcx> { - fn empty(cache: &'o ProvisionalEvaluationCache<'tcx>) -> TraitObligationStackList<'o, 'tcx> { - TraitObligationStackList { cache, head: None } - } - - fn with(r: &'o TraitObligationStack<'o, 'tcx>) -> TraitObligationStackList<'o, 'tcx> { - TraitObligationStackList { cache: r.cache(), head: Some(r) } - } - - fn head(&self) -> Option<&'o TraitObligationStack<'o, 'tcx>> { - self.head - } - - fn depth(&self) -> usize { - if let Some(head) = self.head { head.depth } else { 0 } - } -} - -impl<'o, 'tcx> Iterator for TraitObligationStackList<'o, 'tcx> { - type Item = &'o TraitObligationStack<'o, 'tcx>; - - fn next(&mut self) -> Option<&'o TraitObligationStack<'o, 'tcx>> { - match self.head { - Some(o) => { - *self = o.previous; - Some(o) - } - None => None, - } - } -} - -impl<'o, 'tcx> fmt::Debug for TraitObligationStack<'o, 'tcx> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "TraitObligationStack({:?})", self.obligation) - } -} diff --git a/src/librustc_infer/traits/specialize/mod.rs b/src/librustc_infer/traits/specialize/mod.rs deleted file mode 100644 index ee1c737c208..00000000000 --- a/src/librustc_infer/traits/specialize/mod.rs +++ /dev/null @@ -1,472 +0,0 @@ -//! Logic and data structures related to impl specialization, explained in -//! greater detail below. -//! -//! At the moment, this implementation support only the simple "chain" rule: -//! If any two impls overlap, one must be a strict subset of the other. -//! -//! See the [rustc guide] for a bit more detail on how specialization -//! fits together with the rest of the trait machinery. -//! -//! [rustc guide]: https://rust-lang.github.io/rustc-guide/traits/specialization.html - -pub mod specialization_graph; -use specialization_graph::GraphExt; - -use crate::infer::{InferCtxt, InferOk, TyCtxtInferExt}; -use crate::traits::select::IntercrateAmbiguityCause; -use crate::traits::{self, coherence, FutureCompatOverlapErrorKind, ObligationCause, TraitEngine}; -use rustc::lint::LintDiagnosticBuilder; -use rustc::ty::subst::{InternalSubsts, Subst, SubstsRef}; -use rustc::ty::{self, TyCtxt, TypeFoldable}; -use rustc_data_structures::fx::FxHashSet; -use rustc_errors::struct_span_err; -use rustc_hir::def_id::DefId; -use rustc_session::lint::builtin::COHERENCE_LEAK_CHECK; -use rustc_session::lint::builtin::ORDER_DEPENDENT_TRAIT_OBJECTS; -use rustc_span::DUMMY_SP; - -use super::util::impl_trait_ref_and_oblig; -use super::{FulfillmentContext, SelectionContext}; - -/// Information pertinent to an overlapping impl error. -#[derive(Debug)] -pub struct OverlapError { - pub with_impl: DefId, - pub trait_desc: String, - pub self_desc: Option<String>, - pub intercrate_ambiguity_causes: Vec<IntercrateAmbiguityCause>, - pub involves_placeholder: bool, -} - -/// Given a subst for the requested impl, translate it to a subst -/// appropriate for the actual item definition (whether it be in that impl, -/// a parent impl, or the trait). -/// -/// When we have selected one impl, but are actually using item definitions from -/// a parent impl providing a default, we need a way to translate between the -/// type parameters of the two impls. Here the `source_impl` is the one we've -/// selected, and `source_substs` is a substitution of its generics. -/// And `target_node` is the impl/trait we're actually going to get the -/// definition from. The resulting substitution will map from `target_node`'s -/// generics to `source_impl`'s generics as instantiated by `source_subst`. -/// -/// For example, consider the following scenario: -/// -/// ```rust -/// trait Foo { ... } -/// impl<T, U> Foo for (T, U) { ... } // target impl -/// impl<V> Foo for (V, V) { ... } // source impl -/// ``` -/// -/// Suppose we have selected "source impl" with `V` instantiated with `u32`. -/// This function will produce a substitution with `T` and `U` both mapping to `u32`. -/// -/// where-clauses add some trickiness here, because they can be used to "define" -/// an argument indirectly: -/// -/// ```rust -/// impl<'a, I, T: 'a> Iterator for Cloned<I> -/// where I: Iterator<Item = &'a T>, T: Clone -/// ``` -/// -/// In a case like this, the substitution for `T` is determined indirectly, -/// through associated type projection. We deal with such cases by using -/// *fulfillment* to relate the two impls, requiring that all projections are -/// resolved. -pub fn translate_substs<'a, 'tcx>( - infcx: &InferCtxt<'a, 'tcx>, - param_env: ty::ParamEnv<'tcx>, - source_impl: DefId, - source_substs: SubstsRef<'tcx>, - target_node: specialization_graph::Node, -) -> SubstsRef<'tcx> { - debug!( - "translate_substs({:?}, {:?}, {:?}, {:?})", - param_env, source_impl, source_substs, target_node - ); - let source_trait_ref = - infcx.tcx.impl_trait_ref(source_impl).unwrap().subst(infcx.tcx, &source_substs); - - // translate the Self and Param parts of the substitution, since those - // vary across impls - let target_substs = match target_node { - specialization_graph::Node::Impl(target_impl) => { - // no need to translate if we're targeting the impl we started with - if source_impl == target_impl { - return source_substs; - } - - fulfill_implication(infcx, param_env, source_trait_ref, target_impl).unwrap_or_else( - |_| { - bug!( - "When translating substitutions for specialization, the expected \ - specialization failed to hold" - ) - }, - ) - } - specialization_graph::Node::Trait(..) => source_trait_ref.substs, - }; - - // directly inherent the method generics, since those do not vary across impls - source_substs.rebase_onto(infcx.tcx, source_impl, target_substs) -} - -/// Given a selected impl described by `impl_data`, returns the -/// definition and substitutions for the method with the name `name` -/// the kind `kind`, and trait method substitutions `substs`, in -/// that impl, a less specialized impl, or the trait default, -/// whichever applies. -pub fn find_associated_item<'tcx>( - tcx: TyCtxt<'tcx>, - param_env: ty::ParamEnv<'tcx>, - item: &ty::AssocItem, - substs: SubstsRef<'tcx>, - impl_data: &super::VtableImplData<'tcx, ()>, -) -> (DefId, SubstsRef<'tcx>) { - debug!("find_associated_item({:?}, {:?}, {:?}, {:?})", param_env, item, substs, impl_data); - assert!(!substs.needs_infer()); - - let trait_def_id = tcx.trait_id_of_impl(impl_data.impl_def_id).unwrap(); - let trait_def = tcx.trait_def(trait_def_id); - - let ancestors = trait_def.ancestors(tcx, impl_data.impl_def_id); - match ancestors.leaf_def(tcx, item.ident, item.kind) { - Some(node_item) => { - let substs = tcx.infer_ctxt().enter(|infcx| { - let param_env = param_env.with_reveal_all(); - let substs = substs.rebase_onto(tcx, trait_def_id, impl_data.substs); - let substs = translate_substs( - &infcx, - param_env, - impl_data.impl_def_id, - substs, - node_item.node, - ); - infcx.tcx.erase_regions(&substs) - }); - (node_item.item.def_id, substs) - } - None => bug!("{:?} not found in {:?}", item, impl_data.impl_def_id), - } -} - -/// Is `impl1` a specialization of `impl2`? -/// -/// Specialization is determined by the sets of types to which the impls apply; -/// `impl1` specializes `impl2` if it applies to a subset of the types `impl2` applies -/// to. -pub(super) fn specializes(tcx: TyCtxt<'_>, (impl1_def_id, impl2_def_id): (DefId, DefId)) -> bool { - debug!("specializes({:?}, {:?})", impl1_def_id, impl2_def_id); - - // The feature gate should prevent introducing new specializations, but not - // taking advantage of upstream ones. - if !tcx.features().specialization && (impl1_def_id.is_local() || impl2_def_id.is_local()) { - return false; - } - - // We determine whether there's a subset relationship by: - // - // - skolemizing impl1, - // - assuming the where clauses for impl1, - // - instantiating impl2 with fresh inference variables, - // - unifying, - // - attempting to prove the where clauses for impl2 - // - // The last three steps are encapsulated in `fulfill_implication`. - // - // See RFC 1210 for more details and justification. - - // Currently we do not allow e.g., a negative impl to specialize a positive one - if tcx.impl_polarity(impl1_def_id) != tcx.impl_polarity(impl2_def_id) { - return false; - } - - // create a parameter environment corresponding to a (placeholder) instantiation of impl1 - let penv = tcx.param_env(impl1_def_id); - let impl1_trait_ref = tcx.impl_trait_ref(impl1_def_id).unwrap(); - - // Create a infcx, taking the predicates of impl1 as assumptions: - tcx.infer_ctxt().enter(|infcx| { - // Normalize the trait reference. The WF rules ought to ensure - // that this always succeeds. - let impl1_trait_ref = match traits::fully_normalize( - &infcx, - FulfillmentContext::new(), - ObligationCause::dummy(), - penv, - &impl1_trait_ref, - ) { - Ok(impl1_trait_ref) => impl1_trait_ref, - Err(err) => { - bug!("failed to fully normalize {:?}: {:?}", impl1_trait_ref, err); - } - }; - - // Attempt to prove that impl2 applies, given all of the above. - fulfill_implication(&infcx, penv, impl1_trait_ref, impl2_def_id).is_ok() - }) -} - -/// Attempt to fulfill all obligations of `target_impl` after unification with -/// `source_trait_ref`. If successful, returns a substitution for *all* the -/// generics of `target_impl`, including both those needed to unify with -/// `source_trait_ref` and those whose identity is determined via a where -/// clause in the impl. -fn fulfill_implication<'a, 'tcx>( - infcx: &InferCtxt<'a, 'tcx>, - param_env: ty::ParamEnv<'tcx>, - source_trait_ref: ty::TraitRef<'tcx>, - target_impl: DefId, -) -> Result<SubstsRef<'tcx>, ()> { - debug!( - "fulfill_implication({:?}, trait_ref={:?} |- {:?} applies)", - param_env, source_trait_ref, target_impl - ); - - let selcx = &mut SelectionContext::new(&infcx); - let target_substs = infcx.fresh_substs_for_item(DUMMY_SP, target_impl); - let (target_trait_ref, mut obligations) = - impl_trait_ref_and_oblig(selcx, param_env, target_impl, target_substs); - debug!( - "fulfill_implication: target_trait_ref={:?}, obligations={:?}", - target_trait_ref, obligations - ); - - // do the impls unify? If not, no specialization. - match infcx.at(&ObligationCause::dummy(), param_env).eq(source_trait_ref, target_trait_ref) { - Ok(InferOk { obligations: o, .. }) => { - obligations.extend(o); - } - Err(_) => { - debug!( - "fulfill_implication: {:?} does not unify with {:?}", - source_trait_ref, target_trait_ref - ); - return Err(()); - } - } - - // attempt to prove all of the predicates for impl2 given those for impl1 - // (which are packed up in penv) - - infcx.save_and_restore_in_snapshot_flag(|infcx| { - // If we came from `translate_substs`, we already know that the - // predicates for our impl hold (after all, we know that a more - // specialized impl holds, so our impl must hold too), and - // we only want to process the projections to determine the - // the types in our substs using RFC 447, so we can safely - // ignore region obligations, which allows us to avoid threading - // a node-id to assign them with. - // - // If we came from specialization graph construction, then - // we already make a mockery out of the region system, so - // why not ignore them a bit earlier? - let mut fulfill_cx = FulfillmentContext::new_ignoring_regions(); - for oblig in obligations.into_iter() { - fulfill_cx.register_predicate_obligation(&infcx, oblig); - } - match fulfill_cx.select_all_or_error(infcx) { - Err(errors) => { - // no dice! - debug!( - "fulfill_implication: for impls on {:?} and {:?}, \ - could not fulfill: {:?} given {:?}", - source_trait_ref, target_trait_ref, errors, param_env.caller_bounds - ); - Err(()) - } - - Ok(()) => { - debug!( - "fulfill_implication: an impl for {:?} specializes {:?}", - source_trait_ref, target_trait_ref - ); - - // Now resolve the *substitution* we built for the target earlier, replacing - // the inference variables inside with whatever we got from fulfillment. - Ok(infcx.resolve_vars_if_possible(&target_substs)) - } - } - }) -} - -// Query provider for `specialization_graph_of`. -pub(super) fn specialization_graph_provider( - tcx: TyCtxt<'_>, - trait_id: DefId, -) -> &specialization_graph::Graph { - let mut sg = specialization_graph::Graph::new(); - - let mut trait_impls = tcx.all_impls(trait_id); - - // The coherence checking implementation seems to rely on impls being - // iterated over (roughly) in definition order, so we are sorting by - // negated `CrateNum` (so remote definitions are visited first) and then - // by a flattened version of the `DefIndex`. - trait_impls - .sort_unstable_by_key(|def_id| (-(def_id.krate.as_u32() as i64), def_id.index.index())); - - for impl_def_id in trait_impls { - if impl_def_id.is_local() { - // This is where impl overlap checking happens: - let insert_result = sg.insert(tcx, impl_def_id); - // Report error if there was one. - let (overlap, used_to_be_allowed) = match insert_result { - Err(overlap) => (Some(overlap), None), - Ok(Some(overlap)) => (Some(overlap.error), Some(overlap.kind)), - Ok(None) => (None, None), - }; - - if let Some(overlap) = overlap { - let impl_span = - tcx.sess.source_map().def_span(tcx.span_of_impl(impl_def_id).unwrap()); - - // Work to be done after we've built the DiagnosticBuilder. We have to define it - // now because the struct_lint methods don't return back the DiagnosticBuilder - // that's passed in. - let decorate = |err: LintDiagnosticBuilder<'_>| { - let msg = format!( - "conflicting implementations of trait `{}`{}:{}", - overlap.trait_desc, - overlap - .self_desc - .clone() - .map_or(String::new(), |ty| { format!(" for type `{}`", ty) }), - match used_to_be_allowed { - Some(FutureCompatOverlapErrorKind::Issue33140) => " (E0119)", - _ => "", - } - ); - let mut err = err.build(&msg); - match tcx.span_of_impl(overlap.with_impl) { - Ok(span) => { - err.span_label( - tcx.sess.source_map().def_span(span), - "first implementation here".to_string(), - ); - - err.span_label( - impl_span, - format!( - "conflicting implementation{}", - overlap - .self_desc - .map_or(String::new(), |ty| format!(" for `{}`", ty)) - ), - ); - } - Err(cname) => { - let msg = match to_pretty_impl_header(tcx, overlap.with_impl) { - Some(s) => format!( - "conflicting implementation in crate `{}`:\n- {}", - cname, s - ), - None => format!("conflicting implementation in crate `{}`", cname), - }; - err.note(&msg); - } - } - - for cause in &overlap.intercrate_ambiguity_causes { - cause.add_intercrate_ambiguity_hint(&mut err); - } - - if overlap.involves_placeholder { - coherence::add_placeholder_note(&mut err); - } - err.emit() - }; - - match used_to_be_allowed { - None => { - let err = struct_span_err!(tcx.sess, impl_span, E0119, ""); - decorate(LintDiagnosticBuilder::new(err)); - } - Some(kind) => { - let lint = match kind { - FutureCompatOverlapErrorKind::Issue33140 => { - ORDER_DEPENDENT_TRAIT_OBJECTS - } - FutureCompatOverlapErrorKind::LeakCheck => COHERENCE_LEAK_CHECK, - }; - tcx.struct_span_lint_hir( - lint, - tcx.hir().as_local_hir_id(impl_def_id).unwrap(), - impl_span, - decorate, - ) - } - }; - } - } else { - let parent = tcx.impl_parent(impl_def_id).unwrap_or(trait_id); - sg.record_impl_from_cstore(tcx, parent, impl_def_id) - } - } - - tcx.arena.alloc(sg) -} - -/// Recovers the "impl X for Y" signature from `impl_def_id` and returns it as a -/// string. -fn to_pretty_impl_header(tcx: TyCtxt<'_>, impl_def_id: DefId) -> Option<String> { - use std::fmt::Write; - - let trait_ref = if let Some(tr) = tcx.impl_trait_ref(impl_def_id) { - tr - } else { - return None; - }; - - let mut w = "impl".to_owned(); - - let substs = InternalSubsts::identity_for_item(tcx, impl_def_id); - - // FIXME: Currently only handles ?Sized. - // Needs to support ?Move and ?DynSized when they are implemented. - let mut types_without_default_bounds = FxHashSet::default(); - let sized_trait = tcx.lang_items().sized_trait(); - - if !substs.is_noop() { - types_without_default_bounds.extend(substs.types()); - w.push('<'); - w.push_str( - &substs - .iter() - .map(|k| k.to_string()) - .filter(|k| k != "'_") - .collect::<Vec<_>>() - .join(", "), - ); - w.push('>'); - } - - write!(w, " {} for {}", trait_ref.print_only_trait_path(), tcx.type_of(impl_def_id)).unwrap(); - - // The predicates will contain default bounds like `T: Sized`. We need to - // remove these bounds, and add `T: ?Sized` to any untouched type parameters. - let predicates = tcx.predicates_of(impl_def_id).predicates; - let mut pretty_predicates = - Vec::with_capacity(predicates.len() + types_without_default_bounds.len()); - - for (p, _) in predicates { - if let Some(poly_trait_ref) = p.to_opt_poly_trait_ref() { - if Some(poly_trait_ref.def_id()) == sized_trait { - types_without_default_bounds.remove(poly_trait_ref.self_ty()); - continue; - } - } - pretty_predicates.push(p.to_string()); - } - - pretty_predicates - .extend(types_without_default_bounds.iter().map(|ty| format!("{}: ?Sized", ty))); - - if !pretty_predicates.is_empty() { - write!(w, "\n where {}", pretty_predicates.join(", ")).unwrap(); - } - - w.push(';'); - Some(w) -} diff --git a/src/librustc_infer/traits/specialize/specialization_graph.rs b/src/librustc_infer/traits/specialize/specialization_graph.rs deleted file mode 100644 index 17d4a22b9dd..00000000000 --- a/src/librustc_infer/traits/specialize/specialization_graph.rs +++ /dev/null @@ -1,379 +0,0 @@ -use super::OverlapError; - -use crate::traits; -use rustc::ty::fast_reject::{self, SimplifiedType}; -use rustc::ty::{self, TyCtxt, TypeFoldable}; -use rustc_hir::def_id::DefId; - -pub use rustc::traits::specialization_graph::*; - -#[derive(Copy, Clone, Debug)] -pub enum FutureCompatOverlapErrorKind { - Issue33140, - LeakCheck, -} - -#[derive(Debug)] -pub struct FutureCompatOverlapError { - pub error: OverlapError, - pub kind: FutureCompatOverlapErrorKind, -} - -/// The result of attempting to insert an impl into a group of children. -enum Inserted { - /// The impl was inserted as a new child in this group of children. - BecameNewSibling(Option<FutureCompatOverlapError>), - - /// The impl should replace existing impls [X1, ..], because the impl specializes X1, X2, etc. - ReplaceChildren(Vec<DefId>), - - /// The impl is a specialization of an existing child. - ShouldRecurseOn(DefId), -} - -trait ChildrenExt { - fn insert_blindly(&mut self, tcx: TyCtxt<'tcx>, impl_def_id: DefId); - fn remove_existing(&mut self, tcx: TyCtxt<'tcx>, impl_def_id: DefId); - - fn insert( - &mut self, - tcx: TyCtxt<'tcx>, - impl_def_id: DefId, - simplified_self: Option<SimplifiedType>, - ) -> Result<Inserted, OverlapError>; -} - -impl ChildrenExt for Children { - /// Insert an impl into this set of children without comparing to any existing impls. - fn insert_blindly(&mut self, tcx: TyCtxt<'tcx>, impl_def_id: DefId) { - let trait_ref = tcx.impl_trait_ref(impl_def_id).unwrap(); - if let Some(st) = fast_reject::simplify_type(tcx, trait_ref.self_ty(), false) { - debug!("insert_blindly: impl_def_id={:?} st={:?}", impl_def_id, st); - self.nonblanket_impls.entry(st).or_default().push(impl_def_id) - } else { - debug!("insert_blindly: impl_def_id={:?} st=None", impl_def_id); - self.blanket_impls.push(impl_def_id) - } - } - - /// Removes an impl from this set of children. Used when replacing - /// an impl with a parent. The impl must be present in the list of - /// children already. - fn remove_existing(&mut self, tcx: TyCtxt<'tcx>, impl_def_id: DefId) { - let trait_ref = tcx.impl_trait_ref(impl_def_id).unwrap(); - let vec: &mut Vec<DefId>; - if let Some(st) = fast_reject::simplify_type(tcx, trait_ref.self_ty(), false) { - debug!("remove_existing: impl_def_id={:?} st={:?}", impl_def_id, st); - vec = self.nonblanket_impls.get_mut(&st).unwrap(); - } else { - debug!("remove_existing: impl_def_id={:?} st=None", impl_def_id); - vec = &mut self.blanket_impls; - } - - let index = vec.iter().position(|d| *d == impl_def_id).unwrap(); - vec.remove(index); - } - - /// Attempt to insert an impl into this set of children, while comparing for - /// specialization relationships. - fn insert( - &mut self, - tcx: TyCtxt<'tcx>, - impl_def_id: DefId, - simplified_self: Option<SimplifiedType>, - ) -> Result<Inserted, OverlapError> { - let mut last_lint = None; - let mut replace_children = Vec::new(); - - debug!("insert(impl_def_id={:?}, simplified_self={:?})", impl_def_id, simplified_self,); - - let possible_siblings = match simplified_self { - Some(st) => PotentialSiblings::Filtered(filtered_children(self, st)), - None => PotentialSiblings::Unfiltered(iter_children(self)), - }; - - for possible_sibling in possible_siblings { - debug!( - "insert: impl_def_id={:?}, simplified_self={:?}, possible_sibling={:?}", - impl_def_id, simplified_self, possible_sibling, - ); - - let create_overlap_error = |overlap: traits::coherence::OverlapResult<'_>| { - let trait_ref = overlap.impl_header.trait_ref.unwrap(); - let self_ty = trait_ref.self_ty(); - - OverlapError { - with_impl: possible_sibling, - trait_desc: trait_ref.print_only_trait_path().to_string(), - // Only report the `Self` type if it has at least - // some outer concrete shell; otherwise, it's - // not adding much information. - self_desc: if self_ty.has_concrete_skeleton() { - Some(self_ty.to_string()) - } else { - None - }, - intercrate_ambiguity_causes: overlap.intercrate_ambiguity_causes, - involves_placeholder: overlap.involves_placeholder, - } - }; - - let report_overlap_error = |overlap: traits::coherence::OverlapResult<'_>, - last_lint: &mut _| { - // Found overlap, but no specialization; error out or report future-compat warning. - - // Do we *still* get overlap if we disable the future-incompatible modes? - let should_err = traits::overlapping_impls( - tcx, - possible_sibling, - impl_def_id, - traits::SkipLeakCheck::default(), - |_| true, - || false, - ); - - let error = create_overlap_error(overlap); - - if should_err { - Err(error) - } else { - *last_lint = Some(FutureCompatOverlapError { - error, - kind: FutureCompatOverlapErrorKind::LeakCheck, - }); - - Ok((false, false)) - } - }; - - let last_lint_mut = &mut last_lint; - let (le, ge) = traits::overlapping_impls( - tcx, - possible_sibling, - impl_def_id, - traits::SkipLeakCheck::Yes, - |overlap| { - if let Some(overlap_kind) = - tcx.impls_are_allowed_to_overlap(impl_def_id, possible_sibling) - { - match overlap_kind { - ty::ImplOverlapKind::Permitted { marker: _ } => {} - ty::ImplOverlapKind::Issue33140 => { - *last_lint_mut = Some(FutureCompatOverlapError { - error: create_overlap_error(overlap), - kind: FutureCompatOverlapErrorKind::Issue33140, - }); - } - } - - return Ok((false, false)); - } - - let le = tcx.specializes((impl_def_id, possible_sibling)); - let ge = tcx.specializes((possible_sibling, impl_def_id)); - - if le == ge { - report_overlap_error(overlap, last_lint_mut) - } else { - Ok((le, ge)) - } - }, - || Ok((false, false)), - )?; - - if le && !ge { - debug!( - "descending as child of TraitRef {:?}", - tcx.impl_trait_ref(possible_sibling).unwrap() - ); - - // The impl specializes `possible_sibling`. - return Ok(Inserted::ShouldRecurseOn(possible_sibling)); - } else if ge && !le { - debug!( - "placing as parent of TraitRef {:?}", - tcx.impl_trait_ref(possible_sibling).unwrap() - ); - - replace_children.push(possible_sibling); - } else { - // Either there's no overlap, or the overlap was already reported by - // `overlap_error`. - } - } - - if !replace_children.is_empty() { - return Ok(Inserted::ReplaceChildren(replace_children)); - } - - // No overlap with any potential siblings, so add as a new sibling. - debug!("placing as new sibling"); - self.insert_blindly(tcx, impl_def_id); - Ok(Inserted::BecameNewSibling(last_lint)) - } -} - -fn iter_children(children: &mut Children) -> impl Iterator<Item = DefId> + '_ { - let nonblanket = children.nonblanket_impls.iter_mut().flat_map(|(_, v)| v.iter()); - children.blanket_impls.iter().chain(nonblanket).cloned() -} - -fn filtered_children( - children: &mut Children, - st: SimplifiedType, -) -> impl Iterator<Item = DefId> + '_ { - let nonblanket = children.nonblanket_impls.entry(st).or_default().iter(); - children.blanket_impls.iter().chain(nonblanket).cloned() -} - -// A custom iterator used by Children::insert -enum PotentialSiblings<I, J> -where - I: Iterator<Item = DefId>, - J: Iterator<Item = DefId>, -{ - Unfiltered(I), - Filtered(J), -} - -impl<I, J> Iterator for PotentialSiblings<I, J> -where - I: Iterator<Item = DefId>, - J: Iterator<Item = DefId>, -{ - type Item = DefId; - - fn next(&mut self) -> Option<Self::Item> { - match *self { - PotentialSiblings::Unfiltered(ref mut iter) => iter.next(), - PotentialSiblings::Filtered(ref mut iter) => iter.next(), - } - } -} - -pub trait GraphExt { - /// Insert a local impl into the specialization graph. If an existing impl - /// conflicts with it (has overlap, but neither specializes the other), - /// information about the area of overlap is returned in the `Err`. - fn insert( - &mut self, - tcx: TyCtxt<'tcx>, - impl_def_id: DefId, - ) -> Result<Option<FutureCompatOverlapError>, OverlapError>; - - /// Insert cached metadata mapping from a child impl back to its parent. - fn record_impl_from_cstore(&mut self, tcx: TyCtxt<'tcx>, parent: DefId, child: DefId); -} - -impl GraphExt for Graph { - /// Insert a local impl into the specialization graph. If an existing impl - /// conflicts with it (has overlap, but neither specializes the other), - /// information about the area of overlap is returned in the `Err`. - fn insert( - &mut self, - tcx: TyCtxt<'tcx>, - impl_def_id: DefId, - ) -> Result<Option<FutureCompatOverlapError>, OverlapError> { - assert!(impl_def_id.is_local()); - - let trait_ref = tcx.impl_trait_ref(impl_def_id).unwrap(); - let trait_def_id = trait_ref.def_id; - - debug!( - "insert({:?}): inserting TraitRef {:?} into specialization graph", - impl_def_id, trait_ref - ); - - // If the reference itself contains an earlier error (e.g., due to a - // resolution failure), then we just insert the impl at the top level of - // the graph and claim that there's no overlap (in order to suppress - // bogus errors). - if trait_ref.references_error() { - debug!( - "insert: inserting dummy node for erroneous TraitRef {:?}, \ - impl_def_id={:?}, trait_def_id={:?}", - trait_ref, impl_def_id, trait_def_id - ); - - self.parent.insert(impl_def_id, trait_def_id); - self.children.entry(trait_def_id).or_default().insert_blindly(tcx, impl_def_id); - return Ok(None); - } - - let mut parent = trait_def_id; - let mut last_lint = None; - let simplified = fast_reject::simplify_type(tcx, trait_ref.self_ty(), false); - - // Descend the specialization tree, where `parent` is the current parent node. - loop { - use self::Inserted::*; - - let insert_result = - self.children.entry(parent).or_default().insert(tcx, impl_def_id, simplified)?; - - match insert_result { - BecameNewSibling(opt_lint) => { - last_lint = opt_lint; - break; - } - ReplaceChildren(grand_children_to_be) => { - // We currently have - // - // P - // | - // G - // - // and we are inserting the impl N. We want to make it: - // - // P - // | - // N - // | - // G - - // Adjust P's list of children: remove G and then add N. - { - let siblings = self.children.get_mut(&parent).unwrap(); - for &grand_child_to_be in &grand_children_to_be { - siblings.remove_existing(tcx, grand_child_to_be); - } - siblings.insert_blindly(tcx, impl_def_id); - } - - // Set G's parent to N and N's parent to P. - for &grand_child_to_be in &grand_children_to_be { - self.parent.insert(grand_child_to_be, impl_def_id); - } - self.parent.insert(impl_def_id, parent); - - // Add G as N's child. - for &grand_child_to_be in &grand_children_to_be { - self.children - .entry(impl_def_id) - .or_default() - .insert_blindly(tcx, grand_child_to_be); - } - break; - } - ShouldRecurseOn(new_parent) => { - parent = new_parent; - } - } - } - - self.parent.insert(impl_def_id, parent); - Ok(last_lint) - } - - /// Insert cached metadata mapping from a child impl back to its parent. - fn record_impl_from_cstore(&mut self, tcx: TyCtxt<'tcx>, parent: DefId, child: DefId) { - if self.parent.insert(child, parent).is_some() { - bug!( - "When recording an impl from the crate store, information about its parent \ - was already present." - ); - } - - self.children.entry(parent).or_default().insert_blindly(tcx, child); - } -} diff --git a/src/librustc_infer/traits/structural_impls.rs b/src/librustc_infer/traits/structural_impls.rs index 6630f664f96..595a8cd7683 100644 --- a/src/librustc_infer/traits/structural_impls.rs +++ b/src/librustc_infer/traits/structural_impls.rs @@ -1,7 +1,7 @@ use crate::traits; use crate::traits::project::Normalized; -use rustc::ty; -use rustc::ty::fold::{TypeFoldable, TypeFolder, TypeVisitor}; +use rustc_middle::ty; +use rustc_middle::ty::fold::{TypeFoldable, TypeFolder, TypeVisitor}; use std::fmt; diff --git a/src/librustc_infer/traits/structural_match.rs b/src/librustc_infer/traits/structural_match.rs deleted file mode 100644 index 60682f58129..00000000000 --- a/src/librustc_infer/traits/structural_match.rs +++ /dev/null @@ -1,216 +0,0 @@ -use crate::infer::{InferCtxt, TyCtxtInferExt}; -use crate::traits::ObligationCause; -use crate::traits::{self, ConstPatternStructural, TraitEngine}; - -use rustc::ty::{self, AdtDef, Ty, TyCtxt, TypeFoldable, TypeVisitor}; -use rustc_data_structures::fx::FxHashSet; -use rustc_hir as hir; -use rustc_span::Span; - -#[derive(Debug)] -pub enum NonStructuralMatchTy<'tcx> { - Adt(&'tcx AdtDef), - Param, -} - -/// This method traverses the structure of `ty`, trying to find an -/// instance of an ADT (i.e. struct or enum) that was declared without -/// the `#[structural_match]` attribute, or a generic type parameter -/// (which cannot be determined to be `structural_match`). -/// -/// The "structure of a type" includes all components that would be -/// considered when doing a pattern match on a constant of that -/// type. -/// -/// * This means this method descends into fields of structs/enums, -/// and also descends into the inner type `T` of `&T` and `&mut T` -/// -/// * The traversal doesn't dereference unsafe pointers (`*const T`, -/// `*mut T`), and it does not visit the type arguments of an -/// instantiated generic like `PhantomData<T>`. -/// -/// The reason we do this search is Rust currently require all ADTs -/// reachable from a constant's type to be annotated with -/// `#[structural_match]`, an attribute which essentially says that -/// the implementation of `PartialEq::eq` behaves *equivalently* to a -/// comparison against the unfolded structure. -/// -/// For more background on why Rust has this requirement, and issues -/// that arose when the requirement was not enforced completely, see -/// Rust RFC 1445, rust-lang/rust#61188, and rust-lang/rust#62307. -pub fn search_for_structural_match_violation<'tcx>( - id: hir::HirId, - span: Span, - tcx: TyCtxt<'tcx>, - ty: Ty<'tcx>, -) -> Option<NonStructuralMatchTy<'tcx>> { - // FIXME: we should instead pass in an `infcx` from the outside. - tcx.infer_ctxt().enter(|infcx| { - let mut search = Search { id, span, infcx, found: None, seen: FxHashSet::default() }; - ty.visit_with(&mut search); - search.found - }) -} - -/// This method returns true if and only if `adt_ty` itself has been marked as -/// eligible for structural-match: namely, if it implements both -/// `StructuralPartialEq` and `StructuralEq` (which are respectively injected by -/// `#[derive(PartialEq)]` and `#[derive(Eq)]`). -/// -/// Note that this does *not* recursively check if the substructure of `adt_ty` -/// implements the traits. -pub fn type_marked_structural( - id: hir::HirId, - span: Span, - infcx: &InferCtxt<'_, 'tcx>, - adt_ty: Ty<'tcx>, -) -> bool { - let mut fulfillment_cx = traits::FulfillmentContext::new(); - let cause = ObligationCause::new(span, id, ConstPatternStructural); - // require `#[derive(PartialEq)]` - let structural_peq_def_id = infcx.tcx.lang_items().structural_peq_trait().unwrap(); - fulfillment_cx.register_bound( - infcx, - ty::ParamEnv::empty(), - adt_ty, - structural_peq_def_id, - cause, - ); - // for now, require `#[derive(Eq)]`. (Doing so is a hack to work around - // the type `for<'a> fn(&'a ())` failing to implement `Eq` itself.) - let cause = ObligationCause::new(span, id, ConstPatternStructural); - let structural_teq_def_id = infcx.tcx.lang_items().structural_teq_trait().unwrap(); - fulfillment_cx.register_bound( - infcx, - ty::ParamEnv::empty(), - adt_ty, - structural_teq_def_id, - cause, - ); - - // We deliberately skip *reporting* fulfillment errors (via - // `report_fulfillment_errors`), for two reasons: - // - // 1. The error messages would mention `std::marker::StructuralPartialEq` - // (a trait which is solely meant as an implementation detail - // for now), and - // - // 2. We are sometimes doing future-incompatibility lints for - // now, so we do not want unconditional errors here. - fulfillment_cx.select_all_or_error(infcx).is_ok() -} - -/// This implements the traversal over the structure of a given type to try to -/// find instances of ADTs (specifically structs or enums) that do not implement -/// the structural-match traits (`StructuralPartialEq` and `StructuralEq`). -struct Search<'a, 'tcx> { - id: hir::HirId, - span: Span, - - infcx: InferCtxt<'a, 'tcx>, - - /// Records first ADT that does not implement a structural-match trait. - found: Option<NonStructuralMatchTy<'tcx>>, - - /// Tracks ADTs previously encountered during search, so that - /// we will not recur on them again. - seen: FxHashSet<hir::def_id::DefId>, -} - -impl Search<'a, 'tcx> { - fn tcx(&self) -> TyCtxt<'tcx> { - self.infcx.tcx - } - - fn type_marked_structural(&self, adt_ty: Ty<'tcx>) -> bool { - type_marked_structural(self.id, self.span, &self.infcx, adt_ty) - } -} - -impl<'a, 'tcx> TypeVisitor<'tcx> for Search<'a, 'tcx> { - fn visit_ty(&mut self, ty: Ty<'tcx>) -> bool { - debug!("Search visiting ty: {:?}", ty); - - let (adt_def, substs) = match ty.kind { - ty::Adt(adt_def, substs) => (adt_def, substs), - ty::Param(_) => { - self.found = Some(NonStructuralMatchTy::Param); - return true; // Stop visiting. - } - ty::RawPtr(..) => { - // structural-match ignores substructure of - // `*const _`/`*mut _`, so skip `super_visit_with`. - // - // For example, if you have: - // ``` - // struct NonStructural; - // #[derive(PartialEq, Eq)] - // struct T(*const NonStructural); - // const C: T = T(std::ptr::null()); - // ``` - // - // Even though `NonStructural` does not implement `PartialEq`, - // structural equality on `T` does not recur into the raw - // pointer. Therefore, one can still use `C` in a pattern. - - // (But still tell caller to continue search.) - return false; - } - ty::FnDef(..) | ty::FnPtr(..) => { - // types of formals and return in `fn(_) -> _` are also irrelevant; - // so we do not recur into them via `super_visit_with` - // - // (But still tell caller to continue search.) - return false; - } - ty::Array(_, n) - if { n.try_eval_usize(self.tcx(), ty::ParamEnv::reveal_all()) == Some(0) } => - { - // rust-lang/rust#62336: ignore type of contents - // for empty array. - return false; - } - _ => { - ty.super_visit_with(self); - return false; - } - }; - - if !self.seen.insert(adt_def.did) { - debug!("Search already seen adt_def: {:?}", adt_def); - // let caller continue its search - return false; - } - - if !self.type_marked_structural(ty) { - debug!("Search found ty: {:?}", ty); - self.found = Some(NonStructuralMatchTy::Adt(&adt_def)); - return true; // Halt visiting! - } - - // structural-match does not care about the - // instantiation of the generics in an ADT (it - // instead looks directly at its fields outside - // this match), so we skip super_visit_with. - // - // (Must not recur on substs for `PhantomData<T>` cf - // rust-lang/rust#55028 and rust-lang/rust#55837; but also - // want to skip substs when only uses of generic are - // behind unsafe pointers `*const T`/`*mut T`.) - - // even though we skip super_visit_with, we must recur on - // fields of ADT. - let tcx = self.tcx(); - for field_ty in adt_def.all_fields().map(|field| field.ty(tcx, substs)) { - if field_ty.visit_with(self) { - // found an ADT without structural-match; halt visiting! - assert!(self.found.is_some()); - return true; - } - } - - // Even though we do not want to recur on substs, we do - // want our caller to continue its own search. - false - } -} diff --git a/src/librustc_infer/traits/util.rs b/src/librustc_infer/traits/util.rs index 1dca01b3468..4fa74f93ddc 100644 --- a/src/librustc_infer/traits/util.rs +++ b/src/librustc_infer/traits/util.rs @@ -1,18 +1,13 @@ -use rustc_errors::DiagnosticBuilder; -use rustc_span::Span; use smallvec::smallvec; -use smallvec::SmallVec; -use rustc::ty::outlives::Component; -use rustc::ty::subst::{GenericArg, Subst, SubstsRef}; -use rustc::ty::{self, ToPolyTraitRef, ToPredicate, Ty, TyCtxt, WithConstness}; use rustc_data_structures::fx::FxHashSet; -use rustc_hir as hir; -use rustc_hir::def_id::DefId; +use rustc_middle::ty::outlives::Component; +use rustc_middle::ty::{self, ToPolyTraitRef, ToPredicate, TyCtxt, WithConstness}; -use super::{Normalized, Obligation, ObligationCause, PredicateObligation, SelectionContext}; - -fn anonymize_predicate<'tcx>(tcx: TyCtxt<'tcx>, pred: &ty::Predicate<'tcx>) -> ty::Predicate<'tcx> { +pub fn anonymize_predicate<'tcx>( + tcx: TyCtxt<'tcx>, + pred: &ty::Predicate<'tcx>, +) -> ty::Predicate<'tcx> { match *pred { ty::Predicate::Trait(ref data, constness) => { ty::Predicate::Trait(tcx.anonymize_late_bound_regions(data), constness) @@ -55,7 +50,7 @@ struct PredicateSet<'tcx> { impl PredicateSet<'tcx> { fn new(tcx: TyCtxt<'tcx>) -> Self { - Self { tcx: tcx, set: Default::default() } + Self { tcx, set: Default::default() } } fn insert(&mut self, pred: &ty::Predicate<'tcx>) -> bool { @@ -272,182 +267,6 @@ pub fn transitive_bounds<'tcx>( } /////////////////////////////////////////////////////////////////////////// -// `TraitAliasExpander` iterator -/////////////////////////////////////////////////////////////////////////// - -/// "Trait alias expansion" is the process of expanding a sequence of trait -/// references into another sequence by transitively following all trait -/// aliases. e.g. If you have bounds like `Foo + Send`, a trait alias -/// `trait Foo = Bar + Sync;`, and another trait alias -/// `trait Bar = Read + Write`, then the bounds would expand to -/// `Read + Write + Sync + Send`. -/// Expansion is done via a DFS (depth-first search), and the `visited` field -/// is used to avoid cycles. -pub struct TraitAliasExpander<'tcx> { - tcx: TyCtxt<'tcx>, - stack: Vec<TraitAliasExpansionInfo<'tcx>>, -} - -/// Stores information about the expansion of a trait via a path of zero or more trait aliases. -#[derive(Debug, Clone)] -pub struct TraitAliasExpansionInfo<'tcx> { - pub path: SmallVec<[(ty::PolyTraitRef<'tcx>, Span); 4]>, -} - -impl<'tcx> TraitAliasExpansionInfo<'tcx> { - fn new(trait_ref: ty::PolyTraitRef<'tcx>, span: Span) -> Self { - Self { path: smallvec![(trait_ref, span)] } - } - - /// Adds diagnostic labels to `diag` for the expansion path of a trait through all intermediate - /// trait aliases. - pub fn label_with_exp_info( - &self, - diag: &mut DiagnosticBuilder<'_>, - top_label: &str, - use_desc: &str, - ) { - diag.span_label(self.top().1, top_label); - if self.path.len() > 1 { - for (_, sp) in self.path.iter().rev().skip(1).take(self.path.len() - 2) { - diag.span_label(*sp, format!("referenced here ({})", use_desc)); - } - } - diag.span_label( - self.bottom().1, - format!("trait alias used in trait object type ({})", use_desc), - ); - } - - pub fn trait_ref(&self) -> &ty::PolyTraitRef<'tcx> { - &self.top().0 - } - - pub fn top(&self) -> &(ty::PolyTraitRef<'tcx>, Span) { - self.path.last().unwrap() - } - - pub fn bottom(&self) -> &(ty::PolyTraitRef<'tcx>, Span) { - self.path.first().unwrap() - } - - fn clone_and_push(&self, trait_ref: ty::PolyTraitRef<'tcx>, span: Span) -> Self { - let mut path = self.path.clone(); - path.push((trait_ref, span)); - - Self { path } - } -} - -pub fn expand_trait_aliases<'tcx>( - tcx: TyCtxt<'tcx>, - trait_refs: impl IntoIterator<Item = (ty::PolyTraitRef<'tcx>, Span)>, -) -> TraitAliasExpander<'tcx> { - let items: Vec<_> = trait_refs - .into_iter() - .map(|(trait_ref, span)| TraitAliasExpansionInfo::new(trait_ref, span)) - .collect(); - TraitAliasExpander { tcx, stack: items } -} - -impl<'tcx> TraitAliasExpander<'tcx> { - /// If `item` is a trait alias and its predicate has not yet been visited, then expands `item` - /// to the definition, pushes the resulting expansion onto `self.stack`, and returns `false`. - /// Otherwise, immediately returns `true` if `item` is a regular trait, or `false` if it is a - /// trait alias. - /// The return value indicates whether `item` should be yielded to the user. - fn expand(&mut self, item: &TraitAliasExpansionInfo<'tcx>) -> bool { - let tcx = self.tcx; - let trait_ref = item.trait_ref(); - let pred = trait_ref.without_const().to_predicate(); - - debug!("expand_trait_aliases: trait_ref={:?}", trait_ref); - - // Don't recurse if this bound is not a trait alias. - let is_alias = tcx.is_trait_alias(trait_ref.def_id()); - if !is_alias { - return true; - } - - // Don't recurse if this trait alias is already on the stack for the DFS search. - let anon_pred = anonymize_predicate(tcx, &pred); - if item.path.iter().rev().skip(1).any(|(tr, _)| { - anonymize_predicate(tcx, &tr.without_const().to_predicate()) == anon_pred - }) { - return false; - } - - // Get components of trait alias. - let predicates = tcx.super_predicates_of(trait_ref.def_id()); - - let items = predicates.predicates.iter().rev().filter_map(|(pred, span)| { - pred.subst_supertrait(tcx, &trait_ref) - .to_opt_poly_trait_ref() - .map(|trait_ref| item.clone_and_push(trait_ref, *span)) - }); - debug!("expand_trait_aliases: items={:?}", items.clone()); - - self.stack.extend(items); - - false - } -} - -impl<'tcx> Iterator for TraitAliasExpander<'tcx> { - type Item = TraitAliasExpansionInfo<'tcx>; - - fn size_hint(&self) -> (usize, Option<usize>) { - (self.stack.len(), None) - } - - fn next(&mut self) -> Option<TraitAliasExpansionInfo<'tcx>> { - while let Some(item) = self.stack.pop() { - if self.expand(&item) { - return Some(item); - } - } - None - } -} - -/////////////////////////////////////////////////////////////////////////// -// Iterator over def-IDs of supertraits -/////////////////////////////////////////////////////////////////////////// - -pub struct SupertraitDefIds<'tcx> { - tcx: TyCtxt<'tcx>, - stack: Vec<DefId>, - visited: FxHashSet<DefId>, -} - -pub fn supertrait_def_ids(tcx: TyCtxt<'_>, trait_def_id: DefId) -> SupertraitDefIds<'_> { - SupertraitDefIds { - tcx, - stack: vec![trait_def_id], - visited: Some(trait_def_id).into_iter().collect(), - } -} - -impl Iterator for SupertraitDefIds<'tcx> { - type Item = DefId; - - fn next(&mut self) -> Option<DefId> { - let def_id = self.stack.pop()?; - let predicates = self.tcx.super_predicates_of(def_id); - let visited = &mut self.visited; - self.stack.extend( - predicates - .predicates - .iter() - .filter_map(|(pred, _)| pred.to_opt_poly_trait_ref()) - .map(|trait_ref| trait_ref.def_id()) - .filter(|&super_def_id| visited.insert(super_def_id)), - ); - Some(def_id) - } -} - -/////////////////////////////////////////////////////////////////////////// // Other /////////////////////////////////////////////////////////////////////////// @@ -480,196 +299,3 @@ impl<'tcx, I: Iterator<Item = ty::Predicate<'tcx>>> Iterator for FilterToTraits< (0, upper) } } - -/////////////////////////////////////////////////////////////////////////// -// Other -/////////////////////////////////////////////////////////////////////////// - -/// Instantiate all bound parameters of the impl with the given substs, -/// returning the resulting trait ref and all obligations that arise. -/// The obligations are closed under normalization. -pub fn impl_trait_ref_and_oblig<'a, 'tcx>( - selcx: &mut SelectionContext<'a, 'tcx>, - param_env: ty::ParamEnv<'tcx>, - impl_def_id: DefId, - impl_substs: SubstsRef<'tcx>, -) -> (ty::TraitRef<'tcx>, Vec<PredicateObligation<'tcx>>) { - let impl_trait_ref = selcx.tcx().impl_trait_ref(impl_def_id).unwrap(); - let impl_trait_ref = impl_trait_ref.subst(selcx.tcx(), impl_substs); - let Normalized { value: impl_trait_ref, obligations: normalization_obligations1 } = - super::normalize(selcx, param_env, ObligationCause::dummy(), &impl_trait_ref); - - let predicates = selcx.tcx().predicates_of(impl_def_id); - let predicates = predicates.instantiate(selcx.tcx(), impl_substs); - let Normalized { value: predicates, obligations: normalization_obligations2 } = - super::normalize(selcx, param_env, ObligationCause::dummy(), &predicates); - let impl_obligations = - predicates_for_generics(ObligationCause::dummy(), 0, param_env, &predicates); - - let impl_obligations: Vec<_> = impl_obligations - .into_iter() - .chain(normalization_obligations1) - .chain(normalization_obligations2) - .collect(); - - (impl_trait_ref, impl_obligations) -} - -/// See [`super::obligations_for_generics`]. -pub fn predicates_for_generics<'tcx>( - cause: ObligationCause<'tcx>, - recursion_depth: usize, - param_env: ty::ParamEnv<'tcx>, - generic_bounds: &ty::InstantiatedPredicates<'tcx>, -) -> Vec<PredicateObligation<'tcx>> { - debug!("predicates_for_generics(generic_bounds={:?})", generic_bounds); - - generic_bounds - .predicates - .iter() - .map(|&predicate| Obligation { - cause: cause.clone(), - recursion_depth, - param_env, - predicate, - }) - .collect() -} - -pub fn predicate_for_trait_ref<'tcx>( - cause: ObligationCause<'tcx>, - param_env: ty::ParamEnv<'tcx>, - trait_ref: ty::TraitRef<'tcx>, - recursion_depth: usize, -) -> PredicateObligation<'tcx> { - Obligation { - cause, - param_env, - recursion_depth, - predicate: trait_ref.without_const().to_predicate(), - } -} - -pub fn predicate_for_trait_def( - tcx: TyCtxt<'tcx>, - param_env: ty::ParamEnv<'tcx>, - cause: ObligationCause<'tcx>, - trait_def_id: DefId, - recursion_depth: usize, - self_ty: Ty<'tcx>, - params: &[GenericArg<'tcx>], -) -> PredicateObligation<'tcx> { - let trait_ref = - ty::TraitRef { def_id: trait_def_id, substs: tcx.mk_substs_trait(self_ty, params) }; - predicate_for_trait_ref(cause, param_env, trait_ref, recursion_depth) -} - -/// Casts a trait reference into a reference to one of its super -/// traits; returns `None` if `target_trait_def_id` is not a -/// supertrait. -pub fn upcast_choices( - tcx: TyCtxt<'tcx>, - source_trait_ref: ty::PolyTraitRef<'tcx>, - target_trait_def_id: DefId, -) -> Vec<ty::PolyTraitRef<'tcx>> { - if source_trait_ref.def_id() == target_trait_def_id { - return vec![source_trait_ref]; // Shortcut the most common case. - } - - supertraits(tcx, source_trait_ref).filter(|r| r.def_id() == target_trait_def_id).collect() -} - -/// Given a trait `trait_ref`, returns the number of vtable entries -/// that come from `trait_ref`, excluding its supertraits. Used in -/// computing the vtable base for an upcast trait of a trait object. -pub fn count_own_vtable_entries(tcx: TyCtxt<'tcx>, trait_ref: ty::PolyTraitRef<'tcx>) -> usize { - let mut entries = 0; - // Count number of methods and add them to the total offset. - // Skip over associated types and constants. - for trait_item in tcx.associated_items(trait_ref.def_id()).in_definition_order() { - if trait_item.kind == ty::AssocKind::Method { - entries += 1; - } - } - entries -} - -/// Given an upcast trait object described by `object`, returns the -/// index of the method `method_def_id` (which should be part of -/// `object.upcast_trait_ref`) within the vtable for `object`. -pub fn get_vtable_index_of_object_method<N>( - tcx: TyCtxt<'tcx>, - object: &super::VtableObjectData<'tcx, N>, - method_def_id: DefId, -) -> usize { - // Count number of methods preceding the one we are selecting and - // add them to the total offset. - // Skip over associated types and constants. - let mut entries = object.vtable_base; - for trait_item in tcx.associated_items(object.upcast_trait_ref.def_id()).in_definition_order() { - if trait_item.def_id == method_def_id { - // The item with the ID we were given really ought to be a method. - assert_eq!(trait_item.kind, ty::AssocKind::Method); - return entries; - } - if trait_item.kind == ty::AssocKind::Method { - entries += 1; - } - } - - bug!("get_vtable_index_of_object_method: {:?} was not found", method_def_id); -} - -pub fn closure_trait_ref_and_return_type( - tcx: TyCtxt<'tcx>, - fn_trait_def_id: DefId, - self_ty: Ty<'tcx>, - sig: ty::PolyFnSig<'tcx>, - tuple_arguments: TupleArgumentsFlag, -) -> ty::Binder<(ty::TraitRef<'tcx>, Ty<'tcx>)> { - let arguments_tuple = match tuple_arguments { - TupleArgumentsFlag::No => sig.skip_binder().inputs()[0], - TupleArgumentsFlag::Yes => tcx.intern_tup(sig.skip_binder().inputs()), - }; - let trait_ref = ty::TraitRef { - def_id: fn_trait_def_id, - substs: tcx.mk_substs_trait(self_ty, &[arguments_tuple.into()]), - }; - ty::Binder::bind((trait_ref, sig.skip_binder().output())) -} - -pub fn generator_trait_ref_and_outputs( - tcx: TyCtxt<'tcx>, - fn_trait_def_id: DefId, - self_ty: Ty<'tcx>, - sig: ty::PolyGenSig<'tcx>, -) -> ty::Binder<(ty::TraitRef<'tcx>, Ty<'tcx>, Ty<'tcx>)> { - let trait_ref = ty::TraitRef { - def_id: fn_trait_def_id, - substs: tcx.mk_substs_trait(self_ty, &[sig.skip_binder().resume_ty.into()]), - }; - ty::Binder::bind((trait_ref, sig.skip_binder().yield_ty, sig.skip_binder().return_ty)) -} - -pub fn impl_is_default(tcx: TyCtxt<'_>, node_item_def_id: DefId) -> bool { - match tcx.hir().as_local_hir_id(node_item_def_id) { - Some(hir_id) => { - let item = tcx.hir().expect_item(hir_id); - if let hir::ItemKind::Impl { defaultness, .. } = item.kind { - defaultness.is_default() - } else { - false - } - } - None => tcx.impl_defaultness(node_item_def_id).is_default(), - } -} - -pub fn impl_item_is_final(tcx: TyCtxt<'_>, assoc_item: &ty::AssocItem) -> bool { - assoc_item.defaultness.is_final() && !impl_is_default(tcx, assoc_item.container.id()) -} - -pub enum TupleArgumentsFlag { - Yes, - No, -} diff --git a/src/librustc_infer/traits/wf.rs b/src/librustc_infer/traits/wf.rs deleted file mode 100644 index 980a3f04781..00000000000 --- a/src/librustc_infer/traits/wf.rs +++ /dev/null @@ -1,753 +0,0 @@ -use crate::infer::opaque_types::required_region_bounds; -use crate::infer::InferCtxt; -use crate::traits::{self, AssocTypeBoundData}; -use rustc::middle::lang_items; -use rustc::ty::subst::SubstsRef; -use rustc::ty::{self, ToPredicate, Ty, TyCtxt, TypeFoldable, WithConstness}; -use rustc_hir as hir; -use rustc_hir::def_id::DefId; -use rustc_span::symbol::{kw, Ident}; -use rustc_span::Span; - -/// Returns the set of obligations needed to make `ty` well-formed. -/// If `ty` contains unresolved inference variables, this may include -/// further WF obligations. However, if `ty` IS an unresolved -/// inference variable, returns `None`, because we are not able to -/// make any progress at all. This is to prevent "livelock" where we -/// say "$0 is WF if $0 is WF". -pub fn obligations<'a, 'tcx>( - infcx: &InferCtxt<'a, 'tcx>, - param_env: ty::ParamEnv<'tcx>, - body_id: hir::HirId, - ty: Ty<'tcx>, - span: Span, -) -> Option<Vec<traits::PredicateObligation<'tcx>>> { - let mut wf = WfPredicates { infcx, param_env, body_id, span, out: vec![], item: None }; - if wf.compute(ty) { - debug!("wf::obligations({:?}, body_id={:?}) = {:?}", ty, body_id, wf.out); - - let result = wf.normalize(); - debug!("wf::obligations({:?}, body_id={:?}) ~~> {:?}", ty, body_id, result); - Some(result) - } else { - None // no progress made, return None - } -} - -/// Returns the obligations that make this trait reference -/// well-formed. For example, if there is a trait `Set` defined like -/// `trait Set<K:Eq>`, then the trait reference `Foo: Set<Bar>` is WF -/// if `Bar: Eq`. -pub fn trait_obligations<'a, 'tcx>( - infcx: &InferCtxt<'a, 'tcx>, - param_env: ty::ParamEnv<'tcx>, - body_id: hir::HirId, - trait_ref: &ty::TraitRef<'tcx>, - span: Span, - item: Option<&'tcx hir::Item<'tcx>>, -) -> Vec<traits::PredicateObligation<'tcx>> { - let mut wf = WfPredicates { infcx, param_env, body_id, span, out: vec![], item }; - wf.compute_trait_ref(trait_ref, Elaborate::All); - wf.normalize() -} - -pub fn predicate_obligations<'a, 'tcx>( - infcx: &InferCtxt<'a, 'tcx>, - param_env: ty::ParamEnv<'tcx>, - body_id: hir::HirId, - predicate: &ty::Predicate<'tcx>, - span: Span, -) -> Vec<traits::PredicateObligation<'tcx>> { - let mut wf = WfPredicates { infcx, param_env, body_id, span, out: vec![], item: None }; - - // (*) ok to skip binders, because wf code is prepared for it - match *predicate { - ty::Predicate::Trait(ref t, _) => { - wf.compute_trait_ref(&t.skip_binder().trait_ref, Elaborate::None); // (*) - } - ty::Predicate::RegionOutlives(..) => {} - ty::Predicate::TypeOutlives(ref t) => { - wf.compute(t.skip_binder().0); - } - ty::Predicate::Projection(ref t) => { - let t = t.skip_binder(); // (*) - wf.compute_projection(t.projection_ty); - wf.compute(t.ty); - } - ty::Predicate::WellFormed(t) => { - wf.compute(t); - } - ty::Predicate::ObjectSafe(_) => {} - ty::Predicate::ClosureKind(..) => {} - ty::Predicate::Subtype(ref data) => { - wf.compute(data.skip_binder().a); // (*) - wf.compute(data.skip_binder().b); // (*) - } - ty::Predicate::ConstEvaluatable(def_id, substs) => { - let obligations = wf.nominal_obligations(def_id, substs); - wf.out.extend(obligations); - - for ty in substs.types() { - wf.compute(ty); - } - } - } - - wf.normalize() -} - -struct WfPredicates<'a, 'tcx> { - infcx: &'a InferCtxt<'a, 'tcx>, - param_env: ty::ParamEnv<'tcx>, - body_id: hir::HirId, - span: Span, - out: Vec<traits::PredicateObligation<'tcx>>, - item: Option<&'tcx hir::Item<'tcx>>, -} - -/// Controls whether we "elaborate" supertraits and so forth on the WF -/// predicates. This is a kind of hack to address #43784. The -/// underlying problem in that issue was a trait structure like: -/// -/// ``` -/// trait Foo: Copy { } -/// trait Bar: Foo { } -/// impl<T: Bar> Foo for T { } -/// impl<T> Bar for T { } -/// ``` -/// -/// Here, in the `Foo` impl, we will check that `T: Copy` holds -- but -/// we decide that this is true because `T: Bar` is in the -/// where-clauses (and we can elaborate that to include `T: -/// Copy`). This wouldn't be a problem, except that when we check the -/// `Bar` impl, we decide that `T: Foo` must hold because of the `Foo` -/// impl. And so nowhere did we check that `T: Copy` holds! -/// -/// To resolve this, we elaborate the WF requirements that must be -/// proven when checking impls. This means that (e.g.) the `impl Bar -/// for T` will be forced to prove not only that `T: Foo` but also `T: -/// Copy` (which it won't be able to do, because there is no `Copy` -/// impl for `T`). -#[derive(Debug, PartialEq, Eq, Copy, Clone)] -enum Elaborate { - All, - None, -} - -impl<'a, 'tcx> WfPredicates<'a, 'tcx> { - fn cause(&mut self, code: traits::ObligationCauseCode<'tcx>) -> traits::ObligationCause<'tcx> { - traits::ObligationCause::new(self.span, self.body_id, code) - } - - fn normalize(&mut self) -> Vec<traits::PredicateObligation<'tcx>> { - let cause = self.cause(traits::MiscObligation); - let infcx = &mut self.infcx; - let param_env = self.param_env; - let mut obligations = Vec::with_capacity(self.out.len()); - for pred in &self.out { - assert!(!pred.has_escaping_bound_vars()); - let mut selcx = traits::SelectionContext::new(infcx); - let i = obligations.len(); - let value = - traits::normalize_to(&mut selcx, param_env, cause.clone(), pred, &mut obligations); - obligations.insert(i, value); - } - obligations - } - - /// Pushes the obligations required for `trait_ref` to be WF into `self.out`. - fn compute_trait_ref(&mut self, trait_ref: &ty::TraitRef<'tcx>, elaborate: Elaborate) { - let tcx = self.infcx.tcx; - let obligations = self.nominal_obligations(trait_ref.def_id, trait_ref.substs); - - let cause = self.cause(traits::MiscObligation); - let param_env = self.param_env; - - let item = &self.item; - let extend_cause_with_original_assoc_item_obligation = - |cause: &mut traits::ObligationCause<'_>, - pred: &ty::Predicate<'_>, - trait_assoc_items: &[ty::AssocItem]| { - let trait_item = tcx - .hir() - .as_local_hir_id(trait_ref.def_id) - .and_then(|trait_id| tcx.hir().find(trait_id)); - let (trait_name, trait_generics) = match trait_item { - Some(hir::Node::Item(hir::Item { - ident, - kind: hir::ItemKind::Trait(.., generics, _, _), - .. - })) - | Some(hir::Node::Item(hir::Item { - ident, - kind: hir::ItemKind::TraitAlias(generics, _), - .. - })) => (Some(ident), Some(generics)), - _ => (None, None), - }; - - let item_span = item.map(|i| tcx.sess.source_map().def_span(i.span)); - match pred { - ty::Predicate::Projection(proj) => { - // The obligation comes not from the current `impl` nor the `trait` being - // implemented, but rather from a "second order" obligation, like in - // `src/test/ui/associated-types/point-at-type-on-obligation-failure.rs`: - // - // error[E0271]: type mismatch resolving `<Foo2 as Bar2>::Ok == ()` - // --> $DIR/point-at-type-on-obligation-failure.rs:13:5 - // | - // LL | type Ok; - // | -- associated type defined here - // ... - // LL | impl Bar for Foo { - // | ---------------- in this `impl` item - // LL | type Ok = (); - // | ^^^^^^^^^^^^^ expected `u32`, found `()` - // | - // = note: expected type `u32` - // found type `()` - // - // FIXME: we would want to point a span to all places that contributed to this - // obligation. In the case above, it should be closer to: - // - // error[E0271]: type mismatch resolving `<Foo2 as Bar2>::Ok == ()` - // --> $DIR/point-at-type-on-obligation-failure.rs:13:5 - // | - // LL | type Ok; - // | -- associated type defined here - // LL | type Sibling: Bar2<Ok=Self::Ok>; - // | -------------------------------- obligation set here - // ... - // LL | impl Bar for Foo { - // | ---------------- in this `impl` item - // LL | type Ok = (); - // | ^^^^^^^^^^^^^ expected `u32`, found `()` - // ... - // LL | impl Bar2 for Foo2 { - // | ---------------- in this `impl` item - // LL | type Ok = u32; - // | -------------- obligation set here - // | - // = note: expected type `u32` - // found type `()` - if let Some(hir::ItemKind::Impl { items, .. }) = item.map(|i| &i.kind) { - let trait_assoc_item = tcx.associated_item(proj.projection_def_id()); - if let Some(impl_item) = - items.iter().find(|item| item.ident == trait_assoc_item.ident) - { - cause.span = impl_item.span; - cause.code = traits::AssocTypeBound(Box::new(AssocTypeBoundData { - impl_span: item_span, - original: trait_assoc_item.ident.span, - bounds: vec![], - })); - } - } - } - ty::Predicate::Trait(proj, _) => { - // An associated item obligation born out of the `trait` failed to be met. - // Point at the `impl` that failed the obligation, the associated item that - // needed to meet the obligation, and the definition of that associated item, - // which should hold the obligation in most cases. An example can be seen in - // `src/test/ui/associated-types/point-at-type-on-obligation-failure-2.rs`: - // - // error[E0277]: the trait bound `bool: Bar` is not satisfied - // --> $DIR/point-at-type-on-obligation-failure-2.rs:8:5 - // | - // LL | type Assoc: Bar; - // | ----- associated type defined here - // ... - // LL | impl Foo for () { - // | --------------- in this `impl` item - // LL | type Assoc = bool; - // | ^^^^^^^^^^^^^^^^^^ the trait `Bar` is not implemented for `bool` - // - // If the obligation comes from the where clause in the `trait`, we point at it: - // - // error[E0277]: the trait bound `bool: Bar` is not satisfied - // --> $DIR/point-at-type-on-obligation-failure-2.rs:8:5 - // | - // | trait Foo where <Self as Foo>>::Assoc: Bar { - // | -------------------------- restricted in this bound - // LL | type Assoc; - // | ----- associated type defined here - // ... - // LL | impl Foo for () { - // | --------------- in this `impl` item - // LL | type Assoc = bool; - // | ^^^^^^^^^^^^^^^^^^ the trait `Bar` is not implemented for `bool` - if let ( - ty::Projection(ty::ProjectionTy { item_def_id, .. }), - Some(hir::ItemKind::Impl { items, .. }), - ) = (&proj.skip_binder().self_ty().kind, item.map(|i| &i.kind)) - { - if let Some((impl_item, trait_assoc_item)) = trait_assoc_items - .iter() - .find(|i| i.def_id == *item_def_id) - .and_then(|trait_assoc_item| { - items - .iter() - .find(|i| i.ident == trait_assoc_item.ident) - .map(|impl_item| (impl_item, trait_assoc_item)) - }) - { - let bounds = trait_generics - .map(|generics| { - get_generic_bound_spans( - &generics, - trait_name, - trait_assoc_item.ident, - ) - }) - .unwrap_or_else(Vec::new); - cause.span = impl_item.span; - cause.code = traits::AssocTypeBound(Box::new(AssocTypeBoundData { - impl_span: item_span, - original: trait_assoc_item.ident.span, - bounds, - })); - } - } - } - _ => {} - } - }; - - if let Elaborate::All = elaborate { - // FIXME: Make `extend_cause_with_original_assoc_item_obligation` take an iterator - // instead of a slice. - let trait_assoc_items: Vec<_> = - tcx.associated_items(trait_ref.def_id).in_definition_order().copied().collect(); - - let predicates = obligations.iter().map(|obligation| obligation.predicate).collect(); - let implied_obligations = traits::elaborate_predicates(tcx, predicates); - let implied_obligations = implied_obligations.map(|pred| { - let mut cause = cause.clone(); - extend_cause_with_original_assoc_item_obligation( - &mut cause, - &pred, - &*trait_assoc_items, - ); - traits::Obligation::new(cause, param_env, pred) - }); - self.out.extend(implied_obligations); - } - - self.out.extend(obligations); - - self.out.extend(trait_ref.substs.types().filter(|ty| !ty.has_escaping_bound_vars()).map( - |ty| traits::Obligation::new(cause.clone(), param_env, ty::Predicate::WellFormed(ty)), - )); - } - - /// Pushes the obligations required for `trait_ref::Item` to be WF - /// into `self.out`. - fn compute_projection(&mut self, data: ty::ProjectionTy<'tcx>) { - // A projection is well-formed if (a) the trait ref itself is - // WF and (b) the trait-ref holds. (It may also be - // normalizable and be WF that way.) - let trait_ref = data.trait_ref(self.infcx.tcx); - self.compute_trait_ref(&trait_ref, Elaborate::None); - - if !data.has_escaping_bound_vars() { - let predicate = trait_ref.without_const().to_predicate(); - let cause = self.cause(traits::ProjectionWf(data)); - self.out.push(traits::Obligation::new(cause, self.param_env, predicate)); - } - } - - /// Pushes the obligations required for an array length to be WF - /// into `self.out`. - fn compute_array_len(&mut self, constant: ty::Const<'tcx>) { - if let ty::ConstKind::Unevaluated(def_id, substs, promoted) = constant.val { - assert!(promoted.is_none()); - - let obligations = self.nominal_obligations(def_id, substs); - self.out.extend(obligations); - - let predicate = ty::Predicate::ConstEvaluatable(def_id, substs); - let cause = self.cause(traits::MiscObligation); - self.out.push(traits::Obligation::new(cause, self.param_env, predicate)); - } - } - - fn require_sized(&mut self, subty: Ty<'tcx>, cause: traits::ObligationCauseCode<'tcx>) { - if !subty.has_escaping_bound_vars() { - let cause = self.cause(cause); - let trait_ref = ty::TraitRef { - def_id: self.infcx.tcx.require_lang_item(lang_items::SizedTraitLangItem, None), - substs: self.infcx.tcx.mk_substs_trait(subty, &[]), - }; - self.out.push(traits::Obligation::new( - cause, - self.param_env, - trait_ref.without_const().to_predicate(), - )); - } - } - - /// Pushes new obligations into `out`. Returns `true` if it was able - /// to generate all the predicates needed to validate that `ty0` - /// is WF. Returns false if `ty0` is an unresolved type variable, - /// in which case we are not able to simplify at all. - fn compute(&mut self, ty0: Ty<'tcx>) -> bool { - let mut subtys = ty0.walk(); - let param_env = self.param_env; - while let Some(ty) = subtys.next() { - match ty.kind { - ty::Bool - | ty::Char - | ty::Int(..) - | ty::Uint(..) - | ty::Float(..) - | ty::Error - | ty::Str - | ty::GeneratorWitness(..) - | ty::Never - | ty::Param(_) - | ty::Bound(..) - | ty::Placeholder(..) - | ty::Foreign(..) => { - // WfScalar, WfParameter, etc - } - - ty::Slice(subty) => { - self.require_sized(subty, traits::SliceOrArrayElem); - } - - ty::Array(subty, len) => { - self.require_sized(subty, traits::SliceOrArrayElem); - self.compute_array_len(*len); - } - - ty::Tuple(ref tys) => { - if let Some((_last, rest)) = tys.split_last() { - for elem in rest { - self.require_sized(elem.expect_ty(), traits::TupleElem); - } - } - } - - ty::RawPtr(_) => { - // simple cases that are WF if their type args are WF - } - - ty::Projection(data) => { - subtys.skip_current_subtree(); // subtree handled by compute_projection - self.compute_projection(data); - } - - ty::UnnormalizedProjection(..) => bug!("only used with chalk-engine"), - - ty::Adt(def, substs) => { - // WfNominalType - let obligations = self.nominal_obligations(def.did, substs); - self.out.extend(obligations); - } - - ty::FnDef(did, substs) => { - let obligations = self.nominal_obligations(did, substs); - self.out.extend(obligations); - } - - ty::Ref(r, rty, _) => { - // WfReference - if !r.has_escaping_bound_vars() && !rty.has_escaping_bound_vars() { - let cause = self.cause(traits::ReferenceOutlivesReferent(ty)); - self.out.push(traits::Obligation::new( - cause, - param_env, - ty::Predicate::TypeOutlives(ty::Binder::dummy(ty::OutlivesPredicate( - rty, r, - ))), - )); - } - } - - ty::Generator(..) => { - // Walk ALL the types in the generator: this will - // include the upvar types as well as the yield - // type. Note that this is mildly distinct from - // the closure case, where we have to be careful - // about the signature of the closure. We don't - // have the problem of implied bounds here since - // generators don't take arguments. - } - - ty::Closure(def_id, substs) => { - // Only check the upvar types for WF, not the rest - // of the types within. This is needed because we - // capture the signature and it may not be WF - // without the implied bounds. Consider a closure - // like `|x: &'a T|` -- it may be that `T: 'a` is - // not known to hold in the creator's context (and - // indeed the closure may not be invoked by its - // creator, but rather turned to someone who *can* - // verify that). - // - // The special treatment of closures here really - // ought not to be necessary either; the problem - // is related to #25860 -- there is no way for us - // to express a fn type complete with the implied - // bounds that it is assuming. I think in reality - // the WF rules around fn are a bit messed up, and - // that is the rot problem: `fn(&'a T)` should - // probably always be WF, because it should be - // shorthand for something like `where(T: 'a) { - // fn(&'a T) }`, as discussed in #25860. - // - // Note that we are also skipping the generic - // types. This is consistent with the `outlives` - // code, but anyway doesn't matter: within the fn - // body where they are created, the generics will - // always be WF, and outside of that fn body we - // are not directly inspecting closure types - // anyway, except via auto trait matching (which - // only inspects the upvar types). - subtys.skip_current_subtree(); // subtree handled by compute_projection - for upvar_ty in substs.as_closure().upvar_tys(def_id, self.infcx.tcx) { - self.compute(upvar_ty); - } - } - - ty::FnPtr(_) => { - // let the loop iterate into the argument/return - // types appearing in the fn signature - } - - ty::Opaque(did, substs) => { - // all of the requirements on type parameters - // should've been checked by the instantiation - // of whatever returned this exact `impl Trait`. - - // for named opaque `impl Trait` types we still need to check them - if ty::is_impl_trait_defn(self.infcx.tcx, did).is_none() { - let obligations = self.nominal_obligations(did, substs); - self.out.extend(obligations); - } - } - - ty::Dynamic(data, r) => { - // WfObject - // - // Here, we defer WF checking due to higher-ranked - // regions. This is perhaps not ideal. - self.from_object_ty(ty, data, r); - - // FIXME(#27579) RFC also considers adding trait - // obligations that don't refer to Self and - // checking those - - let defer_to_coercion = self.infcx.tcx.features().object_safe_for_dispatch; - - if !defer_to_coercion { - let cause = self.cause(traits::MiscObligation); - let component_traits = data.auto_traits().chain(data.principal_def_id()); - self.out.extend(component_traits.map(|did| { - traits::Obligation::new( - cause.clone(), - param_env, - ty::Predicate::ObjectSafe(did), - ) - })); - } - } - - // Inference variables are the complicated case, since we don't - // know what type they are. We do two things: - // - // 1. Check if they have been resolved, and if so proceed with - // THAT type. - // 2. If not, check whether this is the type that we - // started with (ty0). In that case, we've made no - // progress at all, so return false. Otherwise, - // we've at least simplified things (i.e., we went - // from `Vec<$0>: WF` to `$0: WF`, so we can - // register a pending obligation and keep - // moving. (Goal is that an "inductive hypothesis" - // is satisfied to ensure termination.) - ty::Infer(_) => { - let ty = self.infcx.shallow_resolve(ty); - if let ty::Infer(_) = ty.kind { - // not yet resolved... - if ty == ty0 { - // ...this is the type we started from! no progress. - return false; - } - - let cause = self.cause(traits::MiscObligation); - self.out.push( - // ...not the type we started from, so we made progress. - traits::Obligation::new( - cause, - self.param_env, - ty::Predicate::WellFormed(ty), - ), - ); - } else { - // Yes, resolved, proceed with the - // result. Should never return false because - // `ty` is not a Infer. - assert!(self.compute(ty)); - } - } - } - } - - // if we made it through that loop above, we made progress! - return true; - } - - fn nominal_obligations( - &mut self, - def_id: DefId, - substs: SubstsRef<'tcx>, - ) -> Vec<traits::PredicateObligation<'tcx>> { - let predicates = self.infcx.tcx.predicates_of(def_id).instantiate(self.infcx.tcx, substs); - let cause = self.cause(traits::ItemObligation(def_id)); - predicates - .predicates - .into_iter() - .map(|pred| traits::Obligation::new(cause.clone(), self.param_env, pred)) - .filter(|pred| !pred.has_escaping_bound_vars()) - .collect() - } - - fn from_object_ty( - &mut self, - ty: Ty<'tcx>, - data: ty::Binder<&'tcx ty::List<ty::ExistentialPredicate<'tcx>>>, - region: ty::Region<'tcx>, - ) { - // Imagine a type like this: - // - // trait Foo { } - // trait Bar<'c> : 'c { } - // - // &'b (Foo+'c+Bar<'d>) - // ^ - // - // In this case, the following relationships must hold: - // - // 'b <= 'c - // 'd <= 'c - // - // The first conditions is due to the normal region pointer - // rules, which say that a reference cannot outlive its - // referent. - // - // The final condition may be a bit surprising. In particular, - // you may expect that it would have been `'c <= 'd`, since - // usually lifetimes of outer things are conservative - // approximations for inner things. However, it works somewhat - // differently with trait objects: here the idea is that if the - // user specifies a region bound (`'c`, in this case) it is the - // "master bound" that *implies* that bounds from other traits are - // all met. (Remember that *all bounds* in a type like - // `Foo+Bar+Zed` must be met, not just one, hence if we write - // `Foo<'x>+Bar<'y>`, we know that the type outlives *both* 'x and - // 'y.) - // - // Note: in fact we only permit builtin traits, not `Bar<'d>`, I - // am looking forward to the future here. - if !data.has_escaping_bound_vars() && !region.has_escaping_bound_vars() { - let implicit_bounds = object_region_bounds(self.infcx.tcx, data); - - let explicit_bound = region; - - self.out.reserve(implicit_bounds.len()); - for implicit_bound in implicit_bounds { - let cause = self.cause(traits::ObjectTypeBound(ty, explicit_bound)); - let outlives = - ty::Binder::dummy(ty::OutlivesPredicate(explicit_bound, implicit_bound)); - self.out.push(traits::Obligation::new( - cause, - self.param_env, - outlives.to_predicate(), - )); - } - } - } -} - -/// Given an object type like `SomeTrait + Send`, computes the lifetime -/// bounds that must hold on the elided self type. These are derived -/// from the declarations of `SomeTrait`, `Send`, and friends -- if -/// they declare `trait SomeTrait : 'static`, for example, then -/// `'static` would appear in the list. The hard work is done by -/// `infer::required_region_bounds`, see that for more information. -pub fn object_region_bounds<'tcx>( - tcx: TyCtxt<'tcx>, - existential_predicates: ty::Binder<&'tcx ty::List<ty::ExistentialPredicate<'tcx>>>, -) -> Vec<ty::Region<'tcx>> { - // Since we don't actually *know* the self type for an object, - // this "open(err)" serves as a kind of dummy standin -- basically - // a placeholder type. - let open_ty = tcx.mk_ty_infer(ty::FreshTy(0)); - - let predicates = existential_predicates - .iter() - .filter_map(|predicate| { - if let ty::ExistentialPredicate::Projection(_) = *predicate.skip_binder() { - None - } else { - Some(predicate.with_self_ty(tcx, open_ty)) - } - }) - .collect(); - - required_region_bounds(tcx, open_ty, predicates) -} - -/// Find the span of a generic bound affecting an associated type. -fn get_generic_bound_spans( - generics: &hir::Generics<'_>, - trait_name: Option<&Ident>, - assoc_item_name: Ident, -) -> Vec<Span> { - let mut bounds = vec![]; - for clause in generics.where_clause.predicates.iter() { - if let hir::WherePredicate::BoundPredicate(pred) = clause { - match &pred.bounded_ty.kind { - hir::TyKind::Path(hir::QPath::Resolved(Some(ty), path)) => { - let mut s = path.segments.iter(); - if let (a, Some(b), None) = (s.next(), s.next(), s.next()) { - if a.map(|s| &s.ident) == trait_name - && b.ident == assoc_item_name - && is_self_path(&ty.kind) - { - // `<Self as Foo>::Bar` - bounds.push(pred.span); - } - } - } - hir::TyKind::Path(hir::QPath::TypeRelative(ty, segment)) => { - if segment.ident == assoc_item_name { - if is_self_path(&ty.kind) { - // `Self::Bar` - bounds.push(pred.span); - } - } - } - _ => {} - } - } - } - bounds -} - -fn is_self_path(kind: &hir::TyKind<'_>) -> bool { - match kind { - hir::TyKind::Path(hir::QPath::Resolved(None, path)) => { - let mut s = path.segments.iter(); - if let (Some(segment), None) = (s.next(), s.next()) { - if segment.ident.name == kw::SelfUpper { - // `type(Self)` - return true; - } - } - } - _ => {} - } - false -} |
