@@ -18,8 +18,9 @@ use hir::def_id::DefId;
1818use infer;
1919use traits:: { self , ProjectionMode } ;
2020use ty:: { self , TyCtxt , ImplOrTraitItem , TraitDef , TypeFoldable } ;
21+ use ty:: fast_reject:: { self , SimplifiedType } ;
2122use syntax:: ast:: Name ;
22- use util:: nodemap:: DefIdMap ;
23+ use util:: nodemap:: { DefIdMap , FnvHashMap } ;
2324
2425/// A per-trait graph of impls in specialization order. At the moment, this
2526/// graph forms a tree rooted with the trait itself, with all other nodes
@@ -42,7 +43,124 @@ pub struct Graph {
4243 parent : DefIdMap < DefId > ,
4344
4445 // 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+ }
46164}
47165
48166impl Graph {
@@ -78,78 +196,53 @@ impl Graph {
78196 trait_ref, impl_def_id, trait_def_id) ;
79197
80198 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) ;
82201 return Ok ( ( ) ) ;
83202 }
84203
85204 let mut parent = trait_def_id;
205+ let simplified = fast_reject:: simplify_type ( tcx, trait_ref. self_ty ( ) , false ) ;
86206
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) ;
131230 }
132231 }
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 ( ( ) ) ;
139232 }
140233
141- self . children . insert ( impl_def_id, vec ! [ child_to_insert ] ) ;
234+ self . parent . insert ( impl_def_id, parent ) ;
142235 Ok ( ( ) )
143236 }
144237
145238 /// 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 ) {
147240 if self . parent . insert ( child, parent) . is_some ( ) {
148241 bug ! ( "When recording an impl from the crate store, information about its parent \
149242 was already present.") ;
150243 }
151244
152- self . children . entry ( parent) . or_insert ( vec ! [ ] ) . push ( child) ;
245+ self . children . entry ( parent) . or_insert ( Children :: new ( ) ) . insert_blindly ( tcx , child) ;
153246 }
154247
155248 /// The parent of a given impl, which is the def id of the trait when the
0 commit comments