Skip to content

Commit

Permalink
Auto merge of #51895 - nikomatsakis:move-self-trait-predicate-to-item…
Browse files Browse the repository at this point in the history
…s, r=scalexm

Move self trait predicate to items

This is a "reimagination" of @tmandry's PR #50183. The main effect is described in this comment from one of the commits:

---

Before we had the following results for `predicates_of`:

```rust
trait Foo { // predicates_of: Self: Foo
  fn bar(); // predicates_of: Self: Foo (inherited from trait)
}
```

Now we have removed the `Self: Foo` from the trait. However, we still
add it to the trait ITEM. This is because when people do things like
`<T as Foo>::bar()`, they still need to prove that `T: Foo`, and
having it in the `predicates_of` seems to be the cleanest way to
ensure that happens right now (otherwise, we'd need special case code
in various places):

```rust
trait Foo { // predicates_of: []
  fn bar(); // predicates_of: Self: Foo
}
```

However, we sometimes want to get the list of *just* the predicates
truly defined on a trait item (e.g., for chalk, but also for a few
other bits of code). For that, we define `predicates_defined_on`,
which does not contain the `Self: Foo` predicate yet, and we plumb
that through metadata and so forth.

---

I'm assigning @eddyb as the main reviewer, but I thought I might delegate to scalexm for this one in any case. I also want to post an alternative that I'll leave in the comments; it occurred to me as I was writing. =)

r? @eddyb
cc @scalexm @tmandry @leodasvacas
  • Loading branch information
bors committed Jul 4, 2018
2 parents a739c51 + 90ea49b commit 8dd715e
Show file tree
Hide file tree
Showing 17 changed files with 205 additions and 67 deletions.
1 change: 1 addition & 0 deletions src/librustc/dep_graph/dep_node.rs
Original file line number Diff line number Diff line change
Expand Up @@ -504,6 +504,7 @@ define_dep_nodes!( <'tcx>
[] GenericsOfItem(DefId),
[] PredicatesOfItem(DefId),
[] ExplicitPredicatesOfItem(DefId),
[] PredicatesDefinedOnItem(DefId),
[] InferredOutlivesOf(DefId),
[] InferredOutlivesCrate(CrateNum),
[] SuperPredicatesOfItem(DefId),
Expand Down
13 changes: 4 additions & 9 deletions src/librustc/traits/object_safety.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@ use hir::def_id::DefId;
use lint;
use traits;
use ty::{self, Ty, TyCtxt, TypeFoldable};
use ty::subst::Substs;
use ty::util::ExplicitSelf;
use std::borrow::Cow;
use syntax::ast;
Expand Down Expand Up @@ -173,10 +172,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
trait_def_id: DefId,
supertraits_only: bool) -> bool
{
let trait_ref = ty::Binder::dummy(ty::TraitRef {
def_id: trait_def_id,
substs: Substs::identity_for_item(self, trait_def_id)
});
let trait_ref = ty::Binder::dummy(ty::TraitRef::identity(self, trait_def_id));
let predicates = if supertraits_only {
self.super_predicates_of(trait_def_id)
} else {
Expand Down Expand Up @@ -391,10 +387,9 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {

// Compute supertraits of current trait lazily.
if supertraits.is_none() {
let trait_ref = ty::Binder::bind(ty::TraitRef {
def_id: trait_def_id,
substs: Substs::identity_for_item(self, trait_def_id)
});
let trait_ref = ty::Binder::bind(
ty::TraitRef::identity(self, trait_def_id),
);
supertraits = Some(traits::supertraits(self, trait_ref).collect());
}

Expand Down
5 changes: 5 additions & 0 deletions src/librustc/traits/select.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1237,6 +1237,11 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
let mut candidates: Vec<EvaluatedCandidate> =
candidates?.into_iter().filter_map(|c| c).collect();

debug!("winnowed to {} candidates for {:?}: {:?}",
candidates.len(),
stack,
candidates);

// If there are STILL multiple candidate, we can further
// reduce the list by dropping duplicates -- including
// resolving specializations.
Expand Down
4 changes: 2 additions & 2 deletions src/librustc/ty/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2862,8 +2862,8 @@ fn param_env<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
}
// Compute the bounds on Self and the type parameters.

let bounds = tcx.predicates_of(def_id).instantiate_identity(tcx);
let predicates = bounds.predicates;
let InstantiatedPredicates { predicates } =
tcx.predicates_of(def_id).instantiate_identity(tcx);

// Finally, we have to normalize the bounds in the environment, in
// case they contain any associated type projections. This process
Expand Down
33 changes: 29 additions & 4 deletions src/librustc/ty/query/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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>>,
Expand Down
1 change: 1 addition & 0 deletions src/librustc/ty/query/plumbing.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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); }
Expand Down
9 changes: 9 additions & 0 deletions src/librustc/ty/sty.rs
Original file line number Diff line number Diff line change
Expand Up @@ -614,6 +614,15 @@ impl<'tcx> TraitRef<'tcx> {
TraitRef { def_id: def_id, substs: substs }
}

