1
Fork 0

Split bounds from predicates

This commit is contained in:
Matthew Jasper 2020-06-24 19:13:44 +01:00
parent a7ead3bd53
commit d297147e62
10 changed files with 153 additions and 231 deletions

View file

@ -937,7 +937,7 @@ impl<'a, 'tcx> CrateMetadataRef<'a> {
.tables .tables
.inferred_outlives .inferred_outlives
.get(self, item_id) .get(self, item_id)
.map(|predicates| predicates.decode((self, tcx))) .map(|predicates| tcx.arena.alloc_from_iter(predicates.decode((self, tcx))))
.unwrap_or_default() .unwrap_or_default()
} }
@ -949,6 +949,19 @@ impl<'a, 'tcx> CrateMetadataRef<'a> {
self.root.tables.super_predicates.get(self, item_id).unwrap().decode((self, tcx)) self.root.tables.super_predicates.get(self, item_id).unwrap().decode((self, tcx))
} }
fn get_explicit_item_bounds(
&self,
item_id: DefIndex,
tcx: TyCtxt<'tcx>,
) -> &'tcx [(ty::Predicate<'tcx>, Span)] {
self.root
.tables
.explicit_item_bounds
.get(self, item_id)
.map(|bounds| tcx.arena.alloc_from_iter(bounds.decode((self, tcx))))
.unwrap_or_default()
}
fn get_generics(&self, item_id: DefIndex, sess: &Session) -> ty::Generics { fn get_generics(&self, item_id: DefIndex, sess: &Session) -> ty::Generics {
self.root.tables.generics.get(self, item_id).unwrap().decode((self, sess)) self.root.tables.generics.get(self, item_id).unwrap().decode((self, sess))
} }

View file

@ -89,6 +89,7 @@ provide! { <'tcx> tcx, def_id, other, cdata,
explicit_predicates_of => { cdata.get_explicit_predicates(def_id.index, tcx) } explicit_predicates_of => { cdata.get_explicit_predicates(def_id.index, tcx) }
inferred_outlives_of => { cdata.get_inferred_outlives(def_id.index, tcx) } inferred_outlives_of => { cdata.get_inferred_outlives(def_id.index, tcx) }
super_predicates_of => { cdata.get_super_predicates(def_id.index, tcx) } super_predicates_of => { cdata.get_super_predicates(def_id.index, tcx) }
explicit_item_bounds => { cdata.get_explicit_item_bounds(def_id.index, tcx) }
trait_def => { cdata.get_trait_def(def_id.index, tcx.sess) } trait_def => { cdata.get_trait_def(def_id.index, tcx.sess) }
adt_def => { cdata.get_adt_def(def_id.index, tcx) } adt_def => { cdata.get_adt_def(def_id.index, tcx) }
adt_destructor => { adt_destructor => {

View file

@ -965,6 +965,14 @@ impl EncodeContext<'a, 'tcx> {
record!(self.tables.super_predicates[def_id] <- self.tcx.super_predicates_of(def_id)); record!(self.tables.super_predicates[def_id] <- self.tcx.super_predicates_of(def_id));
} }
fn encode_explicit_item_bounds(&mut self, def_id: DefId) {
debug!("EncodeContext::encode_explicit_item_bounds({:?})", def_id);
let bounds = self.tcx.explicit_item_bounds(def_id);
if !bounds.is_empty() {
record!(self.tables.explicit_item_bounds[def_id] <- bounds);
}
}
fn encode_info_for_trait_item(&mut self, def_id: DefId) { fn encode_info_for_trait_item(&mut self, def_id: DefId) {
debug!("EncodeContext::encode_info_for_trait_item({:?})", def_id); debug!("EncodeContext::encode_info_for_trait_item({:?})", def_id);
let tcx = self.tcx; let tcx = self.tcx;
@ -1017,7 +1025,10 @@ impl EncodeContext<'a, 'tcx> {
has_self: trait_item.fn_has_self_parameter, has_self: trait_item.fn_has_self_parameter,
})) }))
} }
ty::AssocKind::Type => EntryKind::AssocType(container), ty::AssocKind::Type => {
self.encode_explicit_item_bounds(def_id);
EntryKind::AssocType(container)
}
}); });
record!(self.tables.visibility[def_id] <- trait_item.vis); record!(self.tables.visibility[def_id] <- trait_item.vis);
record!(self.tables.span[def_id] <- ast_item.span); record!(self.tables.span[def_id] <- ast_item.span);

