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:
commit
4640e18572
@ -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 } => {
|
||||
|
@ -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.
|
||||
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
};
|
||||
}
|
||||
|
@ -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()
|
||||
}
|
||||
|
@ -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))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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)
|
||||
}
|
||||
|
@ -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)),
|
||||
}
|
||||
}
|
||||
|
@ -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)
|
||||
}
|
||||
|
@ -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
|
||||
};
|
||||
}
|
||||
|
@ -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),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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)
|
||||
}),
|
||||
|
@ -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,
|
||||
|
||||
|
@ -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)
|
||||
});
|
||||
|
@ -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)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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.
|
||||
|
@ -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;
|
||||
|
@ -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 {
|
||||
|
@ -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())
|
||||
|
@ -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);
|
||||
|
@ -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 {
|
||||
|
@ -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)
|
||||
}
|
||||
|
||||
|
@ -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:
|
||||
|
@ -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() {}
|
@ -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"]
|
||||
|
@ -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
|
||||
|
||||
|
||||
|
33
src/test/run-pass/specialization/assoc-ty-graph-cycle.rs
Normal file
33
src/test/run-pass/specialization/assoc-ty-graph-cycle.rs
Normal 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() {}
|
Loading…
Reference in New Issue
Block a user