]> git.proxmox.com Git - rustc.git/blame - compiler/rustc_hir_analysis/src/coherence/inherent_impls.rs
New upstream version 1.70.0+dfsg1
[rustc.git] / compiler / rustc_hir_analysis / src / coherence / inherent_impls.rs
CommitLineData
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
10use rustc_errors::struct_span_err;
11use rustc_hir as hir;
04454e1e 12use rustc_hir::def::DefKind;
353b0b11 13use rustc_hir::def_id::{DefId, LocalDefId};
5e7ed085
FG
14use rustc_middle::ty::fast_reject::{simplify_type, SimplifiedType, TreatParams};
15use rustc_middle::ty::{self, CrateInherentImpls, Ty, TyCtxt};
16use rustc_span::symbol::sym;
60c5eb7d 17
cc61c64b 18/// On-demand query: yields a map containing all types mapped to their inherent impls.
17df50a5 19pub 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 27pub 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 35pub 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
43struct InherentCollect<'tcx> {
44 tcx: TyCtxt<'tcx>,
cc61c64b 45 impls_map: CrateInherentImpls,
8bb4bdeb
XL
46}
47
04454e1e
FG
48const INTO_CORE: &str = "consider moving this inherent impl into `core` if possible";
49const INTO_DEFINING_CRATE: &str =
50 "consider moving this inherent impl into the crate defining the type if possible";
51const 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";
53const ADD_ATTR: &str =
54 "alternatively add `#[rustc_allow_incoherent_impl]` to the relevant impl items";
55
56impl<'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}