@@ -18,8 +18,9 @@ use middle::def_id::DefId;
18
18
use infer;
19
19
use traits:: { self , ProjectionMode } ;
20
20
use ty:: { self , TyCtxt , ImplOrTraitItem , TraitDef , TypeFoldable } ;
21
+ use ty:: fast_reject:: { self , SimplifiedType } ;
21
22
use syntax:: ast:: Name ;
22
- use util:: nodemap:: DefIdMap ;
23
+ use util:: nodemap:: { DefIdMap , FnvHashMap } ;
23
24
24
25
/// A per-trait graph of impls in specialization order. At the moment, this
25
26
/// graph forms a tree rooted with the trait itself, with all other nodes
@@ -42,7 +43,124 @@ pub struct Graph {
42
43
parent : DefIdMap < DefId > ,
43
44
44
45
// the "root" impls are found by looking up the trait's def_id.
45
- children : DefIdMap < Vec < DefId > > ,
46
+ children : DefIdMap < Children > ,
47
+ }
48
+
49
+ /// Children of a given impl, grouped into blanket/non-blanket varieties as is
50
+ /// done in `TraitDef`.
51
+ struct Children {
52
+ // Impls of a trait (or specializations of a given impl). To allow for
53
+ // quicker lookup, the impls are indexed by a simplified version of their
54
+ // `Self` type: impls with a simplifiable `Self` are stored in
55
+ // `nonblanket_impls` keyed by it, while all other impls are stored in
56
+ // `blanket_impls`.
57
+ //
58
+ // A similar division is used within `TraitDef`, but the lists there collect
59
+ // together *all* the impls for a trait, and are populated prior to building
60
+ // the specialization graph.
61
+
62
+ /// Impls of the trait.
63
+ nonblanket_impls : FnvHashMap < fast_reject:: SimplifiedType , Vec < DefId > > ,
64
+
65
+ /// Blanket impls associated with the trait.
66
+ blanket_impls : Vec < DefId > ,
67
+ }
68
+
69
+ /// The result of attempting to insert an impl into a group of children.
70
+ enum InsertResult < ' a , ' tcx : ' a > {
71
+ /// The impl was inserted as a new child in this group of children.
72
+ BecameNewSibling ,
73
+
74
+ /// The impl replaced an existing impl that specializes it.
75
+ Replaced ( DefId ) ,
76
+
77
+ /// The impl is a specialization of an existing child.
78
+ ShouldRecurseOn ( DefId ) ,
79
+
80
+ /// The impl has an unresolvable overlap with an existing child (neither
81
+ /// specializes the other).
82
+ Overlapped ( Overlap < ' a , ' tcx > ) ,
83
+ }
84
+
85
+ impl Children {
86
+ fn new ( ) -> Children {
87
+ Children {
88
+ nonblanket_impls : FnvHashMap ( ) ,
89
+ blanket_impls : vec ! [ ] ,
90
+ }
91
+ }
92
+
93
+ /// Insert an impl into this set of children without comparing to any existing impls
94
+ fn insert_blindly ( & mut self , tcx : & TyCtxt , impl_def_id : DefId ) {
95
+ let trait_ref = tcx. impl_trait_ref ( impl_def_id) . unwrap ( ) ;
96
+ if let Some ( sty) = fast_reject:: simplify_type ( tcx, trait_ref. self_ty ( ) , false ) {
97
+ self . nonblanket_impls . entry ( sty) . or_insert ( vec ! [ ] ) . push ( impl_def_id)
98
+ } else {
99
+ self . blanket_impls . push ( impl_def_id)
100
+ }
101
+ }
102
+
103
+ /// Attempt to insert an impl into this set of children, while comparing for
104
+ /// specialiation relationships.
105
+ fn insert < ' a , ' tcx > ( & mut self ,
106
+ tcx : & ' a TyCtxt < ' tcx > ,
107
+ impl_def_id : DefId ,
108
+ simplified_self : Option < SimplifiedType > )
109
+ -> InsertResult < ' a , ' tcx >
110
+ {
111
+ for slot in match simplified_self {
112
+ Some ( sty) => self . filtered_mut ( sty) ,
113
+ None => self . iter_mut ( ) ,
114
+ } {
115
+ let possible_sibling = * slot;
116
+
117
+ let infcx = infer:: new_infer_ctxt ( tcx, & tcx. tables , None , ProjectionMode :: Topmost ) ;
118
+ let overlap = traits:: overlapping_impls ( & infcx, possible_sibling, impl_def_id) ;
119
+
120
+ if let Some ( impl_header) = overlap {
121
+ let le = specializes ( tcx, impl_def_id, possible_sibling) ;
122
+ let ge = specializes ( tcx, possible_sibling, impl_def_id) ;
123
+
124
+ if le && !ge {
125
+ debug ! ( "descending as child of TraitRef {:?}" ,
126
+ tcx. impl_trait_ref( possible_sibling) . unwrap( ) ) ;
127
+
128
+ // the impl specializes possible_sibling
129
+ return InsertResult :: ShouldRecurseOn ( possible_sibling) ;
130
+ } else if ge && !le {
131
+ debug ! ( "placing as parent of TraitRef {:?}" ,
132
+ tcx. impl_trait_ref( possible_sibling) . unwrap( ) ) ;
133
+
134
+ // possible_sibling specializes the impl
135
+ * slot = impl_def_id;
136
+ return InsertResult :: Replaced ( possible_sibling) ;
137
+ } else {
138
+ // overlap, but no specialization; error out
139
+ return InsertResult :: Overlapped ( Overlap {
140
+ with_impl : possible_sibling,
141
+ on_trait_ref : impl_header. trait_ref . unwrap ( ) ,
142
+ in_context : infcx,
143
+ } ) ;
144
+ }
145
+ }
146
+ }
147
+
148
+ // no overlap with any potential siblings, so add as a new sibling
149
+ debug ! ( "placing as new sibling" ) ;
150
+ self . insert_blindly ( tcx, impl_def_id) ;
151
+ InsertResult :: BecameNewSibling
152
+ }
153
+
154
+ fn iter_mut < ' a > ( & ' a mut self ) -> Box < Iterator < Item = & ' a mut DefId > + ' a > {
155
+ let nonblanket = self . nonblanket_impls . iter_mut ( ) . flat_map ( |( _, v) | v. iter_mut ( ) ) ;
156
+ Box :: new ( self . blanket_impls . iter_mut ( ) . chain ( nonblanket) )
157
+ }
158
+
159
+ fn filtered_mut < ' a > ( & ' a mut self , sty : SimplifiedType )
160
+ -> Box < Iterator < Item = & ' a mut DefId > + ' a > {
161
+ let nonblanket = self . nonblanket_impls . entry ( sty) . or_insert ( vec ! [ ] ) . iter_mut ( ) ;
162
+ Box :: new ( self . blanket_impls . iter_mut ( ) . chain ( nonblanket) )
163
+ }
46
164
}
47
165
48
166
impl Graph {
@@ -78,78 +196,53 @@ impl Graph {
78
196
trait_ref, impl_def_id, trait_def_id) ;
79
197
80
198
self . parent . insert ( impl_def_id, trait_def_id) ;
81
- self . children . entry ( trait_def_id) . or_insert ( vec ! [ ] ) . push ( impl_def_id) ;
199
+ self . children . entry ( trait_def_id) . or_insert ( Children :: new ( ) )
200
+ . insert_blindly ( tcx, impl_def_id) ;
82
201
return Ok ( ( ) ) ;
83
202
}
84
203
85
204
let mut parent = trait_def_id;
205
+ let simplified = fast_reject:: simplify_type ( tcx, trait_ref. self_ty ( ) , false ) ;
86
206
87
- // Ugly hack around borrowck limitations. Assigned only in the case
88
- // where we bump downward an existing node in the graph.
89
- let child_to_insert;
90
-
91
- ' descend: loop {
92
- let mut possible_siblings = self . children . entry ( parent) . or_insert ( vec ! [ ] ) ;
93
-
94
- for slot in possible_siblings. iter_mut ( ) {
95
- let possible_sibling = * slot;
96
-
97
- let infcx = infer:: new_infer_ctxt ( tcx, & tcx. tables , None , ProjectionMode :: Topmost ) ;
98
- let overlap = traits:: overlapping_impls ( & infcx, possible_sibling, impl_def_id) ;
99
-
100
- if let Some ( impl_header) = overlap {
101
- let le = specializes ( tcx, impl_def_id, possible_sibling) ;
102
- let ge = specializes ( tcx, possible_sibling, impl_def_id) ;
103
-
104
- if le && !ge {
105
- debug ! ( "descending as child of TraitRef {:?}" ,
106
- tcx. impl_trait_ref( possible_sibling) . unwrap( ) ) ;
107
-
108
- // the impl specializes possible_sibling
109
- parent = possible_sibling;
110
- continue ' descend;
111
- } else if ge && !le {
112
- debug ! ( "placing as parent of TraitRef {:?}" ,
113
- tcx. impl_trait_ref( possible_sibling) . unwrap( ) ) ;
114
-
115
- // possible_sibling specializes the impl
116
- * slot = impl_def_id;
117
- self . parent . insert ( impl_def_id, parent) ;
118
- self . parent . insert ( possible_sibling, impl_def_id) ;
119
- // we have to defer the insertion, because we can't
120
- // relinquish the borrow of `self.children`
121
- child_to_insert = possible_sibling;
122
- break ' descend;
123
- } else {
124
- // overlap, but no specialization; error out
125
- return Err ( Overlap {
126
- with_impl : possible_sibling,
127
- on_trait_ref : impl_header. trait_ref . unwrap ( ) ,
128
- in_context : infcx,
129
- } ) ;
130
- }
207
+ // Descend the specialization tree, where `parent` is the current parent node
208
+ loop {
209
+ use self :: InsertResult :: * ;
210
+
211
+ let insert_result = self . children . entry ( parent) . or_insert ( Children :: new ( ) )
212
+ . insert ( tcx, impl_def_id, simplified) ;
213
+
214
+ match insert_result {
215
+ BecameNewSibling => {
216
+ break ;
217
+ }
218
+ Replaced ( new_child) => {
219
+ self . parent . insert ( new_child, impl_def_id) ;
220
+ let mut new_children = Children :: new ( ) ;
221
+ new_children. insert_blindly ( tcx, new_child) ;
222
+ self . children . insert ( impl_def_id, new_children) ;
223
+ break ;
224
+ }
225
+ ShouldRecurseOn ( new_parent) => {
226
+ parent = new_parent;
227
+ }
228
+ Overlapped ( error) => {
229
+ return Err ( error) ;
131
230
}
132
231
}
133
-
134
- // no overlap with any potential siblings, so add as a new sibling
135
- debug ! ( "placing as new sibling" ) ;
136
- self . parent . insert ( impl_def_id, parent) ;
137
- possible_siblings. push ( impl_def_id) ;
138
- return Ok ( ( ) ) ;
139
232
}
140
233
141
- self . children . insert ( impl_def_id, vec ! [ child_to_insert ] ) ;
234
+ self . parent . insert ( impl_def_id, parent ) ;
142
235
Ok ( ( ) )
143
236
}
144
237
145
238
/// Insert cached metadata mapping from a child impl back to its parent.
146
- pub fn record_impl_from_cstore ( & mut self , parent : DefId , child : DefId ) {
239
+ pub fn record_impl_from_cstore ( & mut self , tcx : & TyCtxt , parent : DefId , child : DefId ) {
147
240
if self . parent . insert ( child, parent) . is_some ( ) {
148
241
panic ! ( "When recording an impl from the crate store, information about its parent \
149
242
was already present.") ;
150
243
}
151
244
152
- self . children . entry ( parent) . or_insert ( vec ! [ ] ) . push ( child) ;
245
+ self . children . entry ( parent) . or_insert ( Children :: new ( ) ) . insert_blindly ( tcx , child) ;
153
246
}
154
247
155
248
/// The parent of a given impl, which is the def id of the trait when the
0 commit comments