introduce predicates_defined_on for traits

This new query returns only the predicates *directly defined* on an
item (in contrast to the more common `predicates_of`, which returns
the predicates that must be proven to reference an item). These two
sets are almost always identical except for traits, where
`predicates_of` includes an artificial `Self: Trait<...>` predicate
(basically saying that you cannot use a trait item without proving
that the trait is implemented for the type parameters).

This new query is only used in chalk lowering, where this artificial
`Self: Trait` predicate is problematic. We encode it in metadata but
only where needed since it is kind of repetitive with existing
information.

Co-authored-by: Tyler Mandry <tmandry@gmail.com>
This commit is contained in:
Niko Matsakis 2018-07-02 10:35:30 -04:00
parent 327093007a
commit 90ea49b891
10 changed files with 109 additions and 21 deletions

View File

@ -504,6 +504,7 @@ define_dep_nodes!( <'tcx>
[] GenericsOfItem(DefId),
[] PredicatesOfItem(DefId),
[] ExplicitPredicatesOfItem(DefId),
[] PredicatesDefinedOnItem(DefId),
[] InferredOutlivesOf(DefId),
[] InferredOutlivesCrate(CrateNum),
[] SuperPredicatesOfItem(DefId),

View File

@ -101,11 +101,39 @@ define_queries! { <'tcx>
[] fn type_of: TypeOfItem(DefId) -> Ty<'tcx>,
/// Maps from the def-id of an item (trait/struct/enum/fn) to its
/// associated generics and predicates.
/// associated generics.
[] fn generics_of: GenericsOfItem(DefId) -> &'tcx ty::Generics,
/// Maps from the def-id of an item (trait/struct/enum/fn) to the
/// predicates (where clauses) that must be proven true in order
/// to reference it. This is almost always the "predicates query"
/// that you want.
///
/// `predicates_of` builds on `predicates_defined_on` -- in fact,
/// it is almost always the same as that query, except for the
/// case of traits. For traits, `predicates_of` contains
/// an additional `Self: Trait<...>` predicate that users don't
/// actually write. This reflects the fact that to invoke the
/// trait (e.g., via `Default::default`) you must supply types
/// that actually implement the trait. (However, this extra
/// predicate gets in the way of some checks, which are intended
/// to operate over only the actual where-clauses written by the
/// user.)
[] fn predicates_of: PredicatesOfItem(DefId) -> ty::GenericPredicates<'tcx>,
/// Maps from the def-id of an item (trait/struct/enum/fn) to the
/// predicates (where clauses) directly defined on it. This is
/// equal to the `explicit_predicates_of` predicates plus the
/// `inferred_outlives_of` predicates.
[] fn predicates_defined_on: PredicatesDefinedOnItem(DefId) -> ty::GenericPredicates<'tcx>,
/// Returns the predicates written explicit by the user.
[] fn explicit_predicates_of: ExplicitPredicatesOfItem(DefId) -> ty::GenericPredicates<'tcx>,
/// Returns the inferred outlives predicates (e.g., for `struct
/// Foo<'a, T> { x: &'a T }`, this would return `T: 'a`).
[] fn inferred_outlives_of: InferredOutlivesOf(DefId) -> Lrc<Vec<ty::Predicate<'tcx>>>,
/// Maps from the def-id of a trait to the list of
/// super-predicates. This is a subset of the full list of
/// predicates. We store these in a separate map because we must
@ -141,9 +169,6 @@ define_queries! { <'tcx>
/// (inferred) variance.
[] fn variances_of: ItemVariances(DefId) -> Lrc<Vec<ty::Variance>>,
/// Maps from def-id of a type to its (inferred) outlives.
[] fn inferred_outlives_of: InferredOutlivesOf(DefId) -> Lrc<Vec<ty::Predicate<'tcx>>>,
/// Maps from def-id of a type to its (inferred) outlives.
[] fn inferred_outlives_crate: InferredOutlivesCrate(CrateNum)
-> Lrc<ty::CratePredicatesMap<'tcx>>,

View File

@ -1074,6 +1074,7 @@ pub fn force_from_dep_node<'a, 'gcx, 'lcx>(tcx: TyCtxt<'a, 'gcx, 'lcx>,
DepKind::TypeOfItem => { force!(type_of, def_id!()); }
DepKind::GenericsOfItem => { force!(generics_of, def_id!()); }
DepKind::PredicatesOfItem => { force!(predicates_of, def_id!()); }
DepKind::PredicatesDefinedOnItem => { force!(predicates_defined_on, def_id!()); }
DepKind::ExplicitPredicatesOfItem => { force!(explicit_predicates_of, def_id!()); }
DepKind::InferredOutlivesOf => { force!(inferred_outlives_of, def_id!()); }
DepKind::InferredOutlivesCrate => { force!(inferred_outlives_crate, LOCAL_CRATE); }

View File

@ -107,6 +107,7 @@ provide! { <'tcx> tcx, def_id, other, cdata,
tcx.alloc_generics(cdata.get_generics(def_id.index, tcx.sess))
}
predicates_of => { cdata.get_predicates(def_id.index, tcx) }
predicates_defined_on => { cdata.get_predicates_defined_on(def_id.index, tcx) }
super_predicates_of => { cdata.get_super_predicates(def_id.index, tcx) }
trait_def => {
tcx.alloc_trait_def(cdata.get_trait_def(def_id.index, tcx.sess))

View File

@ -563,6 +563,13 @@ impl<'a, 'tcx> CrateMetadata {
self.entry(item_id).predicates.unwrap().decode((self, tcx))
}
pub fn get_predicates_defined_on(&self,
item_id: DefIndex,
tcx: TyCtxt<'a, 'tcx, 'tcx>)
-> ty::GenericPredicates<'tcx> {
self.entry(item_id).predicates_defined_on.unwrap().decode((self, tcx))
}
pub fn get_super_predicates(&self,
item_id: DefIndex,
tcx: TyCtxt<'a, 'tcx, 'tcx>)

View File

@ -627,6 +627,7 @@ impl<'a, 'b: 'a, 'tcx: 'b> IsolatedEncoder<'a, 'b, 'tcx> {
},
generics: Some(self.encode_generics(def_id)),
predicates: Some(self.encode_predicates(def_id)),
predicates_defined_on: None,
mir: self.encode_optimized_mir(def_id),
}
@ -664,6 +665,7 @@ impl<'a, 'b: 'a, 'tcx: 'b> IsolatedEncoder<'a, 'b, 'tcx> {
variances: LazySeq::empty(),
generics: None,
predicates: None,
predicates_defined_on: None,
mir: None
}
@ -704,6 +706,7 @@ impl<'a, 'b: 'a, 'tcx: 'b> IsolatedEncoder<'a, 'b, 'tcx> {
variances: LazySeq::empty(),
generics: Some(self.encode_generics(def_id)),
predicates: Some(self.encode_predicates(def_id)),
predicates_defined_on: None,
mir: None,
}
@ -761,6 +764,7 @@ impl<'a, 'b: 'a, 'tcx: 'b> IsolatedEncoder<'a, 'b, 'tcx> {
},
generics: Some(self.encode_generics(def_id)),
predicates: Some(self.encode_predicates(def_id)),
predicates_defined_on: None,
mir: self.encode_optimized_mir(def_id),
}
@ -778,6 +782,12 @@ impl<'a, 'b: 'a, 'tcx: 'b> IsolatedEncoder<'a, 'b, 'tcx> {
self.lazy(&tcx.predicates_of(def_id))
}
fn encode_predicates_defined_on(&mut self, def_id: DefId) -> Lazy<ty::GenericPredicates<'tcx>> {
debug!("IsolatedEncoder::encode_predicates_defined_on({:?})", def_id);
let tcx = self.tcx;
self.lazy(&tcx.predicates_defined_on(def_id))
}
fn encode_info_for_trait_item(&mut self, def_id: DefId) -> Entry<'tcx> {
debug!("IsolatedEncoder::encode_info_for_trait_item({:?})", def_id);
let tcx = self.tcx;
@ -867,6 +877,7 @@ impl<'a, 'b: 'a, 'tcx: 'b> IsolatedEncoder<'a, 'b, 'tcx> {
},
generics: Some(self.encode_generics(def_id)),
predicates: Some(self.encode_predicates(def_id)),
predicates_defined_on: None,
mir: self.encode_optimized_mir(def_id),
}
@ -963,6 +974,7 @@ impl<'a, 'b: 'a, 'tcx: 'b> IsolatedEncoder<'a, 'b, 'tcx> {
},
generics: Some(self.encode_generics(def_id)),
predicates: Some(self.encode_predicates(def_id)),
predicates_defined_on: None,
mir: if mir { self.encode_optimized_mir(def_id) } else { None },
}
@ -1226,6 +1238,16 @@ impl<'a, 'b: 'a, 'tcx: 'b> IsolatedEncoder<'a, 'b, 'tcx> {
_ => None,
},
// The only time that `predicates_defined_on` is used (on
// an external item) is for traits, during chalk lowering,
// so only encode it in that case as an efficiency
// hack. (No reason not to expand it in the future if
// necessary.)
predicates_defined_on: match item.node {
hir::ItemTrait(..) => Some(self.encode_predicates_defined_on(def_id)),
_ => None, // not *wrong* for other kinds of items, but not needed
},
mir: match item.node {
hir::ItemStatic(..) => {
self.encode_optimized_mir(def_id)
@ -1276,6 +1298,7 @@ impl<'a, 'b: 'a, 'tcx: 'b> IsolatedEncoder<'a, 'b, 'tcx> {
variances: LazySeq::empty(),
generics: None,
predicates: None,
predicates_defined_on: None,
mir: None,
}
}
@ -1303,6 +1326,7 @@ impl<'a, 'b: 'a, 'tcx: 'b> IsolatedEncoder<'a, 'b, 'tcx> {
variances: LazySeq::empty(),
generics: None,
predicates: None,
predicates_defined_on: None,
mir: None,
}
@ -1347,6 +1371,7 @@ impl<'a, 'b: 'a, 'tcx: 'b> IsolatedEncoder<'a, 'b, 'tcx> {
variances: LazySeq::empty(),
generics: Some(self.encode_generics(def_id)),
predicates: None,
predicates_defined_on: None,
mir: self.encode_optimized_mir(def_id),
}
@ -1374,6 +1399,7 @@ impl<'a, 'b: 'a, 'tcx: 'b> IsolatedEncoder<'a, 'b, 'tcx> {
variances: LazySeq::empty(),
generics: Some(self.encode_generics(def_id)),
predicates: Some(self.encode_predicates(def_id)),
predicates_defined_on: None,
mir: self.encode_optimized_mir(def_id),
}
@ -1575,6 +1601,7 @@ impl<'a, 'b: 'a, 'tcx: 'b> IsolatedEncoder<'a, 'b, 'tcx> {
},
generics: Some(self.encode_generics(def_id)),
predicates: Some(self.encode_predicates(def_id)),
predicates_defined_on: None,
mir: None,
}

