]> git.proxmox.com Git - rustc.git/blobdiff - src/librustc_typeck/coherence/overlap.rs
Imported Upstream version 1.9.0+dfsg1
[rustc.git] / src / librustc_typeck / coherence / overlap.rs
index 470e954781f8bbb6377fe9c84e63cb23af1ebe0e..a05167dbe433333c819515b62aaf9dbd5fb852bb 100644 (file)
@@ -9,23 +9,23 @@
 // except according to those terms.
 
 //! Overlap: No two impls for the same trait are implemented for the
-//! same type.
-
-use middle::cstore::{CrateStore, LOCAL_CRATE};
-use middle::def_id::DefId;
-use middle::traits;
-use middle::ty;
-use middle::infer;
+//! same type. Likewise, no two inherent impls for a given type
+//! constructor provide a method with the same name.
+
+use middle::cstore::CrateStore;
+use hir::def_id::DefId;
+use rustc::traits::{self, ProjectionMode};
+use rustc::infer;
+use rustc::ty::{self, TyCtxt};
 use syntax::ast;
-use syntax::codemap::Span;
 use rustc::dep_graph::DepNode;
-use rustc_front::hir;
-use rustc_front::intravisit;
-use util::nodemap::{DefIdMap, DefIdSet};
+use rustc::hir;
+use rustc::hir::intravisit;
+use util::nodemap::DefIdMap;
+use lint;
 
-pub fn check(tcx: &ty::ctxt) {
+pub fn check(tcx: &TyCtxt) {
     let mut overlap = OverlapChecker { tcx: tcx,
-                                       traits_checked: DefIdSet(),
                                        default_impls: DefIdMap() };
 
     // this secondary walk specifically checks for some other cases,
@@ -34,150 +34,75 @@ pub fn check(tcx: &ty::ctxt) {
 }
 
 struct OverlapChecker<'cx, 'tcx:'cx> {
-    tcx: &'cx ty::ctxt<'tcx>,
-
-    // The set of traits where we have checked for overlap.  This is
-    // used to avoid checking the same trait twice.
-    //
-    // NB. It's ok to skip tracking this set because we fully
-    // encapsulate it, and we always create a task
-    // (`CoherenceOverlapCheck`) corresponding to each entry.
-    traits_checked: DefIdSet,
+    tcx: &'cx TyCtxt<'tcx>,
 
     // maps from a trait def-id to an impl id
     default_impls: DefIdMap<ast::NodeId>,
 }
 
 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);
+    fn check_for_common_items_in_impls(&self, impl1: DefId, impl2: DefId) {
+        #[derive(Copy, Clone, PartialEq)]
+        enum Namespace { Type, Value }
 
-        let _task = self.tcx.dep_graph.in_task(DepNode::CoherenceOverlapCheck(trait_def_id));
-        if !self.traits_checked.insert(trait_def_id) {
-            return;
+        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 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.
+        let impl_items = self.tcx.impl_items.borrow();
 
-        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 item1 in &impl_items[&impl1] {
+            let (name, namespace) = name_and_namespace(&self.tcx, item1);
 
-        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);
+            for item2 in &impl_items[&impl2] {
+                if (name, namespace) == name_and_namespace(&self.tcx, item2) {
+                    let msg = format!("duplicate definitions with name `{}`", name);
+                    let node_id = self.tcx.map.as_local_node_id(item1.def_id()).unwrap();
+                    self.tcx.sess.add_lint(lint::builtin::OVERLAPPING_INHERENT_IMPLS,
+                                           node_id,
+                                           self.tcx.span_of_impl(item1.def_id()).unwrap(),
+                                           msg);
                 }
             }
         }
     }
 
-    // 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(trait_ref) = traits::overlapping_impls(&infcx, impl1_def_id, impl2_def_id) {
-                self.report_overlap_error(impl1_def_id, impl2_def_id, trait_ref);
-            }
-        }
-    }
+    fn check_for_overlapping_inherent_impls(&self, ty_def_id: DefId) {
+        let _task = self.tcx.dep_graph.in_task(DepNode::CoherenceOverlapInherentCheck(ty_def_id));
 
-    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 inherent_impls = self.tcx.inherent_impls.borrow();
+        let impls = match inherent_impls.get(&ty_def_id) {
+            Some(impls) => impls,
+            None => return
         };
 
-        let mut err = struct_span_err!(self.tcx.sess, self.span_of_impl(impl1), E0119,
-                                       "conflicting implementations of trait `{}`{}:",
-                                       trait_ref,
-                                       self_type);
-
-        if impl2.is_local() {
-            span_note!(&mut err, self.span_of_impl(impl2),
-                       "conflicting implementation is here:");
-        } else {
-            let cname = self.tcx.sess.cstore.crate_name(impl2.krate);
-            err.note(&format!("conflicting implementation in crate `{}`", cname));
+        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,
+                                                  ProjectionMode::Topmost);
+                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)
+                }
+            }
         }
-        err.emit();
-    }
-
-    fn span_of_impl(&self, impl_did: DefId) -> Span {
-        let node_id = self.tcx.map.as_local_node_id(impl_did).unwrap();
-        self.tcx.map.span(node_id)
     }
 }
 
-
 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);
             }
 
             hir::ItemDefaultImpl(..) => {
@@ -187,50 +112,90 @@ impl<'cx, 'tcx,'v> intravisit::Visitor<'v> for OverlapChecker<'cx, 'tcx> {
                 let impl_def_id = self.tcx.map.local_def_id(item.id);
                 let trait_ref = self.tcx.impl_trait_ref(impl_def_id).unwrap();
 
-                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 {
+                    let mut err = struct_span_err!(
+                        self.tcx.sess,
+                        self.tcx.span_of_impl(impl_def_id).unwrap(), E0521,
+                        "redundant default implementations of trait `{}`:",
+                        trait_ref);
+                    err.span_note(self.tcx.span_of_impl(self.tcx.map.local_def_id(prev_id))
+                                      .unwrap(),
+                                  "redundant implementation is here:");
+                    err.emit();
                 }
             }
             hir::ItemImpl(_, _, _, Some(_), _, _) => {
                 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);
+
+                // 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())
+                    };
+
+                    let mut err = struct_span_err!(
+                        self.tcx.sess, self.tcx.span_of_impl(impl_def_id).unwrap(), E0119,
+                        "conflicting implementations of trait `{}`{}:",
+                        overlap.on_trait_ref,
+                        self_type);
+
+                    match self.tcx.span_of_impl(overlap.with_impl) {
+                        Ok(span) => {
+                            err.span_note(span, "conflicting implementation is here:");
+                        }
+                        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::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));
                         }
                     }
-                    _ => { }
                 }
             }
-            _ => {
-            }
+            _ => {}
         }
     }
 }