Skip to content

Commit

Permalink
Rollup merge of rust-lang#37402 - eddyb:lazy-3, r=nikomatsakis
Browse files Browse the repository at this point in the history
[3/n] rustc: unify and simplify managing associated items.

_This is part of a series ([prev](rust-lang#37401) | [next](rust-lang#37404)) of patches designed to rework rustc into an out-of-order on-demand pipeline model for both better feature support (e.g. [MIR-based](https://github.com/solson/miri) early constant evaluation) and incremental execution of compiler passes (e.g. type-checking), with beneficial consequences to IDE support as well.
If any motivation is unclear, please ask for additional PR description clarifications or code comments._

<hr>

`ImplOrTraitItem`/`impl_or_trait_item` have been renamed to `AssociatedItem`/`associated_item`.

The common fields from (what used to be) `ty::ImplOrTraitItem`'s variants have been pulled out, leaving only an `AssociatedKind` C-like enum to distinguish between methods, constants and types.

The type information has been removed from `AssociatedItem`, and as such the latter can now be computed on-demand from the local HIR map, i.e. an extern-crate-enabled `TraitItem | ImplItem`.
It may be moved to HIR in the future, if we intend to start using HIR types cross-crate.

`ty::ExplicitSelfCategory` has been moved to `rustc_typeck` and is produced on-demand from the signature of the method, and a `method_has_self_argument` field on `AssociatedItem`, which is used to indicate that the first argument is a sugary "method receiver" and as such, method call syntax can be used.
  • Loading branch information
eddyb authored Nov 10, 2016
2 parents da2ce22 + de0ffad commit 8d4a350
Show file tree
Hide file tree
Showing 45 changed files with 1,039 additions and 1,691 deletions.
12 changes: 6 additions & 6 deletions src/librustc/dep_graph/dep_node.rs
Original file line number Diff line number Diff line change
Expand Up @@ -103,11 +103,11 @@ pub enum DepNode<D: Clone + Debug> {
// nodes. Often we map multiple tables to the same node if there
// is no point in distinguishing them (e.g., both the type and
// predicates for an item wind up in `ItemSignature`).
ImplOrTraitItems(D),
AssociatedItems(D),
ItemSignature(D),
FieldTy(D),
SizedConstraint(D),
ImplOrTraitItemDefIds(D),
AssociatedItemDefIds(D),
InherentImpls(D),

// The set of impls for a given trait. Ultimately, it would be
Expand Down Expand Up @@ -153,10 +153,10 @@ impl<D: Clone + Debug> DepNode<D> {
TransCrateItem,
TypeckItemType,
TypeckItemBody,
ImplOrTraitItems,
AssociatedItems,
ItemSignature,
FieldTy,
ImplOrTraitItemDefIds,
AssociatedItemDefIds,
InherentImpls,
TraitImpls,
ReprHints,
Expand Down Expand Up @@ -219,11 +219,11 @@ impl<D: Clone + Debug> DepNode<D> {
RvalueCheck(ref d) => op(d).map(RvalueCheck),
TransCrateItem(ref d) => op(d).map(TransCrateItem),
TransInlinedItem(ref d) => op(d).map(TransInlinedItem),
ImplOrTraitItems(ref d) => op(d).map(ImplOrTraitItems),
AssociatedItems(ref d) => op(d).map(AssociatedItems),
ItemSignature(ref d) => op(d).map(ItemSignature),
FieldTy(ref d) => op(d).map(FieldTy),
SizedConstraint(ref d) => op(d).map(SizedConstraint),
ImplOrTraitItemDefIds(ref d) => op(d).map(ImplOrTraitItemDefIds),
AssociatedItemDefIds(ref d) => op(d).map(AssociatedItemDefIds),
InherentImpls(ref d) => op(d).map(InherentImpls),
TraitImpls(ref d) => op(d).map(TraitImpls),
TraitItems(ref d) => op(d).map(TraitItems),
Expand Down
14 changes: 7 additions & 7 deletions src/librustc/middle/cstore.rs
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,7 @@ pub trait CrateStore<'tcx> {
fn implementations_of_trait(&self, filter: Option<DefId>) -> Vec<DefId>;

// impl info
fn impl_or_trait_items(&self, def_id: DefId) -> Vec<DefId>;
fn associated_item_def_ids(&self, def_id: DefId) -> Vec<DefId>;
fn impl_trait_ref<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId)
-> Option<ty::TraitRef<'tcx>>;
fn impl_polarity(&self, def: DefId) -> hir::ImplPolarity;
Expand All @@ -157,8 +157,8 @@ pub trait CrateStore<'tcx> {

// trait/impl-item info
fn trait_of_item(&self, def_id: DefId) -> Option<DefId>;
fn impl_or_trait_item<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId)
-> Option<ty::ImplOrTraitItem<'tcx>>;
fn associated_item<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId)
-> Option<ty::AssociatedItem>;

// flags
fn is_const_fn(&self, did: DefId) -> bool;
Expand Down Expand Up @@ -311,8 +311,8 @@ impl<'tcx> CrateStore<'tcx> for DummyCrateStore {
}

// impl info
fn impl_or_trait_items(&self, def_id: DefId) -> Vec<DefId>
{ bug!("impl_or_trait_items") }
fn associated_item_def_ids(&self, def_id: DefId) -> Vec<DefId>
{ bug!("associated_items") }
fn impl_trait_ref<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId)
-> Option<ty::TraitRef<'tcx>> { bug!("impl_trait_ref") }
fn impl_polarity(&self, def: DefId) -> hir::ImplPolarity { bug!("impl_polarity") }
Expand All @@ -323,8 +323,8 @@ impl<'tcx> CrateStore<'tcx> for DummyCrateStore {

// trait/impl-item info
fn trait_of_item(&self, def_id: DefId) -> Option<DefId> { bug!("trait_of_item") }
fn impl_or_trait_item<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId)
-> Option<ty::ImplOrTraitItem<'tcx>> { bug!("impl_or_trait_item") }
fn associated_item<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId)
-> Option<ty::AssociatedItem> { bug!("associated_item") }

