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::DepKind;
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;
27 use rustc_data_structures::sync::Lrc;
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: Lrc<Vec<DefId>> = Lrc::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 let def_path_hash = tcx.def_path_hash(impl_def_id);
83 tcx.dep_graph.read(def_path_hash.to_dep_node(DepKind::Hir));
89 struct InherentCollect<'a, 'tcx: 'a> {
90 tcx: TyCtxt<'a, 'tcx, 'tcx>,
91 impls_map: CrateInherentImpls,
94 impl<'a, 'tcx, 'v> ItemLikeVisitor<'v> for InherentCollect<'a, 'tcx> {
95 fn visit_item(&mut self, item: &hir::Item) {
96 let ty = match item.node {
97 hir::ItemKind::Impl(.., None, ref ty, _) => ty,
101 let def_id = self.tcx.hir.local_def_id(item.id);
102 let self_ty = self.tcx.type_of(def_id);
103 let lang_items = self.tcx.lang_items();
106 self.check_def_id(item, def.did);
108 ty::Foreign(did) => {
109 self.check_def_id(item, did);
111 ty::Dynamic(ref data, ..) if data.principal().is_some() => {
112 self.check_def_id(item, data.principal().unwrap().def_id());
115 self.check_primitive_impl(def_id,
116 lang_items.char_impl(),
123 self.check_primitive_impl(def_id,
124 lang_items.str_impl(),
125 lang_items.str_alloc_impl(),
130 ty::Slice(slice_item) if slice_item == self.tcx.types.u8 => {
131 self.check_primitive_impl(def_id,
132 lang_items.slice_u8_impl(),
133 lang_items.slice_u8_alloc_impl(),
139 self.check_primitive_impl(def_id,
140 lang_items.slice_impl(),
141 lang_items.slice_alloc_impl(),
146 ty::RawPtr(ty::TypeAndMut { ty: _, mutbl: hir::MutImmutable }) => {
147 self.check_primitive_impl(def_id,
148 lang_items.const_ptr_impl(),
154 ty::RawPtr(ty::TypeAndMut { ty: _, mutbl: hir::MutMutable }) => {
155 self.check_primitive_impl(def_id,
156 lang_items.mut_ptr_impl(),
162 ty::Int(ast::IntTy::I8) => {
163 self.check_primitive_impl(def_id,
164 lang_items.i8_impl(),
170 ty::Int(ast::IntTy::I16) => {
171 self.check_primitive_impl(def_id,
172 lang_items.i16_impl(),
178 ty::Int(ast::IntTy::I32) => {
179 self.check_primitive_impl(def_id,
180 lang_items.i32_impl(),
186 ty::Int(ast::IntTy::I64) => {
187 self.check_primitive_impl(def_id,
188 lang_items.i64_impl(),
194 ty::Int(ast::IntTy::I128) => {
195 self.check_primitive_impl(def_id,
196 lang_items.i128_impl(),
202 ty::Int(ast::IntTy::Isize) => {
203 self.check_primitive_impl(def_id,
204 lang_items.isize_impl(),
210 ty::Uint(ast::UintTy::U8) => {
211 self.check_primitive_impl(def_id,
212 lang_items.u8_impl(),
218 ty::Uint(ast::UintTy::U16) => {
219 self.check_primitive_impl(def_id,
220 lang_items.u16_impl(),
226 ty::Uint(ast::UintTy::U32) => {
227 self.check_primitive_impl(def_id,
228 lang_items.u32_impl(),
234 ty::Uint(ast::UintTy::U64) => {
235 self.check_primitive_impl(def_id,
236 lang_items.u64_impl(),
242 ty::Uint(ast::UintTy::U128) => {
243 self.check_primitive_impl(def_id,
244 lang_items.u128_impl(),
250 ty::Uint(ast::UintTy::Usize) => {
251 self.check_primitive_impl(def_id,
252 lang_items.usize_impl(),
258 ty::Float(ast::FloatTy::F32) => {
259 self.check_primitive_impl(def_id,
260 lang_items.f32_impl(),
261 lang_items.f32_runtime_impl(),
266 ty::Float(ast::FloatTy::F64) => {
267 self.check_primitive_impl(def_id,
268 lang_items.f64_impl(),
269 lang_items.f64_runtime_impl(),
278 struct_span_err!(self.tcx.sess,
281 "no base type found for inherent implementation")
282 .span_label(ty.span, "impl requires a base type")
283 .note(&format!("either implement a trait on it or create a newtype \
284 to wrap it instead"))
291 fn visit_trait_item(&mut self, _trait_item: &hir::TraitItem) {
294 fn visit_impl_item(&mut self, _impl_item: &hir::ImplItem) {
298 impl<'a, 'tcx> InherentCollect<'a, 'tcx> {
299 fn check_def_id(&mut self, item: &hir::Item, def_id: DefId) {
300 if def_id.is_local() {
301 // Add the implementation to the mapping from implementation to base
302 // type def ID, if there is a base type for this implementation and
303 // the implementation does not have any associated traits.
304 let impl_def_id = self.tcx.hir.local_def_id(item.id);
305 let mut rc_vec = self.impls_map.inherent_impls
309 // At this point, there should not be any clones of the
310 // `Lrc`, so we can still safely push into it in place:
311 Lrc::get_mut(&mut rc_vec).unwrap().push(impl_def_id);
313 struct_span_err!(self.tcx.sess,
316 "cannot define inherent `impl` for a type outside of the crate \
317 where the type is defined")
318 .span_label(item.span, "impl for type defined outside of crate.")
319 .note("define and implement a trait or new type instead")
324 fn check_primitive_impl(&self,
326 lang_def_id: Option<DefId>,
327 lang_def_id2: Option<DefId>,
331 match (lang_def_id, lang_def_id2) {
332 (Some(lang_def_id), _) if lang_def_id == impl_def_id => {
335 (_, Some(lang_def_id)) if lang_def_id == impl_def_id => {
339 struct_span_err!(self.tcx.sess,
342 "only a single inherent implementation marked with `#[lang = \
343 \"{}\"]` is allowed for the `{}` primitive",
346 .span_help(span, "consider using a trait to implement these methods")