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