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.
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.
11 //! Orphan checker: every impl either implements a trait defined in this
12 //! crate or pertains to a type defined in this crate.
14 use middle::cstore::LOCAL_CRATE;
15 use middle::def_id::DefId;
19 use syntax::codemap::Span;
20 use rustc_front::intravisit;
22 use rustc_front::hir::{Item, ItemImpl};
24 pub fn check(tcx: &ty::ctxt) {
25 let mut orphan = OrphanChecker { tcx: tcx };
26 tcx.map.krate().visit_all_items(&mut orphan);
29 struct OrphanChecker<'cx, 'tcx:'cx> {
30 tcx: &'cx ty::ctxt<'tcx>
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 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; define and implement \
39 a trait or new type instead");
43 fn check_primitive_impl(&self,
45 lang_def_id: Option<DefId>,
50 Some(lang_def_id) if lang_def_id == impl_def_id => { /* OK */ },
52 span_err!(self.tcx.sess, span, E0390,
53 "only a single inherent implementation marked with `#[lang = \"{}\"]` \
54 is allowed for the `{}` primitive", lang, ty);
55 span_help!(self.tcx.sess, span,
56 "consider using a trait to implement these methods");
61 /// Checks exactly one impl for orphan rules and other such
62 /// restrictions. In this fn, it can happen that multiple errors
63 /// apply to a specific impl, so just return after reporting one
64 /// to prevent inundating the user with a bunch of similar error
66 fn check_item(&self, item: &hir::Item) {
67 let def_id = self.tcx.map.local_def_id(item.id);
69 hir::ItemImpl(_, _, _, None, _, _) => {
70 // For inherent impls, self type must be a nominal type
71 // defined in this crate.
72 debug!("coherence2::orphan check: inherent impl {}",
73 self.tcx.map.node_to_string(item.id));
74 let self_ty = self.tcx.lookup_item_type(def_id).ty;
77 ty::TyStruct(def, _) => {
78 self.check_def_id(item, def.did);
80 ty::TyTrait(ref data) => {
81 self.check_def_id(item, data.principal_def_id());
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),
90 self.check_primitive_impl(def_id,
91 self.tcx.lang_items.char_impl(),
97 self.check_primitive_impl(def_id,
98 self.tcx.lang_items.str_impl(),
104 self.check_primitive_impl(def_id,
105 self.tcx.lang_items.slice_impl(),
110 ty::TyRawPtr(ty::TypeAndMut { ty: _, mutbl: hir::MutImmutable }) => {
111 self.check_primitive_impl(def_id,
112 self.tcx.lang_items.const_ptr_impl(),
117 ty::TyRawPtr(ty::TypeAndMut { ty: _, mutbl: hir::MutMutable }) => {
118 self.check_primitive_impl(def_id,
119 self.tcx.lang_items.mut_ptr_impl(),
124 ty::TyInt(ast::TyI8) => {
125 self.check_primitive_impl(def_id,
126 self.tcx.lang_items.i8_impl(),
131 ty::TyInt(ast::TyI16) => {
132 self.check_primitive_impl(def_id,
133 self.tcx.lang_items.i16_impl(),
138 ty::TyInt(ast::TyI32) => {
139 self.check_primitive_impl(def_id,
140 self.tcx.lang_items.i32_impl(),
145 ty::TyInt(ast::TyI64) => {
146 self.check_primitive_impl(def_id,
147 self.tcx.lang_items.i64_impl(),
152 ty::TyInt(ast::TyIs) => {
153 self.check_primitive_impl(def_id,
154 self.tcx.lang_items.isize_impl(),
159 ty::TyUint(ast::TyU8) => {
160 self.check_primitive_impl(def_id,
161 self.tcx.lang_items.u8_impl(),
166 ty::TyUint(ast::TyU16) => {
167 self.check_primitive_impl(def_id,
168 self.tcx.lang_items.u16_impl(),
173 ty::TyUint(ast::TyU32) => {
174 self.check_primitive_impl(def_id,
175 self.tcx.lang_items.u32_impl(),
180 ty::TyUint(ast::TyU64) => {
181 self.check_primitive_impl(def_id,
182 self.tcx.lang_items.u64_impl(),
187 ty::TyUint(ast::TyUs) => {
188 self.check_primitive_impl(def_id,
189 self.tcx.lang_items.usize_impl(),
194 ty::TyFloat(ast::TyF32) => {
195 self.check_primitive_impl(def_id,
196 self.tcx.lang_items.f32_impl(),
201 ty::TyFloat(ast::TyF64) => {
202 self.check_primitive_impl(def_id,
203 self.tcx.lang_items.f64_impl(),
212 span_err!(self.tcx.sess, item.span, E0118,
213 "no base type found for inherent implementation; \
214 implement a trait or new type instead");
219 hir::ItemImpl(_, _, _, Some(_), _, _) => {
221 debug!("coherence2::orphan check: trait impl {}",
222 self.tcx.map.node_to_string(item.id));
223 let trait_ref = self.tcx.impl_trait_ref(def_id).unwrap();
224 let trait_def_id = trait_ref.def_id;
225 match traits::orphan_check(self.tcx, def_id) {
227 Err(traits::OrphanCheckErr::NoLocalInputType) => {
229 self.tcx.sess, item.span, E0117,
230 "the impl does not reference any \
231 types defined in this crate; \
232 only traits defined in the current crate can be \
233 implemented for arbitrary types");
236 Err(traits::OrphanCheckErr::UncoveredTy(param_ty)) => {
237 span_err!(self.tcx.sess, item.span, E0210,
238 "type parameter `{}` must be used as the type parameter for \
239 some local type (e.g. `MyStruct<T>`); only traits defined in \
240 the current crate can be implemented for a type parameter",
246 // In addition to the above rules, we restrict impls of defaulted traits
247 // so that they can only be implemented on structs/enums. To see why this
248 // restriction exists, consider the following example (#22978). Imagine
249 // that crate A defines a defaulted trait `Foo` and a fn that operates
250 // on pairs of types:
255 // impl Foo for .. { }
256 // fn two_foos<A:Foo,B:Foo>(..) {
257 // one_foo::<(A,B)>(..)
259 // fn one_foo<T:Foo>(..) { .. }
262 // This type-checks fine; in particular the fn
263 // `two_foos` is able to conclude that `(A,B):Foo`
264 // because `A:Foo` and `B:Foo`.
266 // Now imagine that crate B comes along and does the following:
271 // impl Foo for A { }
272 // impl Foo for B { }
273 // impl !Send for (A, B) { }
276 // This final impl is legal according to the orpan
277 // rules, but it invalidates the reasoning from
279 debug!("trait_ref={:?} trait_def_id={:?} trait_has_default_impl={}",
282 self.tcx.trait_has_default_impl(trait_def_id));
284 self.tcx.trait_has_default_impl(trait_def_id) &&
285 trait_def_id.krate != LOCAL_CRATE
287 let self_ty = trait_ref.self_ty();
288 let opt_self_def_id = match self_ty.sty {
289 ty::TyStruct(self_def, _) | ty::TyEnum(self_def, _) =>
292 self.tcx.lang_items.owned_box(),
297 let msg = match opt_self_def_id {
298 // We only want to permit structs/enums, but not *all* structs/enums.
299 // They must be local to the current crate, so that people
300 // can't do `unsafe impl Send for Rc<SomethingLocal>` or
301 // `impl !Send for Box<SomethingLocalAndSend>`.
302 Some(self_def_id) => {
303 if self_def_id.is_local() {
307 "cross-crate traits with a default impl, like `{}`, \
308 can only be implemented for a struct/enum type \
309 defined in the current crate",
310 self.tcx.item_path_str(trait_def_id)))
315 "cross-crate traits with a default impl, like `{}`, \
316 can only be implemented for a struct/enum type, \
318 self.tcx.item_path_str(trait_def_id),
323 if let Some(msg) = msg {
324 span_err!(self.tcx.sess, item.span, E0321, "{}", msg);
329 // Disallow *all* explicit impls of `Sized` and `Unsize` for now.
330 if Some(trait_def_id) == self.tcx.lang_items.sized_trait() {
331 span_err!(self.tcx.sess, item.span, E0322,
332 "explicit impls for the `Sized` trait are not permitted");
335 if Some(trait_def_id) == self.tcx.lang_items.unsize_trait() {
336 span_err!(self.tcx.sess, item.span, E0328,
337 "explicit impls for the `Unsize` trait are not permitted");
341 hir::ItemDefaultImpl(..) => {
343 debug!("coherence2::orphan check: default trait impl {}",
344 self.tcx.map.node_to_string(item.id));
345 let trait_ref = self.tcx.impl_trait_ref(def_id).unwrap();
346 if trait_ref.def_id.krate != LOCAL_CRATE {
347 span_err!(self.tcx.sess, item.span, E0318,
348 "cannot create default implementations for traits outside the \
349 crate they're defined in; define a new trait instead");
360 impl<'cx, 'tcx,'v> intravisit::Visitor<'v> for OrphanChecker<'cx, 'tcx> {
361 fn visit_item(&mut self, item: &hir::Item) {
362 self.check_item(item);