]> git.lizzy.rs Git - rust.git/blob - src/librustc_typeck/coherence/inherent_impls.rs
Rollup merge of #68153 - petrochenkov:privdiag, r=estebank
[rust.git] / src / librustc_typeck / coherence / inherent_impls.rs
1 //! The code in this module gathers up all of the inherent impls in
2 //! the current crate and organizes them in a map. It winds up
3 //! touching the whole crate and thus must be recomputed completely
4 //! for any change, but it is very cheap to compute. In practice, most
5 //! code in the compiler never *directly* requests this map. Instead,
6 //! it requests the inherent impls specific to some type (via
7 //! `tcx.inherent_impls(def_id)`). That value, however,
8 //! is computed by selecting an idea from this table.
9
10 use rustc::ty::{self, CrateInherentImpls, TyCtxt};
11 use rustc_errors::struct_span_err;
12 use rustc_hir as hir;
13 use rustc_hir::def_id::{CrateNum, DefId, LOCAL_CRATE};
14 use rustc_hir::itemlikevisit::ItemLikeVisitor;
15
16 use rustc_span::Span;
17 use syntax::ast;
18
19 use rustc_error_codes::*;
20
21 /// On-demand query: yields a map containing all types mapped to their inherent impls.
22 pub fn crate_inherent_impls(tcx: TyCtxt<'_>, crate_num: CrateNum) -> &CrateInherentImpls {
23     assert_eq!(crate_num, LOCAL_CRATE);
24
25     let krate = tcx.hir().krate();
26     let mut collect = InherentCollect { tcx, impls_map: Default::default() };
27     krate.visit_all_item_likes(&mut collect);
28     tcx.arena.alloc(collect.impls_map)
29 }
30
31 /// On-demand query: yields a vector of the inherent impls for a specific type.
32 pub fn inherent_impls(tcx: TyCtxt<'_>, ty_def_id: DefId) -> &[DefId] {
33     assert!(ty_def_id.is_local());
34
35     let crate_map = tcx.crate_inherent_impls(ty_def_id.krate);
36     match crate_map.inherent_impls.get(&ty_def_id) {
37         Some(v) => &v[..],
38         None => &[],
39     }
40 }
41
42 struct InherentCollect<'tcx> {
43     tcx: TyCtxt<'tcx>,
44     impls_map: CrateInherentImpls,
45 }
46
47 impl ItemLikeVisitor<'v> for InherentCollect<'tcx> {
48     fn visit_item(&mut self, item: &hir::Item<'_>) {
49         let ty = match item.kind {
50             hir::ItemKind::Impl(.., None, ref ty, _) => ty,
51             _ => return,
52         };
53
54         let def_id = self.tcx.hir().local_def_id(item.hir_id);
55         let self_ty = self.tcx.type_of(def_id);
56         let lang_items = self.tcx.lang_items();
57         match self_ty.kind {
58             ty::Adt(def, _) => {
59                 self.check_def_id(item, def.did);
60             }
61             ty::Foreign(did) => {
62                 self.check_def_id(item, did);
63             }
64             ty::Dynamic(ref data, ..) if data.principal_def_id().is_some() => {
65                 self.check_def_id(item, data.principal_def_id().unwrap());
66             }
67             ty::Bool => {
68                 self.check_primitive_impl(
69                     def_id,
70                     lang_items.bool_impl(),
71                     None,
72                     "bool",
73                     "bool",
74                     item.span,
75                 );
76             }
77             ty::Char => {
78                 self.check_primitive_impl(
79                     def_id,
80                     lang_items.char_impl(),
81                     None,
82                     "char",
83                     "char",
84                     item.span,
85                 );
86             }
87             ty::Str => {
88                 self.check_primitive_impl(
89                     def_id,
90                     lang_items.str_impl(),
91                     lang_items.str_alloc_impl(),
92                     "str",
93                     "str",
94                     item.span,
95                 );
96             }
97             ty::Slice(slice_item) if slice_item == self.tcx.types.u8 => {
98                 self.check_primitive_impl(
99                     def_id,
100                     lang_items.slice_u8_impl(),
101                     lang_items.slice_u8_alloc_impl(),
102                     "slice_u8",
103                     "[u8]",
104                     item.span,
105                 );
106             }
107             ty::Slice(_) => {
108                 self.check_primitive_impl(
109                     def_id,
110                     lang_items.slice_impl(),
111                     lang_items.slice_alloc_impl(),
112                     "slice",
113                     "[T]",
114                     item.span,
115                 );
116             }
117             ty::RawPtr(ty::TypeAndMut { ty: _, mutbl: hir::Mutability::Not }) => {
118                 self.check_primitive_impl(
119                     def_id,
120                     lang_items.const_ptr_impl(),
121                     None,
122                     "const_ptr",
123                     "*const T",
124                     item.span,
125                 );
126             }
127             ty::RawPtr(ty::TypeAndMut { ty: _, mutbl: hir::Mutability::Mut }) => {
128                 self.check_primitive_impl(
129                     def_id,
130                     lang_items.mut_ptr_impl(),
131                     None,
132                     "mut_ptr",
133                     "*mut T",
134                     item.span,
135                 );
136             }
137             ty::Int(ast::IntTy::I8) => {
138                 self.check_primitive_impl(
139                     def_id,
140                     lang_items.i8_impl(),
141                     None,
142                     "i8",
143                     "i8",
144                     item.span,
145                 );
146             }
147             ty::Int(ast::IntTy::I16) => {
148                 self.check_primitive_impl(
149                     def_id,
150                     lang_items.i16_impl(),
151                     None,
152                     "i16",
153                     "i16",
154                     item.span,
155                 );
156             }
157             ty::Int(ast::IntTy::I32) => {
158                 self.check_primitive_impl(
159                     def_id,
160                     lang_items.i32_impl(),
161                     None,
162                     "i32",
163                     "i32",
164                     item.span,
165                 );
166             }
167             ty::Int(ast::IntTy::I64) => {
168                 self.check_primitive_impl(
169                     def_id,
170                     lang_items.i64_impl(),
171                     None,
172                     "i64",
173                     "i64",
174                     item.span,
175                 );
176             }
177             ty::Int(ast::IntTy::I128) => {
178                 self.check_primitive_impl(
179                     def_id,
180                     lang_items.i128_impl(),
181                     None,
182                     "i128",
183                     "i128",
184                     item.span,
185                 );
186             }
187             ty::Int(ast::IntTy::Isize) => {
188                 self.check_primitive_impl(
189                     def_id,
190                     lang_items.isize_impl(),
191                     None,
192                     "isize",
193                     "isize",
194                     item.span,
195                 );
196             }
197             ty::Uint(ast::UintTy::U8) => {
198                 self.check_primitive_impl(
199                     def_id,
200                     lang_items.u8_impl(),
201                     None,
202                     "u8",
203                     "u8",
204                     item.span,
205                 );
206             }
207             ty::Uint(ast::UintTy::U16) => {
208                 self.check_primitive_impl(
209                     def_id,
210                     lang_items.u16_impl(),
211                     None,
212                     "u16",
213                     "u16",
214                     item.span,
215                 );
216             }
217             ty::Uint(ast::UintTy::U32) => {
218                 self.check_primitive_impl(
219                     def_id,
220                     lang_items.u32_impl(),
221                     None,
222                     "u32",
223                     "u32",
224                     item.span,
225                 );
226             }
227             ty::Uint(ast::UintTy::U64) => {
228                 self.check_primitive_impl(
229                     def_id,
230                     lang_items.u64_impl(),
231                     None,
232                     "u64",
233                     "u64",
234                     item.span,
235                 );
236             }
237             ty::Uint(ast::UintTy::U128) => {
238                 self.check_primitive_impl(
239                     def_id,
240                     lang_items.u128_impl(),
241                     None,
242                     "u128",
243                     "u128",
244                     item.span,
245                 );
246             }
247             ty::Uint(ast::UintTy::Usize) => {
248                 self.check_primitive_impl(
249                     def_id,
250                     lang_items.usize_impl(),
251                     None,
252                     "usize",
253                     "usize",
254                     item.span,
255                 );
256             }
257             ty::Float(ast::FloatTy::F32) => {
258                 self.check_primitive_impl(
259                     def_id,
260                     lang_items.f32_impl(),
261                     lang_items.f32_runtime_impl(),
262                     "f32",
263                     "f32",
264                     item.span,
265                 );
266             }
267             ty::Float(ast::FloatTy::F64) => {
268                 self.check_primitive_impl(
269                     def_id,
270                     lang_items.f64_impl(),
271                     lang_items.f64_runtime_impl(),
272                     "f64",
273                     "f64",
274                     item.span,
275                 );
276             }
277             ty::Error => {
278                 return;
279             }
280             _ => {
281                 struct_span_err!(
282                     self.tcx.sess,
283                     ty.span,
284                     E0118,
285                     "no base type found for inherent implementation"
286                 )
287                 .span_label(ty.span, "impl requires a base type")
288                 .note(&format!(
289                     "either implement a trait on it or create a newtype \
290                                     to wrap it instead"
291                 ))
292                 .emit();
293                 return;
294             }
295         }
296     }
297
298     fn visit_trait_item(&mut self, _trait_item: &hir::TraitItem<'_>) {}
299
300     fn visit_impl_item(&mut self, _impl_item: &hir::ImplItem<'_>) {}
301 }
302
303 impl InherentCollect<'tcx> {
304     fn check_def_id(&mut self, item: &hir::Item<'_>, def_id: DefId) {
305         if def_id.is_local() {
306             // Add the implementation to the mapping from implementation to base
307             // type def ID, if there is a base type for this implementation and
308             // the implementation does not have any associated traits.
309             let impl_def_id = self.tcx.hir().local_def_id(item.hir_id);
310             let vec = self.impls_map.inherent_impls.entry(def_id).or_default();
311             vec.push(impl_def_id);
312         } else {
313             struct_span_err!(
314                 self.tcx.sess,
315                 item.span,
316                 E0116,
317                 "cannot define inherent `impl` for a type outside of the crate \
318                               where the type is defined"
319             )
320             .span_label(item.span, "impl for type defined outside of crate.")
321             .note("define and implement a trait or new type instead")
322             .emit();
323         }
324     }
325
326     fn check_primitive_impl(
327         &self,
328         impl_def_id: DefId,
329         lang_def_id: Option<DefId>,
330         lang_def_id2: Option<DefId>,
331         lang: &str,
332         ty: &str,
333         span: Span,
334     ) {
335         match (lang_def_id, lang_def_id2) {
336             (Some(lang_def_id), _) if lang_def_id == impl_def_id => {
337                 // OK
338             }
339             (_, Some(lang_def_id)) if lang_def_id == impl_def_id => {
340                 // OK
341             }
342             _ => {
343                 struct_span_err!(
344                     self.tcx.sess,
345                     span,
346                     E0390,
347                     "only a single inherent implementation marked with `#[lang = \
348                                   \"{}\"]` is allowed for the `{}` primitive",
349                     lang,
350                     ty
351                 )
352                 .span_help(span, "consider using a trait to implement these methods")
353                 .emit();
354             }
355         }
356     }
357 }