]> git.proxmox.com Git - rustc.git/blob - src/librustc_typeck/coherence/orphan.rs
8376b92da3dea667c3926ad14c169d0b7de6af51
[rustc.git] / src / librustc_typeck / coherence / orphan.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 //! Orphan checker: every impl either implements a trait defined in this
12 //! crate or pertains to a type defined in this crate.
13
14 use middle::traits;
15 use middle::ty;
16 use syntax::ast::{Item, ItemImpl};
17 use syntax::ast;
18 use syntax::ast_util;
19 use syntax::codemap::Span;
20 use syntax::visit;
21
22 pub fn check(tcx: &ty::ctxt) {
23 let mut orphan = OrphanChecker { tcx: tcx };
24 visit::walk_crate(&mut orphan, tcx.map.krate());
25 }
26
27 struct OrphanChecker<'cx, 'tcx:'cx> {
28 tcx: &'cx ty::ctxt<'tcx>
29 }
30
31 impl<'cx, 'tcx> OrphanChecker<'cx, 'tcx> {
32 fn check_def_id(&self, item: &ast::Item, def_id: ast::DefId) {
33 if def_id.krate != ast::LOCAL_CRATE {
34 span_err!(self.tcx.sess, item.span, E0116,
35 "cannot define inherent `impl` for a type outside of the \
36 crate where the type is defined; define and implement \
37 a trait or new type instead");
38 }
39 }
40
41 fn check_primitive_impl(&self,
42 impl_def_id: ast::DefId,
43 lang_def_id: Option<ast::DefId>,
44 lang: &str,
45 ty: &str,
46 span: Span) {
47 match lang_def_id {
48 Some(lang_def_id) if lang_def_id == impl_def_id => { /* OK */ },
49 _ => {
50 span_err!(self.tcx.sess, span, E0390,
51 "only a single inherent implementation marked with `#[lang = \"{}\"]` \
52 is allowed for the `{}` primitive", lang, ty);
53 }
54 }
55 }
56
57 /// Checks exactly one impl for orphan rules and other such
58 /// restrictions. In this fn, it can happen that multiple errors
59 /// apply to a specific impl, so just return after reporting one
60 /// to prevent inundating the user with a bunch of similar error
61 /// reports.
62 fn check_item(&self, item: &ast::Item) {
63 let def_id = ast_util::local_def(item.id);
64 match item.node {
65 ast::ItemImpl(_, _, _, None, _, _) => {
66 // For inherent impls, self type must be a nominal type
67 // defined in this crate.
68 debug!("coherence2::orphan check: inherent impl {}",
69 self.tcx.map.node_to_string(item.id));
70 let self_ty = ty::lookup_item_type(self.tcx, def_id).ty;
71 match self_ty.sty {
72 ty::TyEnum(def_id, _) |
73 ty::TyStruct(def_id, _) => {
74 self.check_def_id(item, def_id);
75 }
76 ty::TyTrait(ref data) => {
77 self.check_def_id(item, data.principal_def_id());
78 }
79 ty::TyBox(..) => {
80 self.check_def_id(item, self.tcx.lang_items.owned_box().unwrap());
81 }
82 ty::TyChar => {
83 self.check_primitive_impl(def_id,
84 self.tcx.lang_items.char_impl(),
85 "char",
86 "char",
87 item.span);
88 }
89 ty::TyStr => {
90 self.check_primitive_impl(def_id,
91 self.tcx.lang_items.str_impl(),
92 "str",
93 "str",
94 item.span);
95 }
96 ty::TySlice(_) => {
97 self.check_primitive_impl(def_id,
98 self.tcx.lang_items.slice_impl(),
99 "slice",
100 "[T]",
101 item.span);
102 }
103 ty::TyRawPtr(ty::mt { ty: _, mutbl: ast::MutImmutable }) => {
104 self.check_primitive_impl(def_id,
105 self.tcx.lang_items.const_ptr_impl(),
106 "const_ptr",
107 "*const T",
108 item.span);
109 }
110 ty::TyRawPtr(ty::mt { ty: _, mutbl: ast::MutMutable }) => {
111 self.check_primitive_impl(def_id,
112 self.tcx.lang_items.mut_ptr_impl(),
113 "mut_ptr",
114 "*mut T",
115 item.span);
116 }
117 ty::TyInt(ast::TyI8) => {
118 self.check_primitive_impl(def_id,
119 self.tcx.lang_items.i8_impl(),
120 "i8",
121 "i8",
122 item.span);
123 }
124 ty::TyInt(ast::TyI16) => {
125 self.check_primitive_impl(def_id,
126 self.tcx.lang_items.i16_impl(),
127 "i16",
128 "i16",
129 item.span);
130 }
131 ty::TyInt(ast::TyI32) => {
132 self.check_primitive_impl(def_id,
133 self.tcx.lang_items.i32_impl(),
134 "i32",
135 "i32",
136 item.span);
137 }
138 ty::TyInt(ast::TyI64) => {
139 self.check_primitive_impl(def_id,
140 self.tcx.lang_items.i64_impl(),
141 "i64",
142 "i64",
143 item.span);
144 }
145 ty::TyInt(ast::TyIs) => {
146 self.check_primitive_impl(def_id,
147 self.tcx.lang_items.isize_impl(),
148 "isize",
149 "isize",
150 item.span);
151 }
152 ty::TyUint(ast::TyU8) => {
153 self.check_primitive_impl(def_id,
154 self.tcx.lang_items.u8_impl(),
155 "u8",
156 "u8",
157 item.span);
158 }
159 ty::TyUint(ast::TyU16) => {
160 self.check_primitive_impl(def_id,
161 self.tcx.lang_items.u16_impl(),
162 "u16",
163 "u16",
164 item.span);
165 }
166 ty::TyUint(ast::TyU32) => {
167 self.check_primitive_impl(def_id,
168 self.tcx.lang_items.u32_impl(),
169 "u32",
170 "u32",
171 item.span);
172 }
173 ty::TyUint(ast::TyU64) => {
174 self.check_primitive_impl(def_id,
175 self.tcx.lang_items.u64_impl(),
176 "u64",
177 "u64",
178 item.span);
179 }
180 ty::TyUint(ast::TyUs) => {
181 self.check_primitive_impl(def_id,
182 self.tcx.lang_items.usize_impl(),
183 "usize",
184 "usize",
185 item.span);
186 }
187 ty::TyFloat(ast::TyF32) => {
188 self.check_primitive_impl(def_id,
189 self.tcx.lang_items.f32_impl(),
190 "f32",
191 "f32",
192 item.span);
193 }
194 ty::TyFloat(ast::TyF64) => {
195 self.check_primitive_impl(def_id,
196 self.tcx.lang_items.f64_impl(),
197 "f64",
198 "f64",
199 item.span);
200 }
201 _ => {
202 span_err!(self.tcx.sess, item.span, E0118,
203 "no base type found for inherent implementation; \
204 implement a trait or new type instead");
205 return;
206 }
207 }
208 }
209 ast::ItemImpl(_, _, _, Some(_), _, _) => {
210 // "Trait" impl
211 debug!("coherence2::orphan check: trait impl {}",
212 self.tcx.map.node_to_string(item.id));
213 let trait_ref = ty::impl_trait_ref(self.tcx, def_id).unwrap();
214 let trait_def_id = trait_ref.def_id;
215 match traits::orphan_check(self.tcx, def_id) {
216 Ok(()) => { }
217 Err(traits::OrphanCheckErr::NoLocalInputType) => {
218 span_err!(
219 self.tcx.sess, item.span, E0117,
220 "the impl does not reference any \
221 types defined in this crate; \
222 only traits defined in the current crate can be \
223 implemented for arbitrary types");
224 return;
225 }
226 Err(traits::OrphanCheckErr::UncoveredTy(param_ty)) => {
227 span_err!(self.tcx.sess, item.span, E0210,
228 "type parameter `{}` must be used as the type parameter for \
229 some local type (e.g. `MyStruct<T>`); only traits defined in \
230 the current crate can be implemented for a type parameter",
231 param_ty);
232 return;
233 }
234 }
235
236 // In addition to the above rules, we restrict impls of defaulted traits
237 // so that they can only be implemented on structs/enums. To see why this
238 // restriction exists, consider the following example (#22978). Imagine
239 // that crate A defines a defaulted trait `Foo` and a fn that operates
240 // on pairs of types:
241 //
242 // ```
243 // // Crate A
244 // trait Foo { }
245 // impl Foo for .. { }
246 // fn two_foos<A:Foo,B:Foo>(..) {
247 // one_foo::<(A,B)>(..)
248 // }
249 // fn one_foo<T:Foo>(..) { .. }
250 // ```
251 //
252 // This type-checks fine; in particular the fn
253 // `two_foos` is able to conclude that `(A,B):Foo`
254 // because `A:Foo` and `B:Foo`.
255 //
256 // Now imagine that crate B comes along and does the following:
257 //
258 // ```
259 // struct A { }
260 // struct B { }
261 // impl Foo for A { }
262 // impl Foo for B { }
263 // impl !Send for (A, B) { }
264 // ```
265 //
266 // This final impl is legal according to the orpan
267 // rules, but it invalidates the reasoning from
268 // `two_foos` above.
269 debug!("trait_ref={:?} trait_def_id={:?} trait_has_default_impl={}",
270 trait_ref,
271 trait_def_id,
272 ty::trait_has_default_impl(self.tcx, trait_def_id));
273 if
274 ty::trait_has_default_impl(self.tcx, trait_def_id) &&
275 trait_def_id.krate != ast::LOCAL_CRATE
276 {
277 let self_ty = trait_ref.self_ty();
278 let opt_self_def_id = match self_ty.sty {
279 ty::TyStruct(self_def_id, _) | ty::TyEnum(self_def_id, _) =>
280 Some(self_def_id),
281 ty::TyBox(..) =>
282 self.tcx.lang_items.owned_box(),
283 _ =>
284 None
285 };
286
287 let msg = match opt_self_def_id {
288 // We only want to permit structs/enums, but not *all* structs/enums.
289 // They must be local to the current crate, so that people
290 // can't do `unsafe impl Send for Rc<SomethingLocal>` or
291 // `impl !Send for Box<SomethingLocalAndSend>`.
292 Some(self_def_id) => {
293 if self_def_id.krate == ast::LOCAL_CRATE {
294 None
295 } else {
296 Some(format!(
297 "cross-crate traits with a default impl, like `{}`, \
298 can only be implemented for a struct/enum type \
299 defined in the current crate",
300 ty::item_path_str(self.tcx, trait_def_id)))
301 }
302 }
303 _ => {
304 Some(format!(
305 "cross-crate traits with a default impl, like `{}`, \
306 can only be implemented for a struct/enum type, \
307 not `{}`",
308 ty::item_path_str(self.tcx, trait_def_id),
309 self_ty))
310 }
311 };
312
313 if let Some(msg) = msg {
314 span_err!(self.tcx.sess, item.span, E0321, "{}", msg);
315 return;
316 }
317 }
318
319 // Disallow *all* explicit impls of `Sized` and `Unsize` for now.
320 if Some(trait_def_id) == self.tcx.lang_items.sized_trait() {
321 span_err!(self.tcx.sess, item.span, E0322,
322 "explicit impls for the `Sized` trait are not permitted");
323 return;
324 }
325 if Some(trait_def_id) == self.tcx.lang_items.unsize_trait() {
326 span_err!(self.tcx.sess, item.span, E0328,
327 "explicit impls for the `Unsize` trait are not permitted");
328 return;
329 }
330 }
331 ast::ItemDefaultImpl(..) => {
332 // "Trait" impl
333 debug!("coherence2::orphan check: default trait impl {}",
334 self.tcx.map.node_to_string(item.id));
335 let trait_ref = ty::impl_trait_ref(self.tcx, def_id).unwrap();
336 if trait_ref.def_id.krate != ast::LOCAL_CRATE {
337 span_err!(self.tcx.sess, item.span, E0318,
338 "cannot create default implementations for traits outside the \
339 crate they're defined in; define a new trait instead");
340 return;
341 }
342 }
343 _ => {
344 // Not an impl
345 }
346 }
347 }
348 }
349
350 impl<'cx, 'tcx,'v> visit::Visitor<'v> for OrphanChecker<'cx, 'tcx> {
351 fn visit_item(&mut self, item: &ast::Item) {
352 self.check_item(item);
353 visit::walk_item(self, item);
354 }
355 }