Split bounds from predicates
This commit is contained in:
parent
a7ead3bd53
commit
d297147e62
@ -937,7 +937,7 @@ impl<'a, 'tcx> CrateMetadataRef<'a> {
|
||||
.tables
|
||||
.inferred_outlives
|
||||
.get(self, item_id)
|
||||
.map(|predicates| predicates.decode((self, tcx)))
|
||||
.map(|predicates| tcx.arena.alloc_from_iter(predicates.decode((self, tcx))))
|
||||
.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))
|
||||
}
|
||||
|
||||
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 {
|
||||
self.root.tables.generics.get(self, item_id).unwrap().decode((self, sess))
|
||||
}
|
||||
|
@ -89,6 +89,7 @@ provide! { <'tcx> tcx, def_id, other, cdata,
|
||||
explicit_predicates_of => { cdata.get_explicit_predicates(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) }
|
||||
explicit_item_bounds => { cdata.get_explicit_item_bounds(def_id.index, tcx) }
|
||||
trait_def => { cdata.get_trait_def(def_id.index, tcx.sess) }
|
||||
adt_def => { cdata.get_adt_def(def_id.index, tcx) }
|
||||
adt_destructor => {
|
||||
|
@ -965,6 +965,14 @@ impl EncodeContext<'a, 'tcx> {
|
||||
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) {
|
||||
debug!("EncodeContext::encode_info_for_trait_item({:?})", def_id);
|
||||
let tcx = self.tcx;
|
||||
@ -1017,7 +1025,10 @@ impl EncodeContext<'a, 'tcx> {
|
||||
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.span[def_id] <- ast_item.span);
|
||||
|
@ -295,13 +295,11 @@ define_tables! {
|
||||
generics: Table<DefIndex, Lazy<ty::Generics>>,
|
||||
explicit_predicates: Table<DefIndex, Lazy!(ty::GenericPredicates<'tcx>)>,
|
||||
expn_that_defined: Table<DefIndex, Lazy<ExpnId>>,
|
||||
// FIXME(eddyb) this would ideally be `Lazy<[...]>` but `ty::Predicate`
|
||||
// doesn't handle shorthands in its own (de)serialization impls,
|
||||
// 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)])>,
|
||||
// As an optimization, a missing entry indicates an empty `&[]`.
|
||||
inferred_outlives: Table<DefIndex, Lazy!([(ty::Predicate<'tcx>, Span)])>,
|
||||
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>)>,
|
||||
promoted_mir: Table<DefIndex, Lazy!(IndexVec<mir::Promoted, mir::Body<'tcx>>)>,
|
||||
mir_abstract_consts: Table<DefIndex, Lazy!(&'tcx [mir::abstract_const::Node<'tcx>])>,
|
||||
|
@ -169,8 +169,13 @@ rustc_queries! {
|
||||
/// ^^^^^^^^^^^^^^^
|
||||
///
|
||||
/// `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>> {
|
||||
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>> {
|
||||
|
@ -607,12 +607,12 @@ pub trait PrettyPrinter<'tcx>:
|
||||
}
|
||||
// Grab the "TraitA + TraitB" from `impl TraitA + TraitB`,
|
||||
// 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 is_sized = false;
|
||||
p!("impl");
|
||||
for predicate in bounds.predicates {
|
||||
for predicate in bounds {
|
||||
// Note: We can't use `to_opt_poly_trait_ref` here as `predicate`
|
||||
// may contain unbound variables. We therefore do this manually.
|
||||
//
|
||||
|
@ -10,7 +10,7 @@ use rustc_infer::infer::free_regions::FreeRegionRelations;
|
||||
use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
|
||||
use rustc_infer::infer::{self, InferCtxt, InferOk};
|
||||
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_session::config::nightly_options;
|
||||
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 opaque_defn.has_required_region_bounds {
|
||||
let predicates_of = tcx.predicates_of(def_id);
|
||||
debug!("constrain_opaque_type: predicates: {:#?}", predicates_of,);
|
||||
let bounds = predicates_of.instantiate(tcx, opaque_defn.substs);
|
||||
let bounds = tcx.explicit_item_bounds(def_id);
|
||||
debug!("constrain_opaque_type: predicates: {:#?}", bounds);
|
||||
let bounds: Vec<_> =
|
||||
bounds.iter().map(|(bound, _)| bound.subst(tcx, opaque_defn.substs)).collect();
|
||||
debug!("constrain_opaque_type: bounds={:#?}", bounds);
|
||||
let opaque_type = tcx.mk_opaque(def_id, opaque_defn.substs);
|
||||
|
||||
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());
|
||||
|
||||
for required_region in required_region_bounds {
|
||||
@ -1112,9 +1113,10 @@ impl<'a, 'tcx> Instantiator<'a, 'tcx> {
|
||||
let ty_var = infcx
|
||||
.next_ty_var(TypeVariableOrigin { kind: TypeVariableOriginKind::TypeInference, span });
|
||||
|
||||
let predicates_of = tcx.predicates_of(def_id);
|
||||
debug!("instantiate_opaque_types: predicates={:#?}", predicates_of,);
|
||||
let bounds = predicates_of.instantiate(tcx, substs);
|
||||
let item_bounds = tcx.explicit_item_bounds(def_id);
|
||||
debug!("instantiate_opaque_types: bounds={:#?}", item_bounds);
|
||||
let bounds: Vec<_> =
|
||||
item_bounds.iter().map(|(bound, _)| bound.subst(tcx, substs)).collect();
|
||||
|
||||
let param_env = tcx.param_env(def_id);
|
||||
let InferOk { value: bounds, obligations } =
|
||||
@ -1123,8 +1125,7 @@ impl<'a, 'tcx> Instantiator<'a, 'tcx> {
|
||||
|
||||
debug!("instantiate_opaque_types: bounds={:?}", bounds);
|
||||
|
||||
let required_region_bounds =
|
||||
required_region_bounds(tcx, ty, bounds.predicates.iter().cloned());
|
||||
let required_region_bounds = required_region_bounds(tcx, ty, bounds.iter().copied());
|
||||
debug!("instantiate_opaque_types: required_region_bounds={:?}", required_region_bounds);
|
||||
|
||||
// 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);
|
||||
|
||||
for predicate in &bounds.predicates {
|
||||
for predicate in &bounds {
|
||||
if let ty::PredicateAtom::Projection(projection) = predicate.skip_binders() {
|
||||
if projection.ty.references_error() {
|
||||
// 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());
|
||||
for predicate in bounds.predicates {
|
||||
self.obligations.reserve(bounds.len());
|
||||
for predicate in bounds {
|
||||
// Change the predicate to refer to the type variable,
|
||||
// which will be the concrete type instead of the opaque type.
|
||||
// This also instantiates nested instances of `impl Trait`.
|
||||
|
@ -71,12 +71,8 @@ impl<'tcx> Bounds<'tcx> {
|
||||
self.region_bounds
|
||||
.iter()
|
||||
.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);
|
||||
(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)| {
|
||||
let predicate = bound_trait_ref.with_constness(constness).to_predicate(tcx);
|
||||
|
@ -70,6 +70,7 @@ pub fn provide(providers: &mut Providers) {
|
||||
opt_const_param_of: type_of::opt_const_param_of,
|
||||
type_of: type_of::type_of,
|
||||
item_bounds: item_bounds::item_bounds,
|
||||
explicit_item_bounds: item_bounds::explicit_item_bounds,
|
||||
generics_of,
|
||||
predicates_of,
|
||||
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_default_impl_trait = None;
|
||||
let mut is_trait_associated_type = None;
|
||||
|
||||
let icx = ItemCtxt::new(tcx, def_id);
|
||||
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 ast_generics = match node {
|
||||
Node::TraitItem(item) => {
|
||||
if let hir::TraitItemKind::Type(bounds, _) = item.kind {
|
||||
is_trait_associated_type = Some((bounds, item.span));
|
||||
}
|
||||
&item.generics
|
||||
}
|
||||
Node::TraitItem(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::Union(_, ref generics) => generics,
|
||||
|
||||
ItemKind::Trait(_, _, ref generics, .., items) => {
|
||||
is_trait = Some((ty::TraitRef::identity(tcx, def_id), items));
|
||||
ItemKind::Trait(_, _, ref generics, ..) => {
|
||||
is_trait = Some(ty::TraitRef::identity(tcx, def_id));
|
||||
generics
|
||||
}
|
||||
ItemKind::TraitAlias(ref generics, _) => {
|
||||
is_trait = Some((ty::TraitRef::identity(tcx, def_id), &[]));
|
||||
is_trait = Some(ty::TraitRef::identity(tcx, def_id));
|
||||
generics
|
||||
}
|
||||
ItemKind::OpaqueTy(OpaqueTy {
|
||||
ref bounds,
|
||||
bounds: _,
|
||||
impl_trait_fn,
|
||||
ref generics,
|
||||
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() {
|
||||
// opaque types
|
||||
return ty::GenericPredicates {
|
||||
parent: None,
|
||||
predicates: tcx.arena.alloc_from_iter(bounds_predicates),
|
||||
};
|
||||
// return-position impl trait
|
||||
// TODO: Investigate why we have this special case?
|
||||
return ty::GenericPredicates { parent: None, predicates: &[] };
|
||||
} else {
|
||||
// named opaque types
|
||||
predicates.extend(bounds_predicates);
|
||||
// type alias impl trait
|
||||
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
|
||||
// on a trait we need to add in the supertrait bounds and bounds found on
|
||||
// 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());
|
||||
}
|
||||
|
||||
@ -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 {
|
||||
predicates.extend(const_evaluatable_predicates_of(tcx, def_id.expect_local()));
|
||||
}
|
||||
@ -2155,55 +2114,6 @@ fn projection_ty_from_predicates(
|
||||
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
|
||||
/// predicates that apply to the self type. A vector is returned
|
||||
/// because this can be anywhere from zero predicates (`T: ?Sized` adds no
|
||||
|
@ -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_middle::ty::subst::InternalSubsts;
|
||||
use rustc_middle::ty::{self, TyCtxt};
|
||||
use rustc_span::def_id::DefId;
|
||||
use rustc_span::Span;
|
||||
|
||||
/// For associated types we allow bounds written on the associated type
|
||||
/// (`type X: Trait`) to be used as candidates. We also allow the same bounds
|
||||
/// when desugared as bounds on the trait `where Self::X: Trait`.
|
||||
/// For associated types we include both bounds written on the type
|
||||
/// (`type X: Trait`) and predicates from the trait: `where Self::X: Trait`.
|
||||
///
|
||||
/// Note that this filtering is done with the items identity substs to
|
||||
/// 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
|
||||
/// `hr-associated-type-bound-1.rs`.
|
||||
fn associated_type_bounds(
|
||||
tcx: TyCtxt<'_>,
|
||||
fn associated_type_bounds<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
assoc_item_def_id: DefId,
|
||||
) -> &'_ ty::List<ty::Predicate<'_>> {
|
||||
let generic_trait_bounds = tcx.predicates_of(assoc_item_def_id);
|
||||
// We include predicates from the trait as well to handle
|
||||
// `where Self::X: Trait`.
|
||||
let item_bounds = generic_trait_bounds.instantiate_identity(tcx);
|
||||
let item_predicates = util::elaborate_predicates(tcx, item_bounds.predicates.into_iter());
|
||||
bounds: &'tcx [hir::GenericBound<'tcx>],
|
||||
span: Span,
|
||||
) -> &'tcx [(ty::Predicate<'tcx>, Span)] {
|
||||
let item_ty = tcx.mk_projection(
|
||||
assoc_item_def_id,
|
||||
InternalSubsts::identity_for_item(tcx, assoc_item_def_id),
|
||||
);
|
||||
|
||||
let assoc_item_ty = ty::ProjectionTy {
|
||||
item_def_id: assoc_item_def_id,
|
||||
substs: InternalSubsts::identity_for_item(tcx, assoc_item_def_id),
|
||||
};
|
||||
let bounds = AstConv::compute_bounds(
|
||||
&ItemCtxt::new(tcx, assoc_item_def_id),
|
||||
item_ty,
|
||||
bounds,
|
||||
SizedByDefault::Yes,
|
||||
span,
|
||||
);
|
||||
|
||||
let predicates = item_predicates.filter_map(|obligation| {
|
||||
let pred = obligation.predicate;
|
||||
match pred.kind() {
|
||||
ty::PredicateKind::Trait(tr, _) => {
|
||||
if let ty::Projection(p) = *tr.skip_binder().self_ty().kind() {
|
||||
if p == assoc_item_ty {
|
||||
return Some(pred);
|
||||
}
|
||||
}
|
||||
}
|
||||
let trait_def_id = tcx.associated_item(assoc_item_def_id).container.id();
|
||||
let trait_predicates = tcx.predicates_of(trait_def_id);
|
||||
|
||||
let bounds_from_parent =
|
||||
trait_predicates.predicates.iter().copied().filter(|(pred, _)| match pred.kind() {
|
||||
ty::PredicateKind::Trait(tr, _) => tr.skip_binder().self_ty() == item_ty,
|
||||
ty::PredicateKind::Projection(proj) => {
|
||||
if let ty::Projection(p) = *proj.skip_binder().projection_ty.self_ty().kind() {
|
||||
if p == assoc_item_ty {
|
||||
return Some(pred);
|
||||
}
|
||||
}
|
||||
proj.skip_binder().projection_ty.self_ty() == item_ty
|
||||
}
|
||||
ty::PredicateKind::TypeOutlives(outlives) => {
|
||||
if let ty::Projection(p) = *outlives.skip_binder().0.kind() {
|
||||
if p == assoc_item_ty {
|
||||
return Some(pred);
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
None
|
||||
});
|
||||
ty::PredicateKind::TypeOutlives(outlives) => outlives.skip_binder().0 == item_ty,
|
||||
_ => false,
|
||||
});
|
||||
|
||||
let result = tcx.mk_predicates(predicates);
|
||||
debug!("associated_type_bounds({}) = {:?}", tcx.def_path_str(assoc_item_def_id), result);
|
||||
result
|
||||
let all_bounds = tcx
|
||||
.arena
|
||||
.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
|
||||
/// predicates on an opaque type (excluding those it inherits from its parent
|
||||
/// item) should be of the form we're expecting.
|
||||
fn opaque_type_bounds(tcx: TyCtxt<'_>, def_id: DefId) -> &'_ ty::List<ty::Predicate<'_>> {
|
||||
let substs = InternalSubsts::identity_for_item(tcx, def_id);
|
||||
/// Opaque types don't inherit bounds from their parent: for return position
|
||||
/// impl trait it isn't possible to write a suitable predicate on the
|
||||
/// containing function and for type-alias impl trait we don't have a backwards
|
||||
/// compatibility issue.
|
||||
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 predicates =
|
||||
util::elaborate_predicates(tcx, bounds.predicates.iter().map(|&(pred, _)| pred));
|
||||
|
||||
let filtered_predicates = predicates.filter_map(|obligation| {
|
||||
let pred = obligation.predicate;
|
||||
match pred.kind() {
|
||||
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 bounds = ty::print::with_no_queries(|| {
|
||||
AstConv::compute_bounds(
|
||||
&ItemCtxt::new(tcx, opaque_def_id),
|
||||
item_ty,
|
||||
bounds,
|
||||
SizedByDefault::Yes,
|
||||
span,
|
||||
)
|
||||
});
|
||||
|
||||
let result = tcx.mk_predicates(filtered_predicates);
|
||||
debug!("opaque_type_bounds({}) = {:?}", tcx.def_path_str(def_id), result);
|
||||
result
|
||||
let bounds = bounds.predicates(tcx, item_ty);
|
||||
debug!("opaque_type_bounds({}) = {:?}", tcx.def_path_str(opaque_def_id), bounds);
|
||||
|
||||
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<'_>> {
|
||||
match tcx.def_kind(def_id) {
|
||||
DefKind::AssocTy => associated_type_bounds(tcx, def_id),
|
||||
DefKind::OpaqueTy => opaque_type_bounds(tcx, def_id),
|
||||
k => bug!("item_bounds called on {}", k.descr(def_id)),
|
||||
}
|
||||
tcx.mk_predicates(
|
||||
util::elaborate_predicates(
|
||||
tcx,
|
||||
tcx.explicit_item_bounds(def_id).iter().map(|&(bound, _span)| bound),
|
||||
)
|
||||
.map(|obligation| obligation.predicate),
|
||||
)
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user