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