about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/librustc/dep_graph/mod.rs1
-rw-r--r--src/librustc/middle/infer/mod.rs31
-rw-r--r--src/librustc/middle/traits/coherence.rs94
-rw-r--r--src/librustc/middle/traits/select.rs1
-rw-r--r--src/librustc/middle/ty/fold.rs4
-rw-r--r--src/librustc/middle/ty/mod.rs35
-rw-r--r--src/librustc/middle/ty/structural_impls.rs21
-rw-r--r--src/librustc_typeck/coherence/mod.rs9
-rw-r--r--src/librustc_typeck/coherence/overlap.rs72
-rw-r--r--src/librustc_typeck/collect.rs13
-rw-r--r--src/librustc_typeck/diagnostics.rs15
-rw-r--r--src/test/compile-fail/associated-item-duplicate-names-2.rs2
-rw-r--r--src/test/compile-fail/associated-item-duplicate-names-3.rs2
-rw-r--r--src/test/compile-fail/associated-item-duplicate-names.rs4
-rw-r--r--src/test/compile-fail/impl-duplicate-methods.rs2
-rw-r--r--src/test/compile-fail/inherent-overlap.rs44
-rw-r--r--src/test/compile-fail/issue-4265.rs2
-rw-r--r--src/test/compile-fail/issue-8153.rs2
-rw-r--r--src/test/compile-fail/method-macro-backtrace.rs2
-rw-r--r--src/test/rustdoc/issue-25001.rs6
20 files changed, 253 insertions, 109 deletions
diff --git a/src/librustc/dep_graph/mod.rs b/src/librustc/dep_graph/mod.rs
index 2fad161652f..f4df6994e04 100644
--- a/src/librustc/dep_graph/mod.rs
+++ b/src/librustc/dep_graph/mod.rs
@@ -58,6 +58,7 @@ pub enum DepNode {
     CoherenceCheckImpl(DefId),
     CoherenceOverlapCheck(DefId),
     CoherenceOverlapCheckSpecial(DefId),
+    CoherenceOverlapInherentCheck(DefId),
     CoherenceOrphanCheck(DefId),
     Variance,
     WfCheck(DefId),
diff --git a/src/librustc/middle/infer/mod.rs b/src/librustc/middle/infer/mod.rs
index 1e3546269db..3eca4624bc1 100644
--- a/src/librustc/middle/infer/mod.rs
+++ b/src/librustc/middle/infer/mod.rs
@@ -458,14 +458,13 @@ pub fn mk_eqty<'a, 'tcx>(cx: &InferCtxt<'a, 'tcx>,
 }
 
 pub fn mk_eq_trait_refs<'a, 'tcx>(cx: &InferCtxt<'a, 'tcx>,
-                                   a_is_expected: bool,
-                                   origin: TypeOrigin,
-                                   a: ty::TraitRef<'tcx>,
-                                   b: ty::TraitRef<'tcx>)
-                                   -> UnitResult<'tcx>
+                                  a_is_expected: bool,
+                                  origin: TypeOrigin,
+                                  a: ty::TraitRef<'tcx>,
+                                  b: ty::TraitRef<'tcx>)
+                                  -> UnitResult<'tcx>
 {
-    debug!("mk_eq_trait_refs({:?} <: {:?})",
-           a, b);
+    debug!("mk_eq_trait_refs({:?} = {:?})", a, b);
     cx.eq_trait_refs(a_is_expected, origin, a, b)
 }
 
@@ -476,11 +475,25 @@ pub fn mk_sub_poly_trait_refs<'a, 'tcx>(cx: &InferCtxt<'a, 'tcx>,
                                         b: ty::PolyTraitRef<'tcx>)
                                         -> UnitResult<'tcx>
 {
-    debug!("mk_sub_poly_trait_refs({:?} <: {:?})",
-           a, b);
+    debug!("mk_sub_poly_trait_refs({:?} <: {:?})", a, b);
     cx.sub_poly_trait_refs(a_is_expected, origin, a, b)
 }
 
+pub fn mk_eq_impl_headers<'a, 'tcx>(cx: &InferCtxt<'a, 'tcx>,
+                                    a_is_expected: bool,
+                                    origin: TypeOrigin,
+                                    a: &ty::ImplHeader<'tcx>,
+                                    b: &ty::ImplHeader<'tcx>)
+                                    -> UnitResult<'tcx>
+{
+    debug!("mk_eq_impl_header({:?} = {:?})", a, b);
+    match (a.trait_ref, b.trait_ref) {
+        (Some(a_ref), Some(b_ref)) => mk_eq_trait_refs(cx, a_is_expected, origin, a_ref, b_ref),
+        (None, None) => mk_eqty(cx, a_is_expected, origin, a.self_ty, b.self_ty),
+        _ => cx.tcx.sess.bug("mk_eq_impl_headers given mismatched impl kinds"),
+    }
+}
+
 fn expected_found<T>(a_is_expected: bool,
                      a: T,
                      b: T)
diff --git a/src/librustc/middle/traits/coherence.rs b/src/librustc/middle/traits/coherence.rs
index b79849e87ff..6005d36ff4e 100644
--- a/src/librustc/middle/traits/coherence.rs
+++ b/src/librustc/middle/traits/coherence.rs
@@ -10,29 +10,25 @@
 
 //! See `README.md` for high-level documentation
 
-use super::Normalized;
-use super::SelectionContext;
-use super::ObligationCause;
-use super::PredicateObligation;
-use super::project;
-use super::util;
+use super::{SelectionContext};
+use super::{Obligation, ObligationCause};
 
 use middle::cstore::LOCAL_CRATE;
 use middle::def_id::DefId;
-use middle::subst::{Subst, Substs, TypeSpace};
+use middle::subst::TypeSpace;
 use middle::ty::{self, Ty, TyCtxt};
 use middle::infer::{self, InferCtxt, TypeOrigin};
-use syntax::codemap::{DUMMY_SP, Span};
+use syntax::codemap::DUMMY_SP;
 
 #[derive(Copy, Clone)]
 struct InferIsLocal(bool);
 
-/// If there are types that satisfy both impls, returns a `TraitRef`
+/// If there are types that satisfy both impls, returns an `ImplTy`
 /// with those types substituted (by updating the given `infcx`)
 pub fn overlapping_impls<'cx, 'tcx>(infcx: &InferCtxt<'cx, 'tcx>,
                                     impl1_def_id: DefId,
                                     impl2_def_id: DefId)
-                                    -> Option<ty::TraitRef<'tcx>>
+                                    -> Option<ty::ImplHeader<'tcx>>
 {
     debug!("impl_can_satisfy(\
            impl1_def_id={:?}, \
@@ -45,34 +41,28 @@ pub fn overlapping_impls<'cx, 'tcx>(infcx: &InferCtxt<'cx, 'tcx>,
 }
 
 /// Can both impl `a` and impl `b` be satisfied by a common type (including
-/// `where` clauses)? If so, returns a `TraitRef` that unifies the two impls.
+/// `where` clauses)? If so, returns an `ImplHeader` that unifies the two impls.
 fn overlap<'cx, 'tcx>(selcx: &mut SelectionContext<'cx, 'tcx>,
                       a_def_id: DefId,
                       b_def_id: DefId)
-                      -> Option<ty::TraitRef<'tcx>>
+                      -> Option<ty::ImplHeader<'tcx>>
 {
     debug!("overlap(a_def_id={:?}, b_def_id={:?})",
            a_def_id,
            b_def_id);
 
-    let (a_trait_ref, a_obligations) = impl_trait_ref_and_oblig(selcx,
-                                                                a_def_id,
-                                                                util::fresh_type_vars_for_impl);
+    let a_impl_header = ty::ImplHeader::with_fresh_ty_vars(selcx, a_def_id);
+    let b_impl_header = ty::ImplHeader::with_fresh_ty_vars(selcx, b_def_id);
 
-    let (b_trait_ref, b_obligations) = impl_trait_ref_and_oblig(selcx,
-                                                                b_def_id,
-                                                                util::fresh_type_vars_for_impl);
-
-    debug!("overlap: a_trait_ref={:?} a_obligations={:?}", a_trait_ref, a_obligations);
-
-    debug!("overlap: b_trait_ref={:?} b_obligations={:?}", b_trait_ref, b_obligations);
+    debug!("overlap: a_impl_header={:?}", a_impl_header);
+    debug!("overlap: b_impl_header={:?}", b_impl_header);
 
     // Do `a` and `b` unify? If not, no overlap.
-    if let Err(_) = infer::mk_eq_trait_refs(selcx.infcx(),
-                                            true,
-                                            TypeOrigin::Misc(DUMMY_SP),
-                                            a_trait_ref,
-                                            b_trait_ref) {
+    if let Err(_) = infer::mk_eq_impl_headers(selcx.infcx(),
+                                              true,
+                                              TypeOrigin::Misc(DUMMY_SP),
+                                              &a_impl_header,
+                                              &b_impl_header) {
         return None;
     }
 
@@ -81,9 +71,13 @@ fn overlap<'cx, 'tcx>(selcx: &mut SelectionContext<'cx, 'tcx>,
     // Are any of the obligations unsatisfiable? If so, no overlap.
     let infcx = selcx.infcx();
     let opt_failing_obligation =
-        a_obligations.iter()
-                     .chain(&b_obligations)
-                     .map(|o| infcx.resolve_type_vars_if_possible(o))
+        a_impl_header.predicates
+                     .iter()
+                     .chain(&b_impl_header.predicates)
+                     .map(|p| infcx.resolve_type_vars_if_possible(p))
+                     .map(|p| Obligation { cause: ObligationCause::dummy(),
+                                           recursion_depth: 0,
+                                           predicate: p })
                      .find(|o| !selcx.evaluate_obligation(o));
 
     if let Some(failing_obligation) = opt_failing_obligation {
@@ -91,7 +85,7 @@ fn overlap<'cx, 'tcx>(selcx: &mut SelectionContext<'cx, 'tcx>,
         return None
     }
 
-    Some(selcx.infcx().resolve_type_vars_if_possible(&a_trait_ref))
+    Some(selcx.infcx().resolve_type_vars_if_possible(&a_impl_header))
 }
 
 pub fn trait_ref_is_knowable<'tcx>(tcx: &TyCtxt<'tcx>, trait_ref: &ty::TraitRef<'tcx>) -> bool
@@ -125,44 +119,6 @@ pub fn trait_ref_is_knowable<'tcx>(tcx: &TyCtxt<'tcx>, trait_ref: &ty::TraitRef<
     orphan_check_trait_ref(tcx, trait_ref, InferIsLocal(true)).is_err()
 }
 
-type SubstsFn = for<'a,'tcx> fn(infcx: &InferCtxt<'a, 'tcx>,
-                                span: Span,
-                                impl_def_id: DefId)
-                                -> Substs<'tcx>;
-
-/// Instantiate fresh variables for all bound parameters of the impl
-/// and return the impl trait ref with those variables substituted.
-fn impl_trait_ref_and_oblig<'a,'tcx>(selcx: &mut SelectionContext<'a,'tcx>,
-                                     impl_def_id: DefId,
-                                     substs_fn: SubstsFn)
-                                     -> (ty::TraitRef<'tcx>,
-                                         Vec<PredicateObligation<'tcx>>)
-{
-    let impl_substs =
-        &substs_fn(selcx.infcx(), DUMMY_SP, impl_def_id);
-    let impl_trait_ref =
-        selcx.tcx().impl_trait_ref(impl_def_id).unwrap();
-    let impl_trait_ref =
-        impl_trait_ref.subst(selcx.tcx(), impl_substs);
-    let Normalized { value: impl_trait_ref, obligations: normalization_obligations1 } =
-        project::normalize(selcx, ObligationCause::dummy(), &impl_trait_ref);
-
-    let predicates = selcx.tcx().lookup_predicates(impl_def_id);
-    let predicates = predicates.instantiate(selcx.tcx(), impl_substs);
-    let Normalized { value: predicates, obligations: normalization_obligations2 } =
-        project::normalize(selcx, ObligationCause::dummy(), &predicates);
-    let impl_obligations =
-        util::predicates_for_generics(ObligationCause::dummy(), 0, &predicates);
-
-    let impl_obligations: Vec<_> =
-        impl_obligations.into_iter()
-        .chain(normalization_obligations1)
-        .chain(normalization_obligations2)
-        .collect();
-
-    (impl_trait_ref, impl_obligations)
-}
-
 pub enum OrphanCheckErr<'tcx> {
     NoLocalInputType,
     UncoveredTy(Ty<'tcx>),
diff --git a/src/librustc/middle/traits/select.rs b/src/librustc/middle/traits/select.rs
index 2ecfa119007..fbfd4b67b5b 100644
--- a/src/librustc/middle/traits/select.rs
+++ b/src/librustc/middle/traits/select.rs
@@ -391,7 +391,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
     // The result is "true" if the obligation *may* hold and "false" if
     // we can be sure it does not.
 
-
     /// Evaluates whether the obligation `obligation` can be satisfied (by any means).
     pub fn evaluate_obligation(&mut self,
                                obligation: &PredicateObligation<'tcx>)
diff --git a/src/librustc/middle/ty/fold.rs b/src/librustc/middle/ty/fold.rs
index 162ea3a7714..090d4eeb874 100644
--- a/src/librustc/middle/ty/fold.rs
+++ b/src/librustc/middle/ty/fold.rs
@@ -146,6 +146,10 @@ pub trait TypeFolder<'tcx> : Sized {
         t.super_fold_with(self)
     }
 
+    fn fold_impl_header(&mut self, imp: &ty::ImplHeader<'tcx>) -> ty::ImplHeader<'tcx> {
+        imp.super_fold_with(self)
+    }
+
     fn fold_substs(&mut self,
                    substs: &subst::Substs<'tcx>)
                    -> subst::Substs<'tcx> {
diff --git a/src/librustc/middle/ty/mod.rs b/src/librustc/middle/ty/mod.rs
index 2e38080bfb0..b54b0b73ef2 100644
--- a/src/librustc/middle/ty/mod.rs
+++ b/src/librustc/middle/ty/mod.rs
@@ -152,6 +152,41 @@ impl ImplOrTraitItemContainer {
     }
 }
 
+/// The "header" of an impl is everything outside the body: a Self type, a trait
+/// ref (in the case of a trait impl), and a set of predicates (from the
+/// bounds/where clauses).
+#[derive(Clone, PartialEq, Eq, Hash, Debug)]
+pub struct ImplHeader<'tcx> {
+    pub impl_def_id: DefId,
+    pub self_ty: Ty<'tcx>,
+    pub trait_ref: Option<TraitRef<'tcx>>,
+    pub predicates: Vec<Predicate<'tcx>>,
+}
+
+impl<'tcx> ImplHeader<'tcx> {
+    pub fn with_fresh_ty_vars<'a>(selcx: &mut traits::SelectionContext<'a, 'tcx>,
+                                  impl_def_id: DefId)
+                                  -> ImplHeader<'tcx>
+    {
+        let tcx = selcx.tcx();
+        let impl_generics = tcx.lookup_item_type(impl_def_id).generics;
+        let impl_substs = selcx.infcx().fresh_substs_for_generics(DUMMY_SP, &impl_generics);
+
+        let header = ImplHeader {
+            impl_def_id: impl_def_id,
+            self_ty: tcx.lookup_item_type(impl_def_id).ty,
+            trait_ref: tcx.impl_trait_ref(impl_def_id),
+            predicates: tcx.lookup_predicates(impl_def_id).predicates.into_vec(),
+        }.subst(tcx, &impl_substs);
+
+        let traits::Normalized { value: mut header, obligations } =
+            traits::normalize(selcx, traits::ObligationCause::dummy(), &header);
+
+        header.predicates.extend(obligations.into_iter().map(|o| o.predicate));
+        header
+    }
+}
+
 #[derive(Clone)]
 pub enum ImplOrTraitItem<'tcx> {
     ConstTraitItem(Rc<AssociatedConst<'tcx>>),
diff --git a/src/librustc/middle/ty/structural_impls.rs b/src/librustc/middle/ty/structural_impls.rs
index 3fe9e02a90d..57cfdd0d8b8 100644
--- a/src/librustc/middle/ty/structural_impls.rs
+++ b/src/librustc/middle/ty/structural_impls.rs
@@ -446,6 +446,27 @@ impl<'tcx> TypeFoldable<'tcx> for ty::TraitRef<'tcx> {
     }
 }
 
+impl<'tcx> TypeFoldable<'tcx> for ty::ImplHeader<'tcx> {
+    fn super_fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Self {
+        ty::ImplHeader {
+            impl_def_id: self.impl_def_id,
+            self_ty: self.self_ty.fold_with(folder),
+            trait_ref: self.trait_ref.map(|t| t.fold_with(folder)),
+            predicates: self.predicates.iter().map(|p| p.fold_with(folder)).collect(),
+        }
+    }
+
+    fn fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Self {
+        folder.fold_impl_header(self)
+    }
+
+    fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
+        self.self_ty.visit_with(visitor) ||
+            self.trait_ref.map(|r| r.visit_with(visitor)).unwrap_or(false) ||
+            self.predicates.iter().any(|p| p.visit_with(visitor))
+    }
+}
+
 impl<'tcx> TypeFoldable<'tcx> for ty::Region {
     fn super_fold_with<F: TypeFolder<'tcx>>(&self, _folder: &mut F) -> Self {
         *self
diff --git a/src/librustc_typeck/coherence/mod.rs b/src/librustc_typeck/coherence/mod.rs
index cad321c0b23..9dc8d7ae943 100644
--- a/src/librustc_typeck/coherence/mod.rs
+++ b/src/librustc_typeck/coherence/mod.rs
@@ -35,7 +35,9 @@ use CrateCtxt;
 use middle::infer::{self, InferCtxt, TypeOrigin, new_infer_ctxt};
 use std::cell::RefCell;
 use std::rc::Rc;
+use syntax::ast;
 use syntax::codemap::Span;
+use syntax::errors::DiagnosticBuilder;
 use util::nodemap::{DefIdMap, FnvHashMap};
 use rustc::dep_graph::DepNode;
 use rustc::front::map as hir_map;
@@ -519,6 +521,13 @@ fn enforce_trait_manually_implementable(tcx: &TyCtxt, sp: Span, trait_def_id: De
     err.emit();
 }
 
+// Factored out into helper because the error cannot be defined in multiple locations.
+pub fn report_duplicate_item<'tcx>(tcx: &TyCtxt<'tcx>, sp: Span, name: ast::Name)
+                                   -> DiagnosticBuilder<'tcx>
+{
+    struct_span_err!(tcx.sess, sp, E0201, "duplicate definitions with name `{}`:", name)
+}
+
 pub fn check_coherence(crate_context: &CrateCtxt) {
     let _task = crate_context.tcx.dep_graph.in_task(DepNode::Coherence);
     let infcx = new_infer_ctxt(crate_context.tcx, &crate_context.tcx.tables, None);
diff --git a/src/librustc_typeck/coherence/overlap.rs b/src/librustc_typeck/coherence/overlap.rs
index 9ec42b6d3f8..80430076f19 100644
--- a/src/librustc_typeck/coherence/overlap.rs
+++ b/src/librustc_typeck/coherence/overlap.rs
@@ -9,7 +9,8 @@
 // except according to those terms.
 
 //! Overlap: No two impls for the same trait are implemented for the
-//! same type.
+//! 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::def_id::DefId;
@@ -115,7 +116,6 @@ impl<'cx, 'tcx> OverlapChecker<'cx, 'tcx> {
         }
     }
 
-
     fn check_if_impls_overlap(&self,
                               impl1_def_id: DefId,
                               impl2_def_id: DefId)
@@ -128,8 +128,8 @@ impl<'cx, 'tcx> OverlapChecker<'cx, 'tcx> {
                    impl2_def_id);
 
             let infcx = infer::new_infer_ctxt(self.tcx, &self.tcx.tables, None);
-            if let Some(trait_ref) = traits::overlapping_impls(&infcx, impl1_def_id, impl2_def_id) {
-                self.report_overlap_error(impl1_def_id, impl2_def_id, trait_ref);
+            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());
             }
         }
     }
@@ -150,13 +150,13 @@ impl<'cx, 'tcx> OverlapChecker<'cx, 'tcx> {
             }).unwrap_or(String::new())
         };
 
