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.
10 use rustc
::dep_graph
::DepKind
;
11 use rustc
::hir
::def_id
::{CrateNum, DefId, LOCAL_CRATE}
;
13 use rustc
::hir
::itemlikevisit
::ItemLikeVisitor
;
14 use rustc
::ty
::{self, CrateInherentImpls, TyCtxt}
;
16 use rustc_data_structures
::sync
::Lrc
;
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
>,
23 -> Lrc
<CrateInherentImpls
> {
24 assert_eq
!(crate_num
, LOCAL_CRATE
);
26 let krate
= tcx
.hir().krate();
27 let mut collect
= InherentCollect
{
29 impls_map
: Default
::default(),
31 krate
.visit_all_item_likes(&mut collect
);
32 Lrc
::new(collect
.impls_map
)
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
>,
39 assert
!(ty_def_id
.is_local());
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).
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.
54 // [the plan]: https://github.com/rust-lang/rust-roadmap/issues/4
57 static EMPTY_DEF_ID_VEC
: Lrc
<Vec
<DefId
>> = Lrc
::new(vec
![])
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
) {
64 None
=> EMPTY_DEF_ID_VEC
.with(|v
| v
.clone())
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
));
76 struct InherentCollect
<'a
, 'tcx
: 'a
> {
77 tcx
: TyCtxt
<'a
, 'tcx
, 'tcx
>,
78 impls_map
: CrateInherentImpls
,
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
,
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();
93 self.check_def_id(item
, def
.did
);
96 self.check_def_id(item
, did
);
98 ty
::Dynamic(ref data
, ..) if data
.principal_def_id().is_some() => {
99 self.check_def_id(item
, data
.principal_def_id().unwrap());
102 self.check_primitive_impl(def_id
,
103 lang_items
.char_impl(),
110 self.check_primitive_impl(def_id
,
111 lang_items
.str_impl(),
112 lang_items
.str_alloc_impl(),
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(),
126 self.check_primitive_impl(def_id
,
127 lang_items
.slice_impl(),
128 lang_items
.slice_alloc_impl(),
133 ty
::RawPtr(ty
::TypeAndMut { ty: _, mutbl: hir::MutImmutable }
) => {
134 self.check_primitive_impl(def_id
,
135 lang_items
.const_ptr_impl(),
141 ty
::RawPtr(ty
::TypeAndMut { ty: _, mutbl: hir::MutMutable }
) => {
142 self.check_primitive_impl(def_id
,
143 lang_items
.mut_ptr_impl(),
149 ty
::Int(ast
::IntTy
::I8
) => {
150 self.check_primitive_impl(def_id
,
151 lang_items
.i8_impl(),
157 ty
::Int(ast
::IntTy
::I16
) => {
158 self.check_primitive_impl(def_id
,
159 lang_items
.i16_impl(),
165 ty
::Int(ast
::IntTy
::I32
) => {
166 self.check_primitive_impl(def_id
,
167 lang_items
.i32_impl(),
173 ty
::Int(ast
::IntTy
::I64
) => {
174 self.check_primitive_impl(def_id
,
175 lang_items
.i64_impl(),
181 ty
::Int(ast
::IntTy
::I128
) => {
182 self.check_primitive_impl(def_id
,
183 lang_items
.i128_impl(),
189 ty
::Int(ast
::IntTy
::Isize
) => {
190 self.check_primitive_impl(def_id
,
191 lang_items
.isize_impl(),
197 ty
::Uint(ast
::UintTy
::U8
) => {
198 self.check_primitive_impl(def_id
,
199 lang_items
.u8_impl(),
205 ty
::Uint(ast
::UintTy
::U16
) => {
206 self.check_primitive_impl(def_id
,
207 lang_items
.u16_impl(),
213 ty
::Uint(ast
::UintTy
::U32
) => {
214 self.check_primitive_impl(def_id
,
215 lang_items
.u32_impl(),
221 ty
::Uint(ast
::UintTy
::U64
) => {
222 self.check_primitive_impl(def_id
,
223 lang_items
.u64_impl(),
229 ty
::Uint(ast
::UintTy
::U128
) => {
230 self.check_primitive_impl(def_id
,
231 lang_items
.u128_impl(),
237 ty
::Uint(ast
::UintTy
::Usize
) => {
238 self.check_primitive_impl(def_id
,
239 lang_items
.usize_impl(),
245 ty
::Float(ast
::FloatTy
::F32
) => {
246 self.check_primitive_impl(def_id
,
247 lang_items
.f32_impl(),
248 lang_items
.f32_runtime_impl(),
253 ty
::Float(ast
::FloatTy
::F64
) => {
254 self.check_primitive_impl(def_id
,
255 lang_items
.f64_impl(),
256 lang_items
.f64_runtime_impl(),
265 struct_span_err
!(self.tcx
.sess
,
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"))
278 fn visit_trait_item(&mut self, _trait_item
: &hir
::TraitItem
) {
281 fn visit_impl_item(&mut self, _impl_item
: &hir
::ImplItem
) {
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
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
);
300 struct_span_err
!(self.tcx
.sess
,
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")
311 fn check_primitive_impl(&self,
313 lang_def_id
: Option
<DefId
>,
314 lang_def_id2
: Option
<DefId
>,
318 match (lang_def_id
, lang_def_id2
) {
319 (Some(lang_def_id
), _
) if lang_def_id
== impl_def_id
=> {
322 (_
, Some(lang_def_id
)) if lang_def_id
== impl_def_id
=> {
326 struct_span_err
!(self.tcx
.sess
,
329 "only a single inherent implementation marked with `#[lang = \
330 \"{}\"]` is allowed for the `{}` primitive",
333 .span_help(span
, "consider using a trait to implement these methods")