]>
Commit | Line | Data |
---|---|---|
dfeec247 XL |
1 | use rustc_errors::struct_span_err; |
2 | use rustc_hir as hir; | |
3 | use rustc_hir::def_id::{CrateNum, DefId, LOCAL_CRATE}; | |
4 | use rustc_hir::itemlikevisit::ItemLikeVisitor; | |
ba9703b0 XL |
5 | use rustc_middle::ty::TyCtxt; |
6 | use rustc_trait_selection::traits::{self, SkipLeakCheck}; | |
60c5eb7d | 7 | |
416331ca | 8 | pub fn crate_inherent_impls_overlap_check(tcx: TyCtxt<'_>, crate_num: CrateNum) { |
cc61c64b | 9 | assert_eq!(crate_num, LOCAL_CRATE); |
0731742a | 10 | let krate = tcx.hir().krate(); |
cc61c64b XL |
11 | krate.visit_all_item_likes(&mut InherentOverlapChecker { tcx }); |
12 | } | |
13 | ||
dc9dc135 XL |
14 | struct InherentOverlapChecker<'tcx> { |
15 | tcx: TyCtxt<'tcx>, | |
cc61c64b XL |
16 | } |
17 | ||
dc9dc135 | 18 | impl InherentOverlapChecker<'tcx> { |
74b04a01 XL |
19 | /// Checks whether any associated items in impls 1 and 2 share the same identifier and |
20 | /// namespace. | |
21 | fn impls_have_common_items(&self, impl1: DefId, impl2: DefId) -> bool { | |
22 | let impl_items1 = self.tcx.associated_items(impl1); | |
23 | let impl_items2 = self.tcx.associated_items(impl2); | |
24 | ||
25 | for item1 in impl_items1.in_definition_order() { | |
26 | let collision = impl_items2.filter_by_name_unhygienic(item1.ident.name).any(|item2| { | |
27 | // Symbols and namespace match, compare hygienically. | |
28 | item1.kind.namespace() == item2.kind.namespace() | |
ba9703b0 XL |
29 | && item1.ident.normalize_to_macros_2_0() |
30 | == item2.ident.normalize_to_macros_2_0() | |
74b04a01 XL |
31 | }); |
32 | ||
33 | if collision { | |
34 | return true; | |
35 | } | |
36 | } | |
37 | ||
38 | false | |
39 | } | |
40 | ||
dfeec247 XL |
41 | fn check_for_common_items_in_impls( |
42 | &self, | |
43 | impl1: DefId, | |
44 | impl2: DefId, | |
45 | overlap: traits::OverlapResult<'_>, | |
46 | ) { | |
74b04a01 XL |
47 | let impl_items1 = self.tcx.associated_items(impl1); |
48 | let impl_items2 = self.tcx.associated_items(impl2); | |
ea8adc8c | 49 | |
74b04a01 XL |
50 | for item1 in impl_items1.in_definition_order() { |
51 | let collision = impl_items2.filter_by_name_unhygienic(item1.ident.name).find(|item2| { | |
52 | // Symbols and namespace match, compare hygienically. | |
53 | item1.kind.namespace() == item2.kind.namespace() | |
ba9703b0 XL |
54 | && item1.ident.normalize_to_macros_2_0() |
55 | == item2.ident.normalize_to_macros_2_0() | |
74b04a01 XL |
56 | }); |
57 | ||
58 | if let Some(item2) = collision { | |
ba9703b0 | 59 | let name = item1.ident.normalize_to_macros_2_0(); |
74b04a01 XL |
60 | let mut err = struct_span_err!( |
61 | self.tcx.sess, | |
62 | self.tcx.span_of_impl(item1.def_id).unwrap(), | |
63 | E0592, | |
64 | "duplicate definitions with name `{}`", | |
65 | name | |
66 | ); | |
67 | err.span_label( | |
68 | self.tcx.span_of_impl(item1.def_id).unwrap(), | |
69 | format!("duplicate definitions for `{}`", name), | |
70 | ); | |
71 | err.span_label( | |
72 | self.tcx.span_of_impl(item2.def_id).unwrap(), | |
73 | format!("other definition for `{}`", name), | |
74 | ); | |
75 | ||
76 | for cause in &overlap.intercrate_ambiguity_causes { | |
77 | cause.add_intercrate_ambiguity_hint(&mut err); | |
78 | } | |
0731742a | 79 | |
74b04a01 XL |
80 | if overlap.involves_placeholder { |
81 | traits::add_placeholder_note(&mut err); | |
cc61c64b | 82 | } |
74b04a01 XL |
83 | |
84 | err.emit(); | |
cc61c64b XL |
85 | } |
86 | } | |
87 | } | |
88 | ||
74b04a01 XL |
89 | fn check_for_overlapping_inherent_impls(&self, impl1_def_id: DefId, impl2_def_id: DefId) { |
90 | traits::overlapping_impls( | |
91 | self.tcx, | |
92 | impl1_def_id, | |
93 | impl2_def_id, | |
94 | // We go ahead and just skip the leak check for | |
95 | // inherent impls without warning. | |
96 | SkipLeakCheck::Yes, | |
97 | |overlap| { | |
98 | self.check_for_common_items_in_impls(impl1_def_id, impl2_def_id, overlap); | |
99 | false | |
100 | }, | |
101 | || true, | |
102 | ); | |
cc61c64b XL |
103 | } |
104 | } | |
105 | ||
dc9dc135 | 106 | impl ItemLikeVisitor<'v> for InherentOverlapChecker<'tcx> { |
dfeec247 | 107 | fn visit_item(&mut self, item: &'v hir::Item<'v>) { |
e74abb32 | 108 | match item.kind { |
dfeec247 XL |
109 | hir::ItemKind::Enum(..) |
110 | | hir::ItemKind::Struct(..) | |
111 | | hir::ItemKind::Trait(..) | |
112 | | hir::ItemKind::Union(..) => { | |
74b04a01 XL |
113 | let ty_def_id = self.tcx.hir().local_def_id(item.hir_id); |
114 | let impls = self.tcx.inherent_impls(ty_def_id); | |
115 | ||
116 | for (i, &impl1_def_id) in impls.iter().enumerate() { | |
117 | for &impl2_def_id in &impls[(i + 1)..] { | |
118 | if self.impls_have_common_items(impl1_def_id, impl2_def_id) { | |
119 | self.check_for_overlapping_inherent_impls(impl1_def_id, impl2_def_id); | |
120 | } | |
121 | } | |
122 | } | |
cc61c64b XL |
123 | } |
124 | _ => {} | |
125 | } | |
126 | } | |
127 | ||
dfeec247 | 128 | fn visit_trait_item(&mut self, _trait_item: &hir::TraitItem<'v>) {} |
cc61c64b | 129 | |
dfeec247 | 130 | fn visit_impl_item(&mut self, _impl_item: &hir::ImplItem<'v>) {} |
cc61c64b | 131 | } |