]>
Commit | Line | Data |
---|---|---|
1a4d82fc JJ |
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::infer::{self, new_infer_ctxt}; | |
c34b1796 AL |
17 | use syntax::ast::DefId; |
18 | use syntax::ast::LOCAL_CRATE; | |
1a4d82fc | 19 | use syntax::ast; |
c34b1796 AL |
20 | use syntax::ast_util; |
21 | use syntax::visit; | |
22 | use syntax::codemap::Span; | |
23 | use util::nodemap::DefIdMap; | |
1a4d82fc JJ |
24 | |
25 | pub fn check(tcx: &ty::ctxt) { | |
c34b1796 | 26 | let mut overlap = OverlapChecker { tcx: tcx, default_impls: DefIdMap() }; |
1a4d82fc | 27 | overlap.check_for_overlapping_impls(); |
c34b1796 | 28 | |
9346a6ac AL |
29 | // this secondary walk specifically checks for some other cases, |
30 | // like defaulted traits, for which additional overlap rules exist | |
c34b1796 | 31 | visit::walk_crate(&mut overlap, tcx.map.krate()); |
1a4d82fc JJ |
32 | } |
33 | ||
34 | struct OverlapChecker<'cx, 'tcx:'cx> { | |
c34b1796 AL |
35 | tcx: &'cx ty::ctxt<'tcx>, |
36 | ||
37 | // maps from a trait def-id to an impl id | |
38 | default_impls: DefIdMap<ast::NodeId>, | |
1a4d82fc JJ |
39 | } |
40 | ||
41 | impl<'cx, 'tcx> OverlapChecker<'cx, 'tcx> { | |
42 | fn check_for_overlapping_impls(&self) { | |
43 | debug!("check_for_overlapping_impls"); | |
44 | ||
45 | // Collect this into a vector to avoid holding the | |
46 | // refcell-lock during the | |
47 | // check_for_overlapping_impls_of_trait() check, since that | |
48 | // check can populate this table further with impls from other | |
49 | // crates. | |
d9579d0f AL |
50 | let trait_defs: Vec<_> = self.tcx.trait_defs.borrow().values().cloned().collect(); |
51 | ||
52 | for trait_def in trait_defs { | |
c1a9b12d | 53 | self.tcx.populate_implementations_for_trait_if_necessary(trait_def.trait_ref.def_id); |
d9579d0f | 54 | self.check_for_overlapping_impls_of_trait(trait_def); |
1a4d82fc JJ |
55 | } |
56 | } | |
57 | ||
58 | fn check_for_overlapping_impls_of_trait(&self, | |
d9579d0f | 59 | trait_def: &'tcx ty::TraitDef<'tcx>) |
1a4d82fc | 60 | { |
62682a34 SL |
61 | debug!("check_for_overlapping_impls_of_trait(trait_def={:?})", |
62 | trait_def); | |
1a4d82fc | 63 | |
d9579d0f AL |
64 | // We should already know all impls of this trait, so these |
65 | // borrows are safe. | |
66 | let blanket_impls = trait_def.blanket_impls.borrow(); | |
67 | let nonblanket_impls = trait_def.nonblanket_impls.borrow(); | |
68 | let trait_def_id = trait_def.trait_ref.def_id; | |
69 | ||
70 | // Conflicts can only occur between a blanket impl and another impl, | |
71 | // or between 2 non-blanket impls of the same kind. | |
1a4d82fc | 72 | |
d9579d0f AL |
73 | for (i, &impl1_def_id) in blanket_impls.iter().enumerate() { |
74 | for &impl2_def_id in &blanket_impls[(i+1)..] { | |
1a4d82fc JJ |
75 | self.check_if_impls_overlap(trait_def_id, |
76 | impl1_def_id, | |
77 | impl2_def_id); | |
78 | } | |
d9579d0f AL |
79 | |
80 | for v in nonblanket_impls.values() { | |
81 | for &impl2_def_id in v { | |
82 | self.check_if_impls_overlap(trait_def_id, | |
83 | impl1_def_id, | |
84 | impl2_def_id); | |
85 | } | |
86 | } | |
87 | } | |
88 | ||
89 | for impl_group in nonblanket_impls.values() { | |
90 | for (i, &impl1_def_id) in impl_group.iter().enumerate() { | |
91 | for &impl2_def_id in &impl_group[(i+1)..] { | |
92 | self.check_if_impls_overlap(trait_def_id, | |
93 | impl1_def_id, | |
94 | impl2_def_id); | |
95 | } | |
96 | } | |
1a4d82fc JJ |
97 | } |
98 | } | |
99 | ||
d9579d0f AL |
100 | // We need to coherently pick which impl will be displayed |
101 | // as causing the error message, and it must be the in the current | |
102 | // crate. Just pick the smaller impl in the file. | |
103 | fn order_impls(&self, impl1_def_id: ast::DefId, impl2_def_id: ast::DefId) | |
104 | -> Option<(ast::DefId, ast::DefId)> { | |
105 | if impl1_def_id.krate != ast::LOCAL_CRATE { | |
106 | if impl2_def_id.krate != ast::LOCAL_CRATE { | |
107 | // we don't need to check impls if both are external; | |
108 | // that's the other crate's job. | |
109 | None | |
110 | } else { | |
111 | Some((impl2_def_id, impl1_def_id)) | |
112 | } | |
113 | } else if impl2_def_id.krate != ast::LOCAL_CRATE { | |
114 | Some((impl1_def_id, impl2_def_id)) | |
115 | } else if impl1_def_id.node < impl2_def_id.node { | |
116 | Some((impl1_def_id, impl2_def_id)) | |
117 | } else { | |
118 | Some((impl2_def_id, impl1_def_id)) | |
119 | } | |
120 | } | |
121 | ||
122 | ||
1a4d82fc JJ |
123 | fn check_if_impls_overlap(&self, |
124 | trait_def_id: ast::DefId, | |
125 | impl1_def_id: ast::DefId, | |
126 | impl2_def_id: ast::DefId) | |
127 | { | |
d9579d0f AL |
128 | if let Some((impl1_def_id, impl2_def_id)) = self.order_impls( |
129 | impl1_def_id, impl2_def_id) | |
130 | { | |
62682a34 SL |
131 | debug!("check_if_impls_overlap({:?}, {:?}, {:?})", |
132 | trait_def_id, | |
133 | impl1_def_id, | |
134 | impl2_def_id); | |
d9579d0f | 135 | |
c1a9b12d | 136 | let infcx = infer::new_infer_ctxt(self.tcx, &self.tcx.tables, None, false); |
d9579d0f AL |
137 | if traits::overlapping_impls(&infcx, impl1_def_id, impl2_def_id) { |
138 | self.report_overlap_error(trait_def_id, impl1_def_id, impl2_def_id); | |
139 | } | |
1a4d82fc | 140 | } |
c34b1796 AL |
141 | } |
142 | ||
143 | fn report_overlap_error(&self, trait_def_id: ast::DefId, | |
144 | impl1: ast::DefId, impl2: ast::DefId) { | |
145 | ||
146 | span_err!(self.tcx.sess, self.span_of_impl(impl1), E0119, | |
1a4d82fc | 147 | "conflicting implementations for trait `{}`", |
c1a9b12d | 148 | self.tcx.item_path_str(trait_def_id)); |
1a4d82fc | 149 | |
c34b1796 AL |
150 | self.report_overlap_note(impl1, impl2); |
151 | } | |
152 | ||
153 | fn report_overlap_note(&self, impl1: ast::DefId, impl2: ast::DefId) { | |
154 | ||
155 | if impl2.krate == ast::LOCAL_CRATE { | |
156 | span_note!(self.tcx.sess, self.span_of_impl(impl2), | |
1a4d82fc JJ |
157 | "note conflicting implementation here"); |
158 | } else { | |
159 | let crate_store = &self.tcx.sess.cstore; | |
c34b1796 AL |
160 | let cdata = crate_store.get_crate_data(impl2.krate); |
161 | span_note!(self.tcx.sess, self.span_of_impl(impl1), | |
1a4d82fc JJ |
162 | "conflicting implementation in crate `{}`", |
163 | cdata.name); | |
164 | } | |
165 | } | |
166 | ||
1a4d82fc JJ |
167 | fn span_of_impl(&self, impl_did: ast::DefId) -> Span { |
168 | assert_eq!(impl_did.krate, ast::LOCAL_CRATE); | |
169 | self.tcx.map.span(impl_did.node) | |
170 | } | |
171 | } | |
c34b1796 AL |
172 | |
173 | ||
174 | impl<'cx, 'tcx,'v> visit::Visitor<'v> for OverlapChecker<'cx, 'tcx> { | |
175 | fn visit_item(&mut self, item: &'v ast::Item) { | |
176 | match item.node { | |
177 | ast::ItemDefaultImpl(_, _) => { | |
178 | // look for another default impl; note that due to the | |
179 | // general orphan/coherence rules, it must always be | |
180 | // in this crate. | |
181 | let impl_def_id = ast_util::local_def(item.id); | |
c1a9b12d | 182 | let trait_ref = self.tcx.impl_trait_ref(impl_def_id).unwrap(); |
c34b1796 AL |
183 | let prev_default_impl = self.default_impls.insert(trait_ref.def_id, item.id); |
184 | match prev_default_impl { | |
185 | Some(prev_id) => { | |
186 | self.report_overlap_error(trait_ref.def_id, | |
187 | impl_def_id, | |
188 | ast_util::local_def(prev_id)); | |
189 | } | |
190 | None => { } | |
191 | } | |
192 | } | |
9346a6ac AL |
193 | ast::ItemImpl(_, _, _, Some(_), ref self_ty, _) => { |
194 | let impl_def_id = ast_util::local_def(item.id); | |
c1a9b12d | 195 | let trait_ref = self.tcx.impl_trait_ref(impl_def_id).unwrap(); |
9346a6ac AL |
196 | let trait_def_id = trait_ref.def_id; |
197 | match trait_ref.self_ty().sty { | |
62682a34 | 198 | ty::TyTrait(ref data) => { |
9346a6ac AL |
199 | // This is something like impl Trait1 for Trait2. Illegal |
200 | // if Trait1 is a supertrait of Trait2 or Trait2 is not object safe. | |
201 | ||
202 | if !traits::is_object_safe(self.tcx, data.principal_def_id()) { | |
203 | // this just means the self-ty is illegal, | |
204 | // and probably this error should have | |
205 | // been reported elsewhere, but I'm trying to avoid | |
206 | // giving a misleading message below. | |
207 | span_err!(self.tcx.sess, self_ty.span, E0372, | |
208 | "the trait `{}` cannot be made into an object", | |
c1a9b12d | 209 | self.tcx.item_path_str(data.principal_def_id())); |
9346a6ac AL |
210 | } else { |
211 | let mut supertrait_def_ids = | |
212 | traits::supertrait_def_ids(self.tcx, data.principal_def_id()); | |
213 | if supertrait_def_ids.any(|d| d == trait_def_id) { | |
214 | span_err!(self.tcx.sess, item.span, E0371, | |
215 | "the object type `{}` automatically \ | |
216 | implements the trait `{}`", | |
62682a34 | 217 | trait_ref.self_ty(), |
c1a9b12d | 218 | self.tcx.item_path_str(trait_def_id)); |
9346a6ac AL |
219 | } |
220 | } | |
221 | } | |
222 | _ => { } | |
223 | } | |
224 | } | |
225 | _ => { | |
226 | } | |
c34b1796 | 227 | } |
9346a6ac | 228 | visit::walk_item(self, item); |
c34b1796 AL |
229 | } |
230 | } |