// flags
fn is_const_fn(&self, did: DefId) -> bool { bug!("is_const_fn") }
Expand Down
5 changes: 2 additions & 3 deletions src/librustc/middle/dead.rs
Original file line number Diff line number Diff line change
Expand Up @@ -471,11 +471,10 @@ impl<'a, 'tcx> DeadVisitor<'a, 'tcx> {
// This is done to handle the case where, for example, the static
// method of a private type is used, but the type itself is never
// called directly.
let impl_items = self.tcx.impl_or_trait_item_def_ids.borrow();
if let Some(impl_list) =
self.tcx.inherent_impls.borrow().get(&self.tcx.map.local_def_id(id)) {
for impl_did in impl_list.iter() {
for &item_did in &impl_items[impl_did][..] {
for &impl_did in impl_list.iter() {
for &item_did in &self.tcx.associated_item_def_ids(impl_did)[..] {
if let Some(item_node_id) = self.tcx.map.as_local_node_id(item_did) {
if self.live_symbols.contains(&item_node_id) {
return true;
Expand Down
4 changes: 2 additions & 2 deletions src/librustc/middle/expr_use_visitor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -227,8 +227,8 @@ impl OverloadedCallType {
}

fn from_method_id(tcx: TyCtxt, method_id: DefId) -> OverloadedCallType {
let method = tcx.impl_or_trait_item(method_id);
OverloadedCallType::from_trait_id(tcx, method.container().id())
let method = tcx.associated_item(method_id);
OverloadedCallType::from_trait_id(tcx, method.container.id())
}
}

Expand Down
20 changes: 5 additions & 15 deletions src/librustc/middle/stability.rs
Original file line number Diff line number Diff line change
Expand Up @@ -529,14 +529,11 @@ pub fn check_item<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
// items.
hir::ItemImpl(.., Some(ref t), _, ref impl_items) => {
let trait_did = tcx.expect_def(t.ref_id).def_id();
let trait_items = tcx.trait_items(trait_did);

for impl_item in impl_items {
let item = trait_items.iter().find(|item| {
item.name() == impl_item.name
}).unwrap();
let item = tcx.associated_items(trait_did)
.find(|item| item.name == impl_item.name).unwrap();
if warn_about_defns {
maybe_do_stability_check(tcx, item.def_id(), impl_item.span, cb);
maybe_do_stability_check(tcx, item.def_id, impl_item.span, cb);
}
}
}
Expand Down Expand Up @@ -685,15 +682,8 @@ fn is_internal<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, span: Span) -> bool {
}

fn is_staged_api<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, id: DefId) -> bool {
match tcx.trait_item_of_item(id) {
Some(trait_method_id) if trait_method_id != id => {
is_staged_api(tcx, trait_method_id)
}
_ => {
*tcx.stability.borrow_mut().staged_api.entry(id.krate).or_insert_with(
|| tcx.sess.cstore.is_staged_api(id.krate))
}
}
*tcx.stability.borrow_mut().staged_api.entry(id.krate).or_insert_with(
|| tcx.sess.cstore.is_staged_api(id.krate))
}

impl<'a, 'tcx> TyCtxt<'a, 'tcx, 'tcx> {
Expand Down
14 changes: 6 additions & 8 deletions src/librustc/traits/error_reporting.rs
Original file line number Diff line number Diff line change
Expand Up @@ -663,25 +663,23 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
in the supertrait listing"
}

ObjectSafetyViolation::Method(method,
ObjectSafetyViolation::Method(name,
MethodViolationCode::StaticMethod) => {
buf = format!("method `{}` has no receiver",
method.name);
buf = format!("method `{}` has no receiver", name);
&buf
}

ObjectSafetyViolation::Method(method,
ObjectSafetyViolation::Method(name,
MethodViolationCode::ReferencesSelf) => {
buf = format!("method `{}` references the `Self` type \
in its arguments or return type",
method.name);
name);
&buf
}

ObjectSafetyViolation::Method(method,
ObjectSafetyViolation::Method(name,
MethodViolationCode::Generic) => {
buf = format!("method `{}` has generic type parameters",
method.name);
buf = format!("method `{}` has generic type parameters", name);
&buf
}
};
Expand Down
20 changes: 8 additions & 12 deletions src/librustc/traits/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -578,18 +578,14 @@ pub fn get_vtable_methods<'a, 'tcx>(
supertraits(tcx, trait_ref).flat_map(move |trait_ref| {
tcx.populate_implementations_for_trait_if_necessary(trait_ref.def_id());

let trait_item_def_ids = tcx.impl_or_trait_items(trait_ref.def_id());
let trait_methods = (0..trait_item_def_ids.len()).filter_map(move |i| {
match tcx.impl_or_trait_item(trait_item_def_ids[i]) {
ty::MethodTraitItem(m) => Some(m),
_ => None
}
});
let trait_methods = tcx.associated_items(trait_ref.def_id())
.filter(|item| item.kind == ty::AssociatedKind::Method);

// Now list each method's DefId and Substs (for within its trait).
// If the method can never be called from this object, produce None.
trait_methods.map(move |trait_method| {
debug!("get_vtable_methods: trait_method={:?}", trait_method);
let def_id = trait_method.def_id;

// Some methods cannot be called on an object; skip those.
if !tcx.is_vtable_safe_method(trait_ref.def_id(), &trait_method) {
Expand All @@ -599,21 +595,21 @@ pub fn get_vtable_methods<'a, 'tcx>(

// the method may have some early-bound lifetimes, add
// regions for those
let substs = Substs::for_item(tcx, trait_method.def_id,
|_, _| tcx.mk_region(ty::ReErased),
|def, _| trait_ref.substs().type_for_def(def));
let substs = Substs::for_item(tcx, def_id,
|_, _| tcx.mk_region(ty::ReErased),
|def, _| trait_ref.substs().type_for_def(def));

// It's possible that the method relies on where clauses that
// do not hold for this particular set of type parameters.
// Note that this method could then never be called, so we
// do not want to try and trans it, in that case (see #23435).
let predicates = trait_method.predicates.instantiate_own(tcx, substs);
let predicates = tcx.lookup_predicates(def_id).instantiate_own(tcx, substs);
if !normalize_and_test_predicates(tcx, predicates.predicates) {
debug!("get_vtable_methods: predicates do not hold");
return None;
}

Some((trait_method.def_id, substs))
Some((def_id, substs))
})
})
}
Expand Down
48 changes: 17 additions & 31 deletions src/librustc/traits/object_safety.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,10 @@ use super::elaborate_predicates;
use hir::def_id::DefId;
use traits;
use ty::{self, ToPolyTraitRef, Ty, TyCtxt, TypeFoldable};
use std::rc::Rc;
use syntax::ast;

#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub enum ObjectSafetyViolation<'tcx> {
pub enum ObjectSafetyViolation {
/// Self : Sized declared on the trait
SizedSelf,

Expand All @@ -35,7 +34,7 @@ pub enum ObjectSafetyViolation<'tcx> {
SupertraitSelf,

/// Method has something illegal
Method(Rc<ty::Method<'tcx>>, MethodViolationCode),
Method(ast::Name, MethodViolationCode),
}

/// Reasons a method might not be object-safe.
Expand Down Expand Up @@ -77,7 +76,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
/// because `object_safety_violations` can't be used during
/// type collection.
pub fn astconv_object_safety_violations(self, trait_def_id: DefId)
-> Vec<ObjectSafetyViolation<'tcx>>
-> Vec<ObjectSafetyViolation>
{
let mut violations = vec![];

Expand All @@ -93,29 +92,23 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
}

pub fn object_safety_violations(self, trait_def_id: DefId)
-> Vec<ObjectSafetyViolation<'tcx>>
-> Vec<ObjectSafetyViolation>
{
traits::supertrait_def_ids(self, trait_def_id)
.flat_map(|def_id| self.object_safety_violations_for_trait(def_id))
.collect()
}

fn object_safety_violations_for_trait(self, trait_def_id: DefId)
-> Vec<ObjectSafetyViolation<'tcx>>
-> Vec<ObjectSafetyViolation>
{
// Check methods for violations.
let mut violations: Vec<_> =
self.trait_items(trait_def_id).iter()
let mut violations: Vec<_> = self.associated_items(trait_def_id)
.filter(|item| item.kind == ty::AssociatedKind::Method)
.filter_map(|item| {
match *item {
ty::MethodTraitItem(ref m) => {
self.object_safety_violation_for_method(trait_def_id, &m)
.map(|code| ObjectSafetyViolation::Method(m.clone(), code))
}
_ => None,
}
})
.collect();
self.object_safety_violation_for_method(trait_def_id, &item)
.map(|code| ObjectSafetyViolation::Method(item.name, code))
}).collect();

// Check the trait itself.
if self.trait_has_sized_self(trait_def_id) {
Expand Down Expand Up @@ -198,7 +191,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
/// Returns `Some(_)` if this method makes the containing trait not object safe.
fn object_safety_violation_for_method(self,
trait_def_id: DefId,
method: &ty::Method<'gcx>)
method: &ty::AssociatedItem)
-> Option<MethodViolationCode>
{
// Any method that has a `Self : Sized` requisite is otherwise
Expand All @@ -216,7 +209,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
/// otherwise ensure that they cannot be used when `Self=Trait`.
pub fn is_vtable_safe_method(self,
trait_def_id: DefId,
method: &ty::Method<'gcx>)
method: &ty::AssociatedItem)
-> bool
{
// Any method that has a `Self : Sized` requisite can't be called.
Expand All @@ -233,26 +226,19 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
/// `Self:Sized`.
fn virtual_call_violation_for_method(self,
trait_def_id: DefId,
method: &ty::Method<'tcx>)
method: &ty::AssociatedItem)
-> Option<MethodViolationCode>
{
// The method's first parameter must be something that derefs (or
// autorefs) to `&self`. For now, we only accept `self`, `&self`
// and `Box<Self>`.
match method.explicit_self {
ty::ExplicitSelfCategory::Static => {
return Some(MethodViolationCode::StaticMethod);
}

ty::ExplicitSelfCategory::ByValue |
ty::ExplicitSelfCategory::ByReference(..) |
ty::ExplicitSelfCategory::ByBox => {
}
if !method.method_has_self_argument {
return Some(MethodViolationCode::StaticMethod);
}

// The `Self` type is erased, so it should not appear in list of
// arguments or return type apart from the receiver.
let ref sig = method.fty.sig;
let ref sig = self.lookup_item_type(method.def_id).ty.fn_sig();
for &input_ty in &sig.0.inputs[1..] {
if self.contains_illegal_self_type_reference(trait_def_id, input_ty) {
return Some(MethodViolationCode::ReferencesSelf);
Expand All @@ -263,7 +249,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
}

// We can't monomorphize things like `fn foo<A>(...)`.
if !method.generics.types.is_empty() {
if !self.lookup_generics(method.def_id).types.is_empty() {
return Some(MethodViolationCode::Generic);
}

Expand Down
Loading

0 comments on commit 8d4a350

Please sign in to comment.