-        let mut err = struct_span_err!(self.tcx.sess, self.span_of_impl(impl1), E0119,
+        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_impl(impl2),
+            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);
@@ -165,10 +165,61 @@ impl<'cx, 'tcx> OverlapChecker<'cx, 'tcx> {
         err.emit();
     }
 
-    fn span_of_impl(&self, impl_did: DefId) -> Span {
-        let node_id = self.tcx.map.as_local_node_id(impl_did).unwrap();
+    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)
     }
+
+    fn check_for_common_items_in_impls(&self, impl1: DefId, impl2: DefId) {
+        #[derive(Copy, Clone, PartialEq)]
+        enum Namespace { Type, Value }
+
+        fn name_and_namespace(tcx: &TyCtxt, item: &ty::ImplOrTraitItemId)
+                              -> (ast::Name, Namespace)
+        {
+            let name = tcx.impl_or_trait_item(item.def_id()).name();
+            (name, match *item {
+                ty::TypeTraitItemId(..) => Namespace::Type,
+                ty::ConstTraitItemId(..) => Namespace::Value,
+                ty::MethodTraitItemId(..) => Namespace::Value,
+            })
+        }
+
+        let impl_items = self.tcx.impl_items.borrow();
+
+        for item1 in &impl_items[&impl1] {
+            let (name, namespace) = name_and_namespace(&self.tcx, item1);
+
+            for item2 in &impl_items[&impl2] {
+                if (name, namespace) == name_and_namespace(&self.tcx, item2) {
+                    let mut err = super::report_duplicate_item(
+                        &self.tcx, self.span_of_def_id(item1.def_id()), name);
+                    span_note!(&mut err, self.span_of_def_id(item2.def_id()),
+                               "conflicting definition is here:");
+                    err.emit();
+                }
+            }
+        }
+    }
+
+    fn check_for_overlapping_inherent_impls(&self, ty_def_id: DefId) {
+        let _task = self.tcx.dep_graph.in_task(DepNode::CoherenceOverlapInherentCheck(ty_def_id));
+
+        let inherent_impls = self.tcx.inherent_impls.borrow();
+        let impls = match inherent_impls.get(&ty_def_id) {
+            Some(impls) => impls,
+            None => return
+        };
+
+        for (i, &impl1_def_id) in impls.iter().enumerate() {
+            for &impl2_def_id in &impls[(i+1)..] {
+                let infcx = infer::new_infer_ctxt(self.tcx, &self.tcx.tables, None);
+                if traits::overlapping_impls(&infcx, impl1_def_id, impl2_def_id).is_some() {
+                    self.check_for_common_items_in_impls(impl1_def_id, impl2_def_id)
+                }
+            }
+        }
+    }
 }
 
 
