@@ -239,6 +239,7 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
239239 // If resolution failed, it may still be a method
240240 // because methods are not handled by the resolver
241241 // If so, bail when we're not looking for a value.
242+ // TODO: is this correct? What about associated types?
242243 if ns != ValueNS {
243244 return Err ( ErrorKind :: ResolutionFailure ) ;
244245 }
@@ -305,7 +306,8 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
305306 // To handle that properly resolve() would have to support
306307 // something like [`ambi_fn`](<SomeStruct as SomeTrait>::ambi_fn)
307308 if kind. is_none ( ) {
308- kind = resolve_associated_trait_item ( did, item_name, & self . cx ) ?;
309+ kind = resolve_associated_trait_item ( did, item_name, ns, & self . cx ) ?;
310+ debug ! ( "got associated item kind {:?}" , kind) ;
309311 }
310312
311313 if let Some ( kind) = kind {
@@ -405,23 +407,27 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
405407 }
406408}
407409
408- fn resolve_associated_trait_item ( did : DefId , item_name : Symbol , cx : & DocContext < ' _ > ) -> Result < Option < ty:: AssocKind > , ErrorKind > {
410+ fn resolve_associated_trait_item ( did : DefId , item_name : Symbol , ns : Namespace , cx : & DocContext < ' _ > ) -> Result < Option < ty:: AssocKind > , ErrorKind > {
411+ use rustc_hir:: def_id:: LOCAL_CRATE ;
412+
409413 let ty = cx. tcx . type_of ( did) ;
410- // Checks if item_name belongs to `impl SomeItem`
411- // `def_id` should be a trait
412- let associated_items_for_def_id = |tcx : ty:: TyCtxt < ' _ > , def_id : DefId | -> Vec < _ > {
413- tcx. associated_items ( def_id)
414- . filter_by_name ( tcx, Ident :: with_dummy_span ( item_name) , def_id)
414+ // Checks if item_name belongs to this `impl_`
415+ // `impl_` should be a trait or trait implementation.
416+ let associated_items_for_impl = |tcx : ty:: TyCtxt < ' _ > , impl_ : DefId | -> Vec < _ > {
417+ tcx. associated_items ( impl_)
418+ // TODO: should this be unhygienic?
419+ . filter_by_name ( tcx, Ident :: with_dummy_span ( item_name) , impl_)
415420 . map ( |assoc| ( assoc. def_id , assoc. kind ) )
416421 // TODO: this collect seems a shame
417422 . collect ( )
418423 } ;
419- let impls = crate :: clean:: get_auto_trait_and_blanket_impls ( cx, ty, did) ;
420- let candidates: Vec < _ > = impls
424+ // First consider automatic impls: `impl From<T> for T`
425+ let implicit_impls = crate :: clean:: get_auto_trait_and_blanket_impls ( cx, ty, did) ;
426+ let mut candidates: Vec < _ > = implicit_impls
421427 . flat_map ( |impl_outer| {
422428 match impl_outer. inner {
423429 ImplItem ( impl_) => {
424- debug ! ( "considering trait {:?}" , impl_. trait_) ;
430+ debug ! ( "considering auto or blanket impl for trait {:?}" , impl_. trait_) ;
425431 // Give precedence to methods that were overridden
426432 if !impl_. provided_trait_methods . contains ( & * item_name. as_str ( ) ) {
427433 impl_. items . into_iter ( )
@@ -449,22 +455,60 @@ fn resolve_associated_trait_item(did: DefId, item_name: Symbol, cx: &DocContext<
449455 // }
450456 // ```
451457 // TODO: this is wrong, it should look at the trait, not the impl
452- associated_items_for_def_id ( cx. tcx , impl_outer. def_id )
458+ associated_items_for_impl ( cx. tcx , impl_outer. def_id )
453459 }
454460 }
455461 _ => panic ! ( "get_impls returned something that wasn't an impl" ) ,
456462 }
457463 } )
458- . chain ( cx. tcx . all_impls ( did) . flat_map ( |impl_| associated_items_for_def_id ( cx. tcx , impl_) ) )
459- //.chain(cx.tcx.all_local_trait_impls(did).flat_map(|impl_| associated_items_for_def_id(cx.tcx, impl_)))
460464 . collect ( ) ;
465+ // Next consider explicit impls: `impl MyTrait for MyType`
466+ // There isn't a cheap way to do this. Just look at every trait!
467+ for & trait_ in cx. tcx . all_traits ( LOCAL_CRATE ) {
468+ debug ! ( "considering explicit impl for trait {:?}" , trait_) ;
469+ // We can skip the trait if it doesn't have the associated item `item_name`
470+ let assoc_item = cx. tcx
471+ . associated_items ( trait_)
472+ . find_by_name_and_namespace ( cx. tcx , Ident :: with_dummy_span ( item_name) , ns, trait_)
473+ . map ( |assoc| ( assoc. def_id , assoc. kind ) ) ;
474+ if let Some ( assoc_item) = assoc_item {
475+ debug ! ( "considering item {:?}" , assoc_item) ;
476+ // Look at each trait implementation to see if it's an impl for `did`
477+ cx. tcx . for_each_relevant_impl ( trait_, ty, |impl_| {
478+ use ty:: TyKind ;
479+
480+ let trait_ref = cx. tcx . impl_trait_ref ( impl_) . expect ( "this is not an inherent impl" ) ;
481+ // Check if these are the same type.
482+ let impl_type = trait_ref. self_ty ( ) ;
483+ debug ! ( "comparing type {} with kind {:?} against def_id {:?}" , impl_type, impl_type. kind, did) ;
484+ // Fast path: if this is a primitive simple `==` will work
485+ let same_type = impl_type == ty || match impl_type. kind {
486+ // Check if these are the same def_id
487+ TyKind :: Adt ( def, _) => {
488+ debug ! ( "adt did: {:?}" , def. did) ;
489+ def. did == did
490+ }
491+ TyKind :: Foreign ( def_id) => def_id == did,
492+ _ => false ,
493+ } ;
494+ if same_type {
495+ // We found it!
496+ debug ! ( "found a match!" ) ;
497+ candidates. push ( assoc_item) ;
498+ }
499+ } ) ;
500+ }
501+ }
502+
461503 if candidates. len ( ) > 1 {
504+ debug ! ( "ambiguous" ) ;
462505 let candidates = candidates. into_iter ( )
463506 . map ( |( def_id, kind) | Res :: Def ( kind. as_def_kind ( ) , def_id) )
464507 . collect ( ) ;
465508 return Err ( ErrorKind :: Ambiguous { candidates } ) ;
466509 }
467- Ok ( candidates. into_iter ( ) . next ( ) . map ( |( _, kind) | kind) )
510+ // Cleanup and go home
511+ Ok ( candidates. pop ( ) . map ( |( _, kind) | kind) )
468512}
469513
470514/// Check for resolve collisions between a trait and its derive
@@ -718,6 +762,7 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> {
718762 continue ;
719763 }
720764 Err ( ErrorKind :: Ambiguous { candidates } ) => {
765+ debug ! ( "got ambiguity error: {:?}" , candidates) ;
721766 ambiguity_error (
722767 cx,
723768 & item,
@@ -776,11 +821,23 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> {
776821 base_node,
777822 & extra_fragment,
778823 ) {
824+ Ok ( res) => Some ( res) ,
779825 Err ( ErrorKind :: AnchorFailure ( msg) ) => {
780826 anchor_failure ( cx, & item, & ori_link, & dox, link_range, msg) ;
781827 continue ;
782828 }
783- x => x. ok ( ) ,
829+ Err ( ErrorKind :: ResolutionFailure ) => None ,
830+ Err ( ErrorKind :: Ambiguous { candidates } ) => {
831+ ambiguity_error (
832+ cx,
833+ & item,
834+ path_str,
835+ & dox,
836+ link_range,
837+ candidates. into_iter ( ) . map ( |res| ( res, TypeNS ) ) . collect ( ) ,
838+ ) ;
839+ continue ;
840+ }
784841 } ,
785842 value_ns : match self . resolve (
786843 path_str,
@@ -790,11 +847,23 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> {
790847 base_node,
791848 & extra_fragment,
792849 ) {
850+ Ok ( res) => Some ( res) ,
793851 Err ( ErrorKind :: AnchorFailure ( msg) ) => {
794852 anchor_failure ( cx, & item, & ori_link, & dox, link_range, msg) ;
795853 continue ;
796854 }
797- x => x. ok ( ) ,
855+ Err ( ErrorKind :: ResolutionFailure ) => None ,
856+ Err ( ErrorKind :: Ambiguous { candidates } ) => {
857+ ambiguity_error (
858+ cx,
859+ & item,
860+ path_str,
861+ & dox,
862+ link_range,
863+ candidates. into_iter ( ) . map ( |res| ( res, TypeNS ) ) . collect ( ) ,
864+ ) ;
865+ continue ;
866+ }
798867 }
799868 . and_then ( |( res, fragment) | {
800869 // Constructors are picked up in the type namespace.
@@ -1028,9 +1097,11 @@ fn ambiguity_error(
10281097 link_range : Option < Range < usize > > ,
10291098 candidates : Vec < ( Res , Namespace ) > ,
10301099) {
1100+ assert ! ( candidates. len( ) >= 2 ) ;
10311101 let hir_id = match cx. as_local_hir_id ( item. def_id ) {
10321102 Some ( hir_id) => hir_id,
10331103 None => {
1104+ debug ! ( "ignoring ambiguity error for non-local item" ) ;
10341105 // If non-local, no need to check anything.
10351106 return ;
10361107 }
0 commit comments