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