diff --git a/compiler/rustc_trait_selection/src/traits/mod.rs b/compiler/rustc_trait_selection/src/traits/mod.rs index c93087a18cf..d819740b596 100644 --- a/compiler/rustc_trait_selection/src/traits/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/mod.rs @@ -59,6 +59,7 @@ 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::NonStructuralMatchTy; +pub use self::util::subst_assoc_item_bound; pub use self::util::{elaborate_predicates, elaborate_trait_ref, elaborate_trait_refs}; pub use self::util::{expand_trait_aliases, TraitAliasExpander}; pub use self::util::{ diff --git a/compiler/rustc_trait_selection/src/traits/util.rs b/compiler/rustc_trait_selection/src/traits/util.rs index f626bb0b7e3..3d52453a5c7 100644 --- a/compiler/rustc_trait_selection/src/traits/util.rs +++ b/compiler/rustc_trait_selection/src/traits/util.rs @@ -11,6 +11,8 @@ use rustc_middle::ty::{self, ToPredicate, Ty, TyCtxt, WithConstness}; use super::{Normalized, Obligation, ObligationCause, PredicateObligation, SelectionContext}; pub use rustc_infer::traits::util::*; +use std::iter; + /////////////////////////////////////////////////////////////////////////// // `TraitAliasExpander` iterator /////////////////////////////////////////////////////////////////////////// @@ -357,6 +359,59 @@ pub fn impl_item_is_final(tcx: TyCtxt<'_>, assoc_item: &ty::AssocItem) -> bool { assoc_item.defaultness.is_final() && tcx.impl_defaultness(assoc_item.container.id()).is_final() } +/// Map a bound from an associated item to apply to some other type. +/// For example, given the following trait +/// +/// trait X { type Y<'a>: PartialEq } +/// +/// Say that we know that `<() as X>::Y<'c> = i32` and we need to check that +/// the `PartialEq` bound applies. This function would return +/// `i32: PartialEq`. +pub fn subst_assoc_item_bound<'tcx>( + tcx: TyCtxt<'tcx>, + bound: ty::Predicate<'tcx>, + normalized_projection_ty: Ty<'tcx>, + assoc_item_substs: &[GenericArg<'tcx>], +) -> ty::Predicate<'tcx> { + let translate_predicate_substs = move |predicate_substs: SubstsRef<'tcx>| { + tcx.mk_substs( + iter::once(normalized_projection_ty.into()) + .chain(predicate_substs[1..].iter().map(|s| s.subst(tcx, assoc_item_substs))), + ) + }; + + match bound.kind() { + ty::PredicateKind::Trait(poly_tr, c) => poly_tr + .map_bound(|tr| { + let trait_substs = translate_predicate_substs(tr.trait_ref.substs); + ty::TraitRef { def_id: tr.def_id(), substs: trait_substs } + }) + .with_constness(*c) + .to_predicate(tcx), + ty::PredicateKind::Projection(poly_projection) => poly_projection + .map_bound(|projection| { + let projection_substs = translate_predicate_substs(projection.projection_ty.substs); + ty::ProjectionPredicate { + projection_ty: ty::ProjectionTy { + substs: projection_substs, + item_def_id: projection.projection_ty.item_def_id, + }, + ty: projection.ty.subst(tcx, assoc_item_substs), + } + }) + .to_predicate(tcx), + ty::PredicateKind::TypeOutlives(poly_outlives) => poly_outlives + .map_bound(|outlives| { + ty::OutlivesPredicate( + normalized_projection_ty, + outlives.1.subst(tcx, assoc_item_substs), + ) + }) + .to_predicate(tcx), + _ => bug!("unexepected projection bound: `{:?}`", bound), + } +} + pub enum TupleArgumentsFlag { Yes, No,