@@ -180,6 +231,11 @@ impl<'cx, 'tcx,'v> intravisit::Visitor<'v> for OverlapChecker<'cx, 'tcx> {
                 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);
+            }
+
             hir::ItemDefaultImpl(..) => {
                 // look for another default impl; note that due to the
                 // general orphan/coherence rules, it must always be
diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs
index 3ce03e24578..b493b64a45f 100644
--- a/src/librustc_typeck/collect.rs
+++ b/src/librustc_typeck/collect.rs
@@ -63,6 +63,7 @@ use lint;
 use middle::def::Def;
 use middle::def_id::DefId;
 use constrained_type_params as ctp;
+use coherence;
 use middle::lang_items::SizedTraitLangItem;
 use middle::resolve_lifetime;
 use middle::const_eval::{self, ConstVal};
@@ -750,17 +751,7 @@ fn convert_item(ccx: &CrateCtxt, it: &hir::Item) {
                     _                    => &mut seen_value_items,
                 };
                 if !seen_items.insert(impl_item.name) {
-                    let desc = match impl_item.node {
-                        hir::ImplItemKind::Const(_, _) => "associated constant",
-                        hir::ImplItemKind::Type(_) => "associated type",
-                        hir::ImplItemKind::Method(ref sig, _) =>
-                            match sig.explicit_self.node {
-                                hir::SelfStatic => "associated function",
-                                _ => "method",
-                            },
-                    };
-
-                    span_err!(tcx.sess, impl_item.span, E0201, "duplicate {}", desc);
+                    coherence::report_duplicate_item(tcx, impl_item.span, impl_item.name).emit();
                 }
 
                 if let hir::ImplItemKind::Const(ref ty, _) = impl_item.node {
diff --git a/src/librustc_typeck/diagnostics.rs b/src/librustc_typeck/diagnostics.rs
index f376b42fbf9..5c411bec506 100644
--- a/src/librustc_typeck/diagnostics.rs
+++ b/src/librustc_typeck/diagnostics.rs
@@ -2285,6 +2285,21 @@ impl Baz for Foo {
     type Quux = u32;
 }
 ```
+
+Note, however, that items with the same name are allowed for inherent `impl`
+blocks that don't overlap:
+
+```
+struct Foo<T>(T);
+
+impl Foo<u8> {
+    fn bar(&self) -> bool { self.0 > 5 }
+}
+
+impl Foo<bool> {
+    fn bar(&self) -> bool { self.0 }
+}
+```
 "##,
 
 E0202: r##"
diff --git a/src/test/compile-fail/associated-item-duplicate-names-2.rs b/src/test/compile-fail/associated-item-duplicate-names-2.rs
index 6a7eaecae7f..ab903591fbb 100644
--- a/src/test/compile-fail/associated-item-duplicate-names-2.rs
+++ b/src/test/compile-fail/associated-item-duplicate-names-2.rs
@@ -14,7 +14,7 @@ struct Foo;
 
 impl Foo {
     const bar: bool = true;
-    fn bar() {} //~ ERROR duplicate associated function
+    fn bar() {} //~ ERROR duplicate definitions
 }
 
 fn main() {}
diff --git a/src/test/compile-fail/associated-item-duplicate-names-3.rs b/src/test/compile-fail/associated-item-duplicate-names-3.rs
index 7c4c5ca6b4e..12cab13d0b9 100644
--- a/src/test/compile-fail/associated-item-duplicate-names-3.rs
+++ b/src/test/compile-fail/associated-item-duplicate-names-3.rs
@@ -20,7 +20,7 @@ struct Baz;
 
 impl Foo for Baz {
     type Bar = i16;
-    type Bar = u16; //~ ERROR duplicate associated type
+    type Bar = u16; //~ ERROR duplicate definitions
 }
 
 fn main() {
diff --git a/src/test/compile-fail/associated-item-duplicate-names.rs b/src/test/compile-fail/associated-item-duplicate-names.rs
index 4c484b49024..85868f5c020 100644
--- a/src/test/compile-fail/associated-item-duplicate-names.rs
+++ b/src/test/compile-fail/associated-item-duplicate-names.rs
@@ -19,9 +19,9 @@ trait Foo {
 
 impl Foo for () {
     type Ty = ();
-    type Ty = usize; //~ ERROR duplicate associated type
+    type Ty = usize; //~ ERROR duplicate definitions
     const BAR: u32 = 7;
-    const BAR: u32 = 8; //~ ERROR duplicate associated constant
+    const BAR: u32 = 8; //~ ERROR duplicate definitions
 }
 
 fn main() {
diff --git a/src/test/compile-fail/impl-duplicate-methods.rs b/src/test/compile-fail/impl-duplicate-methods.rs
index 6201d9862bb..148958ae128 100644
--- a/src/test/compile-fail/impl-duplicate-methods.rs
+++ b/src/test/compile-fail/impl-duplicate-methods.rs
@@ -11,7 +11,7 @@
 struct Foo;
 impl Foo {
     fn orange(&self){}
-    fn orange(&self){}   //~ ERROR duplicate method
+    fn orange(&self){}   //~ ERROR duplicate definitions
 }
 
 fn main() {}
diff --git a/src/test/compile-fail/inherent-overlap.rs b/src/test/compile-fail/inherent-overlap.rs
new file mode 100644
index 00000000000..5b014dbfd22
--- /dev/null
+++ b/src/test/compile-fail/inherent-overlap.rs
@@ -0,0 +1,44 @@
+// Copyright 2016 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.
+
+// Test that you cannot define items with the same name in overlapping inherent
+// impl blocks.
+
+struct Foo;
+
+impl Foo {
+    fn id() {} //~ ERROR E0201
+}
+
+impl Foo {
+    fn id() {}
+}
+
+struct Bar<T>(T);
+
+impl<T> Bar<T> {
+    fn bar(&self) {} //~ ERROR E0201
+}
+
+impl Bar<u32> {
+    fn bar(&self) {}
+}
+
+struct Baz<T>(T);
+
+impl<T: Copy> Baz<T> {
+    fn baz(&self) {} //~ ERROR E0201
+}
+
+impl<T> Baz<Vec<T>> {
+    fn baz(&self) {}
+}
+
+fn main() {}
diff --git a/src/test/compile-fail/issue-4265.rs b/src/test/compile-fail/issue-4265.rs
index 328de9f8187..62db68dcbb2 100644
--- a/src/test/compile-fail/issue-4265.rs
+++ b/src/test/compile-fail/issue-4265.rs
@@ -17,7 +17,7 @@ impl Foo {
         Foo { baz: 0 }.bar();
     }
 
-    fn bar() { //~ ERROR duplicate associated function
+    fn bar() { //~ ERROR duplicate definitions
     }
 }
 
diff --git a/src/test/compile-fail/issue-8153.rs b/src/test/compile-fail/issue-8153.rs
index ea7224939ce..457918b54d4 100644
--- a/src/test/compile-fail/issue-8153.rs
+++ b/src/test/compile-fail/issue-8153.rs
@@ -18,7 +18,7 @@ trait Bar {
 
 impl Bar for Foo {
     fn bar(&self) -> isize {1}
-    fn bar(&self) -> isize {2} //~ ERROR duplicate method
+    fn bar(&self) -> isize {2} //~ ERROR duplicate definitions
 }
 
 fn main() {
diff --git a/src/test/compile-fail/method-macro-backtrace.rs b/src/test/compile-fail/method-macro-backtrace.rs
index 967a8531b2c..f3c227849dc 100644
--- a/src/test/compile-fail/method-macro-backtrace.rs
+++ b/src/test/compile-fail/method-macro-backtrace.rs
@@ -29,7 +29,7 @@ impl S {
 
     // Cause an error. It shouldn't have any macro backtrace frames.
     fn bar(&self) { }
-    fn bar(&self) { } //~ ERROR duplicate method
+    fn bar(&self) { } //~ ERROR duplicate definitions
 }
 
 fn main() { }
diff --git a/src/test/rustdoc/issue-25001.rs b/src/test/rustdoc/issue-25001.rs
index 2343b610ce4..25c97ee2c76 100644
--- a/src/test/rustdoc/issue-25001.rs
+++ b/src/test/rustdoc/issue-25001.rs
@@ -17,15 +17,15 @@ pub trait Bar {
     fn quux(self);
 }
 
-impl<T> Foo<T> {
+impl Foo<u8> {
     // @has - '//*[@id="method.pass"]//code' 'fn pass()'
     pub fn pass() {}
 }
-impl<T> Foo<T> {
+impl Foo<u16> {
     // @has - '//*[@id="method.pass-1"]//code' 'fn pass() -> usize'
     pub fn pass() -> usize { 42 }
 }
-impl<T> Foo<T> {
+impl Foo<u32> {
     // @has - '//*[@id="method.pass-2"]//code' 'fn pass() -> isize'
     pub fn pass() -> isize { 42 }
 }