View file

@ -295,13 +295,11 @@ define_tables! {
generics: Table<DefIndex, Lazy<ty::Generics>>, generics: Table<DefIndex, Lazy<ty::Generics>>,
explicit_predicates: Table<DefIndex, Lazy!(ty::GenericPredicates<'tcx>)>, explicit_predicates: Table<DefIndex, Lazy!(ty::GenericPredicates<'tcx>)>,
expn_that_defined: Table<DefIndex, Lazy<ExpnId>>, expn_that_defined: Table<DefIndex, Lazy<ExpnId>>,
// FIXME(eddyb) this would ideally be `Lazy<[...]>` but `ty::Predicate` // As an optimization, a missing entry indicates an empty `&[]`.
// doesn't handle shorthands in its own (de)serialization impls, inferred_outlives: Table<DefIndex, Lazy!([(ty::Predicate<'tcx>, Span)])>,
// as it's an `enum` for which we want to derive (de)serialization,
// so the `ty::codec` APIs handle the whole `&'tcx [...]` at once.
// Also, as an optimization, a missing entry indicates an empty `&[]`.
inferred_outlives: Table<DefIndex, Lazy!(&'tcx [(ty::Predicate<'tcx>, Span)])>,
super_predicates: Table<DefIndex, Lazy!(ty::GenericPredicates<'tcx>)>, super_predicates: Table<DefIndex, Lazy!(ty::GenericPredicates<'tcx>)>,
// As an optimization, a missing entry indicates an empty `&[]`.
explicit_item_bounds: Table<DefIndex, Lazy!([(ty::Predicate<'tcx>, Span)])>,
mir: Table<DefIndex, Lazy!(mir::Body<'tcx>)>, mir: Table<DefIndex, Lazy!(mir::Body<'tcx>)>,
promoted_mir: Table<DefIndex, Lazy!(IndexVec<mir::Promoted, mir::Body<'tcx>>)>, promoted_mir: Table<DefIndex, Lazy!(IndexVec<mir::Promoted, mir::Body<'tcx>>)>,
mir_abstract_consts: Table<DefIndex, Lazy!(&'tcx [mir::abstract_const::Node<'tcx>])>, mir_abstract_consts: Table<DefIndex, Lazy!(&'tcx [mir::abstract_const::Node<'tcx>])>,

View file

@ -169,8 +169,13 @@ rustc_queries! {
/// ^^^^^^^^^^^^^^^ /// ^^^^^^^^^^^^^^^
/// ///
/// `key` is the `DefId` of the associated type or opaque type. /// `key` is the `DefId` of the associated type or opaque type.
query explicit_item_bounds(key: DefId) -> &'tcx [(ty::Predicate<'tcx>, Span)] {
desc { |tcx| "finding item bounds for `{}`", tcx.def_path_str(key) }
}
/// Elaborated the predicates from `explicit_item_bounds`.
query item_bounds(key: DefId) -> &'tcx ty::List<ty::Predicate<'tcx>> { query item_bounds(key: DefId) -> &'tcx ty::List<ty::Predicate<'tcx>> {
desc { |tcx| "finding projection predicates for `{}`", tcx.def_path_str(key) } desc { |tcx| "elaborating item bounds for `{}`", tcx.def_path_str(key) }
} }
query projection_ty_from_predicates(key: (DefId, DefId)) -> Option<ty::ProjectionTy<'tcx>> { query projection_ty_from_predicates(key: (DefId, DefId)) -> Option<ty::ProjectionTy<'tcx>> {

View file

@ -607,12 +607,12 @@ pub trait PrettyPrinter<'tcx>:
} }
// Grab the "TraitA + TraitB" from `impl TraitA + TraitB`, // Grab the "TraitA + TraitB" from `impl TraitA + TraitB`,
// by looking up the projections associated with the def_id. // by looking up the projections associated with the def_id.
let bounds = self.tcx().predicates_of(def_id).instantiate(self.tcx(), substs); let bounds = self.tcx().item_bounds(def_id).subst(self.tcx(), substs);
let mut first = true; let mut first = true;
let mut is_sized = false; let mut is_sized = false;
p!("impl"); p!("impl");
for predicate in bounds.predicates { for predicate in bounds {
// Note: We can't use `to_opt_poly_trait_ref` here as `predicate` // Note: We can't use `to_opt_poly_trait_ref` here as `predicate`
// may contain unbound variables. We therefore do this manually. // may contain unbound variables. We therefore do this manually.
// //

View file

@ -10,7 +10,7 @@ use rustc_infer::infer::free_regions::FreeRegionRelations;
use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
use rustc_infer::infer::{self, InferCtxt, InferOk}; use rustc_infer::infer::{self, InferCtxt, InferOk};
use rustc_middle::ty::fold::{BottomUpFolder, TypeFoldable, TypeFolder, TypeVisitor}; use rustc_middle::ty::fold::{BottomUpFolder, TypeFoldable, TypeFolder, TypeVisitor};
use rustc_middle::ty::subst::{GenericArg, GenericArgKind, InternalSubsts, SubstsRef}; use rustc_middle::ty::subst::{GenericArg, GenericArgKind, InternalSubsts, Subst, SubstsRef};
use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_middle::ty::{self, Ty, TyCtxt};
use rustc_session::config::nightly_options; use rustc_session::config::nightly_options;
use rustc_span::Span; use rustc_span::Span;
@ -428,14 +428,15 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
// If there are required region bounds, we can use them. // If there are required region bounds, we can use them.
if opaque_defn.has_required_region_bounds { if opaque_defn.has_required_region_bounds {
let predicates_of = tcx.predicates_of(def_id); let bounds = tcx.explicit_item_bounds(def_id);
debug!("constrain_opaque_type: predicates: {:#?}", predicates_of,); debug!("constrain_opaque_type: predicates: {:#?}", bounds);
let bounds = predicates_of.instantiate(tcx, opaque_defn.substs); let bounds: Vec<_> =
bounds.iter().map(|(bound, _)| bound.subst(tcx, opaque_defn.substs)).collect();
debug!("constrain_opaque_type: bounds={:#?}", bounds); debug!("constrain_opaque_type: bounds={:#?}", bounds);
let opaque_type = tcx.mk_opaque(def_id, opaque_defn.substs); let opaque_type = tcx.mk_opaque(def_id, opaque_defn.substs);
let required_region_bounds = let required_region_bounds =
required_region_bounds(tcx, opaque_type, bounds.predicates.into_iter()); required_region_bounds(tcx, opaque_type, bounds.into_iter());
debug_assert!(!required_region_bounds.is_empty()); debug_assert!(!required_region_bounds.is_empty());
for required_region in required_region_bounds { for required_region in required_region_bounds {
@ -1112,9 +1113,10 @@ impl<'a, 'tcx> Instantiator<'a, 'tcx> {
let ty_var = infcx let ty_var = infcx
.next_ty_var(TypeVariableOrigin { kind: TypeVariableOriginKind::TypeInference, span }); .next_ty_var(TypeVariableOrigin { kind: TypeVariableOriginKind::TypeInference, span });
let predicates_of = tcx.predicates_of(def_id); let item_bounds = tcx.explicit_item_bounds(def_id);
debug!("instantiate_opaque_types: predicates={:#?}", predicates_of,); debug!("instantiate_opaque_types: bounds={:#?}", item_bounds);
let bounds = predicates_of.instantiate(tcx, substs); let bounds: Vec<_> =
item_bounds.iter().map(|(bound, _)| bound.subst(tcx, substs)).collect();
let param_env = tcx.param_env(def_id); let param_env = tcx.param_env(def_id);
let InferOk { value: bounds, obligations } = let InferOk { value: bounds, obligations } =
@ -1123,8 +1125,7 @@ impl<'a, 'tcx> Instantiator<'a, 'tcx> {
debug!("instantiate_opaque_types: bounds={:?}", bounds); debug!("instantiate_opaque_types: bounds={:?}", bounds);
let required_region_bounds = let required_region_bounds = required_region_bounds(tcx, ty, bounds.iter().copied());
required_region_bounds(tcx, ty, bounds.predicates.iter().cloned());
debug!("instantiate_opaque_types: required_region_bounds={:?}", required_region_bounds); debug!("instantiate_opaque_types: required_region_bounds={:?}", required_region_bounds);
// Make sure that we are in fact defining the *entire* type // Make sure that we are in fact defining the *entire* type
@ -1153,7 +1154,7 @@ impl<'a, 'tcx> Instantiator<'a, 'tcx> {
); );
debug!("instantiate_opaque_types: ty_var={:?}", ty_var); debug!("instantiate_opaque_types: ty_var={:?}", ty_var);
for predicate in &bounds.predicates { for predicate in &bounds {
if let ty::PredicateAtom::Projection(projection) = predicate.skip_binders() { if let ty::PredicateAtom::Projection(projection) = predicate.skip_binders() {
if projection.ty.references_error() { if projection.ty.references_error() {
// No point on adding these obligations since there's a type error involved. // No point on adding these obligations since there's a type error involved.
@ -1162,8 +1163,8 @@ impl<'a, 'tcx> Instantiator<'a, 'tcx> {
} }
} }
self.obligations.reserve(bounds.predicates.len()); self.obligations.reserve(bounds.len());
for predicate in bounds.predicates { for predicate in bounds {
// Change the predicate to refer to the type variable, // Change the predicate to refer to the type variable,
// which will be the concrete type instead of the opaque type. // which will be the concrete type instead of the opaque type.
// This also instantiates nested instances of `impl Trait`. // This also instantiates nested instances of `impl Trait`.

View file

@ -71,12 +71,8 @@ impl<'tcx> Bounds<'tcx> {
self.region_bounds self.region_bounds
.iter() .iter()
.map(|&(region_bound, span)| { .map(|&(region_bound, span)| {
// Account for the binder being introduced below; no need to shift `param_ty`
// because, at present at least, it either only refers to early-bound regions,
// or it's a generic associated type that deliberately has escaping bound vars.
let region_bound = ty::fold::shift_region(tcx, region_bound, 1);
let outlives = ty::OutlivesPredicate(param_ty, region_bound); let outlives = ty::OutlivesPredicate(param_ty, region_bound);
(ty::Binder::bind(outlives).to_predicate(tcx), span) (ty::Binder::dummy(outlives).to_predicate(tcx), span)
}) })
.chain(self.trait_bounds.iter().map(|&(bound_trait_ref, span, constness)| { .chain(self.trait_bounds.iter().map(|&(bound_trait_ref, span, constness)| {
let predicate = bound_trait_ref.with_constness(constness).to_predicate(tcx); let predicate = bound_trait_ref.with_constness(constness).to_predicate(tcx);

View file

@ -70,6 +70,7 @@ pub fn provide(providers: &mut Providers) {
opt_const_param_of: type_of::opt_const_param_of, opt_const_param_of: type_of::opt_const_param_of,
type_of: type_of::type_of, type_of: type_of::type_of,
item_bounds: item_bounds::item_bounds, item_bounds: item_bounds::item_bounds,
explicit_item_bounds: item_bounds::explicit_item_bounds,
generics_of, generics_of,
predicates_of, predicates_of,
predicates_defined_on, predicates_defined_on,
@ -1728,7 +1729,6 @@ fn explicit_predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericPredicat
let mut is_trait = None; let mut is_trait = None;
let mut is_default_impl_trait = None; let mut is_default_impl_trait = None;
let mut is_trait_associated_type = None;
let icx = ItemCtxt::new(tcx, def_id); let icx = ItemCtxt::new(tcx, def_id);
let constness = icx.default_constness_for_trait_bounds(); let constness = icx.default_constness_for_trait_bounds();
@ -1741,12 +1741,7 @@ fn explicit_predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericPredicat
let mut predicates: FxIndexSet<(ty::Predicate<'_>, Span)> = FxIndexSet::default(); let mut predicates: FxIndexSet<(ty::Predicate<'_>, Span)> = FxIndexSet::default();
let ast_generics = match node { let ast_generics = match node {
Node::TraitItem(item) => { Node::TraitItem(item) => &item.generics,
if let hir::TraitItemKind::Type(bounds, _) = item.kind {
is_trait_associated_type = Some((bounds, item.span));
}
&item.generics
}
Node::ImplItem(item) => &item.generics, Node::ImplItem(item) => &item.generics,
@ -1764,44 +1759,26 @@ fn explicit_predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericPredicat
| ItemKind::Struct(_, ref generics) | ItemKind::Struct(_, ref generics)
| ItemKind::Union(_, ref generics) => generics, | ItemKind::Union(_, ref generics) => generics,
ItemKind::Trait(_, _, ref generics, .., items) => { ItemKind::Trait(_, _, ref generics, ..) => {
is_trait = Some((ty::TraitRef::identity(tcx, def_id), items)); is_trait = Some(ty::TraitRef::identity(tcx, def_id));
generics generics
} }
ItemKind::TraitAlias(ref generics, _) => { ItemKind::TraitAlias(ref generics, _) => {
is_trait = Some((ty::TraitRef::identity(tcx, def_id), &[])); is_trait = Some(ty::TraitRef::identity(tcx, def_id));
generics generics
} }
ItemKind::OpaqueTy(OpaqueTy { ItemKind::OpaqueTy(OpaqueTy {
ref bounds, bounds: _,
impl_trait_fn, impl_trait_fn,
ref generics, ref generics,
origin: _, origin: _,
}) => { }) => {
let bounds_predicates = ty::print::with_no_queries(|| {
let substs = InternalSubsts::identity_for_item(tcx, def_id);
let opaque_ty = tcx.mk_opaque(def_id, substs);
// Collect the bounds, i.e., the `A + B + 'c` in `impl A + B + 'c`.
let bounds = AstConv::compute_bounds(
&icx,
opaque_ty,
bounds,
SizedByDefault::Yes,
tcx.def_span(def_id),
);
bounds.predicates(tcx, opaque_ty)
});
if impl_trait_fn.is_some() { if impl_trait_fn.is_some() {
// opaque types // return-position impl trait
return ty::GenericPredicates { // TODO: Investigate why we have this special case?
parent: None, return ty::GenericPredicates { parent: None, predicates: &[] };
predicates: tcx.arena.alloc_from_iter(bounds_predicates),
};
} else { } else {
// named opaque types // type alias impl trait
predicates.extend(bounds_predicates);
generics generics
} }
} }
@ -1827,7 +1804,7 @@ fn explicit_predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericPredicat
// and the explicit where-clauses, but to get the full set of predicates // and the explicit where-clauses, but to get the full set of predicates
// on a trait we need to add in the supertrait bounds and bounds found on // on a trait we need to add in the supertrait bounds and bounds found on
// associated types. // associated types.
if let Some((_trait_ref, _)) = is_trait { if let Some(_trait_ref) = is_trait {
predicates.extend(tcx.super_predicates_of(def_id).predicates.iter().cloned()); predicates.extend(tcx.super_predicates_of(def_id).predicates.iter().cloned());
} }
@ -1994,24 +1971,6 @@ fn explicit_predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericPredicat
} }
} }
// Add predicates from associated type bounds (`type X: Bound`)
if tcx.features().generic_associated_types {
// New behavior: bounds declared on associate type are predicates of that
// associated type. Not the default because it needs more testing.
if let Some((bounds, span)) = is_trait_associated_type {
let projection_ty =
tcx.mk_projection(def_id, InternalSubsts::identity_for_item(tcx, def_id));
predicates.extend(associated_item_bounds(tcx, def_id, bounds, projection_ty, span))
}
} else if let Some((self_trait_ref, trait_items)) = is_trait {
// Current behavior: bounds declared on associate type are predicates
// of its parent trait.
predicates.extend(trait_items.iter().flat_map(|trait_item_ref| {
trait_associated_item_predicates(tcx, def_id, self_trait_ref, trait_item_ref)
}))
}
if tcx.features().const_evaluatable_checked { if tcx.features().const_evaluatable_checked {
predicates.extend(const_evaluatable_predicates_of(tcx, def_id.expect_local())); predicates.extend(const_evaluatable_predicates_of(tcx, def_id.expect_local()));
} }
@ -2155,55 +2114,6 @@ fn projection_ty_from_predicates(
projection_ty projection_ty
} }
fn trait_associated_item_predicates(
tcx: TyCtxt<'tcx>,
def_id: DefId,
self_trait_ref: ty::TraitRef<'tcx>,
trait_item_ref: &hir::TraitItemRef,
) -> Vec<(ty::Predicate<'tcx>, Span)> {
let trait_item = tcx.hir().trait_item(trait_item_ref.id);
let item_def_id = tcx.hir().local_def_id(trait_item_ref.id.hir_id);
let bounds = match trait_item.kind {
hir::TraitItemKind::Type(ref bounds, _) => bounds,
_ => return Vec::new(),
};
if !tcx.generics_of(item_def_id).params.is_empty() {
// For GATs the substs provided to the mk_projection call below are
// wrong. We should emit a feature gate error if we get here so skip
// this type.
tcx.sess.delay_span_bug(trait_item.span, "gats used without feature gate");
return Vec::new();
}
let assoc_ty = tcx.mk_projection(
tcx.hir().local_def_id(trait_item.hir_id).to_def_id(),
self_trait_ref.substs,
);
associated_item_bounds(tcx, def_id, bounds, assoc_ty, trait_item.span)
}
fn associated_item_bounds(
tcx: TyCtxt<'tcx>,
def_id: DefId,
bounds: &'tcx [hir::GenericBound<'tcx>],
projection_ty: Ty<'tcx>,
span: Span,
) -> Vec<(ty::Predicate<'tcx>, Span)> {
let bounds = AstConv::compute_bounds(
&ItemCtxt::new(tcx, def_id),
projection_ty,
bounds,
SizedByDefault::Yes,
span,
);
let predicates = bounds.predicates(tcx, projection_ty);
predicates
}
/// Converts a specific `GenericBound` from the AST into a set of /// Converts a specific `GenericBound` from the AST into a set of
/// predicates that apply to the self type. A vector is returned /// predicates that apply to the self type. A vector is returned
/// because this can be anywhere from zero predicates (`T: ?Sized` adds no /// because this can be anywhere from zero predicates (`T: ?Sized` adds no

View file

@ -1,126 +1,113 @@
use rustc_hir::def::DefKind; use super::ItemCtxt;
use crate::astconv::{AstConv, SizedByDefault};
use rustc_hir as hir;
use rustc_infer::traits::util; use rustc_infer::traits::util;
use rustc_middle::ty::subst::InternalSubsts; use rustc_middle::ty::subst::InternalSubsts;
use rustc_middle::ty::{self, TyCtxt}; use rustc_middle::ty::{self, TyCtxt};
use rustc_span::def_id::DefId; use rustc_span::def_id::DefId;
use rustc_span::Span;
/// For associated types we allow bounds written on the associated type /// For associated types we include both bounds written on the type
/// (`type X: Trait`) to be used as candidates. We also allow the same bounds /// (`type X: Trait`) and predicates from the trait: `where Self::X: Trait`.
/// when desugared as bounds on the trait `where Self::X: Trait`.
/// ///
/// Note that this filtering is done with the items identity substs to /// Note that this filtering is done with the items identity substs to
/// simplify checking that these bounds are met in impls. This means that /// simplify checking that these bounds are met in impls. This means that
/// a bound such as `for<'b> <Self as X<'b>>::U: Clone` can't be used, as in /// a bound such as `for<'b> <Self as X<'b>>::U: Clone` can't be used, as in
/// `hr-associated-type-bound-1.rs`. /// `hr-associated-type-bound-1.rs`.
fn associated_type_bounds( fn associated_type_bounds<'tcx>(
tcx: TyCtxt<'_>, tcx: TyCtxt<'tcx>,
assoc_item_def_id: DefId, assoc_item_def_id: DefId,
) -> &'_ ty::List<ty::Predicate<'_>> { bounds: &'tcx [hir::GenericBound<'tcx>],
let generic_trait_bounds = tcx.predicates_of(assoc_item_def_id); span: Span,
// We include predicates from the trait as well to handle ) -> &'tcx [(ty::Predicate<'tcx>, Span)] {
// `where Self::X: Trait`. let item_ty = tcx.mk_projection(
let item_bounds = generic_trait_bounds.instantiate_identity(tcx); assoc_item_def_id,
let item_predicates = util::elaborate_predicates(tcx, item_bounds.predicates.into_iter()); InternalSubsts::identity_for_item(tcx, assoc_item_def_id),
);
let assoc_item_ty = ty::ProjectionTy { let bounds = AstConv::compute_bounds(
item_def_id: assoc_item_def_id, &ItemCtxt::new(tcx, assoc_item_def_id),
substs: InternalSubsts::identity_for_item(tcx, assoc_item_def_id), item_ty,
}; bounds,
SizedByDefault::Yes,
span,
);
let predicates = item_predicates.filter_map(|obligation| { let trait_def_id = tcx.associated_item(assoc_item_def_id).container.id();
let pred = obligation.predicate; let trait_predicates = tcx.predicates_of(trait_def_id);
match pred.kind() {
ty::PredicateKind::Trait(tr, _) => { let bounds_from_parent =
if let ty::Projection(p) = *tr.skip_binder().self_ty().kind() { trait_predicates.predicates.iter().copied().filter(|(pred, _)| match pred.kind() {
if p == assoc_item_ty { ty::PredicateKind::Trait(tr, _) => tr.skip_binder().self_ty() == item_ty,
return Some(pred);
}
}
}
ty::PredicateKind::Projection(proj) => { ty::PredicateKind::Projection(proj) => {
if let ty::Projection(p) = *proj.skip_binder().projection_ty.self_ty().kind() { proj.skip_binder().projection_ty.self_ty() == item_ty
if p == assoc_item_ty {
return Some(pred);
}
}
} }
ty::PredicateKind::TypeOutlives(outlives) => { ty::PredicateKind::TypeOutlives(outlives) => outlives.skip_binder().0 == item_ty,
if let ty::Projection(p) = *outlives.skip_binder().0.kind() { _ => false,
if p == assoc_item_ty { });
return Some(pred);
}
}
}
_ => {}
}
None
});
let result = tcx.mk_predicates(predicates); let all_bounds = tcx
debug!("associated_type_bounds({}) = {:?}", tcx.def_path_str(assoc_item_def_id), result); .arena
result .alloc_from_iter(bounds.predicates(tcx, item_ty).into_iter().chain(bounds_from_parent));
debug!("associated_type_bounds({}) = {:?}", tcx.def_path_str(assoc_item_def_id), all_bounds);
all_bounds
} }
/// Opaque types don't have the same issues as associated types: the only /// Opaque types don't inherit bounds from their parent: for return position
/// predicates on an opaque type (excluding those it inherits from its parent /// impl trait it isn't possible to write a suitable predicate on the
/// item) should be of the form we're expecting. /// containing function and for type-alias impl trait we don't have a backwards
fn opaque_type_bounds(tcx: TyCtxt<'_>, def_id: DefId) -> &'_ ty::List<ty::Predicate<'_>> { /// compatibility issue.
let substs = InternalSubsts::identity_for_item(tcx, def_id); fn opaque_type_bounds<'tcx>(
tcx: TyCtxt<'tcx>,
opaque_def_id: DefId,
bounds: &'tcx [hir::GenericBound<'tcx>],
span: Span,
) -> &'tcx [(ty::Predicate<'tcx>, Span)] {
let item_ty =
tcx.mk_opaque(opaque_def_id, InternalSubsts::identity_for_item(tcx, opaque_def_id));
let bounds = tcx.predicates_of(def_id); let bounds = ty::print::with_no_queries(|| {
let predicates = AstConv::compute_bounds(
util::elaborate_predicates(tcx, bounds.predicates.iter().map(|&(pred, _)| pred)); &ItemCtxt::new(tcx, opaque_def_id),
item_ty,
let filtered_predicates = predicates.filter_map(|obligation| { bounds,
let pred = obligation.predicate; SizedByDefault::Yes,
match pred.kind() { span,
ty::PredicateKind::Trait(tr, _) => { )
if let ty::Opaque(opaque_def_id, opaque_substs) = *tr.skip_binder().self_ty().kind()
{
if opaque_def_id == def_id && opaque_substs == substs {
return Some(pred);
}
}
}
ty::PredicateKind::Projection(proj) => {
if let ty::Opaque(opaque_def_id, opaque_substs) =
*proj.skip_binder().projection_ty.self_ty().kind()
{
if opaque_def_id == def_id && opaque_substs == substs {
return Some(pred);
}
}
}
ty::PredicateKind::TypeOutlives(outlives) => {
if let ty::Opaque(opaque_def_id, opaque_substs) = *outlives.skip_binder().0.kind() {
if opaque_def_id == def_id && opaque_substs == substs {
return Some(pred);
}
} else {
// These can come from elaborating other predicates
return None;
}
}
// These can come from elaborating other predicates
ty::PredicateKind::RegionOutlives(_) => return None,
_ => {}
}
tcx.sess.delay_span_bug(
obligation.cause.span(tcx),
&format!("unexpected predicate {:?} on opaque type", pred),
);
None
}); });
let result = tcx.mk_predicates(filtered_predicates); let bounds = bounds.predicates(tcx, item_ty);
debug!("opaque_type_bounds({}) = {:?}", tcx.def_path_str(def_id), result); debug!("opaque_type_bounds({}) = {:?}", tcx.def_path_str(opaque_def_id), bounds);
result
tcx.arena.alloc_slice(&bounds)
}
pub(super) fn explicit_item_bounds(
tcx: TyCtxt<'_>,
def_id: DefId,
) -> &'_ [(ty::Predicate<'_>, Span)] {
let hir_id = tcx.hir().local_def_id_to_hir_id(def_id.expect_local());
match tcx.hir().get(hir_id) {
hir::Node::TraitItem(hir::TraitItem {
kind: hir::TraitItemKind::Type(bounds, _),
span,
..
}) => associated_type_bounds(tcx, def_id, bounds, *span),
hir::Node::Item(hir::Item {
kind: hir::ItemKind::OpaqueTy(hir::OpaqueTy { bounds, .. }),
span,
..
}) => opaque_type_bounds(tcx, def_id, bounds, *span),
_ => bug!("item_bounds called on {:?}", def_id),
}
} }
pub(super) fn item_bounds(tcx: TyCtxt<'_>, def_id: DefId) -> &'_ ty::List<ty::Predicate<'_>> { pub(super) fn item_bounds(tcx: TyCtxt<'_>, def_id: DefId) -> &'_ ty::List<ty::Predicate<'_>> {
match tcx.def_kind(def_id) { tcx.mk_predicates(
DefKind::AssocTy => associated_type_bounds(tcx, def_id), util::elaborate_predicates(
DefKind::OpaqueTy => opaque_type_bounds(tcx, def_id), tcx,
k => bug!("item_bounds called on {}", k.descr(def_id)), tcx.explicit_item_bounds(def_id).iter().map(|&(bound, _span)| bound),
} )
.map(|obligation| obligation.predicate),
)
} }