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.
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.
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.
20 use rustc::dep_graph::DepNode;
21 use rustc::hir::def_id::{CrateNum, DefId, LOCAL_CRATE};
23 use rustc::hir::itemlikevisit::ItemLikeVisitor;
24 use rustc::ty::{self, CrateInherentImpls, TyCtxt};
25 use rustc::util::nodemap::DefIdMap;
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>,
34 -> CrateInherentImpls {
35 assert_eq!(crate_num, LOCAL_CRATE);
37 let krate = tcx.hir.krate();
38 let mut collect = InherentCollect {
40 impls_map: CrateInherentImpls {
41 inherent_impls: DefIdMap()
44 krate.visit_all_item_likes(&mut collect);
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>,
52 assert!(ty_def_id.is_local());
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).
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.
67 // [the plan]: https://github.com/rust-lang/rust-roadmap/issues/4
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) {
73 None => Rc::new(vec![]),
77 for &impl_def_id in &result[..] {
78 tcx.dep_graph.read(DepNode::Hir(impl_def_id));
84 struct InherentCollect<'a, 'tcx: 'a> {
85 tcx: TyCtxt<'a, 'tcx, 'tcx>,
86 impls_map: CrateInherentImpls,
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),
97 hir::Unsafety::Normal => {
100 hir::Unsafety::Unsafe => {
101 span_err!(self.tcx.sess,
104 "inherent impls cannot be declared as unsafe");
108 let def_id = self.tcx.hir.local_def_id(item.id);
109 let self_ty = self.tcx.type_of(def_id);
111 ty::TyAdt(def, _) => {
112 self.check_def_id(item, def.did);
114 ty::TyDynamic(ref data, ..) if data.principal().is_some() => {
115 self.check_def_id(item, data.principal().unwrap().def_id());
118 self.check_primitive_impl(def_id,
119 self.tcx.lang_items.char_impl(),
125 self.check_primitive_impl(def_id,
126 self.tcx.lang_items.str_impl(),
132 self.check_primitive_impl(def_id,
133 self.tcx.lang_items.slice_impl(),
138 ty::TyRawPtr(ty::TypeAndMut { ty: _, mutbl: hir::MutImmutable }) => {
139 self.check_primitive_impl(def_id,
140 self.tcx.lang_items.const_ptr_impl(),
145 ty::TyRawPtr(ty::TypeAndMut { ty: _, mutbl: hir::MutMutable }) => {
146 self.check_primitive_impl(def_id,
147 self.tcx.lang_items.mut_ptr_impl(),
152 ty::TyInt(ast::IntTy::I8) => {
153 self.check_primitive_impl(def_id,
154 self.tcx.lang_items.i8_impl(),
159 ty::TyInt(ast::IntTy::I16) => {
160 self.check_primitive_impl(def_id,
161 self.tcx.lang_items.i16_impl(),
166 ty::TyInt(ast::IntTy::I32) => {
167 self.check_primitive_impl(def_id,
168 self.tcx.lang_items.i32_impl(),
173 ty::TyInt(ast::IntTy::I64) => {
174 self.check_primitive_impl(def_id,
175 self.tcx.lang_items.i64_impl(),
180 ty::TyInt(ast::IntTy::I128) => {
181 self.check_primitive_impl(def_id,
182 self.tcx.lang_items.i128_impl(),
187 ty::TyInt(ast::IntTy::Is) => {
188 self.check_primitive_impl(def_id,
189 self.tcx.lang_items.isize_impl(),
194 ty::TyUint(ast::UintTy::U8) => {
195 self.check_primitive_impl(def_id,
196 self.tcx.lang_items.u8_impl(),
201 ty::TyUint(ast::UintTy::U16) => {
202 self.check_primitive_impl(def_id,
203 self.tcx.lang_items.u16_impl(),
208 ty::TyUint(ast::UintTy::U32) => {
209 self.check_primitive_impl(def_id,
210 self.tcx.lang_items.u32_impl(),
215 ty::TyUint(ast::UintTy::U64) => {
216 self.check_primitive_impl(def_id,
217 self.tcx.lang_items.u64_impl(),
222 ty::TyUint(ast::UintTy::U128) => {
223 self.check_primitive_impl(def_id,
224 self.tcx.lang_items.u128_impl(),
229 ty::TyUint(ast::UintTy::Us) => {
230 self.check_primitive_impl(def_id,
231 self.tcx.lang_items.usize_impl(),
236 ty::TyFloat(ast::FloatTy::F32) => {
237 self.check_primitive_impl(def_id,
238 self.tcx.lang_items.f32_impl(),
243 ty::TyFloat(ast::FloatTy::F64) => {
244 self.check_primitive_impl(def_id,
245 self.tcx.lang_items.f64_impl(),
254 struct_span_err!(self.tcx.sess,
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"))
267 fn visit_trait_item(&mut self, _trait_item: &hir::TraitItem) {
270 fn visit_impl_item(&mut self, _impl_item: &hir::ImplItem) {
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
283 .or_insert_with(|| Rc::new(vec![]));
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);
289 struct_span_err!(self.tcx.sess,
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")
301 fn check_primitive_impl(&self,
303 lang_def_id: Option<DefId>,
308 Some(lang_def_id) if lang_def_id == impl_def_id => {
312 struct_span_err!(self.tcx.sess,
315 "only a single inherent implementation marked with `#[lang = \
316 \"{}\"]` is allowed for the `{}` primitive",
319 .span_help(span, "consider using a trait to implement these methods")