@@ -110,7 +110,6 @@ impl Res {
110110
111111 let prefix = match kind {
112112 DefKind :: Fn | DefKind :: AssocFn => return Suggestion :: Function ,
113- DefKind :: Field => return Suggestion :: RemoveDisambiguator ,
114113 DefKind :: Macro ( MacroKind :: Bang ) => return Suggestion :: Macro ,
115114
116115 DefKind :: Macro ( MacroKind :: Derive ) => "derive" ,
@@ -123,6 +122,8 @@ impl Res {
123122 "const"
124123 }
125124 DefKind :: Static { .. } => "static" ,
125+ DefKind :: Field => "field" ,
126+ DefKind :: Variant | DefKind :: Ctor ( ..) => "variant" ,
126127 // Now handle things that don't have a specific disambiguator
127128 _ => match kind
128129 . ns ( )
@@ -415,6 +416,7 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
415416 & mut self ,
416417 path_str : & ' path str ,
417418 ns : Namespace ,
419+ disambiguator : Option < Disambiguator > ,
418420 item_id : DefId ,
419421 module_id : DefId ,
420422 ) -> Result < Vec < ( Res , Option < DefId > ) > , UnresolvedPath < ' path > > {
@@ -454,7 +456,7 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
454456 match resolve_primitive ( path_root, TypeNS )
455457 . or_else ( || self . resolve_path ( path_root, TypeNS , item_id, module_id) )
456458 . map ( |ty_res| {
457- self . resolve_associated_item ( ty_res, item_name, ns, module_id)
459+ self . resolve_associated_item ( ty_res, item_name, ns, disambiguator , module_id)
458460 . into_iter ( )
459461 . map ( |( res, def_id) | ( res, Some ( def_id) ) )
460462 . collect :: < Vec < _ > > ( )
@@ -557,6 +559,7 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
557559 root_res : Res ,
558560 item_name : Symbol ,
559561 ns : Namespace ,
562+ disambiguator : Option < Disambiguator > ,
560563 module_id : DefId ,
561564 ) -> Vec < ( Res , DefId ) > {
562565 let tcx = self . cx . tcx ;
@@ -583,7 +586,7 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
583586 // FIXME: if the associated item is defined directly on the type alias,
584587 // it will show up on its documentation page, we should link there instead.
585588 let Some ( res) = self . def_id_to_res ( did) else { return Vec :: new ( ) } ;
586- self . resolve_associated_item ( res, item_name, ns, module_id)
589+ self . resolve_associated_item ( res, item_name, ns, disambiguator , module_id)
587590 }
588591 Res :: Def (
589592 def_kind @ ( DefKind :: Struct | DefKind :: Union | DefKind :: Enum | DefKind :: ForeignTy ) ,
@@ -604,6 +607,39 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
604607 }
605608 }
606609
610+ let search_for_field = || {
611+ let ( DefKind :: Struct | DefKind :: Union ) = def_kind else { return vec ! [ ] } ;
612+ debug ! ( "looking for fields named {item_name} for {did:?}" ) ;
613+ // FIXME: this doesn't really belong in `associated_item` (maybe `variant_field` is better?)
614+ // NOTE: it's different from variant_field because it only resolves struct fields,
615+ // not variant fields (2 path segments, not 3).
616+ //
617+ // We need to handle struct (and union) fields in this code because
618+ // syntactically their paths are identical to associated item paths:
619+ // `module::Type::field` and `module::Type::Assoc`.
620+ //
621+ // On the other hand, variant fields can't be mistaken for associated
622+ // items because they look like this: `module::Type::Variant::field`.
623+ //
624+ // Variants themselves don't need to be handled here, even though
625+ // they also look like associated items (`module::Type::Variant`),
626+ // because they are real Rust syntax (unlike the intra-doc links
627+ // field syntax) and are handled by the compiler's resolver.
628+ let ty:: Adt ( def, _) = tcx. type_of ( did) . instantiate_identity ( ) . kind ( ) else {
629+ unreachable ! ( )
630+ } ;
631+ def. non_enum_variant ( )
632+ . fields
633+ . iter ( )
634+ . filter ( |field| field. name == item_name)
635+ . map ( |field| ( root_res, field. did ) )
636+ . collect :: < Vec < _ > > ( )
637+ } ;
638+
639+ if let Some ( Disambiguator :: Kind ( DefKind :: Field ) ) = disambiguator {
640+ return search_for_field ( ) ;
641+ }
642+
607643 // Checks if item_name belongs to `impl SomeItem`
608644 let mut assoc_items: Vec < _ > = tcx
609645 . inherent_impls ( did)
@@ -647,32 +683,8 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
647683 if ns != Namespace :: ValueNS {
648684 return Vec :: new ( ) ;
649685 }
650- debug ! ( "looking for fields named {item_name} for {did:?}" ) ;
651- // FIXME: this doesn't really belong in `associated_item` (maybe `variant_field` is better?)
652- // NOTE: it's different from variant_field because it only resolves struct fields,
653- // not variant fields (2 path segments, not 3).
654- //
655- // We need to handle struct (and union) fields in this code because
656- // syntactically their paths are identical to associated item paths:
657- // `module::Type::field` and `module::Type::Assoc`.
658- //
659- // On the other hand, variant fields can't be mistaken for associated
660- // items because they look like this: `module::Type::Variant::field`.
661- //
662- // Variants themselves don't need to be handled here, even though
663- // they also look like associated items (`module::Type::Variant`),
664- // because they are real Rust syntax (unlike the intra-doc links
665- // field syntax) and are handled by the compiler's resolver.
666- let def = match tcx. type_of ( did) . instantiate_identity ( ) . kind ( ) {
667- ty:: Adt ( def, _) if !def. is_enum ( ) => def,
668- _ => return Vec :: new ( ) ,
669- } ;
670- def. non_enum_variant ( )
671- . fields
672- . iter ( )
673- . filter ( |field| field. name == item_name)
674- . map ( |field| ( root_res, field. did ) )
675- . collect :: < Vec < _ > > ( )
686+
687+ search_for_field ( )
676688 }
677689 Res :: Def ( DefKind :: Trait , did) => filter_assoc_items_by_name_and_namespace (
678690 tcx,
@@ -1298,7 +1310,7 @@ impl LinkCollector<'_, '_> {
12981310
12991311 match disambiguator. map ( Disambiguator :: ns) {
13001312 Some ( expected_ns) => {
1301- match self . resolve ( path_str, expected_ns, item_id, module_id) {
1313+ match self . resolve ( path_str, expected_ns, disambiguator , item_id, module_id) {
13021314 Ok ( candidates) => candidates,
13031315 Err ( err) => {
13041316 // We only looked in one namespace. Try to give a better error if possible.
@@ -1307,8 +1319,9 @@ impl LinkCollector<'_, '_> {
13071319 let mut err = ResolutionFailure :: NotResolved ( err) ;
13081320 for other_ns in [ TypeNS , ValueNS , MacroNS ] {
13091321 if other_ns != expected_ns {
1310- if let Ok ( & [ res, ..] ) =
1311- self . resolve ( path_str, other_ns, item_id, module_id) . as_deref ( )
1322+ if let Ok ( & [ res, ..] ) = self
1323+ . resolve ( path_str, other_ns, None , item_id, module_id)
1324+ . as_deref ( )
13121325 {
13131326 err = ResolutionFailure :: WrongNamespace {
13141327 res : full_res ( self . cx . tcx , res) ,
@@ -1328,7 +1341,7 @@ impl LinkCollector<'_, '_> {
13281341 None => {
13291342 // Try everything!
13301343 let mut candidate = |ns| {
1331- self . resolve ( path_str, ns, item_id, module_id)
1344+ self . resolve ( path_str, ns, None , item_id, module_id)
13321345 . map_err ( ResolutionFailure :: NotResolved )
13331346 } ;
13341347
@@ -1532,6 +1545,8 @@ impl Disambiguator {
15321545 } ) ,
15331546 "function" | "fn" | "method" => Kind ( DefKind :: Fn ) ,
15341547 "derive" => Kind ( DefKind :: Macro ( MacroKind :: Derive ) ) ,
1548+ "field" => Kind ( DefKind :: Field ) ,
1549+ "variant" => Kind ( DefKind :: Variant ) ,
15351550 "type" => NS ( Namespace :: TypeNS ) ,
15361551 "value" => NS ( Namespace :: ValueNS ) ,
15371552 "macro" => NS ( Namespace :: MacroNS ) ,
@@ -1570,6 +1585,8 @@ impl Disambiguator {
15701585 fn ns ( self ) -> Namespace {
15711586 match self {
15721587 Self :: Namespace ( n) => n,
1588+ // for purposes of link resolution, fields are in the value namespace.
1589+ Self :: Kind ( DefKind :: Field ) => ValueNS ,
15731590 Self :: Kind ( k) => {
15741591 k. ns ( ) . expect ( "only DefKinds with a valid namespace can be disambiguators" )
15751592 }
@@ -1604,8 +1621,6 @@ enum Suggestion {
16041621 Function ,
16051622 /// `m!`
16061623 Macro ,
1607- /// `foo` without any disambiguator
1608- RemoveDisambiguator ,
16091624}
16101625
16111626impl Suggestion {
@@ -1614,7 +1629,6 @@ impl Suggestion {
16141629 Self :: Prefix ( x) => format ! ( "prefix with `{x}@`" ) . into ( ) ,
16151630 Self :: Function => "add parentheses" . into ( ) ,
16161631 Self :: Macro => "add an exclamation mark" . into ( ) ,
1617- Self :: RemoveDisambiguator => "remove the disambiguator" . into ( ) ,
16181632 }
16191633 }
16201634
@@ -1624,13 +1638,11 @@ impl Suggestion {
16241638 Self :: Prefix ( prefix) => format ! ( "{prefix}@{path_str}" ) ,
16251639 Self :: Function => format ! ( "{path_str}()" ) ,
16261640 Self :: Macro => format ! ( "{path_str}!" ) ,
1627- Self :: RemoveDisambiguator => path_str. into ( ) ,
16281641 }
16291642 }
16301643
16311644 fn as_help_span (
16321645 & self ,
1633- path_str : & str ,
16341646 ori_link : & str ,
16351647 sp : rustc_span:: Span ,
16361648 ) -> Vec < ( rustc_span:: Span , String ) > {
@@ -1678,7 +1690,6 @@ impl Suggestion {
16781690 }
16791691 sugg
16801692 }
1681- Self :: RemoveDisambiguator => vec ! [ ( sp, path_str. into( ) ) ] ,
16821693 }
16831694 }
16841695}
@@ -1827,7 +1838,9 @@ fn resolution_failure(
18271838 } ;
18281839 name = start;
18291840 for ns in [ TypeNS , ValueNS , MacroNS ] {
1830- if let Ok ( v_res) = collector. resolve ( start, ns, item_id, module_id) {
1841+ if let Ok ( v_res) =
1842+ collector. resolve ( start, ns, None , item_id, module_id)
1843+ {
18311844 debug ! ( "found partial_res={v_res:?}" ) ;
18321845 if let Some ( & res) = v_res. first ( ) {
18331846 * partial_res = Some ( full_res ( tcx, res) ) ;
@@ -2165,7 +2178,7 @@ fn suggest_disambiguator(
21652178 } ;
21662179
21672180 if let ( Some ( sp) , Some ( ori_link) ) = ( sp, ori_link) {
2168- let mut spans = suggestion. as_help_span ( path_str , ori_link, sp) ;
2181+ let mut spans = suggestion. as_help_span ( ori_link, sp) ;
21692182 if spans. len ( ) > 1 {
21702183 diag. multipart_suggestion ( help, spans, Applicability :: MaybeIncorrect ) ;
21712184 } else {
0 commit comments