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