]> git.lizzy.rs Git - rust.git/blob - src/librustc_typeck/coherence/orphan.rs
Auto merge of #68154 - ssomers:btreemap_navigation_benches, 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::traits;
5 use rustc::ty::{self, TyCtxt};
6 use rustc_errors::struct_span_err;
7 use rustc_hir as hir;
8 use rustc_hir::itemlikevisit::ItemLikeVisitor;
9
10 pub fn check(tcx: TyCtxt<'_>) {
11     let mut orphan = OrphanChecker { tcx };
12     tcx.hir().krate().visit_all_item_likes(&mut orphan);
13 }
14
15 struct OrphanChecker<'tcx> {
16     tcx: TyCtxt<'tcx>,
17 }
18
19 impl ItemLikeVisitor<'v> for OrphanChecker<'tcx> {
20     /// Checks exactly one impl for orphan rules and other such
21     /// restrictions. In this fn, it can happen that multiple errors
22     /// apply to a specific impl, so just return after reporting one
23     /// to prevent inundating the user with a bunch of similar error
24     /// reports.
25     fn visit_item(&mut self, item: &hir::Item<'_>) {
26         let def_id = self.tcx.hir().local_def_id(item.hir_id);
27         // "Trait" impl
28         if let hir::ItemKind::Impl { generics, of_trait: Some(ref tr), self_ty, .. } = &item.kind {
29             debug!(
30                 "coherence2::orphan check: trait impl {}",
31                 self.tcx.hir().node_to_string(item.hir_id)
32             );
33             let trait_ref = self.tcx.impl_trait_ref(def_id).unwrap();
34             let trait_def_id = trait_ref.def_id;
35             let cm = self.tcx.sess.source_map();
36             let sp = cm.def_span(item.span);
37             match traits::orphan_check(self.tcx, def_id) {
38                 Ok(()) => {}
39                 Err(traits::OrphanCheckErr::NonLocalInputType(tys)) => {
40                     let mut err = struct_span_err!(
41                         self.tcx.sess,
42                         sp,
43                         E0117,
44                         "only traits defined in the current crate can be implemented for \
45                          arbitrary types"
46                     );
47                     err.span_label(sp, "impl doesn't use only types from inside the current crate");
48                     for (ty, is_target_ty) in &tys {
49                         let mut ty = *ty;
50                         self.tcx.infer_ctxt().enter(|infcx| {
51                             // Remove the lifetimes unnecessary for this error.
52                             ty = infcx.freshen(ty);
53                         });
54                         ty = match ty.kind {
55                             // Remove the type arguments from the output, as they are not relevant.
56                             // You can think of this as the reverse of `resolve_vars_if_possible`.
57                             // That way if we had `Vec<MyType>`, we will properly attribute the
58                             // problem to `Vec<T>` and avoid confusing the user if they were to see
59                             // `MyType` in the error.
60                             ty::Adt(def, _) => self.tcx.mk_adt(def, ty::List::empty()),
61                             _ => ty,
62                         };
63                         let this = "this".to_string();
64                         let (ty, postfix) = match &ty.kind {
65                             ty::Slice(_) => (this, " because slices are always foreign"),
66                             ty::Array(..) => (this, " because arrays are always foreign"),
67                             ty::Tuple(..) => (this, " because tuples are always foreign"),
68                             _ => (format!("`{}`", ty), ""),
69                         };
70                         let msg = format!("{} is not defined in the current crate{}", ty, postfix);
71                         if *is_target_ty {
72                             // Point at `D<A>` in `impl<A, B> for C<B> in D<A>`
73                             err.span_label(self_ty.span, &msg);
74                         } else {
75                             // Point at `C<B>` in `impl<A, B> for C<B> in D<A>`
76                             err.span_label(tr.path.span, &msg);
77                         }
78                     }
79                     err.note("define and implement a trait or new type instead");
80                     err.emit();
81                     return;
82                 }
83                 Err(traits::OrphanCheckErr::UncoveredTy(param_ty, local_type)) => {
84                     let mut sp = sp;
85                     for param in generics.params {
86                         if param.name.ident().to_string() == param_ty.to_string() {
87                             sp = param.span;
88                         }
89                     }
90
91                     match local_type {
92                         Some(local_type) => {
93                             struct_span_err!(
94                                 self.tcx.sess,
95                                 sp,
96                                 E0210,
97                                 "type parameter `{}` must be covered by another type \
98                                 when it appears before the first local type (`{}`)",
99                                 param_ty,
100                                 local_type
101                             )
102                             .span_label(
103                                 sp,
104                                 format!(
105                                     "type parameter `{}` must be covered by another type \
106                                 when it appears before the first local type (`{}`)",
107                                     param_ty, local_type
108                                 ),
109                             )
110                             .note(
111                                 "implementing a foreign trait is only possible if at \
112                                     least one of the types for which is it implemented is local, \
113                                     and no uncovered type parameters appear before that first \
114                                     local type",
115                             )
116                             .note(
117                                 "in this case, 'before' refers to the following order: \
118                                     `impl<..> ForeignTrait<T1, ..., Tn> for T0`, \
119                                     where `T0` is the first and `Tn` is the last",
120                             )
121                             .emit();
122                         }
123                         None => {
124                             struct_span_err!(
125                                 self.tcx.sess,
126                                 sp,
127                                 E0210,
128                                 "type parameter `{}` must be used as the type parameter for some \
129                                 local type (e.g., `MyStruct<{}>`)",
130                                 param_ty,
131                                 param_ty
132                             ).span_label(sp, format!(
133                                 "type parameter `{}` must be used as the type parameter for some \
134                                 local type",
135                                 param_ty,
136                             )).note("implementing a foreign trait is only possible if at \
137                                     least one of the types for which is it implemented is local"
138                             ).note("only traits defined in the current crate can be \
139                                     implemented for a type parameter"
140                             ).emit();
141                         }
142                     };
143                     return;
144                 }
145             }
146
147             // In addition to the above rules, we restrict impls of auto traits
148             // so that they can only be implemented on nominal types, such as structs,
149             // enums or foreign types. To see why this restriction exists, consider the
150             // following example (#22978). Imagine that crate A defines an auto trait
151             // `Foo` and a fn that operates on pairs of types:
152             //
153             // ```
154             // // Crate A
155             // auto trait Foo { }
156             // fn two_foos<A:Foo,B:Foo>(..) {
157             //     one_foo::<(A,B)>(..)
158             // }
159             // fn one_foo<T:Foo>(..) { .. }
160             // ```
161             //
162             // This type-checks fine; in particular the fn
163             // `two_foos` is able to conclude that `(A,B):Foo`
164             // because `A:Foo` and `B:Foo`.
165             //
166             // Now imagine that crate B comes along and does the following:
167             //
168             // ```
169             // struct A { }
170             // struct B { }
171             // impl Foo for A { }
172             // impl Foo for B { }
173             // impl !Send for (A, B) { }
174             // ```
175             //
176             // This final impl is legal according to the orpan
177             // rules, but it invalidates the reasoning from
178             // `two_foos` above.
179             debug!(
180                 "trait_ref={:?} trait_def_id={:?} trait_is_auto={}",
181                 trait_ref,
182                 trait_def_id,
183                 self.tcx.trait_is_auto(trait_def_id)
184             );
185             if self.tcx.trait_is_auto(trait_def_id) && !trait_def_id.is_local() {
186                 let self_ty = trait_ref.self_ty();
187                 let opt_self_def_id = match self_ty.kind {
188                     ty::Adt(self_def, _) => Some(self_def.did),
189                     ty::Foreign(did) => Some(did),
190                     _ => None,
191                 };
192
193                 let msg = match opt_self_def_id {
194                     // We only want to permit nominal types, but not *all* nominal types.
195                     // They must be local to the current crate, so that people
196                     // can't do `unsafe impl Send for Rc<SomethingLocal>` or
197                     // `impl !Send for Box<SomethingLocalAndSend>`.
198                     Some(self_def_id) => {
199                         if self_def_id.is_local() {
200                             None
201                         } else {
202                             Some((
203                                 format!(
204                                     "cross-crate traits with a default impl, like `{}`, \
205                                          can only be implemented for a struct/enum type \
206                                          defined in the current crate",
207                                     self.tcx.def_path_str(trait_def_id)
208                                 ),
209                                 "can't implement cross-crate trait for type in another crate",
210                             ))
211                         }
212                     }
213                     _ => Some((
214                         format!(
215                             "cross-crate traits with a default impl, like `{}`, can \
216                                        only be implemented for a struct/enum type, not `{}`",
217                             self.tcx.def_path_str(trait_def_id),
218                             self_ty
219                         ),
220                         "can't implement cross-crate trait with a default impl for \
221                                non-struct/enum type",
222                     )),
223                 };
224
225                 if let Some((msg, label)) = msg {
226                     struct_span_err!(self.tcx.sess, sp, E0321, "{}", msg)
227                         .span_label(sp, label)
228                         .emit();
229                     return;
230                 }
231             }
232         }
233     }
234
235     fn visit_trait_item(&mut self, _trait_item: &hir::TraitItem<'_>) {}
236
237     fn visit_impl_item(&mut self, _impl_item: &hir::ImplItem<'_>) {}
238 }