1
1
use crate :: namespace:: Namespace ;
2
2
use rustc:: traits:: { self , IntercrateMode , SkipLeakCheck } ;
3
3
use rustc:: ty:: { AssocItem , TyCtxt } ;
4
+ use rustc_data_structures:: fx:: FxHashMap ;
4
5
use rustc_errors:: struct_span_err;
5
6
use rustc_hir as hir;
6
7
use rustc_hir:: def_id:: { CrateNum , DefId , LOCAL_CRATE } ;
7
8
use rustc_hir:: itemlikevisit:: ItemLikeVisitor ;
9
+ use smallvec:: SmallVec ;
10
+ use std:: collections:: hash_map:: Entry ;
8
11
9
12
pub fn crate_inherent_impls_overlap_check ( tcx : TyCtxt < ' _ > , crate_num : CrateNum ) {
10
13
assert_eq ! ( crate_num, LOCAL_CRATE ) ;
@@ -17,78 +20,12 @@ struct InherentOverlapChecker<'tcx> {
17
20
}
18
21
19
22
impl 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 ;
84
28
85
- err. emit ( ) ;
86
- }
87
- }
88
- }
89
- }
90
-
91
- fn check_for_overlapping_inherent_impls ( & self , impl1_def_id : DefId , impl2_def_id : DefId ) {
92
29
traits:: overlapping_impls (
93
30
self . tcx ,
94
31
impl1_def_id,
@@ -98,12 +35,73 @@ impl InherentOverlapChecker<'tcx> {
98
35
// inherent impls without warning.
99
36
SkipLeakCheck :: Yes ,
100
37
|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 ( ) ;
103
63
} ,
104
- || true ,
64
+ || { } ,
105
65
) ;
106
66
}
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
+ }
107
105
}
108
106
109
107
impl ItemLikeVisitor < ' v > for InherentOverlapChecker < ' tcx > {
@@ -114,15 +112,7 @@ impl ItemLikeVisitor<'v> for InherentOverlapChecker<'tcx> {
114
112
| hir:: ItemKind :: Trait ( ..)
115
113
| hir:: ItemKind :: Union ( ..) => {
116
114
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) ;
126
116
}
127
117
_ => { }
128
118
}
0 commit comments