@@ -30,6 +30,7 @@ use rustc_attr as attr;
30
30
use rustc_data_structures:: captures:: Captures ;
31
31
use rustc_data_structures:: fx:: FxHashMap ;
32
32
use rustc_data_structures:: fx:: FxIndexMap ;
33
+ use rustc_data_structures:: sorted_map:: SortedIndexMultiMap ;
33
34
use rustc_data_structures:: stable_hasher:: { HashStable , StableHasher } ;
34
35
use rustc_data_structures:: sync:: { self , par_iter, Lrc , ParallelIterator } ;
35
36
use rustc_hir as hir;
@@ -264,6 +265,81 @@ impl AssocItem {
264
265
}
265
266
}
266
267
268
+ /// A list of `ty::AssocItem`s in definition order that allows for efficient lookup by name.
269
+ ///
270
+ /// When doing lookup by name, we try to postpone hygienic comparison for as long as possible since
271
+ /// it is relatively expensive. Instead, items are indexed by `Symbol` and hygienic comparison is
272
+ /// done only on items with the same name.
273
+ #[ derive( Debug , Clone , PartialEq , HashStable ) ]
274
+ pub struct AssociatedItems {
275
+ items : SortedIndexMultiMap < u32 , Symbol , ty:: AssocItem > ,
276
+ }
277
+
278
+ impl AssociatedItems {
279
+ /// Constructs an `AssociatedItems` map from a series of `ty::AssocItem`s in definition order.
280
+ pub fn new ( items_in_def_order : Vec < ty:: AssocItem > ) -> Self {
281
+ let items = items_in_def_order. into_iter ( ) . map ( |item| ( item. ident . name , item) ) . collect ( ) ;
282
+ AssociatedItems { items }
283
+ }
284
+
285
+ /// Returns a slice of associated items in the order they were defined.
286
+ ///
287
+ /// New code should avoid relying on definition order. If you need a particular associated item
288
+ /// for a known trait, make that trait a lang item instead of indexing this array.
289
+ pub fn in_definition_order ( & self ) -> impl ' _ + Iterator < Item = & ty:: AssocItem > {
290
+ self . items . iter ( ) . map ( |( _, v) | v)
291
+ }
292
+
293
+ /// Returns an iterator over all associated items with the given name, ignoring hygiene.
294
+ pub fn filter_by_name_unhygienic (
295
+ & self ,
296
+ name : Symbol ,
297
+ ) -> impl ' _ + Iterator < Item = & ty:: AssocItem > {
298
+ self . items . get_by_key ( & name)
299
+ }
300
+
301
+ /// Returns an iterator over all associated items with the given name.
302
+ ///
303
+ /// Multiple items may have the same name if they are in different `Namespace`s. For example,
304
+ /// an associated type can have the same name as a method. Use one of the `find_by_name_and_*`
305
+ /// methods below if you know which item you are looking for.
306
+ pub fn filter_by_name (
307
+ & ' a self ,
308
+ tcx : TyCtxt < ' a > ,
309
+ ident : Ident ,
310
+ parent_def_id : DefId ,
311
+ ) -> impl ' a + Iterator < Item = & ' a ty:: AssocItem > {
312
+ self . filter_by_name_unhygienic ( ident. name )
313
+ . filter ( move |item| tcx. hygienic_eq ( ident, item. ident , parent_def_id) )
314
+ }
315
+
316
+ /// Returns the associated item with the given name and `AssocKind`, if one exists.
317
+ pub fn find_by_name_and_kind (
318
+ & self ,
319
+ tcx : TyCtxt < ' _ > ,
320
+ ident : Ident ,
321
+ kind : AssocKind ,
322
+ parent_def_id : DefId ,
323
+ ) -> Option < & ty:: AssocItem > {
324
+ self . filter_by_name_unhygienic ( ident. name )
325
+ . filter ( |item| item. kind == kind)
326
+ . find ( |item| tcx. hygienic_eq ( ident, item. ident , parent_def_id) )
327
+ }
328
+
329
+ /// Returns the associated item with the given name in the given `Namespace`, if one exists.
330
+ pub fn find_by_name_and_namespace (
331
+ & self ,
332
+ tcx : TyCtxt < ' _ > ,
333
+ ident : Ident ,
334
+ ns : Namespace ,
335
+ parent_def_id : DefId ,
336
+ ) -> Option < & ty:: AssocItem > {
337
+ self . filter_by_name_unhygienic ( ident. name )
338
+ . filter ( |item| item. kind . namespace ( ) == ns)
339
+ . find ( |item| tcx. hygienic_eq ( ident, item. ident , parent_def_id) )
340
+ }
341
+ }
342
+
267
343
#[ derive( Clone , Debug , PartialEq , Eq , Copy , RustcEncodable , RustcDecodable , HashStable ) ]
268
344
pub enum Visibility {
269
345
/// Visible everywhere (including in other crates).
@@ -2738,14 +2814,14 @@ impl<'tcx> TyCtxt<'tcx> {
2738
2814
. for_each ( |& body_id| f ( self . hir ( ) . body_owner_def_id ( body_id) ) ) ;
2739
2815
}
2740
2816
2741
- pub fn provided_trait_methods ( self , id : DefId ) -> impl Iterator < Item = & ' tcx AssocItem > {
2817
+ pub fn provided_trait_methods ( self , id : DefId ) -> impl ' tcx + Iterator < Item = & ' tcx AssocItem > {
2742
2818
self . associated_items ( id)
2743
- . iter ( )
2819
+ . in_definition_order ( )
2744
2820
. filter ( |item| item. kind == AssocKind :: Method && item. defaultness . has_value ( ) )
2745
2821
}
2746
2822
2747
2823
pub fn trait_relevant_for_never ( self , did : DefId ) -> bool {
2748
- self . associated_items ( did) . iter ( ) . any ( |item| item. relevant_for_never ( ) )
2824
+ self . associated_items ( did) . in_definition_order ( ) . any ( |item| item. relevant_for_never ( ) )
2749
2825
}
2750
2826
2751
2827
pub fn opt_item_name ( self , def_id : DefId ) -> Option < Ident > {
0 commit comments