Initial incorporation of specialization:

- Rewrites the overlap checker to instead build up a specialization
  graph, checking for overlap errors in the process.

- Use the specialization order during impl selection.

This commit does not yet handle associated types correctly, and assumes
that all items are `default` and are overridden.
This commit is contained in:
Aaron Turon 2015-12-22 10:20:47 -08:00
parent c5849e4dff
commit 1f34086e94
17 changed files with 253 additions and 218 deletions

View File

@ -51,7 +51,7 @@ could invalidate work done for other items. So, for example:
not shared state, because if it changes it does not itself
invalidate other functions (though it may be that it causes new
monomorphizations to occur, but that's handled independently).
Put another way: if the HIR for an item changes, we are going to
recompile that item for sure. But we need the dep tracking map to tell
us what *else* we have to recompile. Shared state is anything that is
@ -177,7 +177,7 @@ reads from `item`, there would be missing edges in the graph:
| ^
| |
+---------------------------------+ // added by `visit_all_items_in_krate`
In particular, the edge from `Hir(X)` to `ItemSignature(X)` is only
present because we called `read` ourselves when entering the `ItemSignature(X)`
task.
@ -273,8 +273,8 @@ should not exist. In contrast, using the memoized helper, you get:
... -> MapVariant(key) -> A
|
+----------> B
which is much cleaner.
which is much cleaner.
**Be aware though that the closure is executed with `MapVariant(key)`
pushed onto the stack as the current task!** That means that you must
@ -387,4 +387,3 @@ RUST_DEP_GRAPH_FILTER='Hir&foo -> TypeckItemBody & bar'
This will dump out all the nodes that lead from `Hir(foo)` to
`TypeckItemBody(bar)`, from which you can (hopefully) see the source
of the erroneous edge.

View File

@ -176,6 +176,7 @@ pub trait CrateStore<'tcx> : Any {
-> Option<ty::adjustment::CustomCoerceUnsized>;
fn associated_consts(&self, tcx: &TyCtxt<'tcx>, def: DefId)
-> Vec<Rc<ty::AssociatedConst<'tcx>>>;
fn impl_parent(&self, impl_def_id: DefId) -> Option<DefId>;
// trait/impl-item info
fn trait_of_item(&self, tcx: &TyCtxt<'tcx>, def_id: DefId)
@ -346,6 +347,7 @@ impl<'tcx> CrateStore<'tcx> for DummyCrateStore {
{ unimplemented!() }
fn associated_consts(&self, tcx: &TyCtxt<'tcx>, def: DefId)
-> Vec<Rc<ty::AssociatedConst<'tcx>>> { unimplemented!() }
fn impl_parent(&self, def: DefId) -> Option<DefId> { unimplemented!() }
// trait/impl-item info
fn trait_of_item(&self, tcx: &TyCtxt<'tcx>, def_id: DefId)

View File

@ -23,8 +23,8 @@ use syntax::codemap::DUMMY_SP;
#[derive(Copy, Clone)]
struct InferIsLocal(bool);
/// If there are types that satisfy both impls, returns an `ImplTy`
/// with those types substituted (by updating the given `infcx`)
/// If there are types that satisfy both impls, returns a suitably-freshened
/// `ImplHeader` with those types substituted
pub fn overlapping_impls<'cx, 'tcx>(infcx: &InferCtxt<'cx, 'tcx>,
impl1_def_id: DefId,
impl2_def_id: DefId)
@ -85,7 +85,10 @@ fn overlap<'cx, 'tcx>(selcx: &mut SelectionContext<'cx, 'tcx>,
return None
}
Some(selcx.infcx().resolve_type_vars_if_possible(&a_impl_header))
let substituted = selcx.infcx().resolve_type_vars_if_possible(&a_impl_header);
let freshened = selcx.infcx().freshen(substituted);
Some(freshened)
}
pub fn trait_ref_is_knowable<'tcx>(tcx: &TyCtxt<'tcx>, trait_ref: &ty::TraitRef<'tcx>) -> bool

View File

@ -50,6 +50,7 @@ pub use self::select::SelectionContext;
pub use self::select::SelectionCache;
pub use self::select::{MethodMatchResult, MethodMatched, MethodAmbiguous, MethodDidNotMatch};
pub use self::select::{MethodMatchedData}; // intentionally don't export variants
pub use self::specialize::{Overlap, SpecializationGraph, specializes};
pub use self::util::elaborate_predicates;
pub use self::util::get_vtable_index_of_object_method;
pub use self::util::trait_ref_for_builtin_bound;
@ -67,6 +68,7 @@ mod fulfill;
mod project;
mod object_safety;
mod select;
mod specialize;
mod structural_impls;
mod util;

View File

@ -40,6 +40,7 @@ use middle::infer;
use middle::infer::{InferCtxt, TypeFreshener, TypeOrigin};
use middle::subst::{Subst, Substs, TypeSpace};
use middle::ty::{self, ToPredicate, ToPolyTraitRef, Ty, TyCtxt, TypeFoldable};
use middle::traits;
use middle::ty::fast_reject;
use middle::ty::relate::TypeRelation;
@ -224,6 +225,12 @@ struct SelectionCandidateSet<'tcx> {
ambiguous: bool,
}
#[derive(PartialEq,Eq,Debug,Clone)]
struct EvaluatedCandidate<'tcx> {
candidate: SelectionCandidate<'tcx>,
evaluation: EvaluationResult,
}
enum BuiltinBoundConditions<'tcx> {
If(ty::Binder<Vec<Ty<'tcx>>>),
ParameterBuiltin,
@ -746,6 +753,17 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
candidate
}
// Treat negative impls as unimplemented
fn filter_negative_impls(&self, candidate: SelectionCandidate<'tcx>)
-> SelectionResult<'tcx, SelectionCandidate<'tcx>> {
if let ImplCandidate(def_id) = candidate {
if self.tcx().trait_impl_polarity(def_id) == Some(hir::ImplPolarity::Negative) {
return Err(Unimplemented)
}
}
Ok(Some(candidate))
}
fn candidate_from_obligation_no_cache<'o>(&mut self,
stack: &TraitObligationStack<'o, 'tcx>)
-> SelectionResult<'tcx, SelectionCandidate<'tcx>>
@ -803,12 +821,27 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
// we were to winnow, we'd wind up with zero candidates.
// Instead, we select the right impl now but report `Bar does
// not implement Clone`.
if candidates.len() > 1 {
candidates.retain(|c| self.evaluate_candidate(stack, c).may_apply())
if candidates.len() == 1 {
return self.filter_negative_impls(candidates.pop().unwrap());
}
// If there are STILL multiple candidate, we can further reduce
// the list by dropping duplicates.
// Winnow, but record the exact outcome of evaluation, which
// is needed for specialization.
let mut candidates: Vec<_> = candidates.into_iter().filter_map(|c| {
let eval = self.evaluate_candidate(stack, &c);
if eval.may_apply() {
Some(EvaluatedCandidate {
candidate: c,
evaluation: eval,
})
} else {
None
}
}).collect();
// If there are STILL multiple candidate, we can further
// reduce the list by dropping duplicates -- including
// resolving specializations.
if candidates.len() > 1 {
let mut i = 0;
while i < candidates.len() {
@ -850,19 +883,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
}
// Just one candidate left.
let candidate = candidates.pop().unwrap();
match candidate {
ImplCandidate(def_id) => {
match self.tcx().trait_impl_polarity(def_id) {
Some(hir::ImplPolarity::Negative) => return Err(Unimplemented),
_ => {}
}
}
_ => {}
}
Ok(Some(candidate))
self.filter_negative_impls(candidates.pop().unwrap().candidate)
}
fn is_knowable<'o>(&mut self,
@ -1564,41 +1585,55 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
/// candidates and prefer where-clause candidates.
///
/// See the comment for "SelectionCandidate" for more details.
fn candidate_should_be_dropped_in_favor_of<'o>(&mut self,
victim: &SelectionCandidate<'tcx>,
other: &SelectionCandidate<'tcx>)
-> bool
fn candidate_should_be_dropped_in_favor_of<'o>(
&mut self,
victim: &EvaluatedCandidate<'tcx>,
other: &EvaluatedCandidate<'tcx>)
-> bool
{
if victim == other {
if victim.candidate == other.candidate {
return true;
}
match other {
&ObjectCandidate |
&ParamCandidate(_) | &ProjectionCandidate => match victim {
&DefaultImplCandidate(..) => {
match other.candidate {
ObjectCandidate |
ParamCandidate(_) | ProjectionCandidate => match victim.candidate {
DefaultImplCandidate(..) => {
self.tcx().sess.bug(
"default implementations shouldn't be recorded \
when there are other valid candidates");
}
&ImplCandidate(..) |
&ClosureCandidate(..) |
&FnPointerCandidate |
&BuiltinObjectCandidate |
&BuiltinUnsizeCandidate |
&DefaultImplObjectCandidate(..) |
&BuiltinCandidate(..) => {
ImplCandidate(..) |
ClosureCandidate(..) |
FnPointerCandidate |
BuiltinObjectCandidate |
BuiltinUnsizeCandidate |
DefaultImplObjectCandidate(..) |
BuiltinCandidate(..) => {
// We have a where-clause so don't go around looking
// for impls.
true
}
&ObjectCandidate |
&ProjectionCandidate => {
ObjectCandidate |
ProjectionCandidate => {
// Arbitrarily give param candidates priority
// over projection and object candidates.
true
},
&ParamCandidate(..) => false,
ParamCandidate(..) => false,
ErrorCandidate => false // propagate errors
},
ImplCandidate(other_def) => {
// See if we can toss out `victim` based on specialization.
// This requires us to know *for sure* that the `other` impl applies
// i.e. EvaluatedToOk:
if other.evaluation == EvaluatedToOk {
if let ImplCandidate(victim_def) = victim.candidate {
return traits::specializes(self.infcx(), other_def, victim_def);
}
}
false
},
_ => false
}

View File

@ -381,7 +381,6 @@ pub fn trait_ref_for_builtin_bound<'tcx>(
}
}
pub fn predicate_for_trait_ref<'tcx>(
cause: ObligationCause<'tcx>,
trait_ref: ty::TraitRef<'tcx>,

View File

@ -2456,8 +2456,13 @@ impl<'tcx> TyCtxt<'tcx> {
for impl_def_id in self.sess.cstore.implementations_of_trait(trait_id) {
let impl_items = self.sess.cstore.impl_items(impl_def_id);
let trait_ref = self.impl_trait_ref(impl_def_id).unwrap();
// Record the trait->implementation mapping.
def.record_impl(self, impl_def_id, trait_ref);
if let Some(parent) = self.sess.cstore.impl_parent(impl_def_id) {
def.record_remote_impl(self, impl_def_id, trait_ref, parent);
} else {
def.record_remote_impl(self, impl_def_id, trait_ref, trait_id);
}
// For any methods that use a default implementation, add them to
// the map. This is a bit unfortunate.

View File

@ -1106,6 +1106,13 @@ impl<'tcx> TyS<'tcx> {
}
}
pub fn has_concrete_skeleton(&self) -> bool {
match self.sty {
TyParam(_) | TyInfer(_) | TyError => false,
_ => true,
}
}
// Returns the type and mutability of *ty.
//
// The parameter `explicit` indicates if this is an *explicit* dereference.

View File

@ -59,6 +59,9 @@ pub struct TraitDef<'tcx> {
/// Blanket impls associated with the trait.
blanket_impls: RefCell<Vec<DefId>>,
/// The specialization order for impls of this trait.
pub specialization_graph: RefCell<traits::SpecializationGraph>,
/// Various flags
pub flags: Cell<TraitFlags>
}
@ -78,7 +81,8 @@ impl<'tcx> TraitDef<'tcx> {
associated_type_names: associated_type_names,
nonblanket_impls: RefCell::new(FnvHashMap()),
blanket_impls: RefCell::new(vec![]),
flags: Cell::new(ty::TraitFlags::NO_TRAIT_FLAGS)
flags: Cell::new(ty::TraitFlags::NO_TRAIT_FLAGS),
specialization_graph: RefCell::new(traits::SpecializationGraph::new()),
}
}
@ -114,42 +118,80 @@ impl<'tcx> TraitDef<'tcx> {
tcx.dep_graph.read(DepNode::TraitImpls(self.trait_ref.def_id));
}
/// Records a trait-to-implementation mapping.
pub fn record_impl(&self,
tcx: &TyCtxt<'tcx>,
impl_def_id: DefId,
impl_trait_ref: ty::TraitRef<'tcx>) {
/// Records a basic trait-to-implementation mapping.
///
/// Returns `true` iff the impl has not previously been recorded.
fn record_impl(&self,
tcx: &TyCtxt<'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 // duplicate - skip
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 // duplicate - skip
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<'tcx>,
impl_def_id: DefId,
impl_trait_ref: TraitRef<'tcx>) {
self.record_impl(tcx, impl_def_id, impl_trait_ref);
}
/// 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 maximally-specialized -- information that
/// should be pulled from the metadata.
pub fn record_remote_impl(&self,
tcx: &TyCtxt<'tcx>,
impl_def_id: DefId,
impl_trait_ref: TraitRef<'tcx>,
parent_impl: DefId) {
// 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(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: &ctxt<'tcx>,
impl_def_id: DefId,
impl_trait_ref: TraitRef<'tcx>)
-> Result<(), traits::Overlap<'tcx>> {
assert!(impl_def_id.is_local());
self.specialization_graph.borrow_mut()
.insert(tcx, impl_def_id, impl_trait_ref)
}
pub fn for_each_impl<F: FnMut(DefId)>(&self, tcx: &TyCtxt<'tcx>, mut f: F) {
self.read_trait_impls(tcx);
tcx.populate_implementations_for_trait_if_necessary(self.trait_ref.def_id);
for &impl_def_id in self.blanket_impls.borrow().iter() {
@ -223,4 +265,3 @@ bitflags! {
const IMPLS_VALID = 1 << 3,
}
}

View File

@ -243,6 +243,8 @@ pub const tag_items_data_item_deprecation: usize = 0xa7;
pub const tag_items_data_item_defaultness: usize = 0xa8;
pub const tag_items_data_parent_impl: usize = 0xa9;
pub const tag_rustc_version: usize = 0x10f;
pub fn rustc_version() -> String {
format!(

View File

@ -225,6 +225,11 @@ impl<'tcx> CrateStore<'tcx> for cstore::CStore {
decoder::get_associated_consts(self.intr.clone(), &cdata, def.index, tcx)
}
fn impl_parent(&self, impl_def: DefId) -> Option<DefId> {
let cdata = self.get_crate_data(impl_def.krate);
decoder::get_parent_impl(&*cdata, impl_def.index)
}
fn trait_of_item(&self, tcx: &TyCtxt<'tcx>, def_id: DefId) -> Option<DefId>
{
let cdata = self.get_crate_data(def_id.krate);

View File

@ -34,6 +34,7 @@ use middle::lang_items;
use middle::subst;
use middle::ty::{ImplContainer, TraitContainer};
use middle::ty::{self, Ty, TyCtxt, TypeFoldable, VariantKind};
use middle::traits;
use rustc_const_eval::ConstInt;
@ -564,6 +565,13 @@ pub fn get_visibility(cdata: Cmd, id: DefIndex) -> hir::Visibility {
item_visibility(cdata.lookup_item(id))
}
pub fn get_parent_impl(cdata: Cmd, id: DefIndex) -> Option<DefId> {
let item = cdata.lookup_item(id);
reader::maybe_get_doc(item, tag_items_data_parent_impl).map(|doc| {
translated_def_id(cdata, doc)
})
}
pub fn get_repr_attrs(cdata: Cmd, id: DefIndex) -> Vec<attr::ReprAttr> {
let item = cdata.lookup_item(id);
match reader::maybe_get_doc(item, tag_items_data_item_repr).map(|doc| {

View File

@ -884,6 +884,12 @@ fn encode_deprecation(rbml_w: &mut Encoder, depr_opt: Option<attr::Deprecation>)
});
}
fn encode_parent_impl(rbml_w: &mut Encoder, parent_opt: Option<DefId>) {
parent_opt.map(|parent| {
rbml_w.wr_tagged_u64(tag_items_data_parent_impl, def_to_u64(parent));
});
}
fn encode_xrefs<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>,
rbml_w: &mut Encoder,
xrefs: FnvHashMap<XRef<'tcx>, u32>)
@ -1161,8 +1167,12 @@ fn encode_info_for_item<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>,
}
rbml_w.end_tag();
}
if let Some(trait_ref) = tcx.impl_trait_ref(ecx.tcx.map.local_def_id(item.id)) {
let did = ecx.tcx.map.local_def_id(item.id);
if let Some(trait_ref) = tcx.impl_trait_ref(did) {
encode_trait_ref(rbml_w, ecx, trait_ref, tag_item_trait_ref);
let parent = tcx.lookup_trait_def(trait_ref.def_id).parent_of_impl(did);
encode_parent_impl(rbml_w, parent);
}
encode_path(rbml_w, path.clone());
encode_stability(rbml_w, stab);

View File

@ -15,7 +15,6 @@
// done by the orphan and overlap modules. Then we build up various
// mappings. That mapping code resides here.
use middle::def_id::DefId;
use middle::lang_items::UnsizeTraitLangItem;
use middle::subst::{self, Subst};
@ -197,7 +196,7 @@ impl<'a, 'tcx> CoherenceChecker<'a, 'tcx> {
debug!("add_trait_impl: impl_trait_ref={:?} impl_def_id={:?}",
impl_trait_ref, impl_def_id);
let trait_def = self.crate_context.tcx.lookup_trait_def(impl_trait_ref.def_id);
trait_def.record_impl(self.crate_context.tcx, impl_def_id, impl_trait_ref);
trait_def.record_local_impl(self.crate_context.tcx, impl_def_id, impl_trait_ref);
}
// Converts an implementation in the AST to a vector of items.

View File

@ -12,7 +12,7 @@
//! same type. Likewise, no two inherent impls for a given type
//! constructor provide a method with the same name.
use middle::cstore::{CrateStore, LOCAL_CRATE};
use middle::cstore::CrateStore;
use middle::def_id::DefId;
use middle::traits;
use middle::ty::{self, TyCtxt};
@ -50,121 +50,6 @@ struct OverlapChecker<'cx, 'tcx:'cx> {
}
impl<'cx, 'tcx> OverlapChecker<'cx, 'tcx> {
fn check_for_overlapping_impls_of_trait(&mut self, trait_def_id: DefId) {
debug!("check_for_overlapping_impls_of_trait(trait_def_id={:?})",
trait_def_id);
let _task = self.tcx.dep_graph.in_task(DepNode::CoherenceOverlapCheck(trait_def_id));
if !self.traits_checked.insert(trait_def_id) {
return;
}
let trait_def = self.tcx.lookup_trait_def(trait_def_id);
self.tcx.populate_implementations_for_trait_if_necessary(
trait_def.trait_ref.def_id);
// We should already know all impls of this trait, so these
// borrows are safe.
let (blanket_impls, nonblanket_impls) = trait_def.borrow_impl_lists(self.tcx);
// Conflicts can only occur between a blanket impl and another impl,
// or between 2 non-blanket impls of the same kind.
for (i, &impl1_def_id) in blanket_impls.iter().enumerate() {
for &impl2_def_id in &blanket_impls[(i+1)..] {
self.check_if_impls_overlap(impl1_def_id,
impl2_def_id);
}
for v in nonblanket_impls.values() {
for &impl2_def_id in v {
self.check_if_impls_overlap(impl1_def_id,
impl2_def_id);
}
}
}
for impl_group in nonblanket_impls.values() {
for (i, &impl1_def_id) in impl_group.iter().enumerate() {
for &impl2_def_id in &impl_group[(i+1)..] {
self.check_if_impls_overlap(impl1_def_id,
impl2_def_id);
}
}
}
}
// We need to coherently pick which impl will be displayed
// as causing the error message, and it must be the in the current
// crate. Just pick the smaller impl in the file.
fn order_impls(&self, impl1_def_id: DefId, impl2_def_id: DefId)
-> Option<(DefId, DefId)> {
if impl1_def_id.krate != LOCAL_CRATE {
if impl2_def_id.krate != LOCAL_CRATE {
// we don't need to check impls if both are external;
// that's the other crate's job.
None
} else {
Some((impl2_def_id, impl1_def_id))
}
} else if impl2_def_id.krate != LOCAL_CRATE {
Some((impl1_def_id, impl2_def_id))
} else if impl1_def_id < impl2_def_id {
Some((impl1_def_id, impl2_def_id))
} else {
Some((impl2_def_id, impl1_def_id))
}
}
fn check_if_impls_overlap(&self,
impl1_def_id: DefId,
impl2_def_id: DefId)
{
if let Some((impl1_def_id, impl2_def_id)) = self.order_impls(
impl1_def_id, impl2_def_id)
{
debug!("check_if_impls_overlap({:?}, {:?})",
impl1_def_id,
impl2_def_id);
let infcx = infer::new_infer_ctxt(self.tcx, &self.tcx.tables, None);
if let Some(header) = traits::overlapping_impls(&infcx, impl1_def_id, impl2_def_id) {
self.report_overlap_error(impl1_def_id, impl2_def_id, header.trait_ref.unwrap());
}
}
}
fn report_overlap_error(&self,
impl1: DefId,
impl2: DefId,
trait_ref: ty::TraitRef)
{
// only print the Self type if it's concrete; otherwise, it's not adding much information.
let self_type = {
trait_ref.substs.self_ty().and_then(|ty| {
if let ty::TyInfer(_) = ty.sty {
None
} else {
Some(format!(" for type `{}`", ty))
}
}).unwrap_or(String::new())
};
let mut err = struct_span_err!(self.tcx.sess, self.span_of_def_id(impl1), E0119,
"conflicting implementations of trait `{}`{}:",
trait_ref,
self_type);
if impl2.is_local() {
span_note!(&mut err, self.span_of_def_id(impl2),
"conflicting implementation is here:");
} else {
let cname = self.tcx.sess.cstore.crate_name(impl2.krate);
err.note(&format!("conflicting implementation in crate `{}`", cname));
}
err.emit();
}
fn span_of_def_id(&self, did: DefId) -> Span {
let node_id = self.tcx.map.as_local_node_id(did).unwrap();
self.tcx.map.span(node_id)
@ -222,15 +107,9 @@ impl<'cx, 'tcx> OverlapChecker<'cx, 'tcx> {
}
}
impl<'cx, 'tcx,'v> intravisit::Visitor<'v> for OverlapChecker<'cx, 'tcx> {
fn visit_item(&mut self, item: &'v hir::Item) {
match item.node {
hir::ItemTrait(..) => {
let trait_def_id = self.tcx.map.local_def_id(item.id);
self.check_for_overlapping_impls_of_trait(trait_def_id);
}
hir::ItemEnum(..) | hir::ItemStruct(..) => {
let type_def_id = self.tcx.map.local_def_id(item.id);
self.check_for_overlapping_inherent_impls(type_def_id);
@ -246,47 +125,84 @@ impl<'cx, 'tcx,'v> intravisit::Visitor<'v> for OverlapChecker<'cx, 'tcx> {
self.check_for_overlapping_impls_of_trait(trait_ref.def_id);
let prev_default_impl = self.default_impls.insert(trait_ref.def_id, item.id);
match prev_default_impl {
Some(prev_id) => {
self.report_overlap_error(impl_def_id,
self.tcx.map.local_def_id(prev_id),
trait_ref);
}
None => { }
if let Some(prev_id) = prev_default_impl {
span_err!(self.tcx.sess,
self.span_of_def_id(impl_def_id), E0519,
"redundant default implementations of trait `{}`:",
trait_ref);
span_note!(self.tcx.sess,
self.span_of_def_id(self.tcx.map.local_def_id(prev_id)),
"redundant implementation is here:");
}
}
hir::ItemImpl(_, _, _, Some(_), _, _) => {
hir::ItemImpl(_, _, _, Some(_), ref self_ty, _) => {
let impl_def_id = self.tcx.map.local_def_id(item.id);
let trait_ref = self.tcx.impl_trait_ref(impl_def_id).unwrap();
let trait_def_id = trait_ref.def_id;
self.check_for_overlapping_impls_of_trait(trait_def_id);
match trait_ref.self_ty().sty {
ty::TyTrait(ref data) => {
// This is something like impl Trait1 for Trait2. Illegal
// if Trait1 is a supertrait of Trait2 or Trait2 is not object safe.
if !traits::is_object_safe(self.tcx, data.principal_def_id()) {
// This is an error, but it will be
// reported by wfcheck. Ignore it
// here. This is tested by
// `coherence-impl-trait-for-trait-object-safe.rs`.
} else {
let mut supertrait_def_ids =
traits::supertrait_def_ids(self.tcx, data.principal_def_id());
if supertrait_def_ids.any(|d| d == trait_def_id) {
span_err!(self.tcx.sess, item.span, E0371,
"the object type `{}` automatically \
implements the trait `{}`",
trait_ref.self_ty(),
self.tcx.item_path_str(trait_def_id));
let _task = self.tcx.dep_graph.in_task(DepNode::CoherenceOverlapCheck(trait_def_id));
let def = self.tcx.lookup_trait_def(trait_def_id);
// attempt to insert into the specialization graph
let insert_result = def.add_impl_for_specialization(self.tcx,
impl_def_id,
trait_ref);
// insertion failed due to overlap
if let Err(overlap) = insert_result {
// only print the Self type if it has at least some outer
// concrete shell; otherwise, it's not adding much
// information.
let self_type = {
overlap.on_trait_ref.substs.self_ty().and_then(|ty| {
if ty.has_concrete_skeleton() {
Some(format!(" for type `{}`", ty))
} else {
None
}
}).unwrap_or(String::new())
};
span_err!(self.tcx.sess, self.span_of_def_id(impl_def_id), E0119,
"conflicting implementations of trait `{}`{}:",
overlap.on_trait_ref,
self_type);
if overlap.with_impl.is_local() {
span_note!(self.tcx.sess, self.span_of_def_id(overlap.with_impl),
"conflicting implementation is here:");
} else {
let cname = self.tcx.sess.cstore.crate_name(overlap.with_impl.krate);
self.tcx.sess.note(&format!("conflicting implementation in crate `{}`",
cname));
}
}
// check for overlap with the automatic `impl Trait for Trait`
if let ty::TyTrait(ref data) = trait_ref.self_ty().sty {
// This is something like impl Trait1 for Trait2. Illegal
// if Trait1 is a supertrait of Trait2 or Trait2 is not object safe.
if !traits::is_object_safe(self.tcx, data.principal_def_id()) {
// This is an error, but it will be
// reported by wfcheck. Ignore it
// here. This is tested by
// `coherence-impl-trait-for-trait-object-safe.rs`.
} else {
let mut supertrait_def_ids =
traits::supertrait_def_ids(self.tcx, data.principal_def_id());
if supertrait_def_ids.any(|d| d == trait_def_id) {
span_err!(self.tcx.sess, item.span, E0371,
"the object type `{}` automatically \
implements the trait `{}`",
trait_ref.self_ty(),
self.tcx.item_path_str(trait_def_id));
}
}
_ => { }
}
}
_ => {
}
_ => {}
}
}
}

View File

@ -69,6 +69,7 @@ use middle::resolve_lifetime;
use middle::const_eval::{self, ConstVal};
use middle::const_eval::EvalHint::UncheckedExprHint;
use middle::subst::{Substs, FnSpace, ParamSpace, SelfSpace, TypeSpace, VecPerParamSpace};
use middle::traits;
use middle::ty::{ToPredicate, ImplContainer, ImplOrTraitItemContainer, TraitContainer};
use middle::ty::{self, ToPolyTraitRef, Ty, TyCtxt, TypeScheme};
use middle::ty::{VariantKind};

View File

@ -3695,5 +3695,6 @@ register_diagnostics! {
E0399, // trait items need to be implemented because the associated
// type `{}` was overridden
E0436, // functional record update requires a struct
E0513 // no type for local variable ..
E0513, // no type for local variable ..
E0519 // redundant default implementations of trait
}