11use crate :: namespace:: Namespace ;
22use rustc:: traits:: { self , IntercrateMode , SkipLeakCheck } ;
33use rustc:: ty:: { AssocItem , TyCtxt } ;
4+ use rustc_data_structures:: fx:: FxHashMap ;
45use rustc_errors:: struct_span_err;
56use rustc_hir as hir;
67use rustc_hir:: def_id:: { CrateNum , DefId , LOCAL_CRATE } ;
78use rustc_hir:: itemlikevisit:: ItemLikeVisitor ;
9+ use smallvec:: SmallVec ;
10+ use std:: collections:: hash_map:: Entry ;
811
912pub fn crate_inherent_impls_overlap_check ( tcx : TyCtxt < ' _ > , crate_num : CrateNum ) {
1013 assert_eq ! ( crate_num, LOCAL_CRATE ) ;
@@ -17,78 +20,12 @@ struct InherentOverlapChecker<'tcx> {
1720}
1821
1922impl InherentOverlapChecker < ' tcx > {
20- /// Checks whether any associated items in impls 1 and 2 share the same identifier and
21- /// namespace.
22- fn impls_have_common_items ( & self , impl1 : DefId , impl2 : DefId ) -> bool {
23- let impl_items1 = self . tcx . associated_items ( impl1) ;
24- let impl_items2 = self . tcx . associated_items ( impl2) ;
25-
26- for item1 in & impl_items1[ ..] {
27- for item2 in & impl_items2[ ..] {
28- // Avoid costly `.modern()` calls as much as possible by doing them as late as we
29- // can. Compare raw symbols first.
30- if item1. ident . name == item2. ident . name
31- && Namespace :: from ( item1. kind ) == Namespace :: from ( item2. kind )
32- {
33- // Symbols and namespace match, compare hygienically.
34- if item1. ident . modern ( ) == item2. ident . modern ( ) {
35- return true ;
36- }
37- }
38- }
39- }
40-
41- false
42- }
43-
44- fn check_for_common_items_in_impls (
45- & self ,
46- impl1 : DefId ,
47- impl2 : DefId ,
48- overlap : traits:: OverlapResult < ' _ > ,
49- ) {
50- let name_and_namespace =
51- |assoc : & AssocItem | ( assoc. ident . modern ( ) , Namespace :: from ( assoc. kind ) ) ;
52-
53- let impl_items1 = self . tcx . associated_items ( impl1) ;
54- let impl_items2 = self . tcx . associated_items ( impl2) ;
55-
56- for item1 in & impl_items1[ ..] {
57- let ( name, namespace) = name_and_namespace ( item1) ;
58-
59- for item2 in & impl_items2[ ..] {
60- if ( name, namespace) == name_and_namespace ( item2) {
61- let mut err = struct_span_err ! (
62- self . tcx. sess,
63- self . tcx. span_of_impl( item1. def_id) . unwrap( ) ,
64- E0592 ,
65- "duplicate definitions with name `{}`" ,
66- name
67- ) ;
68- err. span_label (
69- self . tcx . span_of_impl ( item1. def_id ) . unwrap ( ) ,
70- format ! ( "duplicate definitions for `{}`" , name) ,
71- ) ;
72- err. span_label (
73- self . tcx . span_of_impl ( item2. def_id ) . unwrap ( ) ,
74- format ! ( "other definition for `{}`" , name) ,
75- ) ;
76-
77- for cause in & overlap. intercrate_ambiguity_causes {
78- cause. add_intercrate_ambiguity_hint ( & mut err) ;
79- }
80-
81- if overlap. involves_placeholder {
82- traits:: add_placeholder_note ( & mut err) ;
83- }
23+ /// Emits an error if the impls defining `item1` and `item2` overlap.
24+ fn forbid_overlap ( & self , item1 : & AssocItem , item2 : & AssocItem ) {
25+ let impl1_def_id = item1. container . id ( ) ;
26+ let impl2_def_id = item2. container . id ( ) ;
27+ let name = item1. ident ;
8428
85- err. emit ( ) ;
86- }
87- }
88- }
89- }
90-
91- fn check_for_overlapping_inherent_impls ( & self , impl1_def_id : DefId , impl2_def_id : DefId ) {
9229 traits:: overlapping_impls (
9330 self . tcx ,
9431 impl1_def_id,
@@ -98,12 +35,73 @@ impl InherentOverlapChecker<'tcx> {
9835 // inherent impls without warning.
9936 SkipLeakCheck :: Yes ,
10037 |overlap| {
101- self . check_for_common_items_in_impls ( impl1_def_id, impl2_def_id, overlap) ;
102- false
38+ let mut err = struct_span_err ! (
39+ self . tcx. sess,
40+ self . tcx. span_of_impl( item1. def_id) . unwrap( ) ,
41+ E0592 ,
42+ "duplicate definitions with name `{}`" ,
43+ name
44+ ) ;
45+ err. span_label (
46+ self . tcx . span_of_impl ( item1. def_id ) . unwrap ( ) ,
47+ format ! ( "duplicate definitions for `{}`" , name) ,
48+ ) ;
49+ err. span_label (
50+ self . tcx . span_of_impl ( item2. def_id ) . unwrap ( ) ,
51+ format ! ( "other definition for `{}`" , name) ,
52+ ) ;
53+
54+ for cause in & overlap. intercrate_ambiguity_causes {
55+ cause. add_intercrate_ambiguity_hint ( & mut err) ;
56+ }
57+
58+ if overlap. involves_placeholder {
59+ traits:: add_placeholder_note ( & mut err) ;
60+ }
61+
62+ err. emit ( ) ;
10363 } ,
104- || true ,
64+ || { } ,
10565 ) ;
10666 }
67+
68+ fn process_local_ty ( & self , ty_def_id : DefId ) {
69+ let impls = self . tcx . inherent_impls ( ty_def_id) ;
70+
71+ // Create a map from `Symbol`s to the list of `&'tcx AssocItem`s with that name, across all
72+ // inherent impls.
73+ let mut item_map: FxHashMap < _ , SmallVec < [ & AssocItem ; 1 ] > > = FxHashMap :: default ( ) ;
74+ for impl_def_id in impls {
75+ let impl_items = self . tcx . associated_items ( * impl_def_id) ;
76+
77+ for impl_item in impl_items {
78+ match item_map. entry ( impl_item. ident . name ) {
79+ Entry :: Occupied ( mut occupied) => {
80+ // Do a proper name check respecting namespaces and hygiene against all
81+ // items in this map entry.
82+ let ( ident1, ns1) =
83+ ( impl_item. ident . modern ( ) , Namespace :: from ( impl_item. kind ) ) ;
84+
85+ for impl_item2 in occupied. get ( ) {
86+ let ( ident2, ns2) =
87+ ( impl_item2. ident . modern ( ) , Namespace :: from ( impl_item2. kind ) ) ;
88+
89+ if ns1 == ns2 && ident1 == ident2 {
90+ // Items with same name. Their containing impls must not overlap.
91+
92+ self . forbid_overlap ( impl_item2, impl_item) ;
93+ }
94+ }
95+
96+ occupied. get_mut ( ) . push ( impl_item) ;
97+ }
98+ Entry :: Vacant ( vacant) => {
99+ vacant. insert ( SmallVec :: from ( [ impl_item] ) ) ;
100+ }
101+ }
102+ }
103+ }
104+ }
107105}
108106
109107impl ItemLikeVisitor < ' v > for InherentOverlapChecker < ' tcx > {
@@ -114,15 +112,7 @@ impl ItemLikeVisitor<'v> for InherentOverlapChecker<'tcx> {
114112 | hir:: ItemKind :: Trait ( ..)
115113 | hir:: ItemKind :: Union ( ..) => {
116114 let ty_def_id = self . tcx . hir ( ) . local_def_id ( item. hir_id ) ;
117- let impls = self . tcx . inherent_impls ( ty_def_id) ;
118-
119- for ( i, & impl1_def_id) in impls. iter ( ) . enumerate ( ) {
120- for & impl2_def_id in & impls[ ( i + 1 ) ..] {
121- if self . impls_have_common_items ( impl1_def_id, impl2_def_id) {
122- self . check_for_overlapping_inherent_impls ( impl1_def_id, impl2_def_id) ;
123- }
124- }
125- }
115+ self . process_local_ty ( ty_def_id) ;
126116 }
127117 _ => { }
128118 }
0 commit comments