@@ -368,55 +368,28 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
368
368
}
369
369
370
370
/// 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.
374
371
fn resolve_primitive_associated_item (
375
372
& self ,
376
373
prim_ty : PrimitiveType ,
377
374
ns : Namespace ,
378
- module_id : DefId ,
379
375
item_name : Symbol ,
380
- item_str : & ' path str ,
381
- ) -> Result < ( Res , Option < String > ) , ErrorKind < ' path > > {
376
+ ) -> Option < ( Res , String , Option < ( DefKind , DefId ) > ) > {
382
377
let tcx = self . cx . tcx ;
383
378
384
- prim_ty
385
- . impls ( tcx)
386
- . into_iter ( )
387
- . find_map ( |& impl_| {
388
- tcx. associated_items ( impl_)
389
- . find_by_name_and_namespace ( tcx, Ident :: with_dummy_span ( item_name) , ns, impl_)
390
- . map ( |item| {
391
- let kind = item. kind ;
392
- self . kind_side_channel . set ( Some ( ( kind. as_def_kind ( ) , item. def_id ) ) ) ;
393
- match kind {
394
- ty:: AssocKind :: Fn => "method" ,
395
- ty:: AssocKind :: Const => "associatedconstant" ,
396
- ty:: AssocKind :: Type => "associatedtype" ,
397
- }
398
- } )
399
- . map ( |out| {
400
- (
401
- Res :: Primitive ( prim_ty) ,
402
- Some ( format ! ( "{}#{}.{}" , prim_ty. as_str( ) , out, item_str) ) ,
403
- )
404
- } )
405
- } )
406
- . ok_or_else ( || {
407
- debug ! (
408
- "returning primitive error for {}::{} in {} namespace" ,
409
- prim_ty. as_str( ) ,
410
- item_name,
411
- ns. descr( )
412
- ) ;
413
- ResolutionFailure :: NotResolved {
414
- module_id,
415
- partial_res : Some ( Res :: Primitive ( prim_ty) ) ,
416
- unresolved : item_str. into ( ) ,
417
- }
418
- . into ( )
419
- } )
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
+ } )
420
393
}
421
394
422
395
/// Resolves a string as a macro.
@@ -490,8 +463,6 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
490
463
module_id : DefId ,
491
464
extra_fragment : & Option < String > ,
492
465
) -> Result < ( Res , Option < String > ) , ErrorKind < ' path > > {
493
- let tcx = self . cx . tcx ;
494
-
495
466
if let Some ( res) = self . resolve_path ( path_str, ns, module_id) {
496
467
match res {
497
468
// FIXME(#76467): make this fallthrough to lookup the associated
@@ -534,29 +505,58 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
534
505
}
535
506
} ) ?;
536
507
537
- // FIXME: are these both necessary?
538
- let ty_res = if let Some ( ty_res) = resolve_primitive ( & path_root, TypeNS )
508
+ // FIXME(#83862): this arbitrarily gives precedence to primitives over modules to support
509
+ // links to primitives when `#[doc(primitive)]` is present. It should give an ambiguity
510
+ // error instead and special case *only* modules with `#[doc(primitive)]`, not all
511
+ // primitives.
512
+ resolve_primitive ( & path_root, TypeNS )
539
513
. or_else ( || self . resolve_path ( & path_root, TypeNS , module_id) )
540
- {
541
- ty_res
542
- } else {
543
- // FIXME: this is duplicated on the end of this function.
544
- return if ns == Namespace :: ValueNS {
545
- self . variant_field ( path_str, module_id)
546
- } else {
547
- Err ( ResolutionFailure :: NotResolved {
548
- module_id,
549
- partial_res : None ,
550
- unresolved : path_root. into ( ) ,
514
+ . and_then ( |ty_res| {
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)
530
+ } )
531
+ . unwrap_or_else ( || {
532
+ if ns == Namespace :: ValueNS {
533
+ self . variant_field ( path_str, module_id)
534
+ } else {
535
+ Err ( ResolutionFailure :: NotResolved {
536
+ module_id,
537
+ partial_res : None ,
538
+ unresolved : path_root. into ( ) ,
539
+ }
540
+ . into ( ) )
551
541
}
552
- . into ( ) )
553
- } ;
554
- } ;
542
+ } )
543
+ }
544
+
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
549
+ fn resolve_associated_item (
550
+ & mut self ,
551
+ root_res : Res ,
552
+ item_name : Symbol ,
553
+ ns : Namespace ,
554
+ module_id : DefId ,
555
+ ) -> Option < ( Res , String , Option < ( DefKind , DefId ) > ) > {
556
+ let tcx = self . cx . tcx ;
555
557
556
- let res = match ty_res {
557
- Res :: Primitive ( prim) => Some (
558
- self . resolve_primitive_associated_item ( prim, ns, module_id, item_name, item_str) ,
559
- ) ,
558
+ match root_res {
559
+ Res :: Primitive ( prim) => self . resolve_primitive_associated_item ( prim, ns, item_name) ,
560
560
Res :: Def (
561
561
DefKind :: Struct
562
562
| DefKind :: Union
@@ -599,59 +599,42 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
599
599
ty:: AssocKind :: Const => "associatedconstant" ,
600
600
ty:: AssocKind :: Type => "associatedtype" ,
601
601
} ;
602
- Some ( if extra_fragment. is_some ( ) {
603
- Err ( ErrorKind :: AnchorFailure ( AnchorFailure :: RustdocAnchorConflict ( ty_res) ) )
604
- } else {
605
- // HACK(jynelson): `clean` expects the type, not the associated item
606
- // but the disambiguator logic expects the associated item.
607
- // Store the kind in a side channel so that only the disambiguator logic looks at it.
608
- self . kind_side_channel . set ( Some ( ( kind. as_def_kind ( ) , id) ) ) ;
609
- Ok ( ( ty_res, Some ( format ! ( "{}.{}" , out, item_str) ) ) )
610
- } )
611
- } else if ns == Namespace :: ValueNS {
612
- debug ! ( "looking for variants or fields named {} for {:?}" , item_name, did) ;
613
- // FIXME(jynelson): why is this different from
614
- // `variant_field`?
615
- match tcx. type_of ( did) . kind ( ) {
616
- ty:: Adt ( def, _) => {
617
- let field = if def. is_enum ( ) {
618
- def. all_fields ( ) . find ( |item| item. ident . name == item_name)
619
- } else {
620
- def. non_enum_variant ( )
621
- . fields
622
- . iter ( )
623
- . find ( |item| item. ident . name == item_name)
624
- } ;
625
- field. map ( |item| {
626
- if extra_fragment. is_some ( ) {
627
- let res = Res :: Def (
628
- if def. is_enum ( ) {
629
- DefKind :: Variant
630
- } else {
631
- DefKind :: Field
632
- } ,
633
- item. did ,
634
- ) ;
635
- Err ( ErrorKind :: AnchorFailure (
636
- AnchorFailure :: RustdocAnchorConflict ( res) ,
637
- ) )
638
- } else {
639
- Ok ( (
640
- ty_res,
641
- Some ( format ! (
642
- "{}.{}" ,
643
- if def. is_enum( ) { "variant" } else { "structfield" } ,
644
- item. ident
645
- ) ) ,
646
- ) )
647
- }
648
- } )
649
- }
650
- _ => None ,
651
- }
652
- } else {
653
- None
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
+ ) ) ;
610
+ }
611
+
612
+ if ns != Namespace :: ValueNS {
613
+ return None ;
654
614
}
615
+ debug ! ( "looking for variants or fields named {} for {:?}" , item_name, did) ;
616
+ // FIXME: this doesn't really belong in `associated_item` (maybe `variant_field` is better?)
617
+ // NOTE: it's different from variant_field because it resolves fields and variants,
618
+ // not variant fields (2 path segments, not 3).
619
+ let def = match tcx. type_of ( did) . kind ( ) {
620
+ ty:: Adt ( def, _) => def,
621
+ _ => return None ,
622
+ } ;
623
+ let field = if def. is_enum ( ) {
624
+ def. all_fields ( ) . find ( |item| item. ident . name == item_name)
625
+ } else {
626
+ def. non_enum_variant ( ) . fields . iter ( ) . find ( |item| item. ident . name == item_name)
627
+ } ?;
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
+ ) )
655
638
}
656
639
Res :: Def ( DefKind :: Trait , did) => tcx
657
640
. associated_items ( did)
@@ -669,27 +652,11 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
669
652
}
670
653
} ;
671
654
672
- if extra_fragment. is_some ( ) {
673
- Err ( ErrorKind :: AnchorFailure ( AnchorFailure :: RustdocAnchorConflict ( ty_res) ) )
674
- } else {
675
- let res = Res :: Def ( item. kind . as_def_kind ( ) , item. def_id ) ;
676
- Ok ( ( res, Some ( format ! ( "{}.{}" , kind, item_str) ) ) )
677
- }
655
+ let res = Res :: Def ( item. kind . as_def_kind ( ) , item. def_id ) ;
656
+ ( res, format ! ( "{}.{}" , kind, item_name) , None )
678
657
} ) ,
679
658
_ => None ,
680
- } ;
681
- res. unwrap_or_else ( || {
682
- if ns == Namespace :: ValueNS {
683
- self . variant_field ( path_str, module_id)
684
- } else {
685
- Err ( ResolutionFailure :: NotResolved {
686
- module_id,
687
- partial_res : Some ( ty_res) ,
688
- unresolved : item_str. into ( ) ,
689
- }
690
- . into ( ) )
691
- }
692
- } )
659
+ }
693
660
}
694
661
695
662
/// Used for reporting better errors.
0 commit comments