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
;
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 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 (unsafety
, ty
) = match item
.node
{
97 hir
::ItemImpl(unsafety
, .., None
, ref ty
, _
) => (unsafety
, ty
),
102 hir
::Unsafety
::Normal
=> {
105 hir
::Unsafety
::Unsafe
=> {
106 span_err
!(self.tcx
.sess
,
109 "inherent impls cannot be declared as unsafe");
113 let def_id
= self.tcx
.hir
.local_def_id(item
.id
);
114 let self_ty
= self.tcx
.type_of(def_id
);
115 let lang_items
= self.tcx
.lang_items();
117 ty
::TyAdt(def
, _
) => {
118 self.check_def_id(item
, def
.did
);
120 ty
::TyForeign(did
) => {
121 self.check_def_id(item
, did
);
123 ty
::TyDynamic(ref data
, ..) if data
.principal().is_some() => {
124 self.check_def_id(item
, data
.principal().unwrap().def_id());
127 self.check_primitive_impl(def_id
,
128 lang_items
.char_impl(),
134 self.check_primitive_impl(def_id
,
135 lang_items
.str_impl(),
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(),
148 self.check_primitive_impl(def_id
,
149 lang_items
.slice_impl(),
154 ty
::TyRawPtr(ty
::TypeAndMut { ty: _, mutbl: hir::MutImmutable }
) => {
155 self.check_primitive_impl(def_id
,
156 lang_items
.const_ptr_impl(),
161 ty
::TyRawPtr(ty
::TypeAndMut { ty: _, mutbl: hir::MutMutable }
) => {
162 self.check_primitive_impl(def_id
,
163 lang_items
.mut_ptr_impl(),
168 ty
::TyInt(ast
::IntTy
::I8
) => {
169 self.check_primitive_impl(def_id
,
170 lang_items
.i8_impl(),
175 ty
::TyInt(ast
::IntTy
::I16
) => {
176 self.check_primitive_impl(def_id
,
177 lang_items
.i16_impl(),
182 ty
::TyInt(ast
::IntTy
::I32
) => {
183 self.check_primitive_impl(def_id
,
184 lang_items
.i32_impl(),
189 ty
::TyInt(ast
::IntTy
::I64
) => {
190 self.check_primitive_impl(def_id
,
191 lang_items
.i64_impl(),
196 ty
::TyInt(ast
::IntTy
::I128
) => {
197 self.check_primitive_impl(def_id
,
198 lang_items
.i128_impl(),
203 ty
::TyInt(ast
::IntTy
::Is
) => {
204 self.check_primitive_impl(def_id
,
205 lang_items
.isize_impl(),
210 ty
::TyUint(ast
::UintTy
::U8
) => {
211 self.check_primitive_impl(def_id
,
212 lang_items
.u8_impl(),
217 ty
::TyUint(ast
::UintTy
::U16
) => {
218 self.check_primitive_impl(def_id
,
219 lang_items
.u16_impl(),
224 ty
::TyUint(ast
::UintTy
::U32
) => {
225 self.check_primitive_impl(def_id
,
226 lang_items
.u32_impl(),
231 ty
::TyUint(ast
::UintTy
::U64
) => {
232 self.check_primitive_impl(def_id
,
233 lang_items
.u64_impl(),
238 ty
::TyUint(ast
::UintTy
::U128
) => {
239 self.check_primitive_impl(def_id
,
240 lang_items
.u128_impl(),
245 ty
::TyUint(ast
::UintTy
::Us
) => {
246 self.check_primitive_impl(def_id
,
247 lang_items
.usize_impl(),
252 ty
::TyFloat(ast
::FloatTy
::F32
) => {
253 self.check_primitive_impl(def_id
,
254 lang_items
.f32_impl(),
259 ty
::TyFloat(ast
::FloatTy
::F64
) => {
260 self.check_primitive_impl(def_id
,
261 lang_items
.f64_impl(),
270 struct_span_err
!(self.tcx
.sess
,
273 "no base type found for inherent implementation")
274 .span_label(ty
.span
, "impl requires a base type")
275 .note(&format
!("either implement a trait on it or create a newtype \
276 to wrap it instead"))
283 fn visit_trait_item(&mut self, _trait_item
: &hir
::TraitItem
) {
286 fn visit_impl_item(&mut self, _impl_item
: &hir
::ImplItem
) {
290 impl<'a
, 'tcx
> InherentCollect
<'a
, 'tcx
> {
291 fn check_def_id(&mut self, item
: &hir
::Item
, def_id
: DefId
) {
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
);
297 let mut rc_vec
= self.impls_map
.inherent_impls
299 .or_insert_with(|| Rc
::new(vec
![]));
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
);
305 struct_span_err
!(self.tcx
.sess
,
308 "cannot define inherent `impl` for a type outside of the crate \
309 where the type is defined")
310 .span_label(item
.span
,
311 "impl for type defined outside of crate.")
312 .note("define and implement a trait or new type instead")
317 fn check_primitive_impl(&self,
319 lang_def_id
: Option
<DefId
>,
324 Some(lang_def_id
) if lang_def_id
== impl_def_id
=> {
328 struct_span_err
!(self.tcx
.sess
,
331 "only a single inherent implementation marked with `#[lang = \
332 \"{}\"]` is allowed for the `{}` primitive",
335 .span_help(span
, "consider using a trait to implement these methods")