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
// 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
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 } => {
[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.
}
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
}
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
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);
+ }
+}
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;
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);
+ }
+}
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;
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);
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
+ };
+}
}
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
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()
+}
// 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())
- };
-
- // 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 node_item = assoc_ty_def(selcx,
+ impl_data.impl_def_id,
+ obligation.predicate.item_name);
+
+ 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(..) => {
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
}
}
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);
-
- 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,
- });
- }
+ 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);
+
+ // 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))
}
}
use traits::{self, Reveal, ObligationCause};
use ty::{self, TyCtxt, TypeFoldable};
use syntax_pos::DUMMY_SP;
+use std::rc::Rc;
pub mod specialization_graph;
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| {
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)
+}
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};
}
}
-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));
}
}
-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.
/// 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)),
}
}
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;
}
}
+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
}
}
+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])*
[] 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> {
fn crate_variances(_: CrateNum) -> DepNode<DefId> {
DepNode::CrateVariances
}
+
+fn relevant_trait_impls_for((def_id, _): (DefId, SimplifiedType)) -> DepNode<DefId> {
+ DepNode::TraitImpls(def_id)
+}
pub use self::instance::{Instance, InstanceDef};
-pub use self::trait_def::{TraitDef, TraitFlags};
+pub use self::trait_def::TraitDef;
pub use self::maps::queries;
}
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.
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
};
}
*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
};
}
// 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 {
/// 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,
}
-impl<'a, 'gcx, 'tcx> TraitDef {
- pub fn new(def_id: DefId,
- unsafety: hir::Unsafety,
- paren_sugar: 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,
- }
- }
+// 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>>,
+}
- // 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
+impl TraitImpls {
+ pub fn iter(&self) -> TraitImplsIter {
+ TraitImplsIter {
+ blanket_impls: self.blanket_impls.clone(),
+ non_blanket_impls: self.non_blanket_impls.clone(),
+ index: 0
}
}
+}
- 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);
+#[derive(Clone)]
+pub struct TraitImplsIter {
+ blanket_impls: Rc<Vec<DefId>>,
+ non_blanket_impls: Rc<Vec<DefId>>,
+ index: usize,
+}
- // 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);
- }
+impl Iterator for TraitImplsIter {
+ type Item = DefId;
- // 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)
+ 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 {
- if self.blanket_impls.borrow().contains(&impl_def_id) {
- return false; // duplicate - skip
+ 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
}
- 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);
+ 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))
}
+}
- /// 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());
+impl ExactSizeIterator for TraitImplsIter {}
- // 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)
+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,
+ paren_sugar,
+ unsafety,
+ has_default_impl,
+ def_path_hash,
}
}
- /// 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
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
// 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),
+ }
}
}
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;
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);
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);
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>;
// 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: {:?}",
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> {
}
}
+
+
pub fn compute_incremental_hashes_map<'a, 'tcx: 'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>)
-> IncrementalHashesMap {
let _ignore = tcx.dep_graph.in_ignore();
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);
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)
}),
pub exported_symbols: Tracked<FxHashSet<DefIndex>>,
+ pub trait_impls: Tracked<FxHashMap<(u32, DefIndex), schema::LazySeq<DefIndex>>>,
+
pub dep_kind: Cell<DepKind>,
pub source: CrateSource,
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)
});
_ => 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 {
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;
- }
- result.extend(trait_impls.impls.decode(self).map(|index| self.local_def_id(index)));
-
- if filter.is_some() {
- break;
+ 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)));
+ }
+ } 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)));
}
}
}
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,
/// 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 mut all_impls: Vec<_> = visitor.impls.into_iter().collect();
- let all_impls: Vec<_> = visitor.impls
+ // 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.
#![cfg_attr(stage0, unstable(feature = "rustc_private", issue = "27812"))]
#![cfg_attr(stage0, feature(staged_api))]
+#![feature(sort_unstable)]
#[macro_use]
extern crate log;
}
}
+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 {
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,
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())
}
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);
}
}
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);
let _task =
tcx.dep_graph.in_task(DepNode::CoherenceOverlapCheck(trait_def_id));
- let def = tcx.trait_def(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));
- }
- }
+ // Trigger building the specialization graph for the trait of this impl.
+ // This will detect any overlap errors.
+ tcx.specialization_graph_of(trait_def_id);
- err.emit();
- }
// check for overlap with the automatic `impl Trait for Trait`
if let ty::TyDynamic(ref data, ..) = trait_ref.self_ty().sty {
}
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)
}
```
"##,
-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:
--- /dev/null
+// 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() {}
// 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"]
// 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
--- /dev/null
+// 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() {}