View File

@ -273,6 +273,7 @@ pub struct Entry<'tcx> {
pub variances: LazySeq<ty::Variance>,
pub generics: Option<Lazy<ty::Generics>>,
pub predicates: Option<Lazy<ty::GenericPredicates<'tcx>>>,
pub predicates_defined_on: Option<Lazy<ty::GenericPredicates<'tcx>>>,
pub mir: Option<Lazy<mir::Mir<'tcx>>>,
}
@ -290,6 +291,7 @@ impl_stable_hash_for!(struct Entry<'tcx> {
variances,
generics,
predicates,
predicates_defined_on,
mir
});

View File

@ -252,10 +252,8 @@ fn program_clauses_for_trait<'a, 'tcx>(
// ```
// `FromEnv(WC) :- FromEnv(Self: Trait<P1..Pn>)`, for each where clause WC
// FIXME: Remove the [1..] slice; this is a hack because the query
// predicates_of currently includes the trait itself (`Self: Trait<P1..Pn>`).
let where_clauses = &tcx.predicates_of(def_id).predicates;
let implied_bound_clauses = where_clauses[1..]
let where_clauses = &tcx.predicates_defined_on(def_id).predicates;
let implied_bound_clauses = where_clauses
.into_iter()
.map(|wc| wc.lower())

View File

@ -67,6 +67,7 @@ pub fn provide(providers: &mut Providers) {
type_of,
generics_of,
predicates_of,
predicates_defined_on,
explicit_predicates_of,
super_predicates_of,
type_param_predicates,
@ -1309,10 +1310,10 @@ fn early_bound_lifetimes_from_generics<'a, 'tcx>(
})
}
fn predicates_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
def_id: DefId)
-> ty::GenericPredicates<'tcx> {
let explicit = explicit_predicates_of(tcx, def_id);
fn predicates_defined_on<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
def_id: DefId)
-> ty::GenericPredicates<'tcx> {
let explicit = tcx.explicit_predicates_of(def_id);
let predicates = if tcx.sess.features_untracked().infer_outlives_requirements {
[&explicit.predicates[..], &tcx.inferred_outlives_of(def_id)[..]].concat()
} else { explicit.predicates };
@ -1323,9 +1324,35 @@ fn predicates_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
}
}
pub fn explicit_predicates_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
fn predicates_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
def_id: DefId)
-> ty::GenericPredicates<'tcx> {
let ty::GenericPredicates { parent, mut predicates } =
tcx.predicates_defined_on(def_id);
if tcx.is_trait(def_id) {
// For traits, add `Self: Trait` predicate. This is
// not part of the predicates that a user writes, but it
// is something that one must prove in order to invoke a
// method or project an associated type.
//
// In the chalk setup, this predicate is not part of the
// "predicates" for a trait item. But it is useful in
// rustc because if you directly (e.g.) invoke a trait
// method like `Trait::method(...)`, you must naturally
// prove that the trait applies to the types that were
// used, and adding the predicate into this list ensures
// that this is done.
predicates.push(ty::TraitRef::identity(tcx, def_id).to_predicate());
}
ty::GenericPredicates { parent, predicates }
}
fn explicit_predicates_of<'a, 'tcx>(
tcx: TyCtxt<'a, 'tcx, 'tcx>,
def_id: DefId,
) -> ty::GenericPredicates<'tcx> {
use rustc::hir::map::*;
use rustc::hir::*;
@ -1340,7 +1367,10 @@ pub fn explicit_predicates_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
let icx = ItemCtxt::new(tcx, def_id);
let no_generics = hir::Generics::empty();
let ast_generics = match node {
NodeTraitItem(item) => &item.generics,
NodeTraitItem(item) => {
&item.generics
}
NodeImplItem(item) => &item.generics,
NodeItem(item) => {
@ -1405,12 +1435,8 @@ pub fn explicit_predicates_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
// 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 = tcx.super_predicates_of(def_id).predicates;
// Add in a predicate that `Self:Trait` (where `Trait` is the
// current trait). This is needed for builtin bounds.
predicates.push(trait_ref.to_poly_trait_ref().to_predicate());
}
// In default impls, we can assume that the self type implements

View File

@ -4,7 +4,7 @@ error: program clause dump
LL | #[rustc_dump_program_clauses] //~ ERROR program clause dump
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: FromEnv(Self: Bar) :- FromEnv(Self: Bar).
= note: FromEnv(Self: Foo) :- FromEnv(Self: Bar).
= note: FromEnv(Self: Foo) :- FromEnv(Self: Bar).
= note: Implemented(Self: Bar) :- FromEnv(Self: Bar).
@ -14,7 +14,7 @@ error: program clause dump
LL | #[rustc_dump_env_program_clauses] //~ ERROR program clause dump
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: FromEnv(Self: Bar) :- FromEnv(Self: Bar).
= note: FromEnv(Self: Foo) :- FromEnv(Self: Bar).
= note: FromEnv(Self: Foo) :- FromEnv(Self: Bar).
= note: Implemented(Self: Bar) :- FromEnv(Self: Bar).
= note: Implemented(Self: Foo) :- FromEnv(Self: Foo).