| // Copyright 2014 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. |
| |
| //! Overlap: No two impls for the same trait are implemented for the |
| //! same type. Likewise, no two inherent impls for a given type |
| //! constructor provide a method with the same name. |
| |
| use hir::def_id::DefId; |
| use rustc::traits::{self, ProjectionMode}; |
| use rustc::ty::{self, TyCtxt}; |
| use syntax::ast; |
| use rustc::dep_graph::DepNode; |
| use rustc::hir; |
| use rustc::hir::intravisit; |
| use util::nodemap::DefIdMap; |
| use lint; |
| |
| pub fn check<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) { |
| let mut overlap = OverlapChecker { tcx: tcx, |
| default_impls: DefIdMap() }; |
| |
| // this secondary walk specifically checks for some other cases, |
| // like defaulted traits, for which additional overlap rules exist |
| tcx.visit_all_items_in_krate(DepNode::CoherenceOverlapCheckSpecial, &mut overlap); |
| } |
| |
| struct OverlapChecker<'cx, 'tcx:'cx> { |
| tcx: TyCtxt<'cx, 'tcx, '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_common_items_in_impls(&self, impl1: DefId, impl2: DefId) { |
| #[derive(Copy, Clone, PartialEq)] |
| enum Namespace { Type, Value } |
| |
| fn name_and_namespace<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, |
| 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 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); |
| } |
| } |
| } |
| } |
| |
| 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)..] { |
| self.tcx.infer_ctxt(None, None, ProjectionMode::Topmost).enter(|infcx| { |
| 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) |
| } |
| }); |
| } |
| } |
| } |
| } |
| |
| impl<'cx, 'tcx,'v> intravisit::Visitor<'v> for OverlapChecker<'cx, 'tcx> { |
| fn visit_item(&mut self, item: &'v hir::Item) { |
| match item.node { |
| 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 |
| // in this crate. |
| 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 prev_default_impl = self.default_impls.insert(trait_ref.def_id, item.id); |
| 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; |
| |
| 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 { |
| let mut err = struct_span_err!( |
| self.tcx.sess, self.tcx.span_of_impl(impl_def_id).unwrap(), E0119, |
| "conflicting implementations of trait `{}`{}:", |
| overlap.trait_desc, |
| overlap.self_desc.map_or(String::new(), |
| |ty| format!(" for type `{}`", ty))); |
| |
| 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 !self.tcx.is_object_safe(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)); |
| } |
| } |
| } |
| } |
| _ => {} |
| } |
| } |
| } |