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