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