rustc_hir_analysis/coherence/
inherent_impls.rs1use rustc_attr_data_structures::{AttributeKind, find_attr};
11use rustc_hir as hir;
12use rustc_hir::def::DefKind;
13use rustc_hir::def_id::{DefId, LocalDefId};
14use rustc_middle::bug;
15use rustc_middle::ty::fast_reject::{SimplifiedType, TreatParams, simplify_type};
16use rustc_middle::ty::{self, CrateInherentImpls, Ty, TyCtxt};
17use rustc_span::{ErrorGuaranteed, sym};
18
19use crate::errors;
20
21pub(crate) fn crate_inherent_impls(
23 tcx: TyCtxt<'_>,
24 (): (),
25) -> (&'_ CrateInherentImpls, Result<(), ErrorGuaranteed>) {
26 let mut collect = InherentCollect { tcx, impls_map: Default::default() };
27
28 let mut res = Ok(());
29 for id in tcx.hir_free_items() {
30 res = res.and(collect.check_item(id));
31 }
32
33 (tcx.arena.alloc(collect.impls_map), res)
34}
35
36pub(crate) fn crate_inherent_impls_validity_check(
37 tcx: TyCtxt<'_>,
38 (): (),
39) -> Result<(), ErrorGuaranteed> {
40 tcx.crate_inherent_impls(()).1
41}
42
43pub(crate) fn crate_incoherent_impls(tcx: TyCtxt<'_>, simp: SimplifiedType) -> &[DefId] {
44 let (crate_map, _) = tcx.crate_inherent_impls(());
45 tcx.arena.alloc_from_iter(
46 crate_map.incoherent_impls.get(&simp).unwrap_or(&Vec::new()).iter().map(|d| d.to_def_id()),
47 )
48}
49
50pub(crate) fn inherent_impls(tcx: TyCtxt<'_>, ty_def_id: LocalDefId) -> &[DefId] {
52 let (crate_map, _) = tcx.crate_inherent_impls(());
53 match crate_map.inherent_impls.get(&ty_def_id) {
54 Some(v) => &v[..],
55 None => &[],
56 }
57}
58
59struct InherentCollect<'tcx> {
60 tcx: TyCtxt<'tcx>,
61 impls_map: CrateInherentImpls,
62}
63
64impl<'tcx> InherentCollect<'tcx> {
65 fn check_def_id(
66 &mut self,
67 impl_def_id: LocalDefId,
68 self_ty: Ty<'tcx>,
69 ty_def_id: DefId,
70 ) -> Result<(), ErrorGuaranteed> {
71 if let Some(ty_def_id) = ty_def_id.as_local() {
72 let vec = self.impls_map.inherent_impls.entry(ty_def_id).or_default();
76 vec.push(impl_def_id.to_def_id());
77 return Ok(());
78 }
79
80 if self.tcx.features().rustc_attrs() {
81 let items = self.tcx.associated_item_def_ids(impl_def_id);
82
83 if !self.tcx.has_attr(ty_def_id, sym::rustc_has_incoherent_inherent_impls) {
84 let impl_span = self.tcx.def_span(impl_def_id);
85 return Err(self.tcx.dcx().emit_err(errors::InherentTyOutside { span: impl_span }));
86 }
87
88 for &impl_item in items {
89 if !find_attr!(
90 self.tcx.get_all_attrs(impl_item),
91 AttributeKind::AllowIncoherentImpl(_)
92 ) {
93 let impl_span = self.tcx.def_span(impl_def_id);
94 return Err(self.tcx.dcx().emit_err(errors::InherentTyOutsideRelevant {
95 span: impl_span,
96 help_span: self.tcx.def_span(impl_item),
97 }));
98 }
99 }
100
101 if let Some(simp) = simplify_type(self.tcx, self_ty, TreatParams::InstantiateWithInfer)
102 {
103 self.impls_map.incoherent_impls.entry(simp).or_default().push(impl_def_id);
104 } else {
105 bug!("unexpected self type: {:?}", self_ty);
106 }
107 Ok(())
108 } else {
109 let impl_span = self.tcx.def_span(impl_def_id);
110 Err(self.tcx.dcx().emit_err(errors::InherentTyOutsideNew { span: impl_span }))
111 }
112 }
113
114 fn check_primitive_impl(
115 &mut self,
116 impl_def_id: LocalDefId,
117 ty: Ty<'tcx>,
118 ) -> Result<(), ErrorGuaranteed> {
119 let items = self.tcx.associated_item_def_ids(impl_def_id);
120 if !self.tcx.hir_rustc_coherence_is_core() {
121 if self.tcx.features().rustc_attrs() {
122 for &impl_item in items {
123 if !find_attr!(
124 self.tcx.get_all_attrs(impl_item),
125 AttributeKind::AllowIncoherentImpl(_)
126 ) {
127 let span = self.tcx.def_span(impl_def_id);
128 return Err(self.tcx.dcx().emit_err(errors::InherentTyOutsidePrimitive {
129 span,
130 help_span: self.tcx.def_span(impl_item),
131 }));
132 }
133 }
134 } else {
135 let span = self.tcx.def_span(impl_def_id);
136 let mut note = None;
137 if let ty::Ref(_, subty, _) = ty.kind() {
138 note = Some(errors::InherentPrimitiveTyNote { subty: *subty });
139 }
140 return Err(self.tcx.dcx().emit_err(errors::InherentPrimitiveTy { span, note }));
141 }
142 }
143
144 if let Some(simp) = simplify_type(self.tcx, ty, TreatParams::InstantiateWithInfer) {
145 self.impls_map.incoherent_impls.entry(simp).or_default().push(impl_def_id);
146 } else {
147 bug!("unexpected primitive type: {:?}", ty);
148 }
149 Ok(())
150 }
151
152 fn check_item(&mut self, id: hir::ItemId) -> Result<(), ErrorGuaranteed> {
153 if !matches!(self.tcx.def_kind(id.owner_id), DefKind::Impl { of_trait: false }) {
154 return Ok(());
155 }
156
157 let id = id.owner_id.def_id;
158 let item_span = self.tcx.def_span(id);
159 let self_ty = self.tcx.type_of(id).instantiate_identity();
160 let mut self_ty = self.tcx.peel_off_free_alias_tys(self_ty);
161 while let ty::Pat(base, _) = *self_ty.kind() {
164 self_ty = base;
165 }
166 match *self_ty.kind() {
167 ty::Adt(def, _) => self.check_def_id(id, self_ty, def.did()),
168 ty::Foreign(did) => self.check_def_id(id, self_ty, did),
169 ty::Dynamic(data, ..) if data.principal_def_id().is_some() => {
170 self.check_def_id(id, self_ty, data.principal_def_id().unwrap())
171 }
172 ty::Dynamic(..) => {
173 Err(self.tcx.dcx().emit_err(errors::InherentDyn { span: item_span }))
174 }
175 ty::Pat(_, _) => unreachable!(),
176 ty::Bool
177 | ty::Char
178 | ty::Int(_)
179 | ty::Uint(_)
180 | ty::Float(_)
181 | ty::Str
182 | ty::Array(..)
183 | ty::Slice(_)
184 | ty::RawPtr(_, _)
185 | ty::Ref(..)
186 | ty::Never
187 | ty::FnPtr(..)
188 | ty::Tuple(..)
189 | ty::UnsafeBinder(_) => self.check_primitive_impl(id, self_ty),
190 ty::Alias(ty::Projection | ty::Inherent | ty::Opaque, _) | ty::Param(_) => {
191 Err(self.tcx.dcx().emit_err(errors::InherentNominal { span: item_span }))
192 }
193 ty::FnDef(..)
194 | ty::Closure(..)
195 | ty::CoroutineClosure(..)
196 | ty::Coroutine(..)
197 | ty::CoroutineWitness(..)
198 | ty::Alias(ty::Free, _)
199 | ty::Bound(..)
200 | ty::Placeholder(_)
201 | ty::Infer(_) => {
202 bug!("unexpected impl self type of impl: {:?} {:?}", id, self_ty);
203 }
204 ty::Error(_) => Ok(()),
206 }
207 }
208}