]> git.lizzy.rs Git - rust.git/blob - src/librustc_typeck/coherence/inherent_impls.rs
238952865c7bd91e3525e19fc3e6b5e8e8471c37
[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::DepNode;
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 std::rc::Rc;
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                                 -> Rc<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: Rc<Vec<DefId>> = Rc::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         tcx.dep_graph.read(DepNode::Hir(impl_def_id));
83     }
84
85     result
86 }
87
88 struct InherentCollect<'a, 'tcx: 'a> {
89     tcx: TyCtxt<'a, 'tcx, 'tcx>,
90     impls_map: CrateInherentImpls,
91 }
92
93 impl<'a, 'tcx, 'v> ItemLikeVisitor<'v> for InherentCollect<'a, 'tcx> {
94     fn visit_item(&mut self, item: &hir::Item) {
95         let (unsafety, ty) = match item.node {
96             hir::ItemImpl(unsafety, .., None, ref ty, _) => (unsafety, ty),
97             _ => return
98         };
99
100         match unsafety {
101             hir::Unsafety::Normal => {
102                 // OK
103             }
104             hir::Unsafety::Unsafe => {
105                 span_err!(self.tcx.sess,
106                           item.span,
107                           E0197,
108                           "inherent impls cannot be declared as unsafe");
109             }
110         }
111
112         let def_id = self.tcx.hir.local_def_id(item.id);
113         let self_ty = self.tcx.type_of(def_id);
114         match self_ty.sty {
115             ty::TyAdt(def, _) => {
116                 self.check_def_id(item, def.did);
117             }
118             ty::TyDynamic(ref data, ..) if data.principal().is_some() => {
119                 self.check_def_id(item, data.principal().unwrap().def_id());
120             }
121             ty::TyChar => {
122                 self.check_primitive_impl(def_id,
123                                           self.tcx.lang_items.char_impl(),
124                                           "char",
125                                           "char",
126                                           item.span);
127             }
128             ty::TyStr => {
129                 self.check_primitive_impl(def_id,
130                                           self.tcx.lang_items.str_impl(),
131                                           "str",
132                                           "str",
133                                           item.span);
134             }
135             ty::TySlice(_) => {
136                 self.check_primitive_impl(def_id,
137                                           self.tcx.lang_items.slice_impl(),
138                                           "slice",
139                                           "[T]",
140                                           item.span);
141             }
142             ty::TyRawPtr(ty::TypeAndMut { ty: _, mutbl: hir::MutImmutable }) => {
143                 self.check_primitive_impl(def_id,
144                                           self.tcx.lang_items.const_ptr_impl(),
145                                           "const_ptr",
146                                           "*const T",
147                                           item.span);
148             }
149             ty::TyRawPtr(ty::TypeAndMut { ty: _, mutbl: hir::MutMutable }) => {
150                 self.check_primitive_impl(def_id,
151                                           self.tcx.lang_items.mut_ptr_impl(),
152                                           "mut_ptr",
153                                           "*mut T",
154                                           item.span);
155             }
156             ty::TyInt(ast::IntTy::I8) => {
157                 self.check_primitive_impl(def_id,
158                                           self.tcx.lang_items.i8_impl(),
159                                           "i8",
160                                           "i8",
161                                           item.span);
162             }
163             ty::TyInt(ast::IntTy::I16) => {
164                 self.check_primitive_impl(def_id,
165                                           self.tcx.lang_items.i16_impl(),
166                                           "i16",
167                                           "i16",
168                                           item.span);
169             }
170             ty::TyInt(ast::IntTy::I32) => {
171                 self.check_primitive_impl(def_id,
172                                           self.tcx.lang_items.i32_impl(),
173                                           "i32",
174                                           "i32",
175                                           item.span);
176             }
177             ty::TyInt(ast::IntTy::I64) => {
178                 self.check_primitive_impl(def_id,
179                                           self.tcx.lang_items.i64_impl(),
180                                           "i64",
181                                           "i64",
182                                           item.span);
183             }
184             ty::TyInt(ast::IntTy::I128) => {
185                 self.check_primitive_impl(def_id,
186                                           self.tcx.lang_items.i128_impl(),
187                                           "i128",
188                                           "i128",
189                                           item.span);
190             }
191             ty::TyInt(ast::IntTy::Is) => {
192                 self.check_primitive_impl(def_id,
193                                           self.tcx.lang_items.isize_impl(),
194                                           "isize",
195                                           "isize",
196                                           item.span);
197             }
198             ty::TyUint(ast::UintTy::U8) => {
199                 self.check_primitive_impl(def_id,
200                                           self.tcx.lang_items.u8_impl(),
201                                           "u8",
202                                           "u8",
203                                           item.span);
204             }
205             ty::TyUint(ast::UintTy::U16) => {
206                 self.check_primitive_impl(def_id,
207                                           self.tcx.lang_items.u16_impl(),
208                                           "u16",
209                                           "u16",
210                                           item.span);
211             }
212             ty::TyUint(ast::UintTy::U32) => {
213                 self.check_primitive_impl(def_id,
214                                           self.tcx.lang_items.u32_impl(),
215                                           "u32",
216                                           "u32",
217                                           item.span);
218             }
219             ty::TyUint(ast::UintTy::U64) => {
220                 self.check_primitive_impl(def_id,
221                                           self.tcx.lang_items.u64_impl(),
222                                           "u64",
223                                           "u64",
224                                           item.span);
225             }
226             ty::TyUint(ast::UintTy::U128) => {
227                 self.check_primitive_impl(def_id,
228                                           self.tcx.lang_items.u128_impl(),
229                                           "u128",
230                                           "u128",
231                                           item.span);
232             }
233             ty::TyUint(ast::UintTy::Us) => {
234                 self.check_primitive_impl(def_id,
235                                           self.tcx.lang_items.usize_impl(),
236                                           "usize",
237                                           "usize",
238                                           item.span);
239             }
240             ty::TyFloat(ast::FloatTy::F32) => {
241                 self.check_primitive_impl(def_id,
242                                           self.tcx.lang_items.f32_impl(),
243                                           "f32",
244                                           "f32",
245                                           item.span);
246             }
247             ty::TyFloat(ast::FloatTy::F64) => {
248                 self.check_primitive_impl(def_id,
249                                           self.tcx.lang_items.f64_impl(),
250                                           "f64",
251                                           "f64",
252                                           item.span);
253             }
254             ty::TyError => {
255                 return;
256             }
257             _ => {
258                 struct_span_err!(self.tcx.sess,
259                                  ty.span,
260                                  E0118,
261                                  "no base type found for inherent implementation")
262                     .span_label(ty.span, &format!("impl requires a base type"))
263                     .note(&format!("either implement a trait on it or create a newtype \
264                                     to wrap it instead"))
265                     .emit();
266                 return;
267             }
268         }
269     }
270
271     fn visit_trait_item(&mut self, _trait_item: &hir::TraitItem) {
272     }
273
274     fn visit_impl_item(&mut self, _impl_item: &hir::ImplItem) {
275     }
276 }
277
278 impl<'a, 'tcx> InherentCollect<'a, 'tcx> {
279     fn check_def_id(&mut self, item: &hir::Item, def_id: DefId) {
280         if def_id.is_local() {
281             // Add the implementation to the mapping from implementation to base
282             // type def ID, if there is a base type for this implementation and
283             // the implementation does not have any associated traits.
284             let impl_def_id = self.tcx.hir.local_def_id(item.id);
285             let mut rc_vec = self.impls_map.inherent_impls
286                                            .entry(def_id)
287                                            .or_insert_with(|| Rc::new(vec![]));
288
289             // At this point, there should not be any clones of the
290             // `Rc`, so we can still safely push into it in place:
291             Rc::get_mut(&mut rc_vec).unwrap().push(impl_def_id);
292         } else {
293             struct_span_err!(self.tcx.sess,
294                              item.span,
295                              E0116,
296                              "cannot define inherent `impl` for a type outside of the crate \
297                               where the type is defined")
298                 .span_label(item.span,
299                             &format!("impl for type defined outside of crate."))
300                 .note("define and implement a trait or new type instead")
301                 .emit();
302         }
303     }
304
305     fn check_primitive_impl(&self,
306                             impl_def_id: DefId,
307                             lang_def_id: Option<DefId>,
308                             lang: &str,
309                             ty: &str,
310                             span: Span) {
311         match lang_def_id {
312             Some(lang_def_id) if lang_def_id == impl_def_id => {
313                 // OK
314             }
315             _ => {
316                 struct_span_err!(self.tcx.sess,
317                                  span,
318                                  E0390,
319                                  "only a single inherent implementation marked with `#[lang = \
320                                   \"{}\"]` is allowed for the `{}` primitive",
321                                  lang,
322                                  ty)
323                     .span_help(span, "consider using a trait to implement these methods")
324                     .emit();
325             }
326         }
327     }
328 }