]> git.proxmox.com Git - rustc.git/blob - compiler/rustc_typeck/src/coherence/inherent_impls.rs
New upstream version 1.57.0+dfsg1
[rustc.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 ItemLikeVisitor<'v> 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 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 }