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
70 static EMPTY_DEF_ID_VEC: Rc<Vec<DefId>> = Rc::new(vec![])
73 let result = tcx.dep_graph.with_ignore(|| {
74 let crate_map = tcx.crate_inherent_impls(ty_def_id.krate);
75 match crate_map.inherent_impls.get(&ty_def_id) {
77 None => EMPTY_DEF_ID_VEC.with(|v| v.clone())
81 for &impl_def_id in &result[..] {
82 tcx.dep_graph.read(DepNode::Hir(impl_def_id));
88 struct InherentCollect<'a, 'tcx: 'a> {
89 tcx: TyCtxt<'a, 'tcx, 'tcx>,
90 impls_map: CrateInherentImpls,
93 impl<'a, 'tcx, 'v> ItemLikeVisitor<'v> for InherentCollect<'a, 'tcx> {
94 fn visit_item(&mut self, item: &hir::Item) {
95 let (unsafety, ty) = match item.node {
96 hir::ItemImpl(unsafety, .., None, ref ty, _) => (unsafety, ty),
101 hir::Unsafety::Normal => {
104 hir::Unsafety::Unsafe => {
105 span_err!(self.tcx.sess,
108 "inherent impls cannot be declared as unsafe");
112 let def_id = self.tcx.hir.local_def_id(item.id);
113 let self_ty = self.tcx.type_of(def_id);
115 ty::TyAdt(def, _) => {
116 self.check_def_id(item, def.did);
118 ty::TyDynamic(ref data, ..) if data.principal().is_some() => {
119 self.check_def_id(item, data.principal().unwrap().def_id());
122 self.check_primitive_impl(def_id,
123 self.tcx.lang_items.char_impl(),
129 self.check_primitive_impl(def_id,
130 self.tcx.lang_items.str_impl(),
136 self.check_primitive_impl(def_id,
137 self.tcx.lang_items.slice_impl(),
142 ty::TyRawPtr(ty::TypeAndMut { ty: _, mutbl: hir::MutImmutable }) => {
143 self.check_primitive_impl(def_id,
144 self.tcx.lang_items.const_ptr_impl(),
149 ty::TyRawPtr(ty::TypeAndMut { ty: _, mutbl: hir::MutMutable }) => {
150 self.check_primitive_impl(def_id,
151 self.tcx.lang_items.mut_ptr_impl(),
156 ty::TyInt(ast::IntTy::I8) => {
157 self.check_primitive_impl(def_id,
158 self.tcx.lang_items.i8_impl(),
163 ty::TyInt(ast::IntTy::I16) => {
164 self.check_primitive_impl(def_id,
165 self.tcx.lang_items.i16_impl(),
170 ty::TyInt(ast::IntTy::I32) => {
171 self.check_primitive_impl(def_id,
172 self.tcx.lang_items.i32_impl(),
177 ty::TyInt(ast::IntTy::I64) => {
178 self.check_primitive_impl(def_id,
179 self.tcx.lang_items.i64_impl(),
184 ty::TyInt(ast::IntTy::I128) => {
185 self.check_primitive_impl(def_id,
186 self.tcx.lang_items.i128_impl(),
191 ty::TyInt(ast::IntTy::Is) => {
192 self.check_primitive_impl(def_id,
193 self.tcx.lang_items.isize_impl(),
198 ty::TyUint(ast::UintTy::U8) => {
199 self.check_primitive_impl(def_id,
200 self.tcx.lang_items.u8_impl(),
205 ty::TyUint(ast::UintTy::U16) => {
206 self.check_primitive_impl(def_id,
207 self.tcx.lang_items.u16_impl(),
212 ty::TyUint(ast::UintTy::U32) => {
213 self.check_primitive_impl(def_id,
214 self.tcx.lang_items.u32_impl(),
219 ty::TyUint(ast::UintTy::U64) => {
220 self.check_primitive_impl(def_id,
221 self.tcx.lang_items.u64_impl(),
226 ty::TyUint(ast::UintTy::U128) => {
227 self.check_primitive_impl(def_id,
228 self.tcx.lang_items.u128_impl(),
233 ty::TyUint(ast::UintTy::Us) => {
234 self.check_primitive_impl(def_id,
235 self.tcx.lang_items.usize_impl(),
240 ty::TyFloat(ast::FloatTy::F32) => {
241 self.check_primitive_impl(def_id,
242 self.tcx.lang_items.f32_impl(),
247 ty::TyFloat(ast::FloatTy::F64) => {
248 self.check_primitive_impl(def_id,
249 self.tcx.lang_items.f64_impl(),
258 struct_span_err!(self.tcx.sess,
261 "no base type found for inherent implementation")
262 .span_label(ty.span, &format!("impl requires a base type"))
263 .note(&format!("either implement a trait on it or create a newtype \
264 to wrap it instead"))
271 fn visit_trait_item(&mut self, _trait_item: &hir::TraitItem) {
274 fn visit_impl_item(&mut self, _impl_item: &hir::ImplItem) {
278 impl<'a, 'tcx> InherentCollect<'a, 'tcx> {
279 fn check_def_id(&mut self, item: &hir::Item, def_id: DefId) {
280 if def_id.is_local() {
281 // Add the implementation to the mapping from implementation to base
282 // type def ID, if there is a base type for this implementation and
283 // the implementation does not have any associated traits.
284 let impl_def_id = self.tcx.hir.local_def_id(item.id);
285 let mut rc_vec = self.impls_map.inherent_impls
287 .or_insert_with(|| Rc::new(vec![]));
289 // At this point, there should not be any clones of the
290 // `Rc`, so we can still safely push into it in place:
291 Rc::get_mut(&mut rc_vec).unwrap().push(impl_def_id);
293 struct_span_err!(self.tcx.sess,
296 "cannot define inherent `impl` for a type outside of the crate \
297 where the type is defined")
298 .span_label(item.span,
299 &format!("impl for type defined outside of crate."))
300 .note("define and implement a trait or new type instead")
305 fn check_primitive_impl(&self,
307 lang_def_id: Option<DefId>,
312 Some(lang_def_id) if lang_def_id == impl_def_id => {
316 struct_span_err!(self.tcx.sess,
319 "only a single inherent implementation marked with `#[lang = \
320 \"{}\"]` is allowed for the `{}` primitive",
323 .span_help(span, "consider using a trait to implement these methods")