rustc_hir_analysis/coherence/
inherent_impls.rs1use rustc_hir as hir;
11use rustc_hir::def::DefKind;
12use rustc_hir::def_id::{DefId, LocalDefId};
13use rustc_hir::find_attr;
14use rustc_middle::ty::fast_reject::{SimplifiedType, TreatParams, simplify_type};
15use rustc_middle::ty::{self, CrateInherentImpls, Ty, TyCtxt};
16use rustc_span::{ErrorGuaranteed, bug};
17
18use crate::diagnostics;
19
20pub(crate) fn crate_inherent_impls(
22 tcx: TyCtxt<'_>,
23 (): (),
24) -> (&'_ CrateInherentImpls, Result<(), ErrorGuaranteed>) {
25 let mut collect = InherentCollect { tcx, impls_map: Default::default() };
26
27 let mut res = Ok(());
28 for id in tcx.hir_free_items() {
29 res = res.and(collect.check_item(id));
30 }
31
32 (tcx.arena.alloc(collect.impls_map), res)
33}
34
35pub(crate) fn crate_inherent_impls_validity_check(
36 tcx: TyCtxt<'_>,
37 (): (),
38) -> Result<(), ErrorGuaranteed> {
39 tcx.crate_inherent_impls(()).1
40}
41
42pub(crate) fn crate_incoherent_impls(tcx: TyCtxt<'_>, simp: SimplifiedType) -> &[DefId] {
43 let (crate_map, _) = tcx.crate_inherent_impls(());
44 tcx.arena.alloc_from_iter(
45 crate_map.incoherent_impls.get(&simp).unwrap_or(&Vec::new()).iter().map(|d| d.to_def_id()),
46 )
47}
48
49pub(crate) fn inherent_impls(tcx: TyCtxt<'_>, ty_def_id: LocalDefId) -> &[DefId] {
51 let (crate_map, _) = tcx.crate_inherent_impls(());
52 match crate_map.inherent_impls.get(&ty_def_id) {
53 Some(v) => &v[..],
54 None => &[],
55 }
56}
57
58struct InherentCollect<'tcx> {
59 tcx: TyCtxt<'tcx>,
60 impls_map: CrateInherentImpls,
61}
62
63impl<'tcx> InherentCollect<'tcx> {
64 fn check_def_id(
65 &mut self,
66 impl_def_id: LocalDefId,
67 self_ty: Ty<'tcx>,
68 ty_def_id: DefId,
69 ) -> Result<(), ErrorGuaranteed> {
70 if let Some(ty_def_id) = ty_def_id.as_local() {
71 let vec = self.impls_map.inherent_impls.entry(ty_def_id).or_default();
75 vec.push(impl_def_id.to_def_id());
76 return Ok(());
77 }
78
79 if self.tcx.features().rustc_attrs() {
80 if !{
{
'done:
{
for i in
::rustc_attr_ir::HasAttrs::get_attrs(ty_def_id, &self.tcx) {
#[allow(unused_imports)]
use ::rustc_attr_ir::AttributeKind::*;
let i: &::rustc_attr_ir::Attribute = i;
match i {
::rustc_attr_ir::Attribute::Parsed(RustcHasIncoherentInherentImpls)
=> {
break 'done Some(());
}
::rustc_attr_ir::Attribute::Unparsed(..) =>
{}
#[deny(unreachable_patterns)]
_ => {}
}
}
None
}
}
}.is_some()find_attr!(self.tcx, ty_def_id, RustcHasIncoherentInherentImpls) {
81 let impl_span = self.tcx.def_span(impl_def_id);
82 return Err(self
83 .tcx
84 .dcx()
85 .emit_err(diagnostics::InherentTyOutside { span: impl_span }));
86 }
87
88 let items = self.tcx.associated_item_def_ids(impl_def_id);
89 for &impl_item in items {
90 if !{
{
'done:
{
for i in
::rustc_attr_ir::HasAttrs::get_attrs(impl_item, &self.tcx) {
#[allow(unused_imports)]
use ::rustc_attr_ir::AttributeKind::*;
let i: &::rustc_attr_ir::Attribute = i;
match i {
::rustc_attr_ir::Attribute::Parsed(RustcAllowIncoherentImpl(_))
=> {
break 'done Some(());
}
::rustc_attr_ir::Attribute::Unparsed(..) =>
{}
#[deny(unreachable_patterns)]
_ => {}
}
}
None
}
}
}.is_some()find_attr!(self.tcx, impl_item, RustcAllowIncoherentImpl(_)) {
91 let impl_span = self.tcx.def_span(impl_def_id);
92 return Err(self.tcx.dcx().emit_err(diagnostics::InherentTyOutsideRelevant {
93 span: impl_span,
94 help_span: self.tcx.def_span(impl_item),
95 }));
96 }
97 }
98
99 if let Some(simp) = simplify_type(self.tcx, self_ty, TreatParams::InstantiateWithInfer)
100 {
101 self.impls_map.incoherent_impls.entry(simp).or_default().push(impl_def_id);
102 } else {
103 bug_impl(None, format_args!("unexpected self type: {0:?}", self_ty),
Location::caller());bug!("unexpected self type: {:?}", self_ty);
104 }
105 Ok(())
106 } else {
107 let impl_span = self.tcx.def_span(impl_def_id);
108 let mut err = diagnostics::InherentTyOutsideNew { span: impl_span, note: None };
109
110 if let hir::TyKind::Path(rustc_hir::QPath::Resolved(_, path)) =
111 self.tcx.hir_node_by_def_id(impl_def_id).expect_item().expect_impl().self_ty.kind
112 && let rustc_hir::def::Res::Def(DefKind::TyAlias, def_id) = path.res
113 {
114 let ty_name = self.tcx.def_path_str(def_id);
115 let alias_ty_name = self.tcx.type_of(def_id).skip_binder().to_string();
116 err.note = Some(diagnostics::InherentTyOutsideNewAliasNote {
117 span: self.tcx.def_span(def_id),
118 ty_name,
119 alias_ty_name,
120 });
121 }
122
123 Err(self.tcx.dcx().emit_err(err))
124 }
125 }
126
127 fn check_primitive_impl(
128 &mut self,
129 impl_def_id: LocalDefId,
130 ty: Ty<'tcx>,
131 ) -> Result<(), ErrorGuaranteed> {
132 let items = self.tcx.associated_item_def_ids(impl_def_id);
133 if !self.tcx.hir_rustc_coherence_is_core() {
134 if self.tcx.features().rustc_attrs() {
135 for &impl_item in items {
136 if !{
{
'done:
{
for i in
::rustc_attr_ir::HasAttrs::get_attrs(impl_item, &self.tcx) {
#[allow(unused_imports)]
use ::rustc_attr_ir::AttributeKind::*;
let i: &::rustc_attr_ir::Attribute = i;
match i {
::rustc_attr_ir::Attribute::Parsed(RustcAllowIncoherentImpl(_))
=> {
break 'done Some(());
}
::rustc_attr_ir::Attribute::Unparsed(..) =>
{}
#[deny(unreachable_patterns)]
_ => {}
}
}
None
}
}
}.is_some()find_attr!(self.tcx, impl_item, RustcAllowIncoherentImpl(_)) {
137 let span = self.tcx.def_span(impl_def_id);
138 return Err(self.tcx.dcx().emit_err(
139 diagnostics::InherentTyOutsidePrimitive {
140 span,
141 help_span: self.tcx.def_span(impl_item),
142 },
143 ));
144 }
145 }
146 } else {
147 let span = self.tcx.def_span(impl_def_id);
148 let mut note = None;
149 if let ty::Ref(_, subty, _) = ty.kind() {
150 note = Some(diagnostics::InherentPrimitiveTyNote { subty: *subty });
151 }
152 return Err(self
153 .tcx
154 .dcx()
155 .emit_err(diagnostics::InherentPrimitiveTy { span, note }));
156 }
157 }
158
159 if let Some(simp) = simplify_type(self.tcx, ty, TreatParams::InstantiateWithInfer) {
160 self.impls_map.incoherent_impls.entry(simp).or_default().push(impl_def_id);
161 } else {
162 bug_impl(None, format_args!("unexpected primitive type: {0:?}", ty),
Location::caller());bug!("unexpected primitive type: {:?}", ty);
163 }
164 Ok(())
165 }
166
167 fn check_item(&mut self, id: hir::ItemId) -> Result<(), ErrorGuaranteed> {
168 if !#[allow(non_exhaustive_omitted_patterns)] match self.tcx.def_kind(id.owner_id)
{
DefKind::Impl { of_trait: false } => true,
_ => false,
}matches!(self.tcx.def_kind(id.owner_id), DefKind::Impl { of_trait: false }) {
169 return Ok(());
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).instantiate_identity().skip_norm_wip();
175 let mut self_ty = self.tcx.peel_off_free_alias_tys(self_ty);
176 while let ty::Pat(base, _) = *self_ty.kind() {
179 self_ty = base;
180 }
181 match *self_ty.kind() {
182 ty::Adt(def, _) => self.check_def_id(id, self_ty, def.did()),
183 ty::Foreign(did) => self.check_def_id(id, self_ty, did),
184 ty::Dynamic(data, ..) if data.principal_def_id().is_some() => {
185 self.check_def_id(id, self_ty, data.principal_def_id().unwrap())
186 }
187 ty::Dynamic(..) => {
188 Err(self.tcx.dcx().emit_err(diagnostics::InherentDyn { span: item_span }))
189 }
190 ty::Pat(_, _) => ::core::panicking::panic("internal error: entered unreachable code")unreachable!(),
191 ty::Bool
192 | ty::Char
193 | ty::Int(_)
194 | ty::Uint(_)
195 | ty::Float(_)
196 | ty::Str
197 | ty::Array(..)
198 | ty::Slice(_)
199 | ty::RawPtr(_, _)
200 | ty::Ref(..)
201 | ty::Never
202 | ty::FnPtr(..)
203 | ty::Tuple(..)
204 | ty::UnsafeBinder(_) => self.check_primitive_impl(id, self_ty),
205 ty::Alias(
206 _,
207 ty::AliasTy {
208 kind: ty::Projection { .. } | ty::Inherent { .. } | ty::Opaque { .. },
209 ..
210 },
211 )
212 | ty::Param(_) => {
213 Err(self.tcx.dcx().emit_err(diagnostics::InherentNominal { span: item_span }))
214 }
215 ty::FnDef(..)
216 | ty::Closure(..)
217 | ty::CoroutineClosure(..)
218 | ty::Coroutine(..)
219 | ty::CoroutineWitness(..)
220 | ty::Alias(_, ty::AliasTy { kind: ty::Free { .. }, .. })
221 | ty::Bound(..)
222 | ty::Placeholder(_)
223 | ty::Infer(_) => {
224 bug_impl(None,
format_args!("unexpected impl self type of impl: {0:?} {1:?}", id,
self_ty), Location::caller());bug!("unexpected impl self type of impl: {:?} {:?}", id, self_ty);
225 }
226 ty::Error(_) => Ok(()),
228 }
229 }
230}