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