]> git.lizzy.rs Git - rust.git/blob - src/librustc_typeck/coherence/inherent_impls.rs
A few cleanups and minor improvements to typeck
[rust.git] / src / librustc_typeck / coherence / inherent_impls.rs
1 // Copyright 2017 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
4 //
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
10
11 //! The code in this module gathers up all of the inherent impls in
12 //! the current crate and organizes them in a map. It winds up
13 //! touching the whole crate and thus must be recomputed completely
14 //! for any change, but it is very cheap to compute. In practice, most
15 //! code in the compiler never *directly* requests this map. Instead,
16 //! it requests the inherent impls specific to some type (via
17 //! `tcx.inherent_impls(def_id)`). That value, however,
18 //! is computed by selecting an idea from this table.
19
20 use rustc::dep_graph::DepKind;
21 use rustc::hir::def_id::{CrateNum, DefId, LOCAL_CRATE};
22 use rustc::hir;
23 use rustc::hir::itemlikevisit::ItemLikeVisitor;
24 use rustc::ty::{self, CrateInherentImpls, TyCtxt};
25 use rustc::util::nodemap::DefIdMap;
26
27 use rustc_data_structures::sync::Lrc;
28 use syntax::ast;
29 use syntax_pos::Span;
30
31 /// On-demand query: yields a map containing all types mapped to their inherent impls.
32 pub fn crate_inherent_impls<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
33                                       crate_num: CrateNum)
34                                       -> CrateInherentImpls {
35     assert_eq!(crate_num, LOCAL_CRATE);
36
37     let krate = tcx.hir.krate();
38     let mut collect = InherentCollect {
39         tcx,
40         impls_map: CrateInherentImpls {
41             inherent_impls: DefIdMap()
42         }
43     };
44     krate.visit_all_item_likes(&mut collect);
45     collect.impls_map
46 }
47
48 /// On-demand query: yields a vector of the inherent impls for a specific type.
49 pub fn inherent_impls<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
50                                 ty_def_id: DefId)
51                                 -> Lrc<Vec<DefId>> {
52     assert!(ty_def_id.is_local());
53
54     // NB. Until we adopt the red-green dep-tracking algorithm (see
55     // [the plan] for details on that), we do some hackery here to get
56     // the dependencies correct.  Basically, we use a `with_ignore` to
57     // read the result we want. If we didn't have the `with_ignore`,
58     // we would wind up with a dependency on the entire crate, which
59     // we don't want. Then we go and add dependencies on all the impls
60     // in the result (which is what we wanted).
61     //
62     // The result is a graph with an edge from `Hir(I)` for every impl
63     // `I` defined on some type `T` to `CoherentInherentImpls(T)`,
64     // thus ensuring that if any of those impls change, the set of
65     // inherent impls is considered dirty.
66     //
67     // [the plan]: https://github.com/rust-lang/rust-roadmap/issues/4
68
69     thread_local! {
70         static EMPTY_DEF_ID_VEC: Lrc<Vec<DefId>> = Lrc::new(vec![])
71     }
72
73     let result = tcx.dep_graph.with_ignore(|| {
74         let crate_map = tcx.crate_inherent_impls(ty_def_id.krate);
75         match crate_map.inherent_impls.get(&ty_def_id) {
76             Some(v) => v.clone(),
77             None => EMPTY_DEF_ID_VEC.with(|v| v.clone())
78         }
79     });
80
81     for &impl_def_id in &result[..] {
82         let def_path_hash = tcx.def_path_hash(impl_def_id);
83         tcx.dep_graph.read(def_path_hash.to_dep_node(DepKind::Hir));
84     }
85
86     result
87 }
88
89 struct InherentCollect<'a, 'tcx: 'a> {
90     tcx: TyCtxt<'a, 'tcx, 'tcx>,
91     impls_map: CrateInherentImpls,
92 }
93
94 impl<'a, 'tcx, 'v> ItemLikeVisitor<'v> for InherentCollect<'a, 'tcx> {
95     fn visit_item(&mut self, item: &hir::Item) {
96         let ty = match item.node {
97             hir::ItemKind::Impl(.., None, ref ty, _) => ty,
98             _ => return
99         };
100
101         let def_id = self.tcx.hir.local_def_id(item.id);
102         let self_ty = self.tcx.type_of(def_id);
103         let lang_items = self.tcx.lang_items();
104         match self_ty.sty {
105             ty::Adt(def, _) => {
106                 self.check_def_id(item, def.did);
107             }
108             ty::Foreign(did) => {
109                 self.check_def_id(item, did);
110             }
111             ty::Dynamic(ref data, ..) if data.principal().is_some() => {
112                 self.check_def_id(item, data.principal().unwrap().def_id());
113             }
114             ty::Char => {
115                 self.check_primitive_impl(def_id,
116                                           lang_items.char_impl(),
117                                           None,
118                                           "char",
119                                           "char",
120                                           item.span);
121             }
122             ty::Str => {
123                 self.check_primitive_impl(def_id,
124                                           lang_items.str_impl(),
125                                           lang_items.str_alloc_impl(),
126                                           "str",
127                                           "str",
128                                           item.span);
129             }
130             ty::Slice(slice_item) if slice_item == self.tcx.types.u8 => {
131                 self.check_primitive_impl(def_id,
132                                           lang_items.slice_u8_impl(),
133                                           lang_items.slice_u8_alloc_impl(),
134                                           "slice_u8",
135                                           "[u8]",
136                                           item.span);
137             }
138             ty::Slice(_) => {
139                 self.check_primitive_impl(def_id,
140                                           lang_items.slice_impl(),
141                                           lang_items.slice_alloc_impl(),
142                                           "slice",
143                                           "[T]",
144                                           item.span);
145             }
146             ty::RawPtr(ty::TypeAndMut { ty: _, mutbl: hir::MutImmutable }) => {
147                 self.check_primitive_impl(def_id,
148                                           lang_items.const_ptr_impl(),
149                                           None,
150                                           "const_ptr",
151                                           "*const T",
152                                           item.span);
153             }
154             ty::RawPtr(ty::TypeAndMut { ty: _, mutbl: hir::MutMutable }) => {
155                 self.check_primitive_impl(def_id,
156                                           lang_items.mut_ptr_impl(),
157                                           None,
158                                           "mut_ptr",
159                                           "*mut T",
160                                           item.span);
161             }
162             ty::Int(ast::IntTy::I8) => {
163                 self.check_primitive_impl(def_id,
164                                           lang_items.i8_impl(),
165                                           None,
166                                           "i8",
167                                           "i8",
168                                           item.span);
169             }
170             ty::Int(ast::IntTy::I16) => {
171                 self.check_primitive_impl(def_id,
172                                           lang_items.i16_impl(),
173                                           None,
174                                           "i16",
175                                           "i16",
176                                           item.span);
177             }
178             ty::Int(ast::IntTy::I32) => {
179                 self.check_primitive_impl(def_id,
180                                           lang_items.i32_impl(),
181                                           None,
182                                           "i32",
183                                           "i32",
184                                           item.span);
185             }
186             ty::Int(ast::IntTy::I64) => {
187                 self.check_primitive_impl(def_id,
188                                           lang_items.i64_impl(),
189                                           None,
190                                           "i64",
191                                           "i64",
192                                           item.span);
193             }
194             ty::Int(ast::IntTy::I128) => {
195                 self.check_primitive_impl(def_id,
196                                           lang_items.i128_impl(),
197                                           None,
198                                           "i128",
199                                           "i128",
200                                           item.span);
201             }
202             ty::Int(ast::IntTy::Isize) => {
203                 self.check_primitive_impl(def_id,
204                                           lang_items.isize_impl(),
205                                           None,
206                                           "isize",
207                                           "isize",
208                                           item.span);
209             }
210             ty::Uint(ast::UintTy::U8) => {
211                 self.check_primitive_impl(def_id,
212                                           lang_items.u8_impl(),
213                                           None,
214                                           "u8",
215                                           "u8",
216                                           item.span);
217             }
218             ty::Uint(ast::UintTy::U16) => {
219                 self.check_primitive_impl(def_id,
220                                           lang_items.u16_impl(),
221                                           None,
222                                           "u16",
223                                           "u16",
224                                           item.span);
225             }
226             ty::Uint(ast::UintTy::U32) => {
227                 self.check_primitive_impl(def_id,
228                                           lang_items.u32_impl(),
229                                           None,
230                                           "u32",
231                                           "u32",
232                                           item.span);
233             }
234             ty::Uint(ast::UintTy::U64) => {
235                 self.check_primitive_impl(def_id,
236                                           lang_items.u64_impl(),
237                                           None,
238                                           "u64",
239                                           "u64",
240                                           item.span);
241             }
242             ty::Uint(ast::UintTy::U128) => {
243                 self.check_primitive_impl(def_id,
244                                           lang_items.u128_impl(),
245                                           None,
246                                           "u128",
247                                           "u128",
248                                           item.span);
249             }
250             ty::Uint(ast::UintTy::Usize) => {
251                 self.check_primitive_impl(def_id,
252                                           lang_items.usize_impl(),
253                                           None,
254                                           "usize",
255                                           "usize",
256                                           item.span);
257             }
258             ty::Float(ast::FloatTy::F32) => {
259                 self.check_primitive_impl(def_id,
260                                           lang_items.f32_impl(),
261                                           lang_items.f32_runtime_impl(),
262                                           "f32",
263                                           "f32",
264                                           item.span);
265             }
266             ty::Float(ast::FloatTy::F64) => {
267                 self.check_primitive_impl(def_id,
268                                           lang_items.f64_impl(),
269                                           lang_items.f64_runtime_impl(),
270                                           "f64",
271                                           "f64",
272                                           item.span);
273             }
274             ty::Error => {
275                 return;
276             }
277             _ => {
278                 struct_span_err!(self.tcx.sess,
279                                  ty.span,
280                                  E0118,
281                                  "no base type found for inherent implementation")
282                     .span_label(ty.span, "impl requires a base type")
283                     .note(&format!("either implement a trait on it or create a newtype \
284                                     to wrap it instead"))
285                     .emit();
286                 return;
287             }
288         }
289     }
290
291     fn visit_trait_item(&mut self, _trait_item: &hir::TraitItem) {
292     }
293
294     fn visit_impl_item(&mut self, _impl_item: &hir::ImplItem) {
295     }
296 }
297
298 impl<'a, 'tcx> InherentCollect<'a, 'tcx> {
299     fn check_def_id(&mut self, item: &hir::Item, def_id: DefId) {
300         if def_id.is_local() {
301             // Add the implementation to the mapping from implementation to base
302             // type def ID, if there is a base type for this implementation and
303             // the implementation does not have any associated traits.
304             let impl_def_id = self.tcx.hir.local_def_id(item.id);
305             let mut rc_vec = self.impls_map.inherent_impls
306                                            .entry(def_id)
307                                            .or_default();
308
309             // At this point, there should not be any clones of the
310             // `Lrc`, so we can still safely push into it in place:
311             Lrc::get_mut(&mut rc_vec).unwrap().push(impl_def_id);
312         } else {
313             struct_span_err!(self.tcx.sess,
314                              item.span,
315                              E0116,
316                              "cannot define inherent `impl` for a type outside of the crate \
317                               where the type is defined")
318                 .span_label(item.span, "impl for type defined outside of crate.")
319                 .note("define and implement a trait or new type instead")
320                 .emit();
321         }
322     }
323
324     fn check_primitive_impl(&self,
325                             impl_def_id: DefId,
326                             lang_def_id: Option<DefId>,
327                             lang_def_id2: Option<DefId>,
328                             lang: &str,
329                             ty: &str,
330                             span: Span) {
331         match (lang_def_id, lang_def_id2) {
332             (Some(lang_def_id), _) if lang_def_id == impl_def_id => {
333                 // OK
334             }
335             (_, Some(lang_def_id)) if lang_def_id == impl_def_id => {
336                 // OK
337             }
338             _ => {
339                 struct_span_err!(self.tcx.sess,
340                                  span,
341                                  E0390,
342                                  "only a single inherent implementation marked with `#[lang = \
343                                   \"{}\"]` is allowed for the `{}` primitive",
344                                  lang,
345                                  ty)
346                     .span_help(span, "consider using a trait to implement these methods")
347                     .emit();
348             }
349         }
350     }
351 }