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