rustc_hir_analysis/coherence/
inherent_impls_overlap.rs
1use rustc_data_structures::fx::{FxIndexMap, FxIndexSet, IndexEntry};
2use rustc_errors::codes::*;
3use rustc_errors::struct_span_code_err;
4use rustc_hir as hir;
5use rustc_hir::def::DefKind;
6use rustc_hir::def_id::DefId;
7use rustc_index::IndexVec;
8use rustc_middle::traits::specialization_graph::OverlapMode;
9use rustc_middle::ty::{self, TyCtxt};
10use rustc_span::{ErrorGuaranteed, Symbol};
11use rustc_trait_selection::traits::{self, SkipLeakCheck};
12use smallvec::SmallVec;
13use tracing::debug;
14
15pub(crate) fn crate_inherent_impls_overlap_check(
16 tcx: TyCtxt<'_>,
17 (): (),
18) -> Result<(), ErrorGuaranteed> {
19 let mut inherent_overlap_checker = InherentOverlapChecker { tcx };
20 let mut res = Ok(());
21 for id in tcx.hir().items() {
22 res = res.and(inherent_overlap_checker.check_item(id));
23 }
24 res
25}
26
27struct InherentOverlapChecker<'tcx> {
28 tcx: TyCtxt<'tcx>,
29}
30
31rustc_index::newtype_index! {
32 #[orderable]
33 pub struct RegionId {}
34}
35
36impl<'tcx> InherentOverlapChecker<'tcx> {
37 fn impls_have_common_items(
40 &self,
41 impl_items1: &ty::AssocItems,
42 impl_items2: &ty::AssocItems,
43 ) -> bool {
44 let mut impl_items1 = &impl_items1;
45 let mut impl_items2 = &impl_items2;
46
47 if impl_items1.len() > impl_items2.len() {
49 std::mem::swap(&mut impl_items1, &mut impl_items2);
50 }
51
52 for &item1 in impl_items1.in_definition_order() {
53 let collision = impl_items2
54 .filter_by_name_unhygienic(item1.name)
55 .any(|&item2| self.compare_hygienically(item1, item2));
56
57 if collision {
58 return true;
59 }
60 }
61
62 false
63 }
64
65 fn compare_hygienically(&self, item1: ty::AssocItem, item2: ty::AssocItem) -> bool {
66 item1.kind.namespace() == item2.kind.namespace()
68 && item1.ident(self.tcx).normalize_to_macros_2_0()
69 == item2.ident(self.tcx).normalize_to_macros_2_0()
70 }
71
72 fn check_for_duplicate_items_in_impl(&self, impl_: DefId) -> Result<(), ErrorGuaranteed> {
73 let impl_items = self.tcx.associated_items(impl_);
74
75 let mut seen_items = FxIndexMap::default();
76 let mut res = Ok(());
77 for impl_item in impl_items.in_definition_order() {
78 let span = self.tcx.def_span(impl_item.def_id);
79 let ident = impl_item.ident(self.tcx);
80
81 let norm_ident = ident.normalize_to_macros_2_0();
82 match seen_items.entry(norm_ident) {
83 IndexEntry::Occupied(entry) => {
84 let former = entry.get();
85 res = Err(struct_span_code_err!(
86 self.tcx.dcx(),
87 span,
88 E0592,
89 "duplicate definitions with name `{}`",
90 ident,
91 )
92 .with_span_label(span, format!("duplicate definitions for `{ident}`"))
93 .with_span_label(*former, format!("other definition for `{ident}`"))
94 .emit());
95 }
96 IndexEntry::Vacant(entry) => {
97 entry.insert(span);
98 }
99 }
100 }
101 res
102 }
103
104 fn check_for_common_items_in_impls(
105 &self,
106 impl1: DefId,
107 impl2: DefId,
108 overlap: traits::OverlapResult<'_>,
109 ) -> Result<(), ErrorGuaranteed> {
110 let impl_items1 = self.tcx.associated_items(impl1);
111 let impl_items2 = self.tcx.associated_items(impl2);
112
113 let mut res = Ok(());
114 for &item1 in impl_items1.in_definition_order() {
115 let collision = impl_items2
116 .filter_by_name_unhygienic(item1.name)
117 .find(|&&item2| self.compare_hygienically(item1, item2));
118
119 if let Some(item2) = collision {
120 let name = item1.ident(self.tcx).normalize_to_macros_2_0();
121 let mut err = struct_span_code_err!(
122 self.tcx.dcx(),
123 self.tcx.def_span(item1.def_id),
124 E0592,
125 "duplicate definitions with name `{}`",
126 name
127 );
128 err.span_label(
129 self.tcx.def_span(item1.def_id),
130 format!("duplicate definitions for `{name}`"),
131 );
132 err.span_label(
133 self.tcx.def_span(item2.def_id),
134 format!("other definition for `{name}`"),
135 );
136
137 for cause in &overlap.intercrate_ambiguity_causes {
138 cause.add_intercrate_ambiguity_hint(&mut err);
139 }
140
141 if overlap.involves_placeholder {
142 traits::add_placeholder_note(&mut err);
143 }
144
145 res = Err(err.emit());
146 }
147 }
148 res
149 }
150
151 fn check_for_overlapping_inherent_impls(
152 &self,
153 overlap_mode: OverlapMode,
154 impl1_def_id: DefId,
155 impl2_def_id: DefId,
156 ) -> Result<(), ErrorGuaranteed> {
157 let maybe_overlap = traits::overlapping_impls(
158 self.tcx,
159 impl1_def_id,
160 impl2_def_id,
161 SkipLeakCheck::Yes,
164 overlap_mode,
165 );
166
167 if let Some(overlap) = maybe_overlap {
168 self.check_for_common_items_in_impls(impl1_def_id, impl2_def_id, overlap)
169 } else {
170 Ok(())
171 }
172 }
173
174 fn check_item(&mut self, id: hir::ItemId) -> Result<(), ErrorGuaranteed> {
175 let def_kind = self.tcx.def_kind(id.owner_id);
176 if !matches!(def_kind, DefKind::Enum | DefKind::Struct | DefKind::Trait | DefKind::Union) {
177 return Ok(());
178 }
179
180 let impls = self.tcx.inherent_impls(id.owner_id);
181 let overlap_mode = OverlapMode::get(self.tcx, id.owner_id.to_def_id());
182
183 let impls_items = impls
184 .iter()
185 .map(|impl_def_id| (impl_def_id, self.tcx.associated_items(*impl_def_id)))
186 .collect::<SmallVec<[_; 8]>>();
187
188 const ALLOCATING_ALGO_THRESHOLD: usize = 500;
192 let mut res = Ok(());
193 if impls.len() < ALLOCATING_ALGO_THRESHOLD {
194 for (i, &(&impl1_def_id, impl_items1)) in impls_items.iter().enumerate() {
195 res = res.and(self.check_for_duplicate_items_in_impl(impl1_def_id));
196
197 for &(&impl2_def_id, impl_items2) in &impls_items[(i + 1)..] {
198 if self.impls_have_common_items(impl_items1, impl_items2) {
199 res = res.and(self.check_for_overlapping_inherent_impls(
200 overlap_mode,
201 impl1_def_id,
202 impl2_def_id,
203 ));
204 }
205 }
206 }
207 } else {
208 struct ConnectedRegion {
217 idents: SmallVec<[Symbol; 8]>,
218 impl_blocks: FxIndexSet<usize>,
219 }
220 let mut connected_regions: IndexVec<RegionId, _> = Default::default();
221 let mut connected_region_ids = FxIndexMap::default();
223
224 for (i, &(&_impl_def_id, impl_items)) in impls_items.iter().enumerate() {
225 if impl_items.len() == 0 {
226 continue;
227 }
228 let mut idents_to_add = SmallVec::<[Symbol; 8]>::new();
230 let mut ids = impl_items
231 .in_definition_order()
232 .filter_map(|item| {
233 let entry = connected_region_ids.entry(item.name);
234 if let IndexEntry::Occupied(e) = &entry {
235 Some(*e.get())
236 } else {
237 idents_to_add.push(item.name);
238 None
239 }
240 })
241 .collect::<SmallVec<[RegionId; 8]>>();
242 ids.sort_unstable();
244 ids.dedup();
245 let ids = ids;
246 match &ids[..] {
247 [] => {
249 let id_to_set = connected_regions.next_index();
250 for ident in &idents_to_add {
252 connected_region_ids.insert(*ident, id_to_set);
253 }
254 connected_regions.insert(
255 id_to_set,
256 ConnectedRegion {
257 idents: idents_to_add,
258 impl_blocks: std::iter::once(i).collect(),
259 },
260 );
261 }
262 &[id_to_set] => {
264 let region = connected_regions[id_to_set].as_mut().unwrap();
265 region.impl_blocks.insert(i);
266 region.idents.extend_from_slice(&idents_to_add);
267 for ident in &idents_to_add {
269 connected_region_ids.insert(*ident, id_to_set);
270 }
271 }
272 &[id_to_set, ..] => {
279 let mut region = connected_regions.remove(id_to_set).unwrap();
280 region.impl_blocks.insert(i);
281 region.idents.extend_from_slice(&idents_to_add);
282 for ident in &idents_to_add {
284 connected_region_ids.insert(*ident, id_to_set);
285 }
286
287 for &id in ids.iter() {
289 if id == id_to_set {
290 continue;
291 }
292 let r = connected_regions.remove(id).unwrap();
293 for ident in r.idents.iter() {
294 connected_region_ids.insert(*ident, id_to_set);
295 }
296 region.idents.extend_from_slice(&r.idents);
297 region.impl_blocks.extend(r.impl_blocks);
298 }
299
300 connected_regions.insert(id_to_set, region);
301 }
302 }
303 }
304
305 debug!(
306 "churning through {} components (sum={}, avg={}, var={}, max={})",
307 connected_regions.len(),
308 impls.len(),
309 impls.len() / connected_regions.len(),
310 {
311 let avg = impls.len() / connected_regions.len();
312 let s = connected_regions
313 .iter()
314 .flatten()
315 .map(|r| r.impl_blocks.len() as isize - avg as isize)
316 .map(|v| v.unsigned_abs())
317 .sum::<usize>();
318 s / connected_regions.len()
319 },
320 connected_regions.iter().flatten().map(|r| r.impl_blocks.len()).max().unwrap()
321 );
322 for region in connected_regions.into_iter().flatten() {
325 let impl_blocks = region.impl_blocks.into_iter().collect::<SmallVec<[usize; 8]>>();
326 for (i, &impl1_items_idx) in impl_blocks.iter().enumerate() {
327 let &(&impl1_def_id, impl_items1) = &impls_items[impl1_items_idx];
328 res = res.and(self.check_for_duplicate_items_in_impl(impl1_def_id));
329
330 for &impl2_items_idx in impl_blocks[(i + 1)..].iter() {
331 let &(&impl2_def_id, impl_items2) = &impls_items[impl2_items_idx];
332 if self.impls_have_common_items(impl_items1, impl_items2) {
333 res = res.and(self.check_for_overlapping_inherent_impls(
334 overlap_mode,
335 impl1_def_id,
336 impl2_def_id,
337 ));
338 }
339 }
340 }
341 }
342 }
343 res
344 }
345}