1 //! Orphan checker: every impl either implements a trait defined in this
2 //! crate or pertains to a type defined in this crate.
5 use rustc::ty::{self, TyCtxt};
6 use rustc::hir::itemlikevisit::ItemLikeVisitor;
9 pub fn check<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
10 let mut orphan = OrphanChecker { tcx };
11 tcx.hir().krate().visit_all_item_likes(&mut orphan);
14 struct OrphanChecker<'cx, 'tcx: 'cx> {
15 tcx: TyCtxt<'cx, 'tcx, 'tcx>,
18 impl<'cx, 'tcx, 'v> ItemLikeVisitor<'v> for OrphanChecker<'cx, 'tcx> {
19 /// Checks exactly one impl for orphan rules and other such
20 /// restrictions. In this fn, it can happen that multiple errors
21 /// apply to a specific impl, so just return after reporting one
22 /// to prevent inundating the user with a bunch of similar error
24 fn visit_item(&mut self, item: &hir::Item) {
25 let def_id = self.tcx.hir().local_def_id(item.id);
27 if let hir::ItemKind::Impl(.., Some(_), _, _) = item.node {
28 debug!("coherence2::orphan check: trait impl {}",
29 self.tcx.hir().node_to_string(item.id));
30 let trait_ref = self.tcx.impl_trait_ref(def_id).unwrap();
31 let trait_def_id = trait_ref.def_id;
32 let cm = self.tcx.sess.source_map();
33 let sp = cm.def_span(item.span);
34 match traits::orphan_check(self.tcx, def_id) {
36 Err(traits::OrphanCheckErr::NoLocalInputType) => {
37 struct_span_err!(self.tcx.sess,
40 "only traits defined in the current crate can be \
41 implemented for arbitrary types")
42 .span_label(sp, "impl doesn't use types inside crate")
43 .note("the impl does not reference only types defined in this crate")
44 .note("define and implement a trait or new type instead")
48 Err(traits::OrphanCheckErr::UncoveredTy(param_ty)) => {
49 struct_span_err!(self.tcx.sess,
52 "type parameter `{}` must be used as the type parameter \
53 for some local type (e.g., `MyStruct<{}>`)",
57 format!("type parameter `{}` must be used as the type \
58 parameter for some local type", param_ty))
59 .note("only traits defined in the current crate can be implemented \
60 for a type parameter")
66 // In addition to the above rules, we restrict impls of auto traits
67 // so that they can only be implemented on nominal types, such as structs,
68 // enums or foreign types. To see why this restriction exists, consider the
69 // following example (#22978). Imagine that crate A defines an auto trait
70 // `Foo` and a fn that operates on pairs of types:
75 // fn two_foos<A:Foo,B:Foo>(..) {
76 // one_foo::<(A,B)>(..)
78 // fn one_foo<T:Foo>(..) { .. }
81 // This type-checks fine; in particular the fn
82 // `two_foos` is able to conclude that `(A,B):Foo`
83 // because `A:Foo` and `B:Foo`.
85 // Now imagine that crate B comes along and does the following:
92 // impl !Send for (A, B) { }
95 // This final impl is legal according to the orpan
96 // rules, but it invalidates the reasoning from
98 debug!("trait_ref={:?} trait_def_id={:?} trait_is_auto={}",
101 self.tcx.trait_is_auto(trait_def_id));
102 if self.tcx.trait_is_auto(trait_def_id) &&
103 !trait_def_id.is_local() {
104 let self_ty = trait_ref.self_ty();
105 let opt_self_def_id = match self_ty.sty {
106 ty::Adt(self_def, _) => Some(self_def.did),
107 ty::Foreign(did) => Some(did),
111 let msg = match opt_self_def_id {
112 // We only want to permit nominal types, but not *all* nominal types.
113 // They must be local to the current crate, so that people
114 // can't do `unsafe impl Send for Rc<SomethingLocal>` or
115 // `impl !Send for Box<SomethingLocalAndSend>`.
116 Some(self_def_id) => {
117 if self_def_id.is_local() {
121 format!("cross-crate traits with a default impl, like `{}`, \
122 can only be implemented for a struct/enum type \
123 defined in the current crate",
124 self.tcx.item_path_str(trait_def_id)),
125 "can't implement cross-crate trait for type in another crate"
130 Some((format!("cross-crate traits with a default impl, like `{}`, can \
131 only be implemented for a struct/enum type, not `{}`",
132 self.tcx.item_path_str(trait_def_id),
134 "can't implement cross-crate trait with a default impl for \
135 non-struct/enum type"))
139 if let Some((msg, label)) = msg {
140 struct_span_err!(self.tcx.sess, sp, E0321, "{}", msg)
141 .span_label(sp, label)
149 fn visit_trait_item(&mut self, _trait_item: &hir::TraitItem) {
152 fn visit_impl_item(&mut self, _impl_item: &hir::ImplItem) {