]> git.lizzy.rs Git - rust.git/blob - src/librustc/middle/typeck/coherence/overlap.rs
/*! -> //!
[rust.git] / src / librustc / middle / typeck / coherence / overlap.rs
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.
4 //
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.
10
11 //! Overlap: No two impls for the same trait are implemented for the
12 //! same type.
13
14 use middle::traits;
15 use middle::ty;
16 use middle::typeck::infer::{new_infer_ctxt};
17 use middle::typeck::infer;
18 use syntax::ast::{DefId};
19 use syntax::ast::{LOCAL_CRATE};
20 use syntax::ast;
21 use syntax::codemap::{Span};
22 use util::ppaux::Repr;
23
24 pub fn check(tcx: &ty::ctxt) {
25     let overlap = OverlapChecker { tcx: tcx };
26     overlap.check_for_overlapping_impls();
27 }
28
29 struct OverlapChecker<'cx, 'tcx:'cx> {
30     tcx: &'cx ty::ctxt<'tcx>
31 }
32
33 impl<'cx, 'tcx> OverlapChecker<'cx, 'tcx> {
34     fn check_for_overlapping_impls(&self) {
35         debug!("check_for_overlapping_impls");
36
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
41         // crates.
42         let trait_def_ids: Vec<ast::DefId> =
43             self.tcx.trait_impls.borrow().keys().map(|&d| d).collect();
44
45         for trait_def_id in trait_def_ids.iter() {
46             self.check_for_overlapping_impls_of_trait(*trait_def_id);
47         }
48     }
49
50     fn check_for_overlapping_impls_of_trait(&self,
51                                             trait_def_id: ast::DefId)
52     {
53         debug!("check_for_overlapping_impls_of_trait(trait_def_id={})",
54                trait_def_id.repr(self.tcx));
55
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,
59                                                             trait_def_id);
60
61         let mut impls = Vec::new();
62         self.push_impls_of_trait(trait_def_id, &mut impls);
63
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.
68                 continue;
69             }
70
71             for &impl2_def_id in impls.slice_from(i+1).iter() {
72                 self.check_if_impls_overlap(trait_def_id,
73                                             impl1_def_id,
74                                             impl2_def_id);
75             }
76         }
77     }
78
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)
83     {
84         assert_eq!(impl1_def_id.krate, ast::LOCAL_CRATE);
85
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));
90
91         let infcx = infer::new_infer_ctxt(self.tcx);
92         if !traits::overlapping_impls(&infcx, impl1_def_id, impl2_def_id) {
93             return;
94         }
95
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));
99
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");
103         } else {
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 `{}`",
108                        cdata.name);
109         }
110     }
111
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 */ }
118         }
119     }
120
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)
124     }
125 }