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