@@ -368,54 +368,28 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
368368 }
369369
370370 /// Given a primitive type, try to resolve an associated item.
371- ///
372- /// HACK(jynelson): `item_str` is passed in instead of derived from `item_name` so the
373- /// lifetimes on `&'path` will work.
374371 fn resolve_primitive_associated_item (
375372 & self ,
376373 prim_ty : PrimitiveType ,
377374 ns : Namespace ,
378- module_id : DefId ,
379375 item_name : Symbol ,
380- ) -> Result < ( Res , Option < String > ) , ErrorKind < ' path > > {
376+ ) -> Option < ( Res , String , Option < ( DefKind , DefId ) > ) > {
381377 let tcx = self . cx . tcx ;
382378
383- prim_ty
384- . impls ( tcx)
385- . into_iter ( )
386- . find_map ( |& impl_| {
387- tcx. associated_items ( impl_)
388- . find_by_name_and_namespace ( tcx, Ident :: with_dummy_span ( item_name) , ns, impl_)
389- . map ( |item| {
390- let kind = item. kind ;
391- self . kind_side_channel . set ( Some ( ( kind. as_def_kind ( ) , item. def_id ) ) ) ;
392- match kind {
393- ty:: AssocKind :: Fn => "method" ,
394- ty:: AssocKind :: Const => "associatedconstant" ,
395- ty:: AssocKind :: Type => "associatedtype" ,
396- }
397- } )
398- . map ( |out| {
399- (
400- Res :: Primitive ( prim_ty) ,
401- Some ( format ! ( "{}#{}.{}" , prim_ty. as_str( ) , out, item_name) ) ,
402- )
403- } )
404- } )
405- . ok_or_else ( || {
406- debug ! (
407- "returning primitive error for {}::{} in {} namespace" ,
408- prim_ty. as_str( ) ,
409- item_name,
410- ns. descr( )
411- ) ;
412- ResolutionFailure :: NotResolved {
413- module_id,
414- partial_res : Some ( Res :: Primitive ( prim_ty) ) ,
415- unresolved : item_name. to_string ( ) . into ( ) ,
416- }
417- . into ( )
418- } )
379+ prim_ty. impls ( tcx) . into_iter ( ) . find_map ( |& impl_| {
380+ tcx. associated_items ( impl_)
381+ . find_by_name_and_namespace ( tcx, Ident :: with_dummy_span ( item_name) , ns, impl_)
382+ . map ( |item| {
383+ let kind = item. kind ;
384+ let out = match kind {
385+ ty:: AssocKind :: Fn => "method" ,
386+ ty:: AssocKind :: Const => "associatedconstant" ,
387+ ty:: AssocKind :: Type => "associatedtype" ,
388+ } ;
389+ let fragment = format ! ( "{}#{}.{}" , prim_ty. as_str( ) , out, item_name) ;
390+ ( Res :: Primitive ( prim_ty) , fragment, Some ( ( kind. as_def_kind ( ) , item. def_id ) ) )
391+ } )
392+ } )
419393 }
420394
421395 /// Resolves a string as a macro.
@@ -538,7 +512,21 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
538512 resolve_primitive ( & path_root, TypeNS )
539513 . or_else ( || self . resolve_path ( & path_root, TypeNS , module_id) )
540514 . and_then ( |ty_res| {
541- self . resolve_associated_item ( ty_res, item_name, ns, module_id, extra_fragment)
515+ let ( res, fragment, side_channel) =
516+ self . resolve_associated_item ( ty_res, item_name, ns, module_id) ?;
517+ let result = if extra_fragment. is_some ( ) {
518+ let diag_res = side_channel. map_or ( res, |( k, r) | Res :: Def ( k, r) ) ;
519+ Err ( ErrorKind :: AnchorFailure ( AnchorFailure :: RustdocAnchorConflict ( diag_res) ) )
520+ } else {
521+ // HACK(jynelson): `clean` expects the type, not the associated item
522+ // but the disambiguator logic expects the associated item.
523+ // Store the kind in a side channel so that only the disambiguator logic looks at it.
524+ if let Some ( ( kind, id) ) = side_channel {
525+ self . kind_side_channel . set ( Some ( ( kind, id) ) ) ;
526+ }
527+ Ok ( ( res, Some ( fragment) ) )
528+ } ;
529+ Some ( result)
542530 } )
543531 . unwrap_or_else ( || {
544532 if ns == Namespace :: ValueNS {
@@ -554,21 +542,21 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
554542 } )
555543 }
556544
545+ /// Returns:
546+ /// - None if no associated item was found
547+ /// - Some((_, _, Some(_))) if an item was found and should go through a side channel
548+ /// - Some((_, _, None)) otherwise
557549 fn resolve_associated_item (
558550 & mut self ,
559551 root_res : Res ,
560552 item_name : Symbol ,
561553 ns : Namespace ,
562554 module_id : DefId ,
563- extra_fragment : & Option < String > ,
564- // lol this is so bad
565- ) -> Option < Result < ( Res , Option < String > ) , ErrorKind < ' static > > > {
555+ ) -> Option < ( Res , String , Option < ( DefKind , DefId ) > ) > {
566556 let tcx = self . cx . tcx ;
567557
568558 match root_res {
569- Res :: Primitive ( prim) => {
570- Some ( self . resolve_primitive_associated_item ( prim, ns, module_id, item_name) )
571- }
559+ Res :: Primitive ( prim) => self . resolve_primitive_associated_item ( prim, ns, item_name) ,
572560 Res :: Def (
573561 DefKind :: Struct
574562 | DefKind :: Union
@@ -611,17 +599,14 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
611599 ty:: AssocKind :: Const => "associatedconstant" ,
612600 ty:: AssocKind :: Type => "associatedtype" ,
613601 } ;
614- return Some ( if extra_fragment. is_some ( ) {
615- Err ( ErrorKind :: AnchorFailure ( AnchorFailure :: RustdocAnchorConflict (
616- root_res,
617- ) ) )
618- } else {
619- // HACK(jynelson): `clean` expects the type, not the associated item
620- // but the disambiguator logic expects the associated item.
621- // Store the kind in a side channel so that only the disambiguator logic looks at it.
622- self . kind_side_channel . set ( Some ( ( kind. as_def_kind ( ) , id) ) ) ;
623- Ok ( ( root_res, Some ( format ! ( "{}.{}" , out, item_name) ) ) )
624- } ) ;
602+ // HACK(jynelson): `clean` expects the type, not the associated item
603+ // but the disambiguator logic expects the associated item.
604+ // Store the kind in a side channel so that only the disambiguator logic looks at it.
605+ return Some ( (
606+ root_res,
607+ format ! ( "{}.{}" , out, item_name) ,
608+ Some ( ( kind. as_def_kind ( ) , id) ) ,
609+ ) ) ;
625610 }
626611
627612 if ns != Namespace :: ValueNS {
@@ -640,22 +625,16 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
640625 } else {
641626 def. non_enum_variant ( ) . fields . iter ( ) . find ( |item| item. ident . name == item_name)
642627 } ?;
643- Some ( if extra_fragment. is_some ( ) {
644- let res = Res :: Def (
645- if def. is_enum ( ) { DefKind :: Variant } else { DefKind :: Field } ,
646- field. did ,
647- ) ;
648- Err ( ErrorKind :: AnchorFailure ( AnchorFailure :: RustdocAnchorConflict ( res) ) )
649- } else {
650- Ok ( (
651- root_res,
652- Some ( format ! (
653- "{}.{}" ,
654- if def. is_enum( ) { "variant" } else { "structfield" } ,
655- field. ident
656- ) ) ,
657- ) )
658- } )
628+ let kind = if def. is_enum ( ) { DefKind :: Variant } else { DefKind :: Field } ;
629+ Some ( (
630+ root_res,
631+ format ! (
632+ "{}.{}" ,
633+ if def. is_enum( ) { "variant" } else { "structfield" } ,
634+ field. ident
635+ ) ,
636+ Some ( ( kind, field. did ) ) ,
637+ ) )
659638 }
660639 Res :: Def ( DefKind :: Trait , did) => tcx
661640 . associated_items ( did)
@@ -673,14 +652,8 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
673652 }
674653 } ;
675654
676- if extra_fragment. is_some ( ) {
677- Err ( ErrorKind :: AnchorFailure ( AnchorFailure :: RustdocAnchorConflict (
678- root_res,
679- ) ) )
680- } else {
681- let res = Res :: Def ( item. kind . as_def_kind ( ) , item. def_id ) ;
682- Ok ( ( res, Some ( format ! ( "{}.{}" , kind, item_name) ) ) )
683- }
655+ let res = Res :: Def ( item. kind . as_def_kind ( ) , item. def_id ) ;
656+ ( res, format ! ( "{}.{}" , kind, item_name) , None )
684657 } ) ,
685658 _ => None ,
686659 }
0 commit comments