Auto merge of #41911 - michaelwoerister:querify_trait_def, r=nikomatsakis

Remove interior mutability from TraitDef by turning fields into queries

This PR gets rid of anything `std::cell` in `TraitDef` by
- moving the global list of trait impls from `TraitDef` into a query,
- moving the list of trait impls relevent for some self-type from `TraitDef` into a query
- moving the specialization graph of trait impls into a query, and
- moving `TraitDef::object_safety` into a query.

I really like how querifying things not only helps with incremental compilation and on-demand, but also just plain makes the code cleaner `:)`

There are also some smaller fixes in the PR. Commits can be reviewed separately.

r? @eddyb or @nikomatsakis
This commit is contained in:
bors 2017-05-17 21:44:08 +00:00
commit 4640e18572
32 changed files with 683 additions and 592 deletions

View file

@ -106,6 +106,8 @@ pub enum DepNode<D: Clone + Debug> {
UsedTraitImports(D),
ConstEval(D),
SymbolName(D),
SpecializationGraph(D),
ObjectSafety(D),
// The set of impls for a given trait. Ultimately, it would be
// nice to get more fine-grained here (e.g., to include a
@ -116,6 +118,8 @@ pub enum DepNode<D: Clone + Debug> {
// than changes in the impl body.
TraitImpls(D),
AllLocalTraitImpls,
// Nodes representing caches. To properly handle a true cache, we
// don't use a DepTrackingMap, but rather we push a task node.
// Otherwise the write into the map would be incorrectly
@ -262,7 +266,10 @@ impl<D: Clone + Debug> DepNode<D> {
UsedTraitImports(ref d) => op(d).map(UsedTraitImports),
ConstEval(ref d) => op(d).map(ConstEval),
SymbolName(ref d) => op(d).map(SymbolName),
SpecializationGraph(ref d) => op(d).map(SpecializationGraph),
ObjectSafety(ref d) => op(d).map(ObjectSafety),
TraitImpls(ref d) => op(d).map(TraitImpls),
AllLocalTraitImpls => Some(AllLocalTraitImpls),
TraitItems(ref d) => op(d).map(TraitItems),
ReprHints(ref d) => op(d).map(ReprHints),
TraitSelect { ref trait_def_id, ref input_def_id } => {

View file

@ -409,6 +409,67 @@ RFC. It is, however, [currently unimplemented][iss15872].
[iss15872]: https://github.com/rust-lang/rust/issues/15872
"##,
E0119: r##"
There are conflicting trait implementations for the same type.
Example of erroneous code:
```compile_fail,E0119
trait MyTrait {
fn get(&self) -> usize;
}
impl<T> MyTrait for T {
fn get(&self) -> usize { 0 }
}
struct Foo {
value: usize
}
impl MyTrait for Foo { // error: conflicting implementations of trait
// `MyTrait` for type `Foo`
fn get(&self) -> usize { self.value }
}
```
When looking for the implementation for the trait, the compiler finds
both the `impl<T> MyTrait for T` where T is all types and the `impl
MyTrait for Foo`. Since a trait cannot be implemented multiple times,
this is an error. So, when you write:
```
trait MyTrait {
fn get(&self) -> usize;
}
impl<T> MyTrait for T {
fn get(&self) -> usize { 0 }
}
```
This makes the trait implemented on all types in the scope. So if you
try to implement it on another one after that, the implementations will
conflict. Example:
```
trait MyTrait {
fn get(&self) -> usize;
}
impl<T> MyTrait for T {
fn get(&self) -> usize { 0 }
}
struct Foo;
fn main() {
let f = Foo;
f.get(); // the trait is implemented so we can use it
}
```
"##,
E0133: r##"
Unsafe code was used outside of an unsafe function or block.

View file

@ -497,7 +497,7 @@ impl<'hir> Map<'hir> {
}
pub fn trait_impls(&self, trait_did: DefId) -> &'hir [NodeId] {
self.dep_graph.read(DepNode::TraitImpls(trait_did));
self.dep_graph.read(DepNode::AllLocalTraitImpls);
// NB: intentionally bypass `self.forest.krate()` so that we
// do not trigger a read of the whole krate here
@ -505,7 +505,7 @@ impl<'hir> Map<'hir> {
}
pub fn trait_default_impl(&self, trait_did: DefId) -> Option<NodeId> {
self.dep_graph.read(DepNode::TraitImpls(trait_did));
self.dep_graph.read(DepNode::AllLocalTraitImpls);
// NB: intentionally bypass `self.forest.krate()` so that we
// do not trigger a read of the whole krate here

View file

@ -94,3 +94,11 @@ impl stable_hasher::StableHasherResult for Fingerprint {
fingerprint
}
}
impl<CTX> stable_hasher::HashStable<CTX> for Fingerprint {
fn hash_stable<W: stable_hasher::StableHasherResult>(&self,
_: &mut CTX,
hasher: &mut stable_hasher::StableHasher<W>) {
::std::hash::Hash::hash(&self.0, hasher);
}
}

View file

@ -16,7 +16,7 @@ use ty;
use util::nodemap::NodeMap;
use std::hash as std_hash;
use std::collections::{HashMap, HashSet};
use std::collections::{HashMap, HashSet, BTreeMap};
use syntax::ast;
use syntax::attr;
@ -348,3 +348,25 @@ pub fn hash_stable_nodemap<'a, 'tcx, V, W>(hcx: &mut StableHashingContext<'a, 't
hcx.tcx.hir.definitions().node_to_hir_id(*node_id).local_id
});
}
pub fn hash_stable_btreemap<'a, 'tcx, K, V, SK, F, W>(hcx: &mut StableHashingContext<'a, 'tcx>,
hasher: &mut StableHasher<W>,
map: &BTreeMap<K, V>,
extract_stable_key: F)
where K: Eq + Ord,
V: HashStable<StableHashingContext<'a, 'tcx>>,
SK: HashStable<StableHashingContext<'a, 'tcx>> + Ord + Clone,
F: Fn(&mut StableHashingContext<'a, 'tcx>, &K) -> SK,
W: StableHasherResult,
{
let mut keys: Vec<_> = map.keys()
.map(|k| (extract_stable_key(hcx, k), k))
.collect();
keys.sort_unstable_by_key(|&(ref stable_key, _)| stable_key.clone());
keys.len().hash_stable(hcx, hasher);
for (stable_key, key) in keys {
stable_key.hash_stable(hcx, hasher);
map[key].hash_stable(hcx, hasher);
}
}

View file

@ -13,7 +13,8 @@
pub use self::fingerprint::Fingerprint;
pub use self::caching_codemap_view::CachingCodemapView;
pub use self::hcx::{StableHashingContext, NodeIdHashingMode, hash_stable_hashmap,
hash_stable_hashset, hash_stable_nodemap};
hash_stable_hashset, hash_stable_nodemap,
hash_stable_btreemap};
mod fingerprint;
mod caching_codemap_view;
mod hcx;

View file

@ -619,8 +619,6 @@ pub fn get_vtable_methods<'a, 'tcx>(
debug!("get_vtable_methods({:?})", trait_ref);
supertraits(tcx, trait_ref).flat_map(move |trait_ref| {
tcx.populate_implementations_for_trait_if_necessary(trait_ref.def_id());
let trait_methods = tcx.associated_items(trait_ref.def_id())
.filter(|item| item.kind == ty::AssociatedKind::Method);
@ -782,3 +780,19 @@ impl<'tcx> TraitObligation<'tcx> {
ty::Binder(self.predicate.skip_binder().self_ty())
}
}
pub fn provide(providers: &mut ty::maps::Providers) {
*providers = ty::maps::Providers {
is_object_safe: object_safety::is_object_safe_provider,
specialization_graph_of: specialize::specialization_graph_provider,
..*providers
};
}
pub fn provide_extern(providers: &mut ty::maps::Providers) {
*providers = ty::maps::Providers {
is_object_safe: object_safety::is_object_safe_provider,
specialization_graph_of: specialize::specialization_graph_provider,
..*providers
};
}

View file

@ -77,25 +77,6 @@ pub enum MethodViolationCode {
}
impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
pub fn is_object_safe(self, trait_def_id: DefId) -> bool {
// Because we query yes/no results frequently, we keep a cache:
let def = self.trait_def(trait_def_id);
let result = def.object_safety().unwrap_or_else(|| {
let result = self.object_safety_violations(trait_def_id).is_empty();
// Record just a yes/no result in the cache; this is what is
// queried most frequently. Note that this may overwrite a
// previous result, but always with the same thing.
def.set_object_safety(result);
result
});
debug!("is_object_safe({:?}) = {}", trait_def_id, result);
result
}
/// Returns the object safety violations that affect
/// astconv - currently, Self in supertraits. This is needed
@ -391,3 +372,9 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
error
}
}
pub(super) fn is_object_safe_provider<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
trait_def_id: DefId)
-> bool {
tcx.object_safety_violations(trait_def_id).is_empty()
}

