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.
15 use rustc::ty::{self, TyCtxt};
16 use rustc::hir::itemlikevisit::ItemLikeVisitor;
19 pub fn check<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
20 let mut orphan = OrphanChecker { tcx: tcx };
21 tcx.hir.krate().visit_all_item_likes(&mut orphan);
24 struct OrphanChecker<'cx, 'tcx: 'cx> {
25 tcx: TyCtxt<'cx, 'tcx, 'tcx>,
28 impl<'cx, 'tcx, 'v> ItemLikeVisitor<'v> for OrphanChecker<'cx, 'tcx> {
29 /// Checks exactly one impl for orphan rules and other such
30 /// restrictions. In this fn, it can happen that multiple errors
31 /// apply to a specific impl, so just return after reporting one
32 /// to prevent inundating the user with a bunch of similar error
34 fn visit_item(&mut self, item: &hir::Item) {
35 let def_id = self.tcx.hir.local_def_id(item.id);
37 hir::ItemImpl(.., Some(_), _, _) => {
39 debug!("coherence2::orphan check: trait impl {}",
40 self.tcx.hir.node_to_string(item.id));
41 let trait_ref = self.tcx.impl_trait_ref(def_id).unwrap();
42 let trait_def_id = trait_ref.def_id;
43 match traits::orphan_check(self.tcx, def_id) {
45 Err(traits::OrphanCheckErr::NoLocalInputType) => {
46 struct_span_err!(self.tcx.sess,
49 "only traits defined in the current crate can be \
50 implemented for arbitrary types")
51 .span_label(item.span, &format!("impl doesn't use types inside crate"))
52 .note(&format!("the impl does not reference any types defined in \
54 .note("define and implement a trait or new type instead")
58 Err(traits::OrphanCheckErr::UncoveredTy(param_ty)) => {
59 span_err!(self.tcx.sess,
62 "type parameter `{}` must be used as the type parameter for \
63 some local type (e.g. `MyStruct<T>`); only traits defined in \
64 the current crate can be implemented for a type parameter",
70 // In addition to the above rules, we restrict impls of defaulted traits
71 // so that they can only be implemented on structs/enums. To see why this
72 // restriction exists, consider the following example (#22978). Imagine
73 // that crate A defines a defaulted trait `Foo` and a fn that operates
79 // impl Foo for .. { }
80 // fn two_foos<A:Foo,B:Foo>(..) {
81 // one_foo::<(A,B)>(..)
83 // fn one_foo<T:Foo>(..) { .. }
86 // This type-checks fine; in particular the fn
87 // `two_foos` is able to conclude that `(A,B):Foo`
88 // because `A:Foo` and `B:Foo`.
90 // Now imagine that crate B comes along and does the following:
97 // impl !Send for (A, B) { }
100 // This final impl is legal according to the orpan
101 // rules, but it invalidates the reasoning from
103 debug!("trait_ref={:?} trait_def_id={:?} trait_has_default_impl={}",
106 self.tcx.trait_has_default_impl(trait_def_id));
107 if self.tcx.trait_has_default_impl(trait_def_id) &&
108 !trait_def_id.is_local() {
109 let self_ty = trait_ref.self_ty();
110 let opt_self_def_id = match self_ty.sty {
111 ty::TyAdt(self_def, _) => Some(self_def.did),
115 let msg = match opt_self_def_id {
116 // We only want to permit structs/enums, but not *all* structs/enums.
117 // They must be local to the current crate, so that people
118 // can't do `unsafe impl Send for Rc<SomethingLocal>` or
119 // `impl !Send for Box<SomethingLocalAndSend>`.
120 Some(self_def_id) => {
121 if self_def_id.is_local() {
124 Some(format!("cross-crate traits with a default impl, like `{}`, \
125 can only be implemented for a struct/enum type \
126 defined in the current crate",
127 self.tcx.item_path_str(trait_def_id)))
131 Some(format!("cross-crate traits with a default impl, like `{}`, can \
132 only be implemented for a struct/enum type, not `{}`",
133 self.tcx.item_path_str(trait_def_id),
138 if let Some(msg) = msg {
139 span_err!(self.tcx.sess, item.span, E0321, "{}", msg);
144 hir::ItemDefaultImpl(_, ref item_trait_ref) => {
146 debug!("coherence2::orphan check: default trait impl {}",
147 self.tcx.hir.node_to_string(item.id));
148 let trait_ref = self.tcx.impl_trait_ref(def_id).unwrap();
149 if !trait_ref.def_id.is_local() {
150 struct_span_err!(self.tcx.sess,
151 item_trait_ref.path.span,
153 "cannot create default implementations for traits outside \
154 the crate they're defined in; define a new trait instead")
155 .span_label(item_trait_ref.path.span,
156 &format!("`{}` trait not defined in this crate",
157 self.tcx.hir.node_to_pretty_string(item_trait_ref.ref_id)))
168 fn visit_trait_item(&mut self, _trait_item: &hir::TraitItem) {
171 fn visit_impl_item(&mut self, _impl_item: &hir::ImplItem) {