@@ -35,6 +35,60 @@ pub struct TraitDef {
35
35
pub def_path_hash : u64 ,
36
36
}
37
37
38
+ // We don't store the list of impls in a flat list because each cached list of
39
+ // `relevant_impls_for` we would then duplicate all blanket impls. By keeping
40
+ // blanket and non-blanket impls separate, we can share the list of blanket
41
+ // impls.
42
+ #[ derive( Clone ) ]
43
+ pub struct TraitImpls {
44
+ blanket_impls : Rc < Vec < DefId > > ,
45
+ non_blanket_impls : Rc < Vec < DefId > > ,
46
+ }
47
+
48
+ impl TraitImpls {
49
+ pub fn iter ( & self ) -> TraitImplsIter {
50
+ TraitImplsIter {
51
+ blanket_impls : self . blanket_impls . clone ( ) ,
52
+ non_blanket_impls : self . non_blanket_impls . clone ( ) ,
53
+ index : 0
54
+ }
55
+ }
56
+ }
57
+
58
+ #[ derive( Clone ) ]
59
+ pub struct TraitImplsIter {
60
+ blanket_impls : Rc < Vec < DefId > > ,
61
+ non_blanket_impls : Rc < Vec < DefId > > ,
62
+ index : usize ,
63
+ }
64
+
65
+ impl Iterator for TraitImplsIter {
66
+ type Item = DefId ;
67
+
68
+ fn next ( & mut self ) -> Option < DefId > {
69
+ if self . index < self . blanket_impls . len ( ) {
70
+ let bi_index = self . index ;
71
+ self . index += 1 ;
72
+ Some ( self . blanket_impls [ bi_index] )
73
+ } else {
74
+ let nbi_index = self . index - self . blanket_impls . len ( ) ;
75
+ if nbi_index < self . non_blanket_impls . len ( ) {
76
+ self . index += 1 ;
77
+ Some ( self . non_blanket_impls [ nbi_index] )
78
+ } else {
79
+ None
80
+ }
81
+ }
82
+ }
83
+
84
+ fn size_hint ( & self ) -> ( usize , Option < usize > ) {
85
+ let items_left = ( self . blanket_impls . len ( ) + self . non_blanket_impls . len ( ) ) - self . index ;
86
+ ( items_left, Some ( items_left) )
87
+ }
88
+ }
89
+
90
+ impl ExactSizeIterator for TraitImplsIter { }
91
+
38
92
impl < ' a , ' gcx , ' tcx > TraitDef {
39
93
pub fn new ( def_id : DefId ,
40
94
unsafety : hir:: Unsafety ,
@@ -58,7 +112,7 @@ impl<'a, 'gcx, 'tcx> TraitDef {
58
112
}
59
113
60
114
pub fn for_each_impl < F : FnMut ( DefId ) > ( & self , tcx : TyCtxt < ' a , ' gcx , ' tcx > , mut f : F ) {
61
- for & impl_def_id in tcx. trait_impls_of ( self . def_id ) . iter ( ) {
115
+ for impl_def_id in tcx. trait_impls_of ( self . def_id ) . iter ( ) {
62
116
f ( impl_def_id) ;
63
117
}
64
118
}
@@ -89,7 +143,7 @@ impl<'a, 'gcx, 'tcx> TraitDef {
89
143
tcx. trait_impls_of ( self . def_id )
90
144
} ;
91
145
92
- for & impl_def_id in relevant_impls. iter ( ) {
146
+ for impl_def_id in relevant_impls. iter ( ) {
93
147
f ( impl_def_id) ;
94
148
}
95
149
}
@@ -98,55 +152,70 @@ impl<'a, 'gcx, 'tcx> TraitDef {
98
152
// Query provider for `trait_impls_of`.
99
153
pub ( super ) fn trait_impls_of_provider < ' a , ' tcx > ( tcx : TyCtxt < ' a , ' tcx , ' tcx > ,
100
154
trait_id : DefId )
101
- -> Rc < Vec < DefId > > {
102
- let mut impls = if trait_id. is_local ( ) {
155
+ -> TraitImpls {
156
+ let remote_impls = if trait_id. is_local ( ) {
103
157
// Traits defined in the current crate can't have impls in upstream
104
158
// crates, so we don't bother querying the cstore.
105
159
Vec :: new ( )
106
160
} else {
107
161
tcx. sess . cstore . implementations_of_trait ( Some ( trait_id) )
108
162
} ;
109
163
110
- impls. extend ( tcx. hir
111
- . trait_impls ( trait_id)
112
- . iter ( )
113
- . map ( |& node_id| tcx. hir . local_def_id ( node_id) )
114
- . filter ( |& impl_def_id| {
115
- let trait_ref = tcx. impl_trait_ref ( impl_def_id) . unwrap ( ) ;
116
- !trait_ref. references_error ( )
117
- } ) ) ;
118
- Rc :: new ( impls)
164
+ let mut blanket_impls = Vec :: new ( ) ;
165
+ let mut non_blanket_impls = Vec :: new ( ) ;
166
+
167
+ let local_impls = tcx. hir
168
+ . trait_impls ( trait_id)
169
+ . into_iter ( )
170
+ . map ( |& node_id| tcx. hir . local_def_id ( node_id) ) ;
171
+
172
+ for impl_def_id in local_impls. chain ( remote_impls. into_iter ( ) ) {
173
+ let impl_trait_ref = tcx. impl_trait_ref ( impl_def_id) . unwrap ( ) ;
174
+ if impl_def_id. is_local ( ) && impl_trait_ref. references_error ( ) {
175
+ continue
176
+ }
177
+
178
+ if fast_reject:: simplify_type ( tcx, impl_trait_ref. self_ty ( ) , false ) . is_some ( ) {
179
+ non_blanket_impls. push ( impl_def_id) ;
180
+ } else {
181
+ blanket_impls. push ( impl_def_id) ;
182
+ }
183
+ }
184
+
185
+ TraitImpls {
186
+ blanket_impls : Rc :: new ( blanket_impls) ,
187
+ non_blanket_impls : Rc :: new ( non_blanket_impls) ,
188
+ }
119
189
}
120
190
121
191
// Query provider for `relevant_trait_impls_for`.
122
192
pub ( super ) fn relevant_trait_impls_provider < ' a , ' tcx > (
123
193
tcx : TyCtxt < ' a , ' tcx , ' tcx > ,
124
194
( trait_id, self_ty) : ( DefId , fast_reject:: SimplifiedType ) )
125
- -> Rc < Vec < DefId > >
195
+ -> TraitImpls
126
196
{
127
197
let all_trait_impls = tcx. trait_impls_of ( trait_id) ;
128
198
129
199
let relevant: Vec < DefId > = all_trait_impls
200
+ . non_blanket_impls
130
201
. iter ( )
131
- . map ( | & impl_def_id| impl_def_id )
202
+ . cloned ( )
132
203
. filter ( |& impl_def_id| {
133
204
let impl_trait_ref = tcx. impl_trait_ref ( impl_def_id) . unwrap ( ) ;
134
205
let impl_simple_self_ty = fast_reject:: simplify_type ( tcx,
135
206
impl_trait_ref. self_ty ( ) ,
136
- false ) ;
137
- if let Some ( impl_simple_self_ty) = impl_simple_self_ty {
138
- impl_simple_self_ty == self_ty
139
- } else {
140
- // blanket impl (?)
141
- true
142
- }
207
+ false ) . unwrap ( ) ;
208
+ impl_simple_self_ty == self_ty
143
209
} )
144
210
. collect ( ) ;
145
211
146
- if all_trait_impls. len ( ) == relevant. len ( ) {
212
+ if all_trait_impls. non_blanket_impls . len ( ) == relevant. len ( ) {
147
213
// If we didn't filter anything out, re-use the existing vec.
148
214
all_trait_impls
149
215
} else {
150
- Rc :: new ( relevant)
216
+ TraitImpls {
217
+ blanket_impls : all_trait_impls. blanket_impls . clone ( ) ,
218
+ non_blanket_impls : Rc :: new ( relevant) ,
219
+ }
151
220
}
152
221
}
0 commit comments