]> git.lizzy.rs Git - rust.git/blob - compiler/rustc_typeck/src/coherence/orphan.rs
Rollup merge of #85766 - workingjubilee:file-options, r=yaahc
[rust.git] / compiler / rustc_typeck / src / coherence / orphan.rs
1 //! Orphan checker: every impl either implements a trait defined in this
2 //! crate or pertains to a type defined in this crate.
3
4 use rustc_errors::struct_span_err;
5 use rustc_errors::ErrorReported;
6 use rustc_hir as hir;
7 use rustc_infer::infer::TyCtxtInferExt;
8 use rustc_middle::ty::{self, TyCtxt};
9 use rustc_span::def_id::LocalDefId;
10 use rustc_span::Span;
11 use rustc_trait_selection::traits;
12
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) {
18                 Ok(()) => {}
19                 Err(ErrorReported) => errors.push(impl_of_trait),
20             }
21         }
22     }
23     tcx.arena.alloc_slice(&errors)
24 }
25
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;
30
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),
35     };
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()) {
39         Ok(()) => {}
40         Err(err) => emit_orphan_check_error(
41             tcx,
42             sp,
43             tr.path.span,
44             impl_.self_ty.span,
45             &impl_.generics,
46             err,
47         )?,
48     }
49
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:
55     //
56     // ```
57     // // Crate A
58     // auto trait Foo { }
59     // fn two_foos<A:Foo,B:Foo>(..) {
60     //     one_foo::<(A,B)>(..)
61     // }
62     // fn one_foo<T:Foo>(..) { .. }
63     // ```
64     //
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`.
68     //
69     // Now imagine that crate B comes along and does the following:
70     //
71     // ```
72     // struct A { }
73     // struct B { }
74     // impl Foo for A { }
75     // impl Foo for B { }
76     // impl !Send for (A, B) { }
77     // ```
78     //
79     // This final impl is legal according to the orphan
80     // rules, but it invalidates the reasoning from
81     // `two_foos` above.
82     debug!(
83         "trait_ref={:?} trait_def_id={:?} trait_is_auto={}",
84         trait_ref,
85         trait_def_id,
86         tcx.trait_is_auto(trait_def_id)
87     );
88
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),
94             _ => None,
95         };
96
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() {
104                     None
105                 } else {
106                     Some((
107                         format!(
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)
112                         ),
113                         "can't implement cross-crate trait for type in another crate",
114                     ))
115                 }
116             }
117             _ => Some((
118                 format!(
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),
122                     self_ty
123                 ),
124                 "can't implement cross-crate trait with a default impl for \
125                         non-struct/enum type",
126             )),
127         };
128
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);
132         }
133     }
134
135     if let ty::Opaque(def_id, _) = *trait_ref.self_ty().kind() {
136         tcx.sess
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")
139             .emit();
140         return Err(ErrorReported);
141     }
142
143     Ok(())
144 }
145
146 fn emit_orphan_check_error(
147     tcx: TyCtxt<'tcx>,
148     sp: Span,
149     trait_span: Span,
150     self_ty_span: Span,
151     generics: &hir::Generics<'tcx>,
152     err: traits::OrphanCheckErr<'tcx>,
153 ) -> Result<!, ErrorReported> {
154     match err {
155         traits::OrphanCheckErr::NonLocalInputType(tys) => {
156             let mut err = struct_span_err!(
157                 tcx.sess,
158                 sp,
159                 E0117,
160                 "only traits defined in the current crate can be implemented for \
161                         arbitrary types"
162             );
163             err.span_label(sp, "impl doesn't use only types from inside the current crate");
164             for (ty, is_target_ty) in &tys {
165                 let mut ty = *ty;
166                 tcx.infer_ctxt().enter(|infcx| {
167                     // Remove the lifetimes unnecessary for this error.
168                     ty = infcx.freshen(ty);
169                 });
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()),
177                     _ => ty,
178                 };
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), ""),
185                 };
186                 let msg = format!("{} is not defined in the current crate{}", ty, postfix);
187                 if *is_target_ty {
188                     // Point at `D<A>` in `impl<A, B> for C<B> in D<A>`
189                     err.span_label(self_ty_span, &msg);
190                 } else {
191                     // Point at `C<B>` in `impl<A, B> for C<B> in D<A>`
192                     err.span_label(trait_span, &msg);
193                 }
194             }
195             err.note("define and implement a trait or new type instead");
196             err.emit()
197         }
198         traits::OrphanCheckErr::UncoveredTy(param_ty, local_type) => {
199             let mut sp = sp;
200             for param in generics.params {
201                 if param.name.ident().to_string() == param_ty.to_string() {
202                     sp = param.span;
203                 }
204             }
205
206             match local_type {
207                 Some(local_type) => struct_span_err!(
208                     tcx.sess,
209                     sp,
210                     E0210,
211                     "type parameter `{}` must be covered by another type \
212                     when it appears before the first local type (`{}`)",
213                     param_ty,
214                     local_type
215                 )
216                 .span_label(
217                     sp,
218                     format!(
219                         "type parameter `{}` must be covered by another type \
220                     when it appears before the first local type (`{}`)",
221                         param_ty, local_type
222                     ),
223                 )
224                 .note(
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 \
228                         local type",
229                 )
230                 .note(
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",
234                 )
235                 .emit(),
236                 None => struct_span_err!(
237                     tcx.sess,
238                     sp,
239                     E0210,
240                     "type parameter `{}` must be used as the type parameter for some \
241                     local type (e.g., `MyStruct<{}>`)",
242                     param_ty,
243                     param_ty
244                 )
245                 .span_label(
246                     sp,
247                     format!(
248                         "type parameter `{}` must be used as the type parameter for some \
249                     local type",
250                         param_ty,
251                     ),
252                 )
253                 .note(
254                     "implementing a foreign trait is only possible if at \
255                         least one of the types for which it is implemented is local",
256                 )
257                 .note(
258                     "only traits defined in the current crate can be \
259                         implemented for a type parameter",
260                 )
261                 .emit(),
262             }
263         }
264     }
265
266     Err(ErrorReported)
267 }