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_errors::struct_span_err;
8 use rustc_hir::itemlikevisit::ItemLikeVisitor;
10 use rustc_error_codes::*;
12 pub fn check(tcx: TyCtxt<'_>) {
13 let mut orphan = OrphanChecker { tcx };
14 tcx.hir().krate().visit_all_item_likes(&mut orphan);
17 struct OrphanChecker<'tcx> {
21 impl ItemLikeVisitor<'v> for OrphanChecker<'tcx> {
22 /// Checks exactly one impl for orphan rules and other such
23 /// restrictions. In this fn, it can happen that multiple errors
24 /// apply to a specific impl, so just return after reporting one
25 /// to prevent inundating the user with a bunch of similar error
27 fn visit_item(&mut self, item: &hir::Item<'_>) {
28 let def_id = self.tcx.hir().local_def_id(item.hir_id);
30 if let hir::ItemKind::Impl(.., generics, Some(tr), impl_ty, _) = &item.kind {
32 "coherence2::orphan check: trait impl {}",
33 self.tcx.hir().node_to_string(item.hir_id)
35 let trait_ref = self.tcx.impl_trait_ref(def_id).unwrap();
36 let trait_def_id = trait_ref.def_id;
37 let cm = self.tcx.sess.source_map();
38 let sp = cm.def_span(item.span);
39 match traits::orphan_check(self.tcx, def_id) {
41 Err(traits::OrphanCheckErr::NonLocalInputType(tys)) => {
42 let mut err = struct_span_err!(
46 "only traits defined in the current crate can be implemented for \
49 err.span_label(sp, "impl doesn't use only types from inside the current crate");
50 for (ty, is_target_ty) in &tys {
52 self.tcx.infer_ctxt().enter(|infcx| {
53 // Remove the lifetimes unnecessary for this error.
54 ty = infcx.freshen(ty);
57 // Remove the type arguments from the output, as they are not relevant.
58 // You can think of this as the reverse of `resolve_vars_if_possible`.
59 // That way if we had `Vec<MyType>`, we will properly attribute the
60 // problem to `Vec<T>` and avoid confusing the user if they were to see
61 // `MyType` in the error.
62 ty::Adt(def, _) => self.tcx.mk_adt(def, ty::List::empty()),
65 let this = "this".to_string();
66 let (ty, postfix) = match &ty.kind {
67 ty::Slice(_) => (this, " because slices are always foreign"),
68 ty::Array(..) => (this, " because arrays are always foreign"),
69 ty::Tuple(..) => (this, " because tuples are always foreign"),
70 _ => (format!("`{}`", ty), ""),
72 let msg = format!("{} is not defined in the current crate{}", ty, postfix);
74 // Point at `D<A>` in `impl<A, B> for C<B> in D<A>`
75 err.span_label(impl_ty.span, &msg);
77 // Point at `C<B>` in `impl<A, B> for C<B> in D<A>`
78 err.span_label(tr.path.span, &msg);
81 err.note("define and implement a trait or new type instead");
85 Err(traits::OrphanCheckErr::UncoveredTy(param_ty, local_type)) => {
87 for param in generics.params {
88 if param.name.ident().to_string() == param_ty.to_string() {
99 "type parameter `{}` must be covered by another type \
100 when it appears before the first local type (`{}`)",
107 "type parameter `{}` must be covered by another type \
108 when it appears before the first local type (`{}`)",
113 "implementing a foreign trait is only possible if at \
114 least one of the types for which is it implemented is local, \
115 and no uncovered type parameters appear before that first \
119 "in this case, 'before' refers to the following order: \
120 `impl<..> ForeignTrait<T1, ..., Tn> for T0`, \
121 where `T0` is the first and `Tn` is the last",
130 "type parameter `{}` must be used as the type parameter for some \
131 local type (e.g., `MyStruct<{}>`)",
134 ).span_label(sp, format!(
135 "type parameter `{}` must be used as the type parameter for some \
138 )).note("implementing a foreign trait is only possible if at \
139 least one of the types for which is it implemented is local"
140 ).note("only traits defined in the current crate can be \
141 implemented for a type parameter"
149 // In addition to the above rules, we restrict impls of auto traits
150 // so that they can only be implemented on nominal types, such as structs,
151 // enums or foreign types. To see why this restriction exists, consider the
152 // following example (#22978). Imagine that crate A defines an auto trait
153 // `Foo` and a fn that operates on pairs of types:
157 // auto trait Foo { }
158 // fn two_foos<A:Foo,B:Foo>(..) {
159 // one_foo::<(A,B)>(..)
161 // fn one_foo<T:Foo>(..) { .. }
164 // This type-checks fine; in particular the fn
165 // `two_foos` is able to conclude that `(A,B):Foo`
166 // because `A:Foo` and `B:Foo`.
168 // Now imagine that crate B comes along and does the following:
173 // impl Foo for A { }
174 // impl Foo for B { }
175 // impl !Send for (A, B) { }
178 // This final impl is legal according to the orpan
179 // rules, but it invalidates the reasoning from
182 "trait_ref={:?} trait_def_id={:?} trait_is_auto={}",
185 self.tcx.trait_is_auto(trait_def_id)
187 if self.tcx.trait_is_auto(trait_def_id) && !trait_def_id.is_local() {
188 let self_ty = trait_ref.self_ty();
189 let opt_self_def_id = match self_ty.kind {
190 ty::Adt(self_def, _) => Some(self_def.did),
191 ty::Foreign(did) => Some(did),
195 let msg = match opt_self_def_id {
196 // We only want to permit nominal types, but not *all* nominal types.
197 // They must be local to the current crate, so that people
198 // can't do `unsafe impl Send for Rc<SomethingLocal>` or
199 // `impl !Send for Box<SomethingLocalAndSend>`.
200 Some(self_def_id) => {
201 if self_def_id.is_local() {
206 "cross-crate traits with a default impl, like `{}`, \
207 can only be implemented for a struct/enum type \
208 defined in the current crate",
209 self.tcx.def_path_str(trait_def_id)
211 "can't implement cross-crate trait for type in another crate",
217 "cross-crate traits with a default impl, like `{}`, can \
218 only be implemented for a struct/enum type, not `{}`",
219 self.tcx.def_path_str(trait_def_id),
222 "can't implement cross-crate trait with a default impl for \
223 non-struct/enum type",
227 if let Some((msg, label)) = msg {
228 struct_span_err!(self.tcx.sess, sp, E0321, "{}", msg)
229 .span_label(sp, label)
237 fn visit_trait_item(&mut self, _trait_item: &hir::TraitItem<'_>) {}
239 fn visit_impl_item(&mut self, _impl_item: &hir::ImplItem<'_>) {}