• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.
9 
10 use rustc_errors::struct_span_err;
11 use rustc_hir as hir;
12 use rustc_hir::def::DefKind;
13 use rustc_hir::def_id::{DefId, LocalDefId};
14 use rustc_middle::ty::fast_reject::{simplify_type, SimplifiedType, TreatParams};
15 use rustc_middle::ty::{self, CrateInherentImpls, Ty, TyCtxt};
16 use rustc_span::symbol::sym;
17 
18 /// On-demand query: yields a map containing all types mapped to their inherent impls.
crate_inherent_impls(tcx: TyCtxt<'_>, (): ()) -> CrateInherentImpls19 pub fn crate_inherent_impls(tcx: TyCtxt<'_>, (): ()) -> CrateInherentImpls {
20     let mut collect = InherentCollect { tcx, impls_map: Default::default() };
21     for id in tcx.hir().items() {
22         collect.check_item(id);
23     }
24     collect.impls_map
25 }
26 
crate_incoherent_impls(tcx: TyCtxt<'_>, simp: SimplifiedType) -> &[DefId]27 pub fn crate_incoherent_impls(tcx: TyCtxt<'_>, simp: SimplifiedType) -> &[DefId] {
28     let crate_map = tcx.crate_inherent_impls(());
29     tcx.arena.alloc_from_iter(
30         crate_map.incoherent_impls.get(&simp).unwrap_or(&Vec::new()).iter().map(|d| d.to_def_id()),
31     )
32 }
33 
34 /// On-demand query: yields a vector of the inherent impls for a specific type.
inherent_impls(tcx: TyCtxt<'_>, ty_def_id: LocalDefId) -> &[DefId]35 pub fn inherent_impls(tcx: TyCtxt<'_>, ty_def_id: LocalDefId) -> &[DefId] {
36     let crate_map = tcx.crate_inherent_impls(());
37     match crate_map.inherent_impls.get(&ty_def_id) {
38         Some(v) => &v[..],
39         None => &[],
40     }
41 }
42 
43 struct InherentCollect<'tcx> {
44     tcx: TyCtxt<'tcx>,
45     impls_map: CrateInherentImpls,
46 }
47 
48 const INTO_CORE: &str = "consider moving this inherent impl into `core` if possible";
49 const INTO_DEFINING_CRATE: &str =
50     "consider moving this inherent impl into the crate defining the type if possible";
51 const ADD_ATTR_TO_TY: &str = "alternatively add `#[rustc_has_incoherent_inherent_impls]` to the type \
52      and `#[rustc_allow_incoherent_impl]` to the relevant impl items";
53 const ADD_ATTR: &str =
54     "alternatively add `#[rustc_allow_incoherent_impl]` to the relevant impl items";
55 
56 impl<'tcx> InherentCollect<'tcx> {
check_def_id(&mut self, impl_def_id: LocalDefId, self_ty: Ty<'tcx>, ty_def_id: DefId)57     fn check_def_id(&mut self, impl_def_id: LocalDefId, self_ty: Ty<'tcx>, ty_def_id: DefId) {
58         if let Some(ty_def_id) = ty_def_id.as_local() {
59             // Add the implementation to the mapping from implementation to base
60             // type def ID, if there is a base type for this implementation and
61             // the implementation does not have any associated traits.
62             let vec = self.impls_map.inherent_impls.entry(ty_def_id).or_default();
63             vec.push(impl_def_id.to_def_id());
64             return;
65         }
66 
67         if self.tcx.features().rustc_attrs {
68             let items = self.tcx.associated_item_def_ids(impl_def_id);
69 
70             if !self.tcx.has_attr(ty_def_id, sym::rustc_has_incoherent_inherent_impls) {
71                 let impl_span = self.tcx.def_span(impl_def_id);
72                 struct_span_err!(
73                     self.tcx.sess,
74                     impl_span,
75                     E0390,
76                     "cannot define inherent `impl` for a type outside of the crate where the type is defined",
77                 )
78                 .help(INTO_DEFINING_CRATE)
79                 .span_help(impl_span, ADD_ATTR_TO_TY)
80                 .emit();
81                 return;
82             }
83 
84             for &impl_item in items {
85                 if !self.tcx.has_attr(impl_item, sym::rustc_allow_incoherent_impl) {
86                     let impl_span = self.tcx.def_span(impl_def_id);
87                     struct_span_err!(
88                         self.tcx.sess,
89                         impl_span,
90                         E0390,
91                         "cannot define inherent `impl` for a type outside of the crate where the type is defined",
92                     )
93                     .help(INTO_DEFINING_CRATE)
94                     .span_help(self.tcx.def_span(impl_item), ADD_ATTR)
95                     .emit();
96                     return;
97                 }
98             }
99 
100             if let Some(simp) = simplify_type(self.tcx, self_ty, TreatParams::AsCandidateKey) {
101                 self.impls_map.incoherent_impls.entry(simp).or_default().push(impl_def_id);
102             } else {
103                 bug!("unexpected self type: {:?}", self_ty);
104             }
105         } else {
106             let impl_span = self.tcx.def_span(impl_def_id);
107             struct_span_err!(
108                 self.tcx.sess,
109                 impl_span,
110                 E0116,
111                 "cannot define inherent `impl` for a type outside of the crate \
112                               where the type is defined"
113             )
114             .span_label(impl_span, "impl for type defined outside of crate.")
115             .note("define and implement a trait or new type instead")
116             .emit();
117         }
118     }
119 
check_primitive_impl(&mut self, impl_def_id: LocalDefId, ty: Ty<'tcx>)120     fn check_primitive_impl(&mut self, impl_def_id: LocalDefId, ty: Ty<'tcx>) {
121         let items = self.tcx.associated_item_def_ids(impl_def_id);
122         if !self.tcx.hir().rustc_coherence_is_core() {
123             if self.tcx.features().rustc_attrs {
124                 for &impl_item in items {
125                     if !self.tcx.has_attr(impl_item, sym::rustc_allow_incoherent_impl) {
126                         let span = self.tcx.def_span(impl_def_id);
127                         struct_span_err!(
128                             self.tcx.sess,
129                             span,
130                             E0390,
131                             "cannot define inherent `impl` for primitive types outside of `core`",
132                         )
133                         .help(INTO_CORE)
134                         .span_help(self.tcx.def_span(impl_item), ADD_ATTR)
135                         .emit();
136                         return;
137                     }
138                 }
139             } else {
140                 let span = self.tcx.def_span(impl_def_id);
141                 let mut err = struct_span_err!(
142                     self.tcx.sess,
143                     span,
144                     E0390,
145                     "cannot define inherent `impl` for primitive types",
146                 );
147                 err.help("consider using an extension trait instead");
148                 if let ty::Ref(_, subty, _) = ty.kind() {
149                     err.note(format!(
150                         "you could also try moving the reference to \
151                             uses of `{}` (such as `self`) within the implementation",
152                         subty
153                     ));
154                 }
155                 err.emit();
156                 return;
157             }
158         }
159 
160         if let Some(simp) = simplify_type(self.tcx, ty, TreatParams::AsCandidateKey) {
161             self.impls_map.incoherent_impls.entry(simp).or_default().push(impl_def_id);
162         } else {
163             bug!("unexpected primitive type: {:?}", ty);
164         }
165     }
166 
check_item(&mut self, id: hir::ItemId)167     fn check_item(&mut self, id: hir::ItemId) {
168         if !matches!(self.tcx.def_kind(id.owner_id), DefKind::Impl { of_trait: false }) {
169             return;
170         }
171 
172         let id = id.owner_id.def_id;
173         let item_span = self.tcx.def_span(id);
174         let self_ty = self.tcx.type_of(id).subst_identity();
175         match *self_ty.kind() {
176             ty::Adt(def, _) => self.check_def_id(id, self_ty, def.did()),
177             ty::Foreign(did) => self.check_def_id(id, self_ty, did),
178             ty::Dynamic(data, ..) if data.principal_def_id().is_some() => {
179                 self.check_def_id(id, self_ty, data.principal_def_id().unwrap());
180             }
181             ty::Dynamic(..) => {
182                 struct_span_err!(
183                     self.tcx.sess,
184                     item_span,
185                     E0785,
186                     "cannot define inherent `impl` for a dyn auto trait"
187                 )
188                 .span_label(item_span, "impl requires at least one non-auto trait")
189                 .note("define and implement a new trait or type instead")
190                 .emit();
191             }
192             ty::Bool
193             | ty::Char
194             | ty::Int(_)
195             | ty::Uint(_)
196             | ty::Float(_)
197             | ty::Str
198             | ty::Array(..)
199             | ty::Slice(_)
200             | ty::RawPtr(_)
201             | ty::Ref(..)
202             | ty::Never
203             | ty::FnPtr(_)
204             | ty::Tuple(..) => self.check_primitive_impl(id, self_ty),
205             ty::Alias(..) | ty::Param(_) => {
206                 let mut err = struct_span_err!(
207                     self.tcx.sess,
208                     item_span,
209                     E0118,
210                     "no nominal type found for inherent implementation"
211                 );
212 
213                 err.span_label(item_span, "impl requires a nominal type")
214                     .note("either implement a trait on it or create a newtype to wrap it instead");
215 
216                 err.emit();
217             }
218             ty::FnDef(..)
219             | ty::Closure(..)
220             | ty::Generator(..)
221             | ty::GeneratorWitness(..)
222             | ty::GeneratorWitnessMIR(..)
223             | ty::Bound(..)
224             | ty::Placeholder(_)
225             | ty::Infer(_) => {
226                 bug!("unexpected impl self type of impl: {:?} {:?}", id, self_ty);
227             }
228             ty::Error(_) => {}
229         }
230     }
231 }
232