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