View file

@ -900,96 +900,50 @@ fn assemble_candidates_from_impls<'cx, 'gcx, 'tcx>(
// In either case, we handle this by not adding a
// candidate for an impl if it contains a `default`
// type.
let opt_node_item = assoc_ty_def(selcx,
impl_data.impl_def_id,
obligation.predicate.item_name);
let new_candidate = if let Some(node_item) = opt_node_item {
let is_default = if node_item.node.is_from_trait() {
// If true, the impl inherited a `type Foo = Bar`
// given in the trait, which is implicitly default.
// Otherwise, the impl did not specify `type` and
// neither did the trait:
//
// ```rust
// trait Foo { type T; }
// impl Foo for Bar { }
// ```
//
// This is an error, but it will be
// reported in `check_impl_items_against_trait`.
// We accept it here but will flag it as
// an error when we confirm the candidate
// (which will ultimately lead to `normalize_to_error`
// being invoked).
node_item.item.defaultness.has_value()
} else {
node_item.item.defaultness.is_default() ||
selcx.tcx().impl_is_default(node_item.node.def_id())
};
let node_item = assoc_ty_def(selcx,
impl_data.impl_def_id,
obligation.predicate.item_name);
// Only reveal a specializable default if we're past type-checking
// and the obligations is monomorphic, otherwise passes such as
// transmute checking and polymorphic MIR optimizations could
// get a result which isn't correct for all monomorphizations.
if !is_default {
let is_default = if node_item.node.is_from_trait() {
// If true, the impl inherited a `type Foo = Bar`
// given in the trait, which is implicitly default.
// Otherwise, the impl did not specify `type` and
// neither did the trait:
//
// ```rust
// trait Foo { type T; }
// impl Foo for Bar { }
// ```
//
// This is an error, but it will be
// reported in `check_impl_items_against_trait`.
// We accept it here but will flag it as
// an error when we confirm the candidate
// (which will ultimately lead to `normalize_to_error`
// being invoked).
node_item.item.defaultness.has_value()
} else {
node_item.item.defaultness.is_default() ||
selcx.tcx().impl_is_default(node_item.node.def_id())
};
// Only reveal a specializable default if we're past type-checking
// and the obligations is monomorphic, otherwise passes such as
// transmute checking and polymorphic MIR optimizations could
// get a result which isn't correct for all monomorphizations.
let new_candidate = if !is_default {
Some(ProjectionTyCandidate::Select)
} else if selcx.projection_mode() == Reveal::All {
assert!(!poly_trait_ref.needs_infer());
if !poly_trait_ref.needs_subst() {
Some(ProjectionTyCandidate::Select)
} else if selcx.projection_mode() == Reveal::All {
assert!(!poly_trait_ref.needs_infer());
if !poly_trait_ref.needs_subst() {
Some(ProjectionTyCandidate::Select)
} else {
None
}
} else {
None
}
} else {
// This is saying that neither the trait nor
// the impl contain a definition for this
// associated type. Normally this situation
// could only arise through a compiler bug --
// if the user wrote a bad item name, it
// should have failed in astconv. **However**,
// at coherence-checking time, we only look at
// the topmost impl (we don't even consider
// the trait itself) for the definition -- and
// so in that case it may be that the trait
// *DOES* have a declaration, but we don't see
// it, and we end up in this branch.
//
// This is kind of tricky to handle actually.
// For now, we just unconditionally ICE,
// because otherwise, examples like the
// following will succeed:
//
// ```
// trait Assoc {
// type Output;
// }
//
// impl<T> Assoc for T {
// default type Output = bool;
// }
//
// impl Assoc for u8 {}
// impl Assoc for u16 {}
//
// trait Foo {}
// impl Foo for <u8 as Assoc>::Output {}
// impl Foo for <u16 as Assoc>::Output {}
// return None;
// }
// ```
//
// The essential problem here is that the
// projection fails, leaving two unnormalized
// types, which appear not to unify -- so the
// overlap check succeeds, when it should
// fail.
span_bug!(obligation.cause.span,
"Tried to project an inherited associated type during \
coherence checking, which is currently not supported.");
None
};
candidate_set.vec.extend(new_candidate);
}
super::VtableParam(..) => {
@ -1274,35 +1228,25 @@ fn confirm_impl_candidate<'cx, 'gcx, 'tcx>(
let VtableImplData { substs, nested, impl_def_id } = impl_vtable;
let tcx = selcx.tcx();
let trait_ref = obligation.predicate.trait_ref;
let assoc_ty = assoc_ty_def(selcx, impl_def_id, obligation.predicate.item_name);
match assoc_ty {
Some(node_item) => {
let ty = if !node_item.item.defaultness.has_value() {
// This means that the impl is missing a definition for the
// associated type. This error will be reported by the type
// checker method `check_impl_items_against_trait`, so here we
// just return TyError.
debug!("confirm_impl_candidate: no associated type {:?} for {:?}",
node_item.item.name,
obligation.predicate.trait_ref);
tcx.types.err
} else {
tcx.type_of(node_item.item.def_id)
};
let substs = translate_substs(selcx.infcx(), impl_def_id, substs, node_item.node);
Progress {
ty: ty.subst(tcx, substs),
obligations: nested,
cacheable: true
}
}
None => {
span_bug!(obligation.cause.span,
"No associated type for {:?}",
trait_ref);
}
let ty = if !assoc_ty.item.defaultness.has_value() {
// This means that the impl is missing a definition for the
// associated type. This error will be reported by the type
// checker method `check_impl_items_against_trait`, so here we
// just return TyError.
debug!("confirm_impl_candidate: no associated type {:?} for {:?}",
assoc_ty.item.name,
obligation.predicate.trait_ref);
tcx.types.err
} else {
tcx.type_of(assoc_ty.item.def_id)
};
let substs = translate_substs(selcx.infcx(), impl_def_id, substs, assoc_ty.node);
Progress {
ty: ty.subst(tcx, substs),
obligations: nested,
cacheable: true
}
}
@ -1315,27 +1259,43 @@ fn assoc_ty_def<'cx, 'gcx, 'tcx>(
selcx: &SelectionContext<'cx, 'gcx, 'tcx>,
impl_def_id: DefId,
assoc_ty_name: ast::Name)
-> Option<specialization_graph::NodeItem<ty::AssociatedItem>>
-> specialization_graph::NodeItem<ty::AssociatedItem>
{
let trait_def_id = selcx.tcx().impl_trait_ref(impl_def_id).unwrap().def_id;
let trait_def = selcx.tcx().trait_def(trait_def_id);
let tcx = selcx.tcx();
let trait_def_id = tcx.impl_trait_ref(impl_def_id).unwrap().def_id;
let trait_def = tcx.trait_def(trait_def_id);
if !trait_def.is_complete(selcx.tcx()) {
let impl_node = specialization_graph::Node::Impl(impl_def_id);
for item in impl_node.items(selcx.tcx()) {
if item.kind == ty::AssociatedKind::Type && item.name == assoc_ty_name {
return Some(specialization_graph::NodeItem {
node: specialization_graph::Node::Impl(impl_def_id),
item: item,
});
}
// This function may be called while we are still building the
// specialization graph that is queried below (via TraidDef::ancestors()),
// so, in order to avoid unnecessary infinite recursion, we manually look
// for the associated item at the given impl.
// If there is no such item in that impl, this function will fail with a
// cycle error if the specialization graph is currently being built.
let impl_node = specialization_graph::Node::Impl(impl_def_id);
for item in impl_node.items(tcx) {
if item.kind == ty::AssociatedKind::Type && item.name == assoc_ty_name {
return specialization_graph::NodeItem {
node: specialization_graph::Node::Impl(impl_def_id),
item: item,
};
}
None
}
if let Some(assoc_item) = trait_def
.ancestors(tcx, impl_def_id)
.defs(tcx, assoc_ty_name, ty::AssociatedKind::Type)
.next() {
assoc_item
} else {
trait_def
.ancestors(impl_def_id)
.defs(selcx.tcx(), assoc_ty_name, ty::AssociatedKind::Type)
.next()
// This is saying that neither the trait nor
// the impl contain a definition for this
// associated type. Normally this situation
// could only arise through a compiler bug --
// if the user wrote a bad item name, it
// should have failed in astconv.
bug!("No associated type `{}` for {}",
assoc_ty_name,
tcx.item_path_str(impl_def_id))
}
}

View file

@ -27,6 +27,7 @@ use ty::subst::{Subst, Substs};
use traits::{self, Reveal, ObligationCause};
use ty::{self, TyCtxt, TypeFoldable};
use syntax_pos::DUMMY_SP;
use std::rc::Rc;
pub mod specialization_graph;
@ -118,7 +119,7 @@ pub fn find_associated_item<'a, 'tcx>(
let trait_def_id = tcx.trait_id_of_impl(impl_data.impl_def_id).unwrap();
let trait_def = tcx.trait_def(trait_def_id);
let ancestors = trait_def.ancestors(impl_data.impl_def_id);
let ancestors = trait_def.ancestors(tcx, impl_data.impl_def_id);
match ancestors.defs(tcx, item.name, item.kind).next() {
Some(node_item) => {
let substs = tcx.infer_ctxt((), Reveal::All).enter(|infcx| {
@ -285,3 +286,62 @@ impl SpecializesCache {
self.map.insert((a, b), result);
}
}
// Query provider for `specialization_graph_of`.
pub(super) fn specialization_graph_provider<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
trait_id: DefId)
-> Rc<specialization_graph::Graph> {
let mut sg = specialization_graph::Graph::new();
let mut trait_impls: Vec<DefId> = tcx.trait_impls_of(trait_id).iter().collect();
// The coherence checking implementation seems to rely on impls being
// iterated over (roughly) in definition order, so we are sorting by
// negated CrateNum (so remote definitions are visited first) and then
// by a flattend version of the DefIndex.
trait_impls.sort_unstable_by_key(|def_id| {
(-(def_id.krate.as_u32() as i64),
def_id.index.address_space().index(),
def_id.index.as_array_index())
});
for impl_def_id in trait_impls {
if impl_def_id.is_local() {
// This is where impl overlap checking happens:
let insert_result = sg.insert(tcx, impl_def_id);
// Report error if there was one.
if let Err(overlap) = insert_result {
let mut err = struct_span_err!(tcx.sess,
tcx.span_of_impl(impl_def_id).unwrap(),
E0119,
"conflicting implementations of trait `{}`{}:",
overlap.trait_desc,
overlap.self_desc.clone().map_or(String::new(),
|ty| {
format!(" for type `{}`", ty)
}));
match tcx.span_of_impl(overlap.with_impl) {
Ok(span) => {
err.span_label(span, format!("first implementation here"));
err.span_label(tcx.span_of_impl(impl_def_id).unwrap(),
format!("conflicting implementation{}",
overlap.self_desc
.map_or(String::new(),
|ty| format!(" for `{}`", ty))));
}
Err(cname) => {
err.note(&format!("conflicting implementation in crate `{}`", cname));
}
}
err.emit();
}
} else {
let parent = tcx.impl_parent(impl_def_id).unwrap_or(trait_id);
sg.record_impl_from_cstore(tcx, parent, impl_def_id)
}
}
Rc::new(sg)
}

View file

@ -12,8 +12,9 @@ use super::{OverlapError, specializes};
use hir::def_id::DefId;
use traits::{self, Reveal};
use ty::{self, TyCtxt, TraitDef, TypeFoldable};
use ty::{self, TyCtxt, TypeFoldable};
use ty::fast_reject::{self, SimplifiedType};
use std::rc::Rc;
use syntax::ast::Name;
use util::nodemap::{DefIdMap, FxHashMap};
@ -301,18 +302,19 @@ impl<'a, 'gcx, 'tcx> Node {
}
}
pub struct Ancestors<'a> {
trait_def: &'a TraitDef,
pub struct Ancestors {
trait_def_id: DefId,
specialization_graph: Rc<Graph>,
current_source: Option<Node>,
}
impl<'a> Iterator for Ancestors<'a> {
impl Iterator for Ancestors {
type Item = Node;
fn next(&mut self) -> Option<Node> {
let cur = self.current_source.take();
if let Some(Node::Impl(cur_impl)) = cur {
let parent = self.trait_def.specialization_graph.borrow().parent(cur_impl);
if parent == self.trait_def.def_id {
let parent = self.specialization_graph.parent(cur_impl);
if parent == self.trait_def_id {
self.current_source = Some(Node::Trait(parent));
} else {
self.current_source = Some(Node::Impl(parent));
@ -336,7 +338,7 @@ impl<T> NodeItem<T> {
}
}
impl<'a, 'gcx, 'tcx> Ancestors<'a> {
impl<'a, 'gcx, 'tcx> Ancestors {
/// Search the items from the given ancestors, returning each definition
/// with the given name and the given kind.
#[inline] // FIXME(#35870) Avoid closures being unexported due to impl Trait.
@ -351,9 +353,14 @@ impl<'a, 'gcx, 'tcx> Ancestors<'a> {
/// Walk up the specialization ancestors of a given impl, starting with that
/// impl itself.
pub fn ancestors<'a>(trait_def: &'a TraitDef, start_from_impl: DefId) -> Ancestors<'a> {
pub fn ancestors(tcx: TyCtxt,
trait_def_id: DefId,
start_from_impl: DefId)
-> Ancestors {
let specialization_graph = tcx.specialization_graph_of(trait_def_id);
Ancestors {
trait_def: trait_def,
trait_def_id,
specialization_graph,
current_source: Some(Node::Impl(start_from_impl)),
}
}

View file

@ -18,10 +18,12 @@ use middle::region::RegionMaps;
use mir;
use mir::transform::{MirSuite, MirPassIndex};
use session::CompileResult;
use traits::specialization_graph;
use ty::{self, CrateInherentImpls, Ty, TyCtxt};
use ty::item_path;
use ty::steal::Steal;
use ty::subst::Substs;
use ty::fast_reject::SimplifiedType;
use util::nodemap::{DefIdSet, NodeSet};
use rustc_data_structures::indexed_vec::IndexVec;
@ -98,6 +100,15 @@ impl Key for (CrateNum, DefId) {
}
}
impl Key for (DefId, SimplifiedType) {
fn map_crate(&self) -> CrateNum {
self.0.krate
}
fn default_span(&self, tcx: TyCtxt) -> Span {
self.0.default_span(tcx)
}
}
impl<'tcx> Key for (DefId, &'tcx Substs<'tcx>) {
fn map_crate(&self) -> CrateNum {
self.0.krate
@ -391,6 +402,24 @@ impl<'tcx> QueryDescription for queries::is_mir_available<'tcx> {
}
}
impl<'tcx> QueryDescription for queries::trait_impls_of<'tcx> {
fn describe(tcx: TyCtxt, def_id: DefId) -> String {
format!("trait impls of `{}`", tcx.item_path_str(def_id))
}
}
impl<'tcx> QueryDescription for queries::relevant_trait_impls_for<'tcx> {
fn describe(tcx: TyCtxt, (def_id, ty): (DefId, SimplifiedType)) -> String {
format!("relevant impls for: `({}, {:?})`", tcx.item_path_str(def_id), ty)
}
}
impl<'tcx> QueryDescription for queries::is_object_safe<'tcx> {
fn describe(tcx: TyCtxt, def_id: DefId) -> String {
format!("determine object safety of trait `{}`", tcx.item_path_str(def_id))
}
}
macro_rules! define_maps {
(<$tcx:tt>
$($(#[$attr:meta])*
@ -820,6 +849,13 @@ define_maps! { <'tcx>
[] item_body_nested_bodies: ItemBodyNestedBodies(DefId) -> Rc<BTreeMap<hir::BodyId, hir::Body>>,
[] const_is_rvalue_promotable_to_static: ConstIsRvaluePromotableToStatic(DefId) -> bool,
[] is_mir_available: IsMirAvailable(DefId) -> bool,
[] trait_impls_of: TraitImpls(DefId) -> ty::trait_def::TraitImpls,
// Note that TraitDef::for_each_relevant_impl() will do type simplication for you.
[] relevant_trait_impls_for: relevant_trait_impls_for((DefId, SimplifiedType))
-> ty::trait_def::TraitImpls,
[] specialization_graph_of: SpecializationGraph(DefId) -> Rc<specialization_graph::Graph>,
[] is_object_safe: ObjectSafety(DefId) -> bool,
}
fn coherent_trait_dep_node((_, def_id): (CrateNum, DefId)) -> DepNode<DefId> {
@ -859,3 +895,7 @@ fn mir_keys(_: CrateNum) -> DepNode<DefId> {
fn crate_variances(_: CrateNum) -> DepNode<DefId> {
DepNode::CrateVariances
}
fn relevant_trait_impls_for((def_id, _): (DefId, SimplifiedType)) -> DepNode<DefId> {
DepNode::TraitImpls(def_id)
}

View file

@ -80,7 +80,7 @@ pub use self::context::{Lift, TypeckTables};
pub use self::instance::{Instance, InstanceDef};
pub use self::trait_def::{TraitDef, TraitFlags};
pub use self::trait_def::TraitDef;
pub use self::maps::queries;
@ -2324,37 +2324,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
}
pub fn trait_has_default_impl(self, trait_def_id: DefId) -> bool {
let def = self.trait_def(trait_def_id);
def.flags.get().intersects(TraitFlags::HAS_DEFAULT_IMPL)
}
/// Populates the type context with all the implementations for the given
/// trait if necessary.
pub fn populate_implementations_for_trait_if_necessary(self, trait_id: DefId) {
if trait_id.is_local() {
return
}
// The type is not local, hence we are reading this out of
// metadata and don't need to track edges.
let _ignore = self.dep_graph.in_ignore();
let def = self.trait_def(trait_id);
if def.flags.get().intersects(TraitFlags::HAS_REMOTE_IMPLS) {
return;
}
debug!("populate_implementations_for_trait_if_necessary: searching for {:?}", def);
for impl_def_id in self.sess.cstore.implementations_of_trait(Some(trait_id)) {
let trait_ref = self.impl_trait_ref(impl_def_id).unwrap();
// Record the trait->implementation mapping.
let parent = self.impl_parent(impl_def_id).unwrap_or(trait_id);
def.record_remote_impl(self, impl_def_id, trait_ref, parent);
}
def.flags.set(def.flags.get() | TraitFlags::HAS_REMOTE_IMPLS);
self.trait_def(trait_def_id).has_default_impl
}
/// Given the def_id of an impl, return the def_id of the trait it implements.
@ -2603,6 +2573,8 @@ pub fn provide(providers: &mut ty::maps::Providers) {
adt_dtorck_constraint,
def_span,
trait_of_item,
trait_impls_of: trait_def::trait_impls_of_provider,
relevant_trait_impls_for: trait_def::relevant_trait_impls_provider,
..*providers
};
}
@ -2611,6 +2583,8 @@ pub fn provide_extern(providers: &mut ty::maps::Providers) {
*providers = ty::maps::Providers {
adt_sized_constraint,
adt_dtorck_constraint,
trait_impls_of: trait_def::trait_impls_of_provider,
relevant_trait_impls_for: trait_def::relevant_trait_impls_provider,
..*providers
};
}

View file

@ -8,18 +8,13 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use dep_graph::DepNode;
use hir::def_id::{DefId, LOCAL_CRATE};
use traits::{self, specialization_graph};
use ty;
use hir::def_id::DefId;
use traits::specialization_graph;
use ty::fast_reject;
use ty::{Ty, TyCtxt, TraitRef};
use std::cell::{Cell, RefCell};
use ty::fold::TypeFoldable;
use ty::{Ty, TyCtxt};
use std::rc::Rc;
use hir;
use util::nodemap::FxHashMap;
use syntax::ast;
use syntax_pos::DUMMY_SP;
/// A trait's definition with type information.
pub struct TraitDef {
@ -33,237 +28,93 @@ pub struct TraitDef {
/// be usable with the sugar (or without it).
pub paren_sugar: bool,
// Impls of a trait. To allow for quicker lookup, the impls are indexed by a
// simplified version of their `Self` type: impls with a simplifiable `Self`
// are stored in `nonblanket_impls` keyed by it, while all other impls are
// stored in `blanket_impls`.
//
// A similar division is used within `specialization_graph`, but the ones
// here are (1) stored as a flat list for the trait and (2) populated prior
// to -- and used while -- determining specialization order.
//
// FIXME: solve the reentrancy issues and remove these lists in favor of the
// ones in `specialization_graph`.
//
// These lists are tracked by `DepNode::TraitImpls`; we don't use
// a DepTrackingMap but instead have the `TraitDef` insert the
// required reads/writes.
/// Impls of the trait.
nonblanket_impls: RefCell<
FxHashMap<fast_reject::SimplifiedType, Vec<DefId>>
>,
/// Blanket impls associated with the trait.
blanket_impls: RefCell<Vec<DefId>>,
/// The specialization order for impls of this trait.
pub specialization_graph: RefCell<traits::specialization_graph::Graph>,
/// Various flags
pub flags: Cell<TraitFlags>,
/// The number of impls we've added from the local crate.
/// When this number matches up the list in the HIR map,
/// we're done, and the specialization graph is correct.
local_impl_count: Cell<usize>,
pub has_default_impl: bool,
/// The ICH of this trait's DefPath, cached here so it doesn't have to be
/// recomputed all the time.
pub def_path_hash: u64,
}
// We don't store the list of impls in a flat list because each cached list of
// `relevant_impls_for` we would then duplicate all blanket impls. By keeping
// blanket and non-blanket impls separate, we can share the list of blanket
// impls.
#[derive(Clone)]
pub struct TraitImpls {
blanket_impls: Rc<Vec<DefId>>,
non_blanket_impls: Rc<Vec<DefId>>,
}
impl TraitImpls {
pub fn iter(&self) -> TraitImplsIter {
TraitImplsIter {
blanket_impls: self.blanket_impls.clone(),
non_blanket_impls: self.non_blanket_impls.clone(),
index: 0
}
}
}
#[derive(Clone)]
pub struct TraitImplsIter {
blanket_impls: Rc<Vec<DefId>>,
non_blanket_impls: Rc<Vec<DefId>>,
index: usize,
}
impl Iterator for TraitImplsIter {
type Item = DefId;
fn next(&mut self) -> Option<DefId> {
if self.index < self.blanket_impls.len() {
let bi_index = self.index;
self.index += 1;
Some(self.blanket_impls[bi_index])
} else {
let nbi_index = self.index - self.blanket_impls.len();
if nbi_index < self.non_blanket_impls.len() {
self.index += 1;
Some(self.non_blanket_impls[nbi_index])
} else {
None
}
}
}
fn size_hint(&self) -> (usize, Option<usize>) {
let items_left = (self.blanket_impls.len() + self.non_blanket_impls.len()) - self.index;
(items_left, Some(items_left))
}
}
impl ExactSizeIterator for TraitImplsIter {}
impl<'a, 'gcx, 'tcx> TraitDef {
pub fn new(def_id: DefId,
unsafety: hir::Unsafety,
paren_sugar: bool,
has_default_impl: bool,
def_path_hash: u64)
-> TraitDef {
TraitDef {
def_id: def_id,
paren_sugar: paren_sugar,
unsafety: unsafety,
nonblanket_impls: RefCell::new(FxHashMap()),
blanket_impls: RefCell::new(vec![]),
flags: Cell::new(ty::TraitFlags::NO_TRAIT_FLAGS),
local_impl_count: Cell::new(0),
specialization_graph: RefCell::new(traits::specialization_graph::Graph::new()),
def_path_hash: def_path_hash,
def_id,
paren_sugar,
unsafety,
has_default_impl,
def_path_hash,
}
}
// returns None if not yet calculated
pub fn object_safety(&self) -> Option<bool> {
if self.flags.get().intersects(TraitFlags::OBJECT_SAFETY_VALID) {
Some(self.flags.get().intersects(TraitFlags::IS_OBJECT_SAFE))
} else {
None
}
}
pub fn set_object_safety(&self, is_safe: bool) {
assert!(self.object_safety().map(|cs| cs == is_safe).unwrap_or(true));
self.flags.set(
self.flags.get() | if is_safe {
TraitFlags::OBJECT_SAFETY_VALID | TraitFlags::IS_OBJECT_SAFE
} else {
TraitFlags::OBJECT_SAFETY_VALID
}
);
}
fn write_trait_impls(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>) {
tcx.dep_graph.write(DepNode::TraitImpls(self.def_id));
}
fn read_trait_impls(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>) {
tcx.dep_graph.read(DepNode::TraitImpls(self.def_id));
}
/// Records a basic trait-to-implementation mapping.
///
/// Returns `true` iff the impl has not previously been recorded.
fn record_impl(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>,
impl_def_id: DefId,
impl_trait_ref: TraitRef<'tcx>)
-> bool {
debug!("TraitDef::record_impl for {:?}, from {:?}",
self, impl_trait_ref);
// Record the write into the impl set, but only for local
// impls: external impls are handled differently.
if impl_def_id.is_local() {
self.write_trait_impls(tcx);
}
// We don't want to borrow_mut after we already populated all impls,
// so check if an impl is present with an immutable borrow first.
if let Some(sty) = fast_reject::simplify_type(tcx,
impl_trait_ref.self_ty(), false) {
if let Some(is) = self.nonblanket_impls.borrow().get(&sty) {
if is.contains(&impl_def_id) {
return false; // duplicate - skip
}
}
self.nonblanket_impls.borrow_mut().entry(sty).or_insert(vec![]).push(impl_def_id)
} else {
if self.blanket_impls.borrow().contains(&impl_def_id) {
return false; // duplicate - skip
}
self.blanket_impls.borrow_mut().push(impl_def_id)
}
true
}
/// Records a trait-to-implementation mapping for a crate-local impl.
pub fn record_local_impl(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>,
impl_def_id: DefId,
impl_trait_ref: TraitRef<'tcx>) {
assert!(impl_def_id.is_local());
let was_new = self.record_impl(tcx, impl_def_id, impl_trait_ref);
assert!(was_new);
self.local_impl_count.set(self.local_impl_count.get() + 1);
}
/// Records a trait-to-implementation mapping.
pub fn record_has_default_impl(&self) {
self.flags.set(self.flags.get() | TraitFlags::HAS_DEFAULT_IMPL);
}
/// Records a trait-to-implementation mapping for a non-local impl.
///
/// The `parent_impl` is the immediately-less-specialized impl, or the
/// trait's def ID if the impl is not a specialization -- information that
/// should be pulled from the metadata.
pub fn record_remote_impl(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>,
impl_def_id: DefId,
impl_trait_ref: TraitRef<'tcx>,
parent_impl: DefId) {
assert!(!impl_def_id.is_local());
// if the impl has not previously been recorded
if self.record_impl(tcx, impl_def_id, impl_trait_ref) {
// if the impl is non-local, it's placed directly into the
// specialization graph using parent information drawn from metadata.
self.specialization_graph.borrow_mut()
.record_impl_from_cstore(tcx, parent_impl, impl_def_id)
}
}
/// Adds a local impl into the specialization graph, returning an error with
/// overlap information if the impl overlaps but does not specialize an
/// existing impl.
pub fn add_impl_for_specialization(&self,
tcx: TyCtxt<'a, 'gcx, 'tcx>,
impl_def_id: DefId)
-> Result<(), traits::OverlapError> {
assert!(impl_def_id.is_local());
self.specialization_graph.borrow_mut()
.insert(tcx, impl_def_id)
}
pub fn ancestors(&'a self, of_impl: DefId) -> specialization_graph::Ancestors<'a> {
specialization_graph::ancestors(self, of_impl)
}
/// Whether the impl set and specialization graphs are complete.
pub fn is_complete(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> bool {
tcx.populate_implementations_for_trait_if_necessary(self.def_id);
ty::queries::coherent_trait::try_get(tcx, DUMMY_SP, (LOCAL_CRATE, self.def_id)).is_ok()
}
/// If any local impls haven't been added yet, returns
/// Some(list of local impls for this trait).
fn missing_local_impls(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>)
-> Option<&'gcx [ast::NodeId]> {
if self.flags.get().intersects(TraitFlags::HAS_LOCAL_IMPLS) {
return None;
}
if self.is_complete(tcx) {
self.flags.set(self.flags.get() | TraitFlags::HAS_LOCAL_IMPLS);
return None;
}
let impls = tcx.hir.trait_impls(self.def_id);
assert!(self.local_impl_count.get() <= impls.len());
if self.local_impl_count.get() == impls.len() {
self.flags.set(self.flags.get() | TraitFlags::HAS_LOCAL_IMPLS);
return None;
}
Some(impls)
pub fn ancestors(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>,
of_impl: DefId)
-> specialization_graph::Ancestors {
specialization_graph::ancestors(tcx, self.def_id, of_impl)
}
pub fn for_each_impl<F: FnMut(DefId)>(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>, mut f: F) {
self.read_trait_impls(tcx);
tcx.populate_implementations_for_trait_if_necessary(self.def_id);
let local_impls = self.missing_local_impls(tcx);
if let Some(impls) = local_impls {
for &id in impls {
f(tcx.hir.local_def_id(id));
}
}
let mut f = |def_id: DefId| {
if !(local_impls.is_some() && def_id.is_local()) {
f(def_id);
}
};
for &impl_def_id in self.blanket_impls.borrow().iter() {
for impl_def_id in tcx.trait_impls_of(self.def_id).iter() {
f(impl_def_id);
}
for v in self.nonblanket_impls.borrow().values() {
for &impl_def_id in v {
f(impl_def_id);
}
}
}
/// Iterate over every impl that could possibly match the
@ -273,25 +124,6 @@ impl<'a, 'gcx, 'tcx> TraitDef {
self_ty: Ty<'tcx>,
mut f: F)
{
self.read_trait_impls(tcx);
tcx.populate_implementations_for_trait_if_necessary(self.def_id);
let local_impls = self.missing_local_impls(tcx);
if let Some(impls) = local_impls {
for &id in impls {
f(tcx.hir.local_def_id(id));
}
}
let mut f = |def_id: DefId| {
if !(local_impls.is_some() && def_id.is_local()) {
f(def_id);
}
};
for &impl_def_id in self.blanket_impls.borrow().iter() {
f(impl_def_id);
}
// simplify_type(.., false) basically replaces type parameters and
// projections with infer-variables. This is, of course, done on
// the impl trait-ref when it is instantiated, but not on the
@ -304,29 +136,86 @@ impl<'a, 'gcx, 'tcx> TraitDef {
// replace `S` with anything - this impl of course can't be
// selected, and as there are hundreds of similar impls,
// considering them would significantly harm performance.
if let Some(simp) = fast_reject::simplify_type(tcx, self_ty, true) {
if let Some(impls) = self.nonblanket_impls.borrow().get(&simp) {
for &impl_def_id in impls {
f(impl_def_id);
}
}
let relevant_impls = if let Some(simplified_self_ty) =
fast_reject::simplify_type(tcx, self_ty, true) {
tcx.relevant_trait_impls_for((self.def_id, simplified_self_ty))
} else {
for v in self.nonblanket_impls.borrow().values() {
for &impl_def_id in v {
f(impl_def_id);
}
}
tcx.trait_impls_of(self.def_id)
};
for impl_def_id in relevant_impls.iter() {
f(impl_def_id);
}
}
}
bitflags! {
flags TraitFlags: u32 {
const NO_TRAIT_FLAGS = 0,
const HAS_DEFAULT_IMPL = 1 << 0,
const IS_OBJECT_SAFE = 1 << 1,
const OBJECT_SAFETY_VALID = 1 << 2,
const HAS_REMOTE_IMPLS = 1 << 3,
const HAS_LOCAL_IMPLS = 1 << 4,
// Query provider for `trait_impls_of`.
pub(super) fn trait_impls_of_provider<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
trait_id: DefId)
-> TraitImpls {
let remote_impls = if trait_id.is_local() {
// Traits defined in the current crate can't have impls in upstream
// crates, so we don't bother querying the cstore.
Vec::new()
} else {
tcx.sess.cstore.implementations_of_trait(Some(trait_id))
};
let mut blanket_impls = Vec::new();
let mut non_blanket_impls = Vec::new();
let local_impls = tcx.hir
.trait_impls(trait_id)
.into_iter()
.map(|&node_id| tcx.hir.local_def_id(node_id));
for impl_def_id in local_impls.chain(remote_impls.into_iter()) {
let impl_self_ty = tcx.type_of(impl_def_id);
if impl_def_id.is_local() && impl_self_ty.references_error() {
continue
}
if fast_reject::simplify_type(tcx, impl_self_ty, false).is_some() {
non_blanket_impls.push(impl_def_id);
} else {
blanket_impls.push(impl_def_id);
}
}
TraitImpls {
blanket_impls: Rc::new(blanket_impls),
non_blanket_impls: Rc::new(non_blanket_impls),
}
}
// Query provider for `relevant_trait_impls_for`.
pub(super) fn relevant_trait_impls_provider<'a, 'tcx>(
tcx: TyCtxt<'a, 'tcx, 'tcx>,
(trait_id, self_ty): (DefId, fast_reject::SimplifiedType))
-> TraitImpls
{
let all_trait_impls = tcx.trait_impls_of(trait_id);
let relevant: Vec<DefId> = all_trait_impls
.non_blanket_impls
.iter()
.cloned()
.filter(|&impl_def_id| {
let impl_self_ty = tcx.type_of(impl_def_id);
let impl_simple_self_ty = fast_reject::simplify_type(tcx,
impl_self_ty,
false).unwrap();
impl_simple_self_ty == self_ty
})
.collect();
if all_trait_impls.non_blanket_impls.len() == relevant.len() {
// If we didn't filter anything out, re-use the existing vec.
all_trait_impls
} else {
TraitImpls {
blanket_impls: all_trait_impls.blanket_impls.clone(),
non_blanket_impls: Rc::new(relevant),
}
}
}

View file

@ -22,6 +22,7 @@ use rustc::middle::{self, dependency_format, stability, reachable};
use rustc::middle::privacy::AccessLevels;
use rustc::mir::transform::{MIR_CONST, MIR_VALIDATED, MIR_OPTIMIZED, Passes};
use rustc::ty::{self, TyCtxt, Resolutions, GlobalArenas};
use rustc::traits;
use rustc::util::common::time;
use rustc::util::nodemap::NodeSet;
use rustc::util::fs::rename_or_copy_remove;
@ -894,6 +895,7 @@ pub fn phase_3_run_analysis_passes<'tcx, F, R>(sess: &'tcx Session,
trans::provide(&mut local_providers);
typeck::provide(&mut local_providers);
ty::provide(&mut local_providers);
traits::provide(&mut local_providers);
reachable::provide(&mut local_providers);
rustc_const_eval::provide(&mut local_providers);
middle::region::provide(&mut local_providers);
@ -902,6 +904,7 @@ pub fn phase_3_run_analysis_passes<'tcx, F, R>(sess: &'tcx Session,
cstore::provide(&mut extern_providers);
trans::provide(&mut extern_providers);
ty::provide_extern(&mut extern_providers);
traits::provide_extern(&mut extern_providers);
// FIXME(eddyb) get rid of this once we replace const_eval with miri.
rustc_const_eval::provide(&mut extern_providers);

View file

@ -36,9 +36,10 @@ use rustc::hir::def_id::{LOCAL_CRATE, CRATE_DEF_INDEX, DefId};
use rustc::hir::itemlikevisit::ItemLikeVisitor;
use rustc::ich::{Fingerprint, StableHashingContext};
use rustc::ty::TyCtxt;
use rustc::util::common::record_time;
use rustc_data_structures::stable_hasher::{StableHasher, HashStable};
use rustc_data_structures::fx::FxHashMap;
use rustc::util::common::record_time;
use rustc_data_structures::accumulate_vec::AccumulateVec;
pub type IchHasher = StableHasher<Fingerprint>;
@ -159,6 +160,11 @@ impl<'a, 'tcx: 'a> ComputeItemHashesVisitor<'a, 'tcx> {
// difference, filter them out.
return None
}
DepNode::AllLocalTraitImpls => {
// These are already covered by hashing
// the HIR.
return None
}
ref other => {
bug!("Found unexpected DepNode during \
SVH computation: {:?}",
@ -213,6 +219,49 @@ impl<'a, 'tcx: 'a> ComputeItemHashesVisitor<'a, 'tcx> {
true,
(module, (span, attrs)));
}
fn compute_and_store_ich_for_trait_impls(&mut self, krate: &'tcx hir::Crate)
{
let tcx = self.hcx.tcx();
let mut impls: Vec<(u64, Fingerprint)> = krate
.trait_impls
.iter()
.map(|(&trait_id, impls)| {
let trait_id = tcx.def_path_hash(trait_id);
let mut impls: AccumulateVec<[_; 32]> = impls
.iter()
.map(|&node_id| {
let def_id = tcx.hir.local_def_id(node_id);
tcx.def_path_hash(def_id)
})
.collect();
impls.sort_unstable();
let mut hasher = StableHasher::new();
impls.hash_stable(&mut self.hcx, &mut hasher);
(trait_id, hasher.finish())
})
.collect();
impls.sort_unstable();
let mut default_impls: AccumulateVec<[_; 32]> = krate
.trait_default_impl
.iter()
.map(|(&trait_def_id, &impl_node_id)| {
let impl_def_id = tcx.hir.local_def_id(impl_node_id);
(tcx.def_path_hash(trait_def_id), tcx.def_path_hash(impl_def_id))
})
.collect();
default_impls.sort_unstable();
let mut hasher = StableHasher::new();
impls.hash_stable(&mut self.hcx, &mut hasher);
self.hashes.insert(DepNode::AllLocalTraitImpls, hasher.finish());
}
}
impl<'a, 'tcx: 'a> ItemLikeVisitor<'tcx> for ComputeItemHashesVisitor<'a, 'tcx> {
@ -235,6 +284,8 @@ impl<'a, 'tcx: 'a> ItemLikeVisitor<'tcx> for ComputeItemHashesVisitor<'a, 'tcx>
}
}
pub fn compute_incremental_hashes_map<'a, 'tcx: 'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>)
-> IncrementalHashesMap {
let _ignore = tcx.dep_graph.in_ignore();
@ -272,6 +323,8 @@ pub fn compute_incremental_hashes_map<'a, 'tcx: 'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>)
let fingerprint = hasher.finish();
visitor.hashes.insert(dep_node, fingerprint);
}
visitor.compute_and_store_ich_for_trait_impls(krate);
});
tcx.sess.perf_stats.incr_comp_hashes_count.set(visitor.hashes.len() as u64);

View file

@ -315,11 +315,20 @@ impl<'a> CrateLoader<'a> {
let exported_symbols = crate_root.exported_symbols
.map(|x| x.decode(&metadata).collect());
let trait_impls = crate_root
.impls
.map(|impls| {
impls.decode(&metadata)
.map(|trait_impls| (trait_impls.trait_id, trait_impls.impls))
.collect()
});
let mut cmeta = cstore::CrateMetadata {
name: name,
extern_crate: Cell::new(None),
def_path_table: def_path_table,
exported_symbols: exported_symbols,
trait_impls: trait_impls,
proc_macros: crate_root.macro_derive_registrar.map(|_| {
self.load_derive_macros(&crate_root, dylib.clone().map(|p| p.0), span)
}),

View file

@ -80,6 +80,8 @@ pub struct CrateMetadata {
pub exported_symbols: Tracked<FxHashSet<DefIndex>>,
pub trait_impls: Tracked<FxHashMap<(u32, DefIndex), schema::LazySeq<DefIndex>>>,
pub dep_kind: Cell<DepKind>,
pub source: CrateSource,

View file

@ -149,10 +149,8 @@ impl CrateStore for cstore::CStore {
fn implementations_of_trait(&self, filter: Option<DefId>) -> Vec<DefId>
{
if let Some(def_id) = filter {
self.dep_graph.read(DepNode::MetaData(def_id));
}
let mut result = vec![];
self.iter_crate_data(|_, cdata| {
cdata.get_implementations_for_trait(filter, &self.dep_graph, &mut result)
});

View file

@ -501,16 +501,11 @@ impl<'a, 'tcx> CrateMetadata {
_ => bug!(),
};
let def = ty::TraitDef::new(self.local_def_id(item_id),
data.unsafety,
data.paren_sugar,
self.def_path_table.def_path_hash(item_id));
if data.has_default_impl {
def.record_has_default_impl();
}
def
ty::TraitDef::new(self.local_def_id(item_id),
data.unsafety,
data.paren_sugar,
data.has_default_impl,
self.def_path_table.def_path_hash(item_id))
}
fn get_variant(&self, item: &Entry, index: DefIndex) -> ty::VariantDef {
@ -957,17 +952,17 @@ impl<'a, 'tcx> CrateMetadata {
None => None,
};
// FIXME(eddyb) Make this O(1) instead of O(n).
let dep_node = self.metadata_dep_node(GlobalMetaDataKind::Impls);
for trait_impls in self.root.impls.get(dep_graph, dep_node).decode(self) {
if filter.is_some() && filter != Some(trait_impls.trait_id) {
continue;
if let Some(filter) = filter {
if let Some(impls) = self.trait_impls
.get(dep_graph, dep_node)
.get(&filter) {
result.extend(impls.decode(self).map(|idx| self.local_def_id(idx)));
}
result.extend(trait_impls.impls.decode(self).map(|index| self.local_def_id(index)));
if filter.is_some() {
break;
} else {
for impls in self.trait_impls.get(dep_graph, dep_node).values() {
result.extend(impls.decode(self).map(|idx| self.local_def_id(idx)));
}
}
}

View file

@ -943,7 +943,7 @@ impl<'a, 'b: 'a, 'tcx: 'b> IsolatedEncoder<'a, 'b, 'tcx> {
let trait_ref = tcx.impl_trait_ref(def_id);
let parent = if let Some(trait_ref) = trait_ref {
let trait_def = tcx.trait_def(trait_ref.def_id);
trait_def.ancestors(def_id).skip(1).next().and_then(|node| {
trait_def.ancestors(tcx, def_id).skip(1).next().and_then(|node| {
match node {
specialization_graph::Node::Impl(parent) => Some(parent),
_ => None,
@ -1295,23 +1295,37 @@ impl<'a, 'b: 'a, 'tcx: 'b> IsolatedEncoder<'a, 'b, 'tcx> {
/// Encodes an index, mapping each trait to its (local) implementations.
fn encode_impls(&mut self, _: ()) -> LazySeq<TraitImpls> {
debug!("IsolatedEncoder::encode_impls()");
let tcx = self.tcx;
let mut visitor = ImplVisitor {
tcx: self.tcx,
tcx: tcx,
impls: FxHashMap(),
};
self.tcx.hir.krate().visit_all_item_likes(&mut visitor);
tcx.hir.krate().visit_all_item_likes(&mut visitor);
let all_impls: Vec<_> = visitor.impls
let mut all_impls: Vec<_> = visitor.impls.into_iter().collect();
// Bring everything into deterministic order for hashing
all_impls.sort_unstable_by_key(|&(trait_def_id, _)| {
tcx.def_path_hash(trait_def_id)
});
let all_impls: Vec<_> = all_impls
.into_iter()
.map(|(trait_def_id, impls)| {
.map(|(trait_def_id, mut impls)| {
// Bring everything into deterministic order for hashing
impls.sort_unstable_by_key(|&def_index| {
tcx.hir.definitions().def_path_hash(def_index)
});
TraitImpls {
trait_id: (trait_def_id.krate.as_u32(), trait_def_id.index),
impls: self.lazy_seq(impls),
impls: self.lazy_seq_from_slice(&impls[..]),
}
})
.collect();
self.lazy_seq(all_impls)
self.lazy_seq_from_slice(&all_impls[..])
}
// Encodes all symbols exported from this crate into the metadata.

View file

@ -29,6 +29,7 @@
#![cfg_attr(stage0, unstable(feature = "rustc_private", issue = "27812"))]
#![cfg_attr(stage0, feature(staged_api))]
#![feature(sort_unstable)]
#[macro_use]
extern crate log;

View file

@ -221,6 +221,20 @@ impl<T> Tracked<T> {
}
}
impl<'a, 'tcx, T> HashStable<StableHashingContext<'a, 'tcx>> for Tracked<T>
where T: HashStable<StableHashingContext<'a, 'tcx>>
{
fn hash_stable<W: StableHasherResult>(&self,
hcx: &mut StableHashingContext<'a, 'tcx>,
hasher: &mut StableHasher<W>) {
let Tracked {
ref state
} = *self;
state.hash_stable(hcx, hasher);
}
}
#[derive(RustcEncodable, RustcDecodable)]
pub struct CrateRoot {

View file

@ -1200,7 +1200,7 @@ fn check_specialization_validity<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
impl_id: DefId,
impl_item: &hir::ImplItem)
{
let ancestors = trait_def.ancestors(impl_id);
let ancestors = trait_def.ancestors(tcx, impl_id);
let kind = match impl_item.node {
hir::ImplItemKind::Const(..) => ty::AssociatedKind::Const,
@ -1330,7 +1330,7 @@ fn check_impl_items_against_trait<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
let mut invalidated_items = Vec::new();
let associated_type_overridden = overridden_associated_type.is_some();
for trait_item in tcx.associated_items(impl_trait_ref.def_id) {
let is_implemented = trait_def.ancestors(impl_id)
let is_implemented = trait_def.ancestors(tcx, impl_id)
.defs(tcx, trait_item.name, trait_item.kind)
.next()
.map(|node_item| !node_item.node.is_from_trait())

View file

@ -46,8 +46,6 @@ fn check_impl<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, node_id: ast::NodeId) {
}
enforce_trait_manually_implementable(tcx, impl_def_id, trait_ref.def_id);
let trait_def = tcx.trait_def(trait_ref.def_id);
trait_def.record_local_impl(tcx, impl_def_id, trait_ref);
}
}
@ -117,8 +115,6 @@ pub fn provide(providers: &mut Providers) {
fn coherent_trait<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
(_, def_id): (CrateNum, DefId)) {
tcx.populate_implementations_for_trait_if_necessary(def_id);
let impls = tcx.hir.trait_impls(def_id);
for &impl_id in impls {
check_impl(tcx, impl_id);

View file

@ -41,39 +41,10 @@ pub fn check_impl<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, node_id: ast::NodeId) {
let _task =
tcx.dep_graph.in_task(DepNode::CoherenceOverlapCheck(trait_def_id));
let def = tcx.trait_def(trait_def_id);
// Trigger building the specialization graph for the trait of this impl.
// This will detect any overlap errors.
tcx.specialization_graph_of(trait_def_id);
// attempt to insert into the specialization graph
let insert_result = def.add_impl_for_specialization(tcx, impl_def_id);
// insertion failed due to overlap
if let Err(overlap) = insert_result {
let mut err = struct_span_err!(tcx.sess,
tcx.span_of_impl(impl_def_id).unwrap(),
E0119,
"conflicting implementations of trait `{}`{}:",
overlap.trait_desc,
overlap.self_desc.clone().map_or(String::new(),
|ty| {
format!(" for type `{}`", ty)
}));
match tcx.span_of_impl(overlap.with_impl) {
Ok(span) => {
err.span_label(span, "first implementation here");
err.span_label(tcx.span_of_impl(impl_def_id).unwrap(),
format!("conflicting implementation{}",
overlap.self_desc
.map_or(String::new(),
|ty| format!(" for `{}`", ty))));
}
Err(cname) => {
err.note(&format!("conflicting implementation in crate `{}`", cname));
}
}
err.emit();
}
// check for overlap with the automatic `impl Trait for Trait`
if let ty::TyDynamic(ref data, ..) = trait_ref.self_ty().sty {

View file

@ -749,12 +749,12 @@ fn trait_def<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
}
let def_path_hash = tcx.def_path_hash(def_id);
let def = ty::TraitDef::new(def_id, unsafety, paren_sugar, def_path_hash);
if tcx.hir.trait_is_auto(def_id) {
def.record_has_default_impl();
}
let has_default_impl = tcx.hir.trait_is_auto(def_id);
let def = ty::TraitDef::new(def_id,
unsafety,
paren_sugar,
has_default_impl,
def_path_hash);
tcx.alloc_trait_def(def)
}

View file

@ -1524,67 +1524,6 @@ impl TypeWrapper {
```
"##,
E0119: r##"
There are conflicting trait implementations for the same type.
Example of erroneous code:
```compile_fail,E0119
trait MyTrait {
fn get(&self) -> usize;
}
impl<T> MyTrait for T {
fn get(&self) -> usize { 0 }
}
struct Foo {
value: usize
}
impl MyTrait for Foo { // error: conflicting implementations of trait
// `MyTrait` for type `Foo`
fn get(&self) -> usize { self.value }
}
```
When looking for the implementation for the trait, the compiler finds
both the `impl<T> MyTrait for T` where T is all types and the `impl
MyTrait for Foo`. Since a trait cannot be implemented multiple times,
this is an error. So, when you write:
```
trait MyTrait {
fn get(&self) -> usize;
}
impl<T> MyTrait for T {
fn get(&self) -> usize { 0 }
}
```
This makes the trait implemented on all types in the scope. So if you
try to implement it on another one after that, the implementations will
conflict. Example:
```
trait MyTrait {
fn get(&self) -> usize;
}
impl<T> MyTrait for T {
fn get(&self) -> usize { 0 }
}
struct Foo;
fn main() {
let f = Foo;
f.get(); // the trait is implemented so we can use it
}
```
"##,
E0120: r##"
An attempt was made to implement Drop on a trait, which is not allowed: only
structs and enums can implement Drop. An example causing this error:

View file

@ -0,0 +1,34 @@
// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// Formerly this ICEd with the following message:
// Tried to project an inherited associated type during coherence checking,
// which is currently not supported.
//
// No we expect to run into a more user-friendly cycle error instead.
#![feature(specialization)]
trait Trait<T> { type Assoc; }
//~^ unsupported cyclic reference between types/traits detected [E0391]
impl<T> Trait<T> for Vec<T> {
type Assoc = ();
}
impl Trait<u8> for Vec<u8> {}
impl<T> Trait<T> for String {
type Assoc = ();
}
impl Trait<<Vec<u8> as Trait<u8>>::Assoc> for String {}
fn main() {}

View file

@ -10,10 +10,9 @@
// ignore-tidy-linelength
// aux-build:extern_crate.rs
//[rpass1] compile-flags: -g
//[rpass2] compile-flags: -g
//[rpass3] compile-flags: -g -Zremap-path-prefix-from={{src-base}} -Zremap-path-prefix-to=/the/src
//[rpass1] compile-flags: -g -Zincremental-cc
//[rpass2] compile-flags: -g -Zincremental-cc
//[rpass3] compile-flags: -g -Zincremental-cc -Zremap-path-prefix-from={{src-base}} -Zremap-path-prefix-to=/the/src
#![feature(rustc_attrs)]
#![crate_type="rlib"]

View file

@ -9,7 +9,7 @@
// except according to those terms.
// revisions:rpass1 rpass2 rpass3
// compile-flags: -Z query-dep-graph -g
// compile-flags: -Z query-dep-graph -g -Zincremental-cc
// aux-build:extern_crate.rs

View file

@ -0,0 +1,33 @@
// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// Make sure we don't crash with a cycle error during coherence.
#![feature(specialization)]
trait Trait<T> {
type Assoc;
}
impl<T> Trait<T> for Vec<T> {
default type Assoc = ();
}
impl Trait<u8> for Vec<u8> {
type Assoc = u8;
}
impl<T> Trait<T> for String {
type Assoc = ();
}
impl Trait<<Vec<u8> as Trait<u8>>::Assoc> for String {}
fn main() {}