1 // Copyright 2014 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
11 //! Overlap: No two impls for the same trait are implemented for the
16 use middle::infer::{self, new_infer_ctxt};
17 use syntax::ast::{DefId};
18 use syntax::ast::{LOCAL_CRATE};
20 use syntax::codemap::{Span};
21 use util::ppaux::Repr;
23 pub fn check(tcx: &ty::ctxt) {
24 let overlap = OverlapChecker { tcx: tcx };
25 overlap.check_for_overlapping_impls();
28 struct OverlapChecker<'cx, 'tcx:'cx> {
29 tcx: &'cx ty::ctxt<'tcx>
32 impl<'cx, 'tcx> OverlapChecker<'cx, 'tcx> {
33 fn check_for_overlapping_impls(&self) {
34 debug!("check_for_overlapping_impls");
36 // Collect this into a vector to avoid holding the
37 // refcell-lock during the
38 // check_for_overlapping_impls_of_trait() check, since that
39 // check can populate this table further with impls from other
41 let trait_def_ids: Vec<ast::DefId> =
42 self.tcx.trait_impls.borrow().keys().map(|&d| d).collect();
44 for trait_def_id in trait_def_ids.iter() {
45 self.check_for_overlapping_impls_of_trait(*trait_def_id);
49 fn check_for_overlapping_impls_of_trait(&self,
50 trait_def_id: ast::DefId)
52 debug!("check_for_overlapping_impls_of_trait(trait_def_id={})",
53 trait_def_id.repr(self.tcx));
55 // FIXME -- it seems like this method actually pushes
56 // duplicate impls onto the list
57 ty::populate_implementations_for_trait_if_necessary(self.tcx,
60 let mut impls = Vec::new();
61 self.push_impls_of_trait(trait_def_id, &mut impls);
63 for (i, &impl1_def_id) in impls.iter().enumerate() {
64 if impl1_def_id.krate != ast::LOCAL_CRATE {
65 // we don't need to check impls if both are external;
66 // that's the other crate's job.
70 for &impl2_def_id in impls.slice_from(i+1).iter() {
71 self.check_if_impls_overlap(trait_def_id,
78 fn check_if_impls_overlap(&self,
79 trait_def_id: ast::DefId,
80 impl1_def_id: ast::DefId,
81 impl2_def_id: ast::DefId)
83 assert_eq!(impl1_def_id.krate, ast::LOCAL_CRATE);
85 debug!("check_if_impls_overlap({}, {}, {})",
86 trait_def_id.repr(self.tcx),
87 impl1_def_id.repr(self.tcx),
88 impl2_def_id.repr(self.tcx));
90 let infcx = infer::new_infer_ctxt(self.tcx);
91 if !traits::overlapping_impls(&infcx, impl1_def_id, impl2_def_id) {
95 span_err!(self.tcx.sess, self.span_of_impl(impl1_def_id), E0119,
96 "conflicting implementations for trait `{}`",
97 ty::item_path_str(self.tcx, trait_def_id));
99 if impl2_def_id.krate == ast::LOCAL_CRATE {
100 span_note!(self.tcx.sess, self.span_of_impl(impl2_def_id),
101 "note conflicting implementation here");
103 let crate_store = &self.tcx.sess.cstore;
104 let cdata = crate_store.get_crate_data(impl2_def_id.krate);
105 span_note!(self.tcx.sess, self.span_of_impl(impl1_def_id),
106 "conflicting implementation in crate `{}`",
111 fn push_impls_of_trait(&self,
112 trait_def_id: ast::DefId,
113 out: &mut Vec<ast::DefId>) {
114 match self.tcx.trait_impls.borrow().get(&trait_def_id) {
115 Some(impls) => { out.push_all(impls.borrow().as_slice()); }
116 None => { /* no impls */ }
120 fn span_of_impl(&self, impl_did: ast::DefId) -> Span {
121 assert_eq!(impl_did.krate, ast::LOCAL_CRATE);
122 self.tcx.map.span(impl_did.node)