/// Returns a TraitRef of the form `P0: Foo<P1..Pn>` where `Pi`
/// are the parameters defined on trait.
pub fn identity<'a, 'gcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>, def_id: DefId) -> TraitRef<'tcx> {
TraitRef {
def_id,
substs: Substs::identity_for_item(tcx, def_id),
}
}

pub fn self_ty(&self) -> Ty<'tcx> {
self.substs.type_at(0)
}
Expand Down
15 changes: 15 additions & 0 deletions src/librustc/ty/util.rs
Original file line number Diff line number Diff line change
Expand Up @@ -518,10 +518,25 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
result
}

/// True if `def_id` refers to a closure (e.g., `|x| x * 2`). Note
/// that closures have a def-id, but the closure *expression* also
/// has a `HirId` that is located within the context where the
/// closure appears (and, sadly, a corresponding `NodeId`, since
/// those are not yet phased out). The parent of the closure's
/// def-id will also be the context where it appears.
pub fn is_closure(self, def_id: DefId) -> bool {
self.def_key(def_id).disambiguated_data.data == DefPathData::ClosureExpr
}

/// True if `def_id` refers to a trait (e.g., `trait Foo { ... }`).
pub fn is_trait(self, def_id: DefId) -> bool {
if let DefPathData::Trait(_) = self.def_key(def_id).disambiguated_data.data {
true
} else {
false
}
}

/// True if this def-id refers to the implicit constructor for
/// a tuple struct like `struct Foo(u32)`.
pub fn is_struct_constructor(self, def_id: DefId) -> bool {
Expand Down
1 change: 1 addition & 0 deletions src/librustc_metadata/cstore_impl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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))
Expand Down
7 changes: 7 additions & 0 deletions src/librustc_metadata/decoder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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>)
Expand Down
27 changes: 27 additions & 0 deletions src/librustc_metadata/encoder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -629,6 +629,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),
}
Expand Down Expand Up @@ -666,6 +667,7 @@ impl<'a, 'b: 'a, 'tcx: 'b> IsolatedEncoder<'a, 'b, 'tcx> {
variances: LazySeq::empty(),
generics: None,
predicates: None,
predicates_defined_on: None,

mir: None
}
Expand Down Expand Up @@ -706,6 +708,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,
}
Expand Down Expand Up @@ -763,6 +766,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),
}
Expand All @@ -780,6 +784,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;
Expand Down Expand Up @@ -869,6 +879,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),
}
Expand Down Expand Up @@ -965,6 +976,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 },
}
Expand Down Expand Up @@ -1228,6 +1240,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)
Expand Down Expand Up @@ -1278,6 +1300,7 @@ impl<'a, 'b: 'a, 'tcx: 'b> IsolatedEncoder<'a, 'b, 'tcx> {
variances: LazySeq::empty(),
generics: None,
predicates: None,
predicates_defined_on: None,
mir: None,
}
}
Expand Down Expand Up @@ -1305,6 +1328,7 @@ impl<'a, 'b: 'a, 'tcx: 'b> IsolatedEncoder<'a, 'b, 'tcx> {
variances: LazySeq::empty(),
generics: None,
predicates: None,
predicates_defined_on: None,

mir: None,
}
Expand Down Expand Up @@ -1349,6 +1373,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),
}
Expand Down Expand Up @@ -1376,6 +1401,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),
}
Expand Down Expand Up @@ -1577,6 +1603,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,
}
Expand Down
2 changes: 2 additions & 0 deletions src/librustc_metadata/schema.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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>>>,
}
Expand All @@ -290,6 +291,7 @@ impl_stable_hash_for!(struct Entry<'tcx> {
variances,
generics,
predicates,
predicates_defined_on,
mir
});

Expand Down
12 changes: 3 additions & 9 deletions src/librustc_traits/lowering.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ use rustc::hir::{self, ImplPolarity};
use rustc::traits::{Clause, Clauses, DomainGoal, Goal, PolyDomainGoal, ProgramClause,
WhereClause, FromEnv, WellFormed};
use rustc::ty::query::Providers;
use rustc::ty::subst::Substs;
use rustc::ty::{self, Slice, TyCtxt};
use rustc_data_structures::fx::FxHashSet;
use std::mem;
Expand Down Expand Up @@ -225,10 +224,7 @@ fn program_clauses_for_trait<'a, 'tcx>(

// `Self: Trait<P1..Pn>`
let trait_pred = ty::TraitPredicate {
trait_ref: ty::TraitRef {
def_id,
substs: Substs::identity_for_item(tcx, def_id),
},
trait_ref: ty::TraitRef::identity(tcx, def_id),
};

// `Implemented(Self: Trait<P1..Pn>)`
Expand Down Expand Up @@ -256,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())

Expand Down
Loading

0 comments on commit 8dd715e

Please sign in to comment.