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::typeck::infer::{new_infer_ctxt};
17 use middle::typeck::infer;
18 use syntax::ast::{DefId};
19 use syntax::ast::{LOCAL_CRATE};
21 use syntax::codemap::{Span};
22 use util::ppaux::Repr;
24 pub fn check(tcx: &ty::ctxt) {
25 let overlap = OverlapChecker { tcx: tcx };
26 overlap.check_for_overlapping_impls();
29 struct OverlapChecker<'cx, 'tcx:'cx> {
30 tcx: &'cx ty::ctxt<'tcx>
33 impl<'cx, 'tcx> OverlapChecker<'cx, 'tcx> {
34 fn check_for_overlapping_impls(&self) {
35 debug!("check_for_overlapping_impls");
37 // Collect this into a vector to avoid holding the
38 // refcell-lock during the
39 // check_for_overlapping_impls_of_trait() check, since that
40 // check can populate this table further with impls from other
42 let trait_def_ids: Vec<ast::DefId> =
43 self.tcx.trait_impls.borrow().keys().map(|&d| d).collect();
45 for trait_def_id in trait_def_ids.iter() {
46 self.check_for_overlapping_impls_of_trait(*trait_def_id);
50 fn check_for_overlapping_impls_of_trait(&self,
51 trait_def_id: ast::DefId)
53 debug!("check_for_overlapping_impls_of_trait(trait_def_id={})",
54 trait_def_id.repr(self.tcx));
56 // FIXME -- it seems like this method actually pushes
57 // duplicate impls onto the list
58 ty::populate_implementations_for_trait_if_necessary(self.tcx,
61 let mut impls = Vec::new();
62 self.push_impls_of_trait(trait_def_id, &mut impls);
64 for (i, &impl1_def_id) in impls.iter().enumerate() {
65 if impl1_def_id.krate != ast::LOCAL_CRATE {
66 // we don't need to check impls if both are external;
67 // that's the other crate's job.
71 for &impl2_def_id in impls.slice_from(i+1).iter() {
72 self.check_if_impls_overlap(trait_def_id,
79 fn check_if_impls_overlap(&self,
80 trait_def_id: ast::DefId,
81 impl1_def_id: ast::DefId,
82 impl2_def_id: ast::DefId)
84 assert_eq!(impl1_def_id.krate, ast::LOCAL_CRATE);
86 debug!("check_if_impls_overlap({}, {}, {})",
87 trait_def_id.repr(self.tcx),
88 impl1_def_id.repr(self.tcx),
89 impl2_def_id.repr(self.tcx));
91 let infcx = infer::new_infer_ctxt(self.tcx);
92 if !traits::overlapping_impls(&infcx, impl1_def_id, impl2_def_id) {
96 span_err!(self.tcx.sess, self.span_of_impl(impl1_def_id), E0119,
97 "conflicting implementations for trait `{}`",
98 ty::item_path_str(self.tcx, trait_def_id));
100 if impl2_def_id.krate == ast::LOCAL_CRATE {
101 span_note!(self.tcx.sess, self.span_of_impl(impl2_def_id),
102 "note conflicting implementation here");
104 let crate_store = &self.tcx.sess.cstore;
105 let cdata = crate_store.get_crate_data(impl2_def_id.krate);
106 span_note!(self.tcx.sess, self.span_of_impl(impl1_def_id),
107 "conflicting implementation in crate `{}`",
112 fn push_impls_of_trait(&self,
113 trait_def_id: ast::DefId,
114 out: &mut Vec<ast::DefId>) {
115 match self.tcx.trait_impls.borrow().get(&trait_def_id) {
116 Some(impls) => { out.push_all(impls.borrow().as_slice()); }
117 None => { /* no impls */ }
121 fn span_of_impl(&self, impl_did: ast::DefId) -> Span {
122 assert_eq!(impl_did.krate, ast::LOCAL_CRATE);
123 self.tcx.map.span(impl_did.node)