]> git.proxmox.com Git - rustc.git/blob - compiler/rustc_typeck/src/coherence/inherent_impls.rs
New upstream version 1.54.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 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 }