@@ -487,6 +487,7 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
487
487
& mut self ,
488
488
path_str : & ' path str ,
489
489
ns : Namespace ,
490
+ expect_field : bool ,
490
491
module_id : DefId ,
491
492
extra_fragment : & Option < String > ,
492
493
) -> Result < ( Res , Option < String > ) , ErrorKind < ' path > > {
@@ -565,92 +566,60 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
565
566
| DefKind :: ForeignTy ,
566
567
did,
567
568
) => {
568
- debug ! ( "looking for associated item named {} for item {:?}" , item_name, did) ;
569
- // Checks if item_name belongs to `impl SomeItem`
570
- let assoc_item = tcx
571
- . inherent_impls ( did)
572
- . iter ( )
573
- . flat_map ( |& imp| {
574
- tcx. associated_items ( imp) . find_by_name_and_namespace (
575
- tcx,
576
- Ident :: with_dummy_span ( item_name) ,
577
- ns,
578
- imp,
579
- )
580
- } )
581
- . map ( |item| ( item. kind , item. def_id ) )
582
- // There should only ever be one associated item that matches from any inherent impl
583
- . next ( )
584
- // Check if item_name belongs to `impl SomeTrait for SomeItem`
585
- // FIXME(#74563): This gives precedence to `impl SomeItem`:
586
- // Although having both would be ambiguous, use impl version for compatibility's sake.
587
- // To handle that properly resolve() would have to support
588
- // something like [`ambi_fn`](<SomeStruct as SomeTrait>::ambi_fn)
589
- . or_else ( || {
590
- let kind =
591
- resolve_associated_trait_item ( did, module_id, item_name, ns, self . cx ) ;
592
- debug ! ( "got associated item kind {:?}" , kind) ;
593
- kind
594
- } ) ;
595
-
596
- if let Some ( ( kind, id) ) = assoc_item {
597
- let out = match kind {
598
- ty:: AssocKind :: Fn => "method" ,
599
- ty:: AssocKind :: Const => "associatedconstant" ,
600
- ty:: AssocKind :: Type => "associatedtype" ,
601
- } ;
602
- Some ( if extra_fragment. is_some ( ) {
603
- Err ( ErrorKind :: AnchorFailure ( AnchorFailure :: RustdocAnchorConflict ( ty_res) ) )
569
+ if expect_field {
570
+ self . resolve_variant_or_field ( item_name, did, ty_res, extra_fragment)
571
+ } else {
572
+ debug ! ( "looking for associated item named {} for item {:?}" , item_name, did) ;
573
+ // Checks if item_name belongs to `impl SomeItem`
574
+ let assoc_item = tcx
575
+ . inherent_impls ( did)
576
+ . iter ( )
577
+ . flat_map ( |& imp| {
578
+ tcx. associated_items ( imp) . find_by_name_and_namespace (
579
+ tcx,
580
+ Ident :: with_dummy_span ( item_name) ,
581
+ ns,
582
+ imp,
583
+ )
584
+ } )
585
+ . map ( |item| ( item. kind , item. def_id ) )
586
+ // There should only ever be one associated item that matches from any inherent impl
587
+ . next ( )
588
+ // Check if item_name belongs to `impl SomeTrait for SomeItem`
589
+ // FIXME(#74563): This gives precedence to `impl SomeItem`:
590
+ // Although having both would be ambiguous, use impl version for compatibility's sake.
591
+ // To handle that properly resolve() would have to support
592
+ // something like [`ambi_fn`](<SomeStruct as SomeTrait>::ambi_fn)
593
+ . or_else ( || {
594
+ let kind = resolve_associated_trait_item (
595
+ did, module_id, item_name, ns, self . cx ,
596
+ ) ;
597
+ debug ! ( "got associated item kind {:?}" , kind) ;
598
+ kind
599
+ } ) ;
600
+
601
+ if let Some ( ( kind, id) ) = assoc_item {
602
+ let out = match kind {
603
+ ty:: AssocKind :: Fn => "method" ,
604
+ ty:: AssocKind :: Const => "associatedconstant" ,
605
+ ty:: AssocKind :: Type => "associatedtype" ,
606
+ } ;
607
+ Some ( if extra_fragment. is_some ( ) {
608
+ Err ( ErrorKind :: AnchorFailure ( AnchorFailure :: RustdocAnchorConflict (
609
+ ty_res,
610
+ ) ) )
611
+ } else {
612
+ // HACK(jynelson): `clean` expects the type, not the associated item
613
+ // but the disambiguator logic expects the associated item.
614
+ // Store the kind in a side channel so that only the disambiguator logic looks at it.
615
+ self . kind_side_channel . set ( Some ( ( kind. as_def_kind ( ) , id) ) ) ;
616
+ Ok ( ( ty_res, Some ( format ! ( "{}.{}" , out, item_str) ) ) )
617
+ } )
618
+ } else if ns == Namespace :: ValueNS {
619
+ self . resolve_variant_or_field ( item_name, did, ty_res, extra_fragment)
604
620
} 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 ,
621
+ None
651
622
}
652
- } else {
653
- None
654
623
}
655
624
}
656
625
Res :: Def ( DefKind :: Trait , did) => tcx
@@ -692,6 +661,46 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
692
661
} )
693
662
}
694
663
664
+ fn resolve_variant_or_field (
665
+ & self ,
666
+ item_name : Symbol ,
667
+ did : DefId ,
668
+ ty_res : Res ,
669
+ extra_fragment : & Option < String > ,
670
+ ) -> Option < Result < ( Res , Option < String > ) , ErrorKind < ' path > > > {
671
+ debug ! ( "looking for variants or fields named {} for {:?}" , item_name, did) ;
672
+ // FIXME(jynelson): why is this different from
673
+ // `variant_field`?
674
+ match self . cx . tcx . type_of ( did) . kind ( ) {
675
+ ty:: Adt ( def, _) => {
676
+ let field = if def. is_enum ( ) {
677
+ def. all_fields ( ) . find ( |item| item. ident . name == item_name)
678
+ } else {
679
+ def. non_enum_variant ( ) . fields . iter ( ) . find ( |item| item. ident . name == item_name)
680
+ } ;
681
+ field. map ( |item| {
682
+ if extra_fragment. is_some ( ) {
683
+ let res = Res :: Def (
684
+ if def. is_enum ( ) { DefKind :: Variant } else { DefKind :: Field } ,
685
+ item. did ,
686
+ ) ;
687
+ Err ( ErrorKind :: AnchorFailure ( AnchorFailure :: RustdocAnchorConflict ( res) ) )
688
+ } else {
689
+ Ok ( (
690
+ ty_res,
691
+ Some ( format ! (
692
+ "{}.{}" ,
693
+ if def. is_enum( ) { "variant" } else { "structfield" } ,
694
+ item. ident
695
+ ) ) ,
696
+ ) )
697
+ }
698
+ } )
699
+ }
700
+ _ => None ,
701
+ }
702
+ }
703
+
695
704
/// Used for reporting better errors.
696
705
///
697
706
/// Returns whether the link resolved 'fully' in another namespace.
@@ -701,16 +710,17 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
701
710
fn check_full_res (
702
711
& mut self ,
703
712
ns : Namespace ,
713
+ expect_field : bool ,
704
714
path_str : & str ,
705
715
module_id : DefId ,
706
716
extra_fragment : & Option < String > ,
707
717
) -> Option < Res > {
708
718
// resolve() can't be used for macro namespace
709
719
let result = match ns {
710
720
Namespace :: MacroNS => self . resolve_macro ( path_str, module_id) . map_err ( ErrorKind :: from) ,
711
- Namespace :: TypeNS | Namespace :: ValueNS => {
712
- self . resolve ( path_str, ns, module_id , extra_fragment ) . map ( | ( res , _ ) | res )
713
- }
721
+ Namespace :: TypeNS | Namespace :: ValueNS => self
722
+ . resolve ( path_str, ns, expect_field , module_id , extra_fragment )
723
+ . map ( | ( res , _ ) | res ) ,
714
724
} ;
715
725
716
726
let res = match result {
@@ -1165,6 +1175,9 @@ impl LinkCollector<'_, '_> {
1165
1175
debug ! ( "saw kind {:?} with disambiguator {:?}" , kind, disambiguator) ;
1166
1176
match ( kind, disambiguator) {
1167
1177
| ( DefKind :: Const | DefKind :: ConstParam | DefKind :: AssocConst | DefKind :: AnonConst , Some ( Disambiguator :: Kind ( DefKind :: Const ) ) )
1178
+ // Fields are resolved to their parent type's Res.
1179
+ // FIXME: what about DefKind::Variant?
1180
+ | ( DefKind :: Struct | DefKind :: Enum , Some ( Disambiguator :: Kind ( DefKind :: Field ) ) )
1168
1181
// NOTE: this allows 'method' to mean both normal functions and associated functions
1169
1182
// This can't cause ambiguity because both are in the same namespace.
1170
1183
| ( DefKind :: Fn | DefKind :: AssocFn , Some ( Disambiguator :: Kind ( DefKind :: Fn ) ) )
@@ -1315,10 +1328,11 @@ impl LinkCollector<'_, '_> {
1315
1328
let path_str = & key. path_str ;
1316
1329
let base_node = key. module_id ;
1317
1330
let extra_fragment = & key. extra_fragment ;
1331
+ let expect_field = disambiguator. map_or ( false , Disambiguator :: is_field) ;
1318
1332
1319
1333
match disambiguator. map ( Disambiguator :: ns) {
1320
1334
Some ( expected_ns @ ( ValueNS | TypeNS ) ) => {
1321
- match self . resolve ( path_str, expected_ns, base_node, extra_fragment) {
1335
+ match self . resolve ( path_str, expected_ns, expect_field , base_node, extra_fragment) {
1322
1336
Ok ( res) => Some ( res) ,
1323
1337
Err ( ErrorKind :: Resolve ( box mut kind) ) => {
1324
1338
// We only looked in one namespace. Try to give a better error if possible.
@@ -1327,9 +1341,13 @@ impl LinkCollector<'_, '_> {
1327
1341
// FIXME: really it should be `resolution_failure` that does this, not `resolve_with_disambiguator`
1328
1342
// See https://github.com/rust-lang/rust/pull/76955#discussion_r493953382 for a good approach
1329
1343
for & new_ns in & [ other_ns, MacroNS ] {
1330
- if let Some ( res) =
1331
- self . check_full_res ( new_ns, path_str, base_node, extra_fragment)
1332
- {
1344
+ if let Some ( res) = self . check_full_res (
1345
+ new_ns,
1346
+ expect_field,
1347
+ path_str,
1348
+ base_node,
1349
+ extra_fragment,
1350
+ ) {
1333
1351
kind = ResolutionFailure :: WrongNamespace { res, expected_ns } ;
1334
1352
break ;
1335
1353
}
@@ -1368,7 +1386,13 @@ impl LinkCollector<'_, '_> {
1368
1386
macro_ns : self
1369
1387
. resolve_macro ( path_str, base_node)
1370
1388
. map ( |res| ( res, extra_fragment. clone ( ) ) ) ,
1371
- type_ns : match self . resolve ( path_str, TypeNS , base_node, extra_fragment) {
1389
+ type_ns : match self . resolve (
1390
+ path_str,
1391
+ TypeNS ,
1392
+ expect_field,
1393
+ base_node,
1394
+ extra_fragment,
1395
+ ) {
1372
1396
Ok ( res) => {
1373
1397
debug ! ( "got res in TypeNS: {:?}" , res) ;
1374
1398
Ok ( res)
@@ -1386,7 +1410,13 @@ impl LinkCollector<'_, '_> {
1386
1410
}
1387
1411
Err ( ErrorKind :: Resolve ( box kind) ) => Err ( kind) ,
1388
1412
} ,
1389
- value_ns : match self . resolve ( path_str, ValueNS , base_node, extra_fragment) {
1413
+ value_ns : match self . resolve (
1414
+ path_str,
1415
+ ValueNS ,
1416
+ expect_field,
1417
+ base_node,
1418
+ extra_fragment,
1419
+ ) {
1390
1420
Ok ( res) => Ok ( res) ,
1391
1421
Err ( ErrorKind :: AnchorFailure ( msg) ) => {
1392
1422
anchor_failure (
@@ -1463,9 +1493,13 @@ impl LinkCollector<'_, '_> {
1463
1493
Err ( mut kind) => {
1464
1494
// `resolve_macro` only looks in the macro namespace. Try to give a better error if possible.
1465
1495
for & ns in & [ TypeNS , ValueNS ] {
1466
- if let Some ( res) =
1467
- self . check_full_res ( ns, path_str, base_node, extra_fragment)
1468
- {
1496
+ if let Some ( res) = self . check_full_res (
1497
+ ns,
1498
+ expect_field,
1499
+ path_str,
1500
+ base_node,
1501
+ extra_fragment,
1502
+ ) {
1469
1503
kind =
1470
1504
ResolutionFailure :: WrongNamespace { res, expected_ns : MacroNS } ;
1471
1505
break ;
@@ -1542,6 +1576,7 @@ impl Disambiguator {
1542
1576
"enum" => Kind ( DefKind :: Enum ) ,
1543
1577
"trait" => Kind ( DefKind :: Trait ) ,
1544
1578
"union" => Kind ( DefKind :: Union ) ,
1579
+ "field" => Kind ( DefKind :: Field ) ,
1545
1580
"module" | "mod" => Kind ( DefKind :: Mod ) ,
1546
1581
"const" | "constant" => Kind ( DefKind :: Const ) ,
1547
1582
"static" => Kind ( DefKind :: Static ) ,
@@ -1604,11 +1639,22 @@ impl Disambiguator {
1604
1639
Suggestion :: Prefix ( prefix)
1605
1640
}
1606
1641
1642
+ fn is_field ( self ) -> bool {
1643
+ self == Self :: Kind ( DefKind :: Field )
1644
+ }
1645
+
1607
1646
fn ns ( self ) -> Namespace {
1608
1647
match self {
1609
1648
Self :: Namespace ( n) => n,
1610
1649
Self :: Kind ( k) => {
1611
- k. ns ( ) . expect ( "only DefKinds with a valid namespace can be disambiguators" )
1650
+ match k {
1651
+ // Fields technically don't have a namespace, but we treat
1652
+ // fields as if they belong to the value namespace.
1653
+ DefKind :: Field => TypeNS ,
1654
+ _ => {
1655
+ k. ns ( ) . expect ( "only DefKinds with a valid namespace can be disambiguators" )
1656
+ }
1657
+ }
1612
1658
}
1613
1659
Self :: Primitive => TypeNS ,
1614
1660
}
@@ -1795,9 +1841,13 @@ fn resolution_failure(
1795
1841
} ;
1796
1842
name = start;
1797
1843
for & ns in & [ TypeNS , ValueNS , MacroNS ] {
1798
- if let Some ( res) =
1799
- collector. check_full_res ( ns, & start, module_id, & None )
1800
- {
1844
+ if let Some ( res) = collector. check_full_res (
1845
+ ns,
1846
+ disambiguator. map_or ( false , Disambiguator :: is_field) ,
1847
+ & start,
1848
+ module_id,
1849
+ & None ,
1850
+ ) {
1801
1851
debug ! ( "found partial_res={:?}" , res) ;
1802
1852
* partial_res = Some ( res) ;
1803
1853
* unresolved = end. into ( ) ;
0 commit comments