@@ -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)
@@ -646,32 +682,8 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
646682 if ns != Namespace :: ValueNS {
647683 return Vec :: new ( ) ;
648684 }
649- debug ! ( "looking for fields named {item_name} for {did:?}" ) ;
650- // FIXME: this doesn't really belong in `associated_item` (maybe `variant_field` is better?)
651- // NOTE: it's different from variant_field because it only resolves struct fields,
652- // not variant fields (2 path segments, not 3).
653- //
654- // We need to handle struct (and union) fields in this code because
655- // syntactically their paths are identical to associated item paths:
656- // `module::Type::field` and `module::Type::Assoc`.
657- //
658- // On the other hand, variant fields can't be mistaken for associated
659- // items because they look like this: `module::Type::Variant::field`.
660- //
661- // Variants themselves don't need to be handled here, even though
662- // they also look like associated items (`module::Type::Variant`),
663- // because they are real Rust syntax (unlike the intra-doc links
664- // field syntax) and are handled by the compiler's resolver.
665- let def = match tcx. type_of ( did) . instantiate_identity ( ) . kind ( ) {
666- ty:: Adt ( def, _) if !def. is_enum ( ) => def,
667- _ => return Vec :: new ( ) ,
668- } ;
669- def. non_enum_variant ( )
670- . fields
671- . iter ( )
672- . filter ( |field| field. name == item_name)
673- . map ( |field| ( root_res, field. did ) )
674- . collect :: < Vec < _ > > ( )
685+
686+ search_for_field ( )
675687 }
676688 Res :: Def ( DefKind :: Trait , did) => filter_assoc_items_by_name_and_namespace (
677689 tcx,
@@ -1297,7 +1309,7 @@ impl LinkCollector<'_, '_> {
12971309
12981310 match disambiguator. map ( Disambiguator :: ns) {
12991311 Some ( expected_ns) => {
1300- match self . resolve ( path_str, expected_ns, item_id, module_id) {
1312+ match self . resolve ( path_str, expected_ns, disambiguator , item_id, module_id) {
13011313 Ok ( candidates) => candidates,
13021314 Err ( err) => {
13031315 // We only looked in one namespace. Try to give a better error if possible.
@@ -1306,8 +1318,9 @@ impl LinkCollector<'_, '_> {
13061318 let mut err = ResolutionFailure :: NotResolved ( err) ;
13071319 for other_ns in [ TypeNS , ValueNS , MacroNS ] {
13081320 if other_ns != expected_ns {
1309- if let Ok ( & [ res, ..] ) =
1310- self . resolve ( path_str, other_ns, item_id, module_id) . as_deref ( )
1321+ if let Ok ( & [ res, ..] ) = self
1322+ . resolve ( path_str, other_ns, None , item_id, module_id)
1323+ . as_deref ( )
13111324 {
13121325 err = ResolutionFailure :: WrongNamespace {
13131326 res : full_res ( self . cx . tcx , res) ,
@@ -1327,7 +1340,7 @@ impl LinkCollector<'_, '_> {
13271340 None => {
13281341 // Try everything!
13291342 let mut candidate = |ns| {
1330- self . resolve ( path_str, ns, item_id, module_id)
1343+ self . resolve ( path_str, ns, None , item_id, module_id)
13311344 . map_err ( ResolutionFailure :: NotResolved )
13321345 } ;
13331346
@@ -1531,6 +1544,8 @@ impl Disambiguator {
15311544 } ) ,
15321545 "function" | "fn" | "method" => Kind ( DefKind :: Fn ) ,
15331546 "derive" => Kind ( DefKind :: Macro ( MacroKind :: Derive ) ) ,
1547+ "field" => Kind ( DefKind :: Field ) ,
1548+ "variant" => Kind ( DefKind :: Variant ) ,
15341549 "type" => NS ( Namespace :: TypeNS ) ,
15351550 "value" => NS ( Namespace :: ValueNS ) ,
15361551 "macro" => NS ( Namespace :: MacroNS ) ,
@@ -1569,6 +1584,8 @@ impl Disambiguator {
15691584 fn ns ( self ) -> Namespace {
15701585 match self {
15711586 Self :: Namespace ( n) => n,
1587+ // for purposes of link resolution, fields are in the value namespace.
1588+ Self :: Kind ( DefKind :: Field ) => ValueNS ,
15721589 Self :: Kind ( k) => {
15731590 k. ns ( ) . expect ( "only DefKinds with a valid namespace can be disambiguators" )
15741591 }
@@ -1603,8 +1620,6 @@ enum Suggestion {
16031620 Function ,
16041621 /// `m!`
16051622 Macro ,
1606- /// `foo` without any disambiguator
1607- RemoveDisambiguator ,
16081623}
16091624
16101625impl Suggestion {
@@ -1613,7 +1628,6 @@ impl Suggestion {
16131628 Self :: Prefix ( x) => format ! ( "prefix with `{x}@`" ) . into ( ) ,
16141629 Self :: Function => "add parentheses" . into ( ) ,
16151630 Self :: Macro => "add an exclamation mark" . into ( ) ,
1616- Self :: RemoveDisambiguator => "remove the disambiguator" . into ( ) ,
16171631 }
16181632 }
16191633
@@ -1623,13 +1637,11 @@ impl Suggestion {
16231637 Self :: Prefix ( prefix) => format ! ( "{prefix}@{path_str}" ) ,
16241638 Self :: Function => format ! ( "{path_str}()" ) ,
16251639 Self :: Macro => format ! ( "{path_str}!" ) ,
1626- Self :: RemoveDisambiguator => path_str. into ( ) ,
16271640 }
16281641 }
16291642
16301643 fn as_help_span (
16311644 & self ,
1632- path_str : & str ,
16331645 ori_link : & str ,
16341646 sp : rustc_span:: Span ,
16351647 ) -> Vec < ( rustc_span:: Span , String ) > {
@@ -1677,7 +1689,6 @@ impl Suggestion {
16771689 }
16781690 sugg
16791691 }
1680- Self :: RemoveDisambiguator => vec ! [ ( sp, path_str. into( ) ) ] ,
16811692 }
16821693 }
16831694}
@@ -1826,7 +1837,9 @@ fn resolution_failure(
18261837 } ;
18271838 name = start;
18281839 for ns in [ TypeNS , ValueNS , MacroNS ] {
1829- if let Ok ( v_res) = collector. resolve ( start, ns, item_id, module_id) {
1840+ if let Ok ( v_res) =
1841+ collector. resolve ( start, ns, None , item_id, module_id)
1842+ {
18301843 debug ! ( "found partial_res={v_res:?}" ) ;
18311844 if let Some ( & res) = v_res. first ( ) {
18321845 * partial_res = Some ( full_res ( tcx, res) ) ;
@@ -2164,7 +2177,7 @@ fn suggest_disambiguator(
21642177 } ;
21652178
21662179 if let ( Some ( sp) , Some ( ori_link) ) = ( sp, ori_link) {
2167- let mut spans = suggestion. as_help_span ( path_str , ori_link, sp) ;
2180+ let mut spans = suggestion. as_help_span ( ori_link, sp) ;
21682181 if spans. len ( ) > 1 {
21692182 diag. multipart_suggestion ( help, spans, Applicability :: MaybeIncorrect ) ;
21702183 } else {
0 commit comments