11use rustc_ast as ast;
2+ use rustc_data_structures:: stable_set:: FxHashSet ;
23use rustc_errors:: { Applicability , DiagnosticBuilder } ;
34use rustc_expand:: base:: SyntaxExtensionKind ;
45use rustc_feature:: UnstableFeatures ;
@@ -9,7 +10,7 @@ use rustc_hir::def::{
910 PerNS , Res ,
1011} ;
1112use rustc_hir:: def_id:: DefId ;
12- use rustc_middle:: ty;
13+ use rustc_middle:: ty:: { self , TyCtxt } ;
1314use rustc_resolve:: ParentScope ;
1415use rustc_session:: lint;
1516use rustc_span:: hygiene:: MacroKind ;
@@ -347,7 +348,7 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
347348 // HACK(jynelson): `clean` expects the type, not the associated item.
348349 // but the disambiguator logic expects the associated item.
349350 // Store the kind in a side channel so that only the disambiguator logic looks at it.
350- self . kind_side_channel . replace ( Some ( item . kind . as_def_kind ( ) ) ) ;
351+ self . kind_side_channel . set ( Some ( kind. as_def_kind ( ) ) ) ;
351352 Ok ( ( ty_res, Some ( format ! ( "{}.{}" , out, item_name) ) ) )
352353 } )
353354 } else if ns == Namespace :: ValueNS {
@@ -443,8 +444,6 @@ fn resolve_associated_trait_item(
443444 ns : Namespace ,
444445 cx : & DocContext < ' _ > ,
445446) -> Option < ty:: AssocKind > {
446- use rustc_hir:: def_id:: LOCAL_CRATE ;
447-
448447 let ty = cx. tcx . type_of ( did) ;
449448 // First consider automatic impls: `impl From<T> for T`
450449 let implicit_impls = crate :: clean:: get_auto_trait_and_blanket_impls ( cx, ty, did) ;
@@ -501,54 +500,69 @@ fn resolve_associated_trait_item(
501500 }
502501 } )
503502 . collect ( ) ;
503+
504504 // Next consider explicit impls: `impl MyTrait for MyType`
505- // There isn't a cheap way to do this. Just look at every trait!
506- for & trait_ in cx. tcx . all_traits ( LOCAL_CRATE ) {
507- trace ! ( "considering explicit impl for trait {:?}" , trait_) ;
508- // We can skip the trait if it doesn't have the associated item `item_name`
509- let assoc_item = cx
510- . tcx
511- . associated_items ( trait_)
512- . find_by_name_and_namespace ( cx. tcx , Ident :: with_dummy_span ( item_name) , ns, trait_)
513- . map ( |assoc| ( assoc. def_id , assoc. kind ) ) ;
514- if let Some ( assoc_item) = assoc_item {
515- debug ! ( "considering item {:?}" , assoc_item) ;
516- // Look at each trait implementation to see if it's an impl for `did`
517- cx. tcx . for_each_relevant_impl ( trait_, ty, |impl_| {
518- use ty:: TyKind ;
519-
520- let trait_ref = cx. tcx . impl_trait_ref ( impl_) . expect ( "this is not an inherent impl" ) ;
521- // Check if these are the same type.
522- let impl_type = trait_ref. self_ty ( ) ;
523- debug ! (
524- "comparing type {} with kind {:?} against def_id {:?}" ,
525- impl_type, impl_type. kind, did
526- ) ;
527- // Fast path: if this is a primitive simple `==` will work
528- let same_type = impl_type == ty
529- || match impl_type. kind {
530- // Check if these are the same def_id
531- TyKind :: Adt ( def, _) => {
532- debug ! ( "adt did: {:?}" , def. did) ;
533- def. did == did
534- }
535- TyKind :: Foreign ( def_id) => def_id == did,
536- _ => false ,
537- } ;
538- if same_type {
539- // We found it!
540- debug ! ( "found a match!" ) ;
541- candidates. push ( assoc_item) ;
542- }
543- } ) ;
544- }
505+ // Give precedence to inherent impls.
506+ if candidates. is_empty ( ) {
507+ let mut cache = cx. type_trait_cache . borrow_mut ( ) ;
508+ let traits = cache. entry ( did) . or_insert_with ( || traits_implemented_by ( cx. tcx , did) ) ;
509+ debug ! ( "considering traits {:?}" , traits) ;
510+ candidates. extend ( traits. iter ( ) . filter_map ( |& trait_| {
511+ cx. tcx
512+ . associated_items ( trait_)
513+ . find_by_name_and_namespace ( cx. tcx , Ident :: with_dummy_span ( item_name) , ns, trait_)
514+ . map ( |assoc| ( assoc. def_id , assoc. kind ) )
515+ } ) ) ;
545516 }
546-
547517 // FIXME: warn about ambiguity
548518 debug ! ( "the candidates were {:?}" , candidates) ;
549519 candidates. pop ( ) . map ( |( _, kind) | kind)
550520}
551521
522+ /// Given a type, return all traits implemented by that type.
523+ ///
524+ /// NOTE: this cannot be a query because more traits could be available when more crates are compiled!
525+ /// So it is not stable to serialize cross-crate.
526+ /// FIXME: this should only search traits in scope
527+ fn traits_implemented_by < ' a > ( tcx : TyCtxt < ' a > , type_ : DefId ) -> FxHashSet < DefId > {
528+ use rustc_hir:: def_id:: LOCAL_CRATE ;
529+
530+ let all_traits = tcx. all_traits ( LOCAL_CRATE ) . iter ( ) . copied ( ) ;
531+ let ty = tcx. type_of ( type_) ;
532+ let iter = all_traits. flat_map ( |trait_| {
533+ trace ! ( "considering explicit impl for trait {:?}" , trait_) ;
534+ let mut saw_impl = false ;
535+ // Look at each trait implementation to see if it's an impl for `did`
536+ tcx. for_each_relevant_impl ( trait_, ty, |impl_| {
537+ // FIXME: this is inefficient, find a way to short-circuit for_each_* so this doesn't take as long
538+ if saw_impl {
539+ return ;
540+ }
541+
542+ let trait_ref = tcx. impl_trait_ref ( impl_) . expect ( "this is not an inherent impl" ) ;
543+ // Check if these are the same type.
544+ let impl_type = trait_ref. self_ty ( ) ;
545+ debug ! (
546+ "comparing type {} with kind {:?} against type {:?}" ,
547+ impl_type, impl_type. kind, type_
548+ ) ;
549+ // Fast path: if this is a primitive simple `==` will work
550+ saw_impl = impl_type == ty
551+ || match impl_type. kind {
552+ // Check if these are the same def_id
553+ ty:: Adt ( def, _) => {
554+ debug ! ( "adt def_id: {:?}" , def. did) ;
555+ def. did == type_
556+ }
557+ ty:: Foreign ( def_id) => def_id == type_,
558+ _ => false ,
559+ } ;
560+ } ) ;
561+ if saw_impl { Some ( trait_) } else { None }
562+ } ) ;
563+ iter. collect ( )
564+ }
565+
552566/// Check for resolve collisions between a trait and its derive
553567///
554568/// These are common and we should just resolve to the trait in that case
0 commit comments