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