]>
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; |
353b0b11 | 13 | use rustc_hir::def_id::{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; | |
60c5eb7d | 17 | |
cc61c64b | 18 | /// On-demand query: yields a map containing all types mapped to their inherent impls. |
17df50a5 | 19 | pub fn crate_inherent_impls(tcx: TyCtxt<'_>, (): ()) -> CrateInherentImpls { |
dfeec247 | 20 | let mut collect = InherentCollect { tcx, impls_map: Default::default() }; |
04454e1e FG |
21 | for id in tcx.hir().items() { |
22 | collect.check_item(id); | |
23 | } | |
f9f354fc | 24 | collect.impls_map |
cc61c64b XL |
25 | } |
26 | ||
353b0b11 | 27 | pub fn crate_incoherent_impls(tcx: TyCtxt<'_>, simp: SimplifiedType) -> &[DefId] { |
5e7ed085 FG |
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 | ||
cc61c64b | 34 | /// On-demand query: yields a vector of the inherent impls for a specific type. |
353b0b11 | 35 | pub fn inherent_impls(tcx: TyCtxt<'_>, ty_def_id: LocalDefId) -> &[DefId] { |
17df50a5 | 36 | let crate_map = tcx.crate_inherent_impls(()); |
416331ca XL |
37 | match crate_map.inherent_impls.get(&ty_def_id) { |
38 | Some(v) => &v[..], | |
39 | None => &[], | |
cc61c64b | 40 | } |
cc61c64b | 41 | } |
8bb4bdeb | 42 | |
dc9dc135 XL |
43 | struct InherentCollect<'tcx> { |
44 | tcx: TyCtxt<'tcx>, | |
cc61c64b | 45 | impls_map: CrateInherentImpls, |
8bb4bdeb XL |
46 | } |
47 | ||
04454e1e FG |
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> { | |
9ffffee4 FG |
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() { | |
04454e1e FG |
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. | |
9ffffee4 | 62 | let vec = self.impls_map.inherent_impls.entry(ty_def_id).or_default(); |
04454e1e | 63 | vec.push(impl_def_id.to_def_id()); |
5e7ed085 | 64 | return; |
04454e1e | 65 | } |
8bb4bdeb | 66 | |
04454e1e | 67 | if self.tcx.features().rustc_attrs { |
9ffffee4 | 68 | let items = self.tcx.associated_item_def_ids(impl_def_id); |
04454e1e | 69 | |
9ffffee4 FG |
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); | |
94222f64 XL |
72 | struct_span_err!( |
73 | self.tcx.sess, | |
9ffffee4 | 74 | impl_span, |
04454e1e FG |
75 | E0390, |
76 | "cannot define inherent `impl` for a type outside of the crate where the type is defined", | |
94222f64 | 77 | ) |
04454e1e | 78 | .help(INTO_DEFINING_CRATE) |
9ffffee4 | 79 | .span_help(impl_span, ADD_ATTR_TO_TY) |
94222f64 | 80 | .emit(); |
04454e1e | 81 | return; |
94222f64 | 82 | } |
1b1a35ee | 83 | |
9ffffee4 FG |
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); | |
04454e1e FG |
87 | struct_span_err!( |
88 | self.tcx.sess, | |
9ffffee4 | 89 | impl_span, |
04454e1e FG |
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) | |
9ffffee4 | 94 | .span_help(self.tcx.def_span(impl_item), ADD_ATTR) |
04454e1e FG |
95 | .emit(); |
96 | return; | |
97 | } | |
5e7ed085 | 98 | } |
fc512014 | 99 | |
353b0b11 | 100 | if let Some(simp) = simplify_type(self.tcx, self_ty, TreatParams::AsCandidateKey) { |
9ffffee4 | 101 | self.impls_map.incoherent_impls.entry(simp).or_default().push(impl_def_id); |
04454e1e FG |
102 | } else { |
103 | bug!("unexpected self type: {:?}", self_ty); | |
104 | } | |
8bb4bdeb | 105 | } else { |
9ffffee4 | 106 | let impl_span = self.tcx.def_span(impl_def_id); |
dfeec247 XL |
107 | struct_span_err!( |
108 | self.tcx.sess, | |
9ffffee4 | 109 | impl_span, |
dfeec247 XL |
110 | E0116, |
111 | "cannot define inherent `impl` for a type outside of the crate \ | |
112 | where the type is defined" | |
113 | ) | |
9ffffee4 | 114 | .span_label(impl_span, "impl for type defined outside of crate.") |
dfeec247 XL |
115 | .note("define and implement a trait or new type instead") |
116 | .emit(); | |
8bb4bdeb XL |
117 | } |
118 | } | |
119 | ||
9ffffee4 FG |
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); | |
5e7ed085 FG |
122 | if !self.tcx.hir().rustc_coherence_is_core() { |
123 | if self.tcx.features().rustc_attrs { | |
9ffffee4 FG |
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); | |
5e7ed085 FG |
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) | |
9ffffee4 | 134 | .span_help(self.tcx.def_span(impl_item), ADD_ATTR) |
5e7ed085 FG |
135 | .emit(); |
136 | return; | |
137 | } | |
138 | } | |
139 | } else { | |
9ffffee4 | 140 | let span = self.tcx.def_span(impl_def_id); |
5e7ed085 | 141 | let mut err = struct_span_err!( |
dfeec247 XL |
142 | self.tcx.sess, |
143 | span, | |
144 | E0390, | |
5e7ed085 FG |
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; | |
8bb4bdeb XL |
157 | } |
158 | } | |
5e7ed085 | 159 | |
353b0b11 | 160 | if let Some(simp) = simplify_type(self.tcx, ty, TreatParams::AsCandidateKey) { |
5e7ed085 FG |
161 | self.impls_map.incoherent_impls.entry(simp).or_default().push(impl_def_id); |
162 | } else { | |
163 | bug!("unexpected primitive type: {:?}", ty); | |
164 | } | |
8bb4bdeb | 165 | } |
04454e1e FG |
166 | |
167 | fn check_item(&mut self, id: hir::ItemId) { | |
9ffffee4 | 168 | if !matches!(self.tcx.def_kind(id.owner_id), DefKind::Impl { of_trait: false }) { |
04454e1e FG |
169 | return; |
170 | } | |
171 | ||
9ffffee4 FG |
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(); | |
04454e1e | 175 | match *self_ty.kind() { |
9ffffee4 FG |
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), | |
04454e1e | 178 | ty::Dynamic(data, ..) if data.principal_def_id().is_some() => { |
9ffffee4 | 179 | self.check_def_id(id, self_ty, data.principal_def_id().unwrap()); |
04454e1e FG |
180 | } |
181 | ty::Dynamic(..) => { | |
182 | struct_span_err!( | |
183 | self.tcx.sess, | |
9ffffee4 | 184 | item_span, |
04454e1e FG |
185 | E0785, |
186 | "cannot define inherent `impl` for a dyn auto trait" | |
187 | ) | |
9ffffee4 | 188 | .span_label(item_span, "impl requires at least one non-auto trait") |
04454e1e FG |
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 | |
064997fb | 203 | | ty::FnPtr(_) |
9ffffee4 | 204 | | ty::Tuple(..) => self.check_primitive_impl(id, self_ty), |
9c376795 | 205 | ty::Alias(..) | ty::Param(_) => { |
04454e1e FG |
206 | let mut err = struct_span_err!( |
207 | self.tcx.sess, | |
9ffffee4 | 208 | item_span, |
04454e1e FG |
209 | E0118, |
210 | "no nominal type found for inherent implementation" | |
211 | ); | |
212 | ||
9ffffee4 | 213 | err.span_label(item_span, "impl requires a nominal type") |
04454e1e FG |
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(..) | |
9ffffee4 | 222 | | ty::GeneratorWitnessMIR(..) |
04454e1e FG |
223 | | ty::Bound(..) |
224 | | ty::Placeholder(_) | |
225 | | ty::Infer(_) => { | |
9ffffee4 | 226 | bug!("unexpected impl self type of impl: {:?} {:?}", id, self_ty); |
04454e1e FG |
227 | } |
228 | ty::Error(_) => {} | |
229 | } | |
230 | } | |
8bb4bdeb | 231 | } |