1 //! Orphan checker: every impl either implements a trait defined in this
2 //! crate or pertains to a type defined in this crate.
4 use rustc::ty::{self, TyCtxt};
5 use rustc_errors::struct_span_err;
7 use rustc_hir::itemlikevisit::ItemLikeVisitor;
8 use rustc_infer::infer::TyCtxtInferExt;
9 use rustc_infer::traits;
11 pub fn check(tcx: TyCtxt<'_>) {
12 let mut orphan = OrphanChecker { tcx };
13 tcx.hir().krate().visit_all_item_likes(&mut orphan);
16 struct OrphanChecker<'tcx> {
20 impl ItemLikeVisitor<'v> for OrphanChecker<'tcx> {
21 /// Checks exactly one impl for orphan rules and other such
22 /// restrictions. In this fn, it can happen that multiple errors
23 /// apply to a specific impl, so just return after reporting one
24 /// to prevent inundating the user with a bunch of similar error
26 fn visit_item(&mut self, item: &hir::Item<'_>) {
27 let def_id = self.tcx.hir().local_def_id(item.hir_id);
29 if let hir::ItemKind::Impl { generics, of_trait: Some(ref tr), self_ty, .. } = &item.kind {
31 "coherence2::orphan check: trait impl {}",
32 self.tcx.hir().node_to_string(item.hir_id)
34 let trait_ref = self.tcx.impl_trait_ref(def_id).unwrap();
35 let trait_def_id = trait_ref.def_id;
36 let sm = self.tcx.sess.source_map();
37 let sp = sm.def_span(item.span);
38 match traits::orphan_check(self.tcx, def_id) {
40 Err(traits::OrphanCheckErr::NonLocalInputType(tys)) => {
41 let mut err = struct_span_err!(
45 "only traits defined in the current crate can be implemented for \
48 err.span_label(sp, "impl doesn't use only types from inside the current crate");
49 for (ty, is_target_ty) in &tys {
51 self.tcx.infer_ctxt().enter(|infcx| {
52 // Remove the lifetimes unnecessary for this error.
53 ty = infcx.freshen(ty);
56 // Remove the type arguments from the output, as they are not relevant.
57 // You can think of this as the reverse of `resolve_vars_if_possible`.
58 // That way if we had `Vec<MyType>`, we will properly attribute the
59 // problem to `Vec<T>` and avoid confusing the user if they were to see
60 // `MyType` in the error.
61 ty::Adt(def, _) => self.tcx.mk_adt(def, ty::List::empty()),
64 let this = "this".to_string();
65 let (ty, postfix) = match &ty.kind {
66 ty::Slice(_) => (this, " because slices are always foreign"),
67 ty::Array(..) => (this, " because arrays are always foreign"),
68 ty::Tuple(..) => (this, " because tuples are always foreign"),
69 _ => (format!("`{}`", ty), ""),
71 let msg = format!("{} is not defined in the current crate{}", ty, postfix);
73 // Point at `D<A>` in `impl<A, B> for C<B> in D<A>`
74 err.span_label(self_ty.span, &msg);
76 // Point at `C<B>` in `impl<A, B> for C<B> in D<A>`
77 err.span_label(tr.path.span, &msg);
80 err.note("define and implement a trait or new type instead");
84 Err(traits::OrphanCheckErr::UncoveredTy(param_ty, local_type)) => {
86 for param in generics.params {
87 if param.name.ident().to_string() == param_ty.to_string() {
98 "type parameter `{}` must be covered by another type \
99 when it appears before the first local type (`{}`)",
106 "type parameter `{}` must be covered by another type \
107 when it appears before the first local type (`{}`)",
112 "implementing a foreign trait is only possible if at \
113 least one of the types for which is it implemented is local, \
114 and no uncovered type parameters appear before that first \
118 "in this case, 'before' refers to the following order: \
119 `impl<..> ForeignTrait<T1, ..., Tn> for T0`, \
120 where `T0` is the first and `Tn` is the last",
129 "type parameter `{}` must be used as the type parameter for some \
130 local type (e.g., `MyStruct<{}>`)",
133 ).span_label(sp, format!(
134 "type parameter `{}` must be used as the type parameter for some \
137 )).note("implementing a foreign trait is only possible if at \
138 least one of the types for which is it implemented is local"
139 ).note("only traits defined in the current crate can be \
140 implemented for a type parameter"
148 // In addition to the above rules, we restrict impls of auto traits
149 // so that they can only be implemented on nominal types, such as structs,
150 // enums or foreign types. To see why this restriction exists, consider the
151 // following example (#22978). Imagine that crate A defines an auto trait
152 // `Foo` and a fn that operates on pairs of types:
156 // auto trait Foo { }
157 // fn two_foos<A:Foo,B:Foo>(..) {
158 // one_foo::<(A,B)>(..)
160 // fn one_foo<T:Foo>(..) { .. }
163 // This type-checks fine; in particular the fn
164 // `two_foos` is able to conclude that `(A,B):Foo`
165 // because `A:Foo` and `B:Foo`.
167 // Now imagine that crate B comes along and does the following:
172 // impl Foo for A { }
173 // impl Foo for B { }
174 // impl !Send for (A, B) { }
177 // This final impl is legal according to the orpan
178 // rules, but it invalidates the reasoning from
181 "trait_ref={:?} trait_def_id={:?} trait_is_auto={}",
184 self.tcx.trait_is_auto(trait_def_id)
186 if self.tcx.trait_is_auto(trait_def_id) && !trait_def_id.is_local() {
187 let self_ty = trait_ref.self_ty();
188 let opt_self_def_id = match self_ty.kind {
189 ty::Adt(self_def, _) => Some(self_def.did),
190 ty::Foreign(did) => Some(did),
194 let msg = match opt_self_def_id {
195 // We only want to permit nominal types, but not *all* nominal types.
196 // They must be local to the current crate, so that people
197 // can't do `unsafe impl Send for Rc<SomethingLocal>` or
198 // `impl !Send for Box<SomethingLocalAndSend>`.
199 Some(self_def_id) => {
200 if self_def_id.is_local() {
205 "cross-crate traits with a default impl, like `{}`, \
206 can only be implemented for a struct/enum type \
207 defined in the current crate",
208 self.tcx.def_path_str(trait_def_id)
210 "can't implement cross-crate trait for type in another crate",
216 "cross-crate traits with a default impl, like `{}`, can \
217 only be implemented for a struct/enum type, not `{}`",
218 self.tcx.def_path_str(trait_def_id),
221 "can't implement cross-crate trait with a default impl for \
222 non-struct/enum type",
226 if let Some((msg, label)) = msg {
227 struct_span_err!(self.tcx.sess, sp, E0321, "{}", msg)
228 .span_label(sp, label)
236 fn visit_trait_item(&mut self, _trait_item: &hir::TraitItem<'_>) {}
238 fn visit_impl_item(&mut self, _impl_item: &hir::ImplItem<'_>) {}