]> git.lizzy.rs Git - rust.git/blob - src/librustc_typeck/coherence/orphan.rs
Auto merge of #30641 - tsion:match-range, r=eddyb
[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 middle::def_id::DefId;
16 use middle::traits;
17 use middle::ty;
18 use syntax::ast;
19 use syntax::codemap::Span;
20 use rustc_front::intravisit;
21 use rustc_front::hir;
22
23 pub fn check(tcx: &ty::ctxt) {
24     let mut orphan = OrphanChecker { tcx: tcx };
25     tcx.map.krate().visit_all_items(&mut orphan);
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                 struct_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(span, "consider using a trait to implement these methods")
55                     .emit();
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 = self.tcx.map.local_def_id(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                     ty::TyError => {
208                         return;
209                     }
210                     _ => {
211                         span_err!(self.tcx.sess, item.span, E0118,
212                                   "no base type found for inherent implementation; \
213                                    implement a trait or new type instead");
214                         return;
215                     }
216                 }
217             }
218             hir::ItemImpl(_, _, _, Some(_), _, _) => {
219                 // "Trait" impl
220                 debug!("coherence2::orphan check: trait impl {}",
221                        self.tcx.map.node_to_string(item.id));
222                 let trait_ref = self.tcx.impl_trait_ref(def_id).unwrap();
223                 let trait_def_id = trait_ref.def_id;
224                 match traits::orphan_check(self.tcx, def_id) {
225                     Ok(()) => { }
226                     Err(traits::OrphanCheckErr::NoLocalInputType) => {
227                         span_err!(
228                             self.tcx.sess, item.span, E0117,
229                             "the impl does not reference any \
230                              types defined in this crate; \
231                              only traits defined in the current crate can be \
232                              implemented for arbitrary types");
233                         return;
234                     }
235                     Err(traits::OrphanCheckErr::UncoveredTy(param_ty)) => {
236                         span_err!(self.tcx.sess, item.span, E0210,
237                                 "type parameter `{}` must be used as the type parameter for \
238                                  some local type (e.g. `MyStruct<T>`); only traits defined in \
239                                  the current crate can be implemented for a type parameter",
240                                 param_ty);
241                         return;
242                     }
243                 }
244
245                 // In addition to the above rules, we restrict impls of defaulted traits
246                 // so that they can only be implemented on structs/enums. To see why this
247                 // restriction exists, consider the following example (#22978). Imagine
248                 // that crate A defines a defaulted trait `Foo` and a fn that operates
249                 // on pairs of types:
250                 //
251                 // ```
252                 // // Crate A
253                 // trait Foo { }
254                 // impl Foo for .. { }
255                 // fn two_foos<A:Foo,B:Foo>(..) {
256                 //     one_foo::<(A,B)>(..)
257                 // }
258                 // fn one_foo<T:Foo>(..) { .. }
259                 // ```
260                 //
261                 // This type-checks fine; in particular the fn
262                 // `two_foos` is able to conclude that `(A,B):Foo`
263                 // because `A:Foo` and `B:Foo`.
264                 //
265                 // Now imagine that crate B comes along and does the following:
266                 //
267                 // ```
268                 // struct A { }
269                 // struct B { }
270                 // impl Foo for A { }
271                 // impl Foo for B { }
272                 // impl !Send for (A, B) { }
273                 // ```
274                 //
275                 // This final impl is legal according to the orpan
276                 // rules, but it invalidates the reasoning from
277                 // `two_foos` above.
278                 debug!("trait_ref={:?} trait_def_id={:?} trait_has_default_impl={}",
279                        trait_ref,
280                        trait_def_id,
281                        self.tcx.trait_has_default_impl(trait_def_id));
282                 if
283                     self.tcx.trait_has_default_impl(trait_def_id) &&
284                     trait_def_id.krate != LOCAL_CRATE
285                 {
286                     let self_ty = trait_ref.self_ty();
287                     let opt_self_def_id = match self_ty.sty {
288                         ty::TyStruct(self_def, _) | ty::TyEnum(self_def, _) =>
289                             Some(self_def.did),
290                         ty::TyBox(..) =>
291                             self.tcx.lang_items.owned_box(),
292                         _ =>
293                             None
294                     };
295
296                     let msg = match opt_self_def_id {
297                         // We only want to permit structs/enums, but not *all* structs/enums.
298                         // They must be local to the current crate, so that people
299                         // can't do `unsafe impl Send for Rc<SomethingLocal>` or
300                         // `impl !Send for Box<SomethingLocalAndSend>`.
301                         Some(self_def_id) => {
302                             if self_def_id.is_local() {
303                                 None
304                             } else {
305                                 Some(format!(
306                                     "cross-crate traits with a default impl, like `{}`, \
307                                      can only be implemented for a struct/enum type \
308                                      defined in the current crate",
309                                     self.tcx.item_path_str(trait_def_id)))
310                             }
311                         }
312                         _ => {
313                             Some(format!(
314                                 "cross-crate traits with a default impl, like `{}`, \
315                                  can only be implemented for a struct/enum type, \
316                                  not `{}`",
317                                 self.tcx.item_path_str(trait_def_id),
318                                 self_ty))
319                         }
320                     };
321
322                     if let Some(msg) = msg {
323                         span_err!(self.tcx.sess, item.span, E0321, "{}", msg);
324                         return;
325                     }
326                 }
327
328                 // Disallow *all* explicit impls of `Sized` and `Unsize` for now.
329                 if Some(trait_def_id) == self.tcx.lang_items.sized_trait() {
330                     span_err!(self.tcx.sess, item.span, E0322,
331                               "explicit impls for the `Sized` trait are not permitted");
332                     return;
333                 }
334                 if Some(trait_def_id) == self.tcx.lang_items.unsize_trait() {
335                     span_err!(self.tcx.sess, item.span, E0328,
336                               "explicit impls for the `Unsize` trait are not permitted");
337                     return;
338                 }
339             }
340             hir::ItemDefaultImpl(..) => {
341                 // "Trait" impl
342                 debug!("coherence2::orphan check: default trait impl {}",
343                        self.tcx.map.node_to_string(item.id));
344                 let trait_ref = self.tcx.impl_trait_ref(def_id).unwrap();
345                 if trait_ref.def_id.krate != LOCAL_CRATE {
346                     span_err!(self.tcx.sess, item.span, E0318,
347                               "cannot create default implementations for traits outside the \
348                                crate they're defined in; define a new trait instead");
349                     return;
350                 }
351             }
352             _ => {
353                 // Not an impl
354             }
355         }
356     }
357 }
358
359 impl<'cx, 'tcx,'v> intravisit::Visitor<'v> for OrphanChecker<'cx, 'tcx> {
360     fn visit_item(&mut self, item: &hir::Item) {
361         self.check_item(item);
362     }
363 }