@@ -30,6 +30,7 @@ use rustc_attr as attr;
3030use rustc_data_structures:: captures:: Captures ;
3131use rustc_data_structures:: fx:: FxHashMap ;
3232use rustc_data_structures:: fx:: FxIndexMap ;
33+ use rustc_data_structures:: sorted_map:: SortedIndexMultiMap ;
3334use rustc_data_structures:: stable_hasher:: { HashStable , StableHasher } ;
3435use rustc_data_structures:: sync:: { self , par_iter, Lrc , ParallelIterator } ;
3536use rustc_hir as hir;
@@ -264,6 +265,81 @@ impl AssocItem {
264265 }
265266}
266267
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+
267343#[ derive( Clone , Debug , PartialEq , Eq , Copy , RustcEncodable , RustcDecodable , HashStable ) ]
268344pub enum Visibility {
269345 /// Visible everywhere (including in other crates).
@@ -2738,14 +2814,14 @@ impl<'tcx> TyCtxt<'tcx> {
27382814 . for_each ( |& body_id| f ( self . hir ( ) . body_owner_def_id ( body_id) ) ) ;
27392815 }
27402816
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 > {
27422818 self . associated_items ( id)
2743- . iter ( )
2819+ . in_definition_order ( )
27442820 . filter ( |item| item. kind == AssocKind :: Method && item. defaultness . has_value ( ) )
27452821 }
27462822
27472823 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 ( ) )
27492825 }
27502826
27512827 pub fn opt_item_name ( self , def_id : DefId ) -> Option < Ident > {
0 commit comments