]> git.proxmox.com Git - rustc.git/blame - src/librustc_typeck/coherence/inherent_impls.rs
New upstream version 1.23.0+dfsg1
[rustc.git] / src / librustc_typeck / coherence / inherent_impls.rs
CommitLineData
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 20use rustc::dep_graph::DepKind;
cc61c64b 21use rustc::hir::def_id::{CrateNum, DefId, LOCAL_CRATE};
8bb4bdeb
XL
22use rustc::hir;
23use rustc::hir::itemlikevisit::ItemLikeVisitor;
cc61c64b
XL
24use rustc::ty::{self, CrateInherentImpls, TyCtxt};
25use rustc::util::nodemap::DefIdMap;
8bb4bdeb 26
cc61c64b 27use std::rc::Rc;
8bb4bdeb 28use syntax::ast;
7cac9316 29use syntax_pos::Span;
cc61c64b
XL
30
31/// On-demand query: yields a map containing all types mapped to their inherent impls.
32pub 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.
49pub 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
89struct InherentCollect<'a, 'tcx: 'a> {
cc61c64b
XL
90 tcx: TyCtxt<'a, 'tcx, 'tcx>,
91 impls_map: CrateInherentImpls,
8bb4bdeb
XL
92}
93
94impl<'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
290impl<'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}