]> git.lizzy.rs Git - rust.git/blob - src/librustc_typeck/coherence/orphan.rs
Rollup merge of #69387 - petrochenkov:idprint, r=Mark-Simulacrum
[rust.git] / src / librustc_typeck / 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::ty::{self, TyCtxt};
5 use rustc_errors::struct_span_err;
6 use rustc_hir as hir;
7 use rustc_hir::itemlikevisit::ItemLikeVisitor;
8 use rustc_infer::infer::TyCtxtInferExt;
9 use rustc_infer::traits;
10
11 pub fn check(tcx: TyCtxt<'_>) {
12     let mut orphan = OrphanChecker { tcx };
13     tcx.hir().krate().visit_all_item_likes(&mut orphan);
14 }
15
16 struct OrphanChecker<'tcx> {
17     tcx: TyCtxt<'tcx>,
18 }
19
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
25     /// reports.
26     fn visit_item(&mut self, item: &hir::Item<'_>) {
27         let def_id = self.tcx.hir().local_def_id(item.hir_id);
28         // "Trait" impl
29         if let hir::ItemKind::Impl { generics, of_trait: Some(ref tr), self_ty, .. } = &item.kind {
30             debug!(
31                 "coherence2::orphan check: trait impl {}",
32                 self.tcx.hir().node_to_string(item.hir_id)
33             );
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) {
39                 Ok(()) => {}
40                 Err(traits::OrphanCheckErr::NonLocalInputType(tys)) => {
41                     let mut err = struct_span_err!(
42                         self.tcx.sess,
43                         sp,
44                         E0117,
45                         "only traits defined in the current crate can be implemented for \
46                          arbitrary types"
47                     );
48                     err.span_label(sp, "impl doesn't use only types from inside the current crate");
49                     for (ty, is_target_ty) in &tys {
50                         let mut ty = *ty;
51                         self.tcx.infer_ctxt().enter(|infcx| {
52                             // Remove the lifetimes unnecessary for this error.
53                             ty = infcx.freshen(ty);
54                         });
55                         ty = match ty.kind {
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()),
62                             _ => ty,
63                         };
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), ""),
70                         };
71                         let msg = format!("{} is not defined in the current crate{}", ty, postfix);
72                         if *is_target_ty {
73                             // Point at `D<A>` in `impl<A, B> for C<B> in D<A>`
74                             err.span_label(self_ty.span, &msg);
75                         } else {
76                             // Point at `C<B>` in `impl<A, B> for C<B> in D<A>`
77                             err.span_label(tr.path.span, &msg);
78                         }
79                     }
80                     err.note("define and implement a trait or new type instead");
81                     err.emit();
82                     return;
83                 }
84                 Err(traits::OrphanCheckErr::UncoveredTy(param_ty, local_type)) => {
85                     let mut sp = sp;
86                     for param in generics.params {
87                         if param.name.ident().to_string() == param_ty.to_string() {
88                             sp = param.span;
89                         }
90                     }
91
92                     match local_type {
93                         Some(local_type) => {
94                             struct_span_err!(
95                                 self.tcx.sess,
96                                 sp,
97                                 E0210,
98                                 "type parameter `{}` must be covered by another type \
99                                 when it appears before the first local type (`{}`)",
100                                 param_ty,
101                                 local_type
102                             )
103                             .span_label(
104                                 sp,
105                                 format!(
106                                     "type parameter `{}` must be covered by another type \
107                                 when it appears before the first local type (`{}`)",
108                                     param_ty, local_type
109                                 ),
110                             )
111                             .note(
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 \
115                                     local type",
116                             )
117                             .note(
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",
121                             )
122                             .emit();
123                         }
124                         None => {
125                             struct_span_err!(
126                                 self.tcx.sess,
127                                 sp,
128                                 E0210,
129                                 "type parameter `{}` must be used as the type parameter for some \
130                                 local type (e.g., `MyStruct<{}>`)",
131                                 param_ty,
132                                 param_ty
133                             ).span_label(sp, format!(
134                                 "type parameter `{}` must be used as the type parameter for some \
135                                 local type",
136                                 param_ty,
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"
141                             ).emit();
142                         }
143                     };
144                     return;
145                 }
146             }
147
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:
153             //
154             // ```
155             // // Crate A
156             // auto trait Foo { }
157             // fn two_foos<A:Foo,B:Foo>(..) {
158             //     one_foo::<(A,B)>(..)
159             // }
160             // fn one_foo<T:Foo>(..) { .. }
161             // ```
162             //
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`.
166             //
167             // Now imagine that crate B comes along and does the following:
168             //
169             // ```
170             // struct A { }
171             // struct B { }
172             // impl Foo for A { }
173             // impl Foo for B { }
174             // impl !Send for (A, B) { }
175             // ```
176             //
177             // This final impl is legal according to the orpan
178             // rules, but it invalidates the reasoning from
179             // `two_foos` above.
180             debug!(
181                 "trait_ref={:?} trait_def_id={:?} trait_is_auto={}",
182                 trait_ref,
183                 trait_def_id,
184                 self.tcx.trait_is_auto(trait_def_id)
185             );
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),
191                     _ => None,
192                 };
193
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() {
201                             None
202                         } else {
203                             Some((
204                                 format!(
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)
209                                 ),
210                                 "can't implement cross-crate trait for type in another crate",
211                             ))
212                         }
213                     }
214                     _ => Some((
215                         format!(
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),
219                             self_ty
220                         ),
221                         "can't implement cross-crate trait with a default impl for \
222                                non-struct/enum type",
223                     )),
224                 };
225
226                 if let Some((msg, label)) = msg {
227                     struct_span_err!(self.tcx.sess, sp, E0321, "{}", msg)
228                         .span_label(sp, label)
229                         .emit();
230                     return;
231                 }
232             }
233         }
234     }
235
236     fn visit_trait_item(&mut self, _trait_item: &hir::TraitItem<'_>) {}
237
238     fn visit_impl_item(&mut self, _impl_item: &hir::ImplItem<'_>) {}
239 }