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_errors::struct_span_err;
5 use rustc_errors::ErrorReported;
7 use rustc_infer::infer::TyCtxtInferExt;
8 use rustc_middle::ty::{self, TyCtxt};
9 use rustc_span::def_id::LocalDefId;
11 use rustc_trait_selection::traits;
13 pub(super) fn orphan_check_crate(tcx: TyCtxt<'_>, (): ()) -> &[LocalDefId] {
14 let mut errors = Vec::new();
15 for (_trait, impls_of_trait) in tcx.all_local_trait_impls(()) {
16 for &impl_of_trait in impls_of_trait {
17 match orphan_check_impl(tcx, impl_of_trait) {
19 Err(ErrorReported) => errors.push(impl_of_trait),
23 tcx.arena.alloc_slice(&errors)
26 #[instrument(skip(tcx), level = "debug")]
27 fn orphan_check_impl(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Result<(), ErrorReported> {
28 let trait_ref = tcx.impl_trait_ref(def_id).unwrap();
29 let trait_def_id = trait_ref.def_id;
31 let item = tcx.hir().item(hir::ItemId { def_id });
32 let impl_ = match item.kind {
33 hir::ItemKind::Impl(ref impl_) => impl_,
34 _ => bug!("{:?} is not an impl: {:?}", def_id, item),
36 let sp = tcx.sess.source_map().guess_head_span(item.span);
37 let tr = impl_.of_trait.as_ref().unwrap();
38 match traits::orphan_check(tcx, item.def_id.to_def_id()) {
40 Err(err) => emit_orphan_check_error(
50 // In addition to the above rules, we restrict impls of auto traits
51 // so that they can only be implemented on nominal types, such as structs,
52 // enums or foreign types. To see why this restriction exists, consider the
53 // following example (#22978). Imagine that crate A defines an auto trait
54 // `Foo` and a fn that operates on pairs of types:
59 // fn two_foos<A:Foo,B:Foo>(..) {
60 // one_foo::<(A,B)>(..)
62 // fn one_foo<T:Foo>(..) { .. }
65 // This type-checks fine; in particular the fn
66 // `two_foos` is able to conclude that `(A,B):Foo`
67 // because `A:Foo` and `B:Foo`.
69 // Now imagine that crate B comes along and does the following:
76 // impl !Send for (A, B) { }
79 // This final impl is legal according to the orphan
80 // rules, but it invalidates the reasoning from
83 "trait_ref={:?} trait_def_id={:?} trait_is_auto={}",
86 tcx.trait_is_auto(trait_def_id)
89 if tcx.trait_is_auto(trait_def_id) && !trait_def_id.is_local() {
90 let self_ty = trait_ref.self_ty();
91 let opt_self_def_id = match *self_ty.kind() {
92 ty::Adt(self_def, _) => Some(self_def.did),
93 ty::Foreign(did) => Some(did),
97 let msg = match opt_self_def_id {
98 // We only want to permit nominal types, but not *all* nominal types.
99 // They must be local to the current crate, so that people
100 // can't do `unsafe impl Send for Rc<SomethingLocal>` or
101 // `impl !Send for Box<SomethingLocalAndSend>`.
102 Some(self_def_id) => {
103 if self_def_id.is_local() {
108 "cross-crate traits with a default impl, like `{}`, \
109 can only be implemented for a struct/enum type \
110 defined in the current crate",
111 tcx.def_path_str(trait_def_id)
113 "can't implement cross-crate trait for type in another crate",
119 "cross-crate traits with a default impl, like `{}`, can \
120 only be implemented for a struct/enum type, not `{}`",
121 tcx.def_path_str(trait_def_id),
124 "can't implement cross-crate trait with a default impl for \
125 non-struct/enum type",
129 if let Some((msg, label)) = msg {
130 struct_span_err!(tcx.sess, sp, E0321, "{}", msg).span_label(sp, label).emit();
131 return Err(ErrorReported);
135 if let ty::Opaque(def_id, _) = *trait_ref.self_ty().kind() {
137 .struct_span_err(sp, "cannot implement trait on type alias impl trait")
138 .span_note(tcx.def_span(def_id), "type alias impl trait defined here")
140 return Err(ErrorReported);
146 fn emit_orphan_check_error(
151 generics: &hir::Generics<'tcx>,
152 err: traits::OrphanCheckErr<'tcx>,
153 ) -> Result<!, ErrorReported> {
155 traits::OrphanCheckErr::NonLocalInputType(tys) => {
156 let mut err = struct_span_err!(
160 "only traits defined in the current crate can be implemented for \
163 err.span_label(sp, "impl doesn't use only types from inside the current crate");
164 for (ty, is_target_ty) in &tys {
166 tcx.infer_ctxt().enter(|infcx| {
167 // Remove the lifetimes unnecessary for this error.
168 ty = infcx.freshen(ty);
170 ty = match ty.kind() {
171 // Remove the type arguments from the output, as they are not relevant.
172 // You can think of this as the reverse of `resolve_vars_if_possible`.
173 // That way if we had `Vec<MyType>`, we will properly attribute the
174 // problem to `Vec<T>` and avoid confusing the user if they were to see
175 // `MyType` in the error.
176 ty::Adt(def, _) => tcx.mk_adt(def, ty::List::empty()),
179 let this = "this".to_string();
180 let (ty, postfix) = match &ty.kind() {
181 ty::Slice(_) => (this, " because slices are always foreign"),
182 ty::Array(..) => (this, " because arrays are always foreign"),
183 ty::Tuple(..) => (this, " because tuples are always foreign"),
184 _ => (format!("`{}`", ty), ""),
186 let msg = format!("{} is not defined in the current crate{}", ty, postfix);
188 // Point at `D<A>` in `impl<A, B> for C<B> in D<A>`
189 err.span_label(self_ty_span, &msg);
191 // Point at `C<B>` in `impl<A, B> for C<B> in D<A>`
192 err.span_label(trait_span, &msg);
195 err.note("define and implement a trait or new type instead");
198 traits::OrphanCheckErr::UncoveredTy(param_ty, local_type) => {
200 for param in generics.params {
201 if param.name.ident().to_string() == param_ty.to_string() {
207 Some(local_type) => struct_span_err!(
211 "type parameter `{}` must be covered by another type \
212 when it appears before the first local type (`{}`)",
219 "type parameter `{}` must be covered by another type \
220 when it appears before the first local type (`{}`)",
225 "implementing a foreign trait is only possible if at \
226 least one of the types for which it is implemented is local, \
227 and no uncovered type parameters appear before that first \
231 "in this case, 'before' refers to the following order: \
232 `impl<..> ForeignTrait<T1, ..., Tn> for T0`, \
233 where `T0` is the first and `Tn` is the last",
236 None => struct_span_err!(
240 "type parameter `{}` must be used as the type parameter for some \
241 local type (e.g., `MyStruct<{}>`)",
248 "type parameter `{}` must be used as the type parameter for some \
254 "implementing a foreign trait is only possible if at \
255 least one of the types for which it is implemented is local",
258 "only traits defined in the current crate can be \
259 implemented for a type parameter",