]> git.proxmox.com Git - rustc.git/blame - src/librustc_typeck/coherence/overlap.rs
Imported Upstream version 1.3.0+dfsg1
[rustc.git] / src / librustc_typeck / coherence / overlap.rs
CommitLineData
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
14use middle::traits;
15use middle::ty;
16use middle::infer::{self, new_infer_ctxt};
c34b1796
AL
17use syntax::ast::DefId;
18use syntax::ast::LOCAL_CRATE;
1a4d82fc 19use syntax::ast;
c34b1796
AL
20use syntax::ast_util;
21use syntax::visit;
22use syntax::codemap::Span;
23use util::nodemap::DefIdMap;
1a4d82fc
JJ
24
25pub 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
34struct 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
41impl<'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
174impl<'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}