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