@@ -10,7 +10,7 @@ use rustc_hir::def::{
10
10
PerNS ,
11
11
} ;
12
12
use rustc_hir:: def_id:: { CrateNum , DefId , CRATE_DEF_ID } ;
13
- use rustc_middle:: ty:: { DefIdTree , Ty , TyCtxt , TyKind } ;
13
+ use rustc_middle:: ty:: { DefIdTree , Ty , TyCtxt } ;
14
14
use rustc_middle:: { bug, span_bug, ty} ;
15
15
use rustc_session:: lint:: Lint ;
16
16
use rustc_span:: hygiene:: MacroKind ;
@@ -26,7 +26,8 @@ use std::fmt::Write;
26
26
use std:: mem;
27
27
use std:: ops:: Range ;
28
28
29
- use crate :: clean:: { self , utils:: find_nearest_parent_module, Crate , Item , ItemLink , PrimitiveType } ;
29
+ use crate :: clean:: { self , utils:: find_nearest_parent_module} ;
30
+ use crate :: clean:: { Crate , Item , ItemId , ItemLink , PrimitiveType } ;
30
31
use crate :: core:: DocContext ;
31
32
use crate :: html:: markdown:: { markdown_links, MarkdownLink } ;
32
33
use crate :: lint:: { BROKEN_INTRA_DOC_LINKS , PRIVATE_INTRA_DOC_LINKS } ;
@@ -177,6 +178,8 @@ enum ResolutionFailure<'a> {
177
178
/// The link failed to resolve. [`resolution_failure`] should look to see if there's
178
179
/// a more helpful error that can be given.
179
180
NotResolved {
181
+ /// Item on which the link is resolved, used for resolving `Self`.
182
+ item_id : ItemId ,
180
183
/// The scope the link was resolved in.
181
184
module_id : DefId ,
182
185
/// If part of the link resolved, this has the `Res`.
@@ -343,6 +346,7 @@ impl ItemFragment {
343
346
344
347
#[ derive( Clone , Debug , Hash , PartialEq , Eq ) ]
345
348
struct ResolutionInfo {
349
+ item_id : ItemId ,
346
350
module_id : DefId ,
347
351
dis : Option < Disambiguator > ,
348
352
path_str : String ,
@@ -384,10 +388,12 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
384
388
fn variant_field < ' path > (
385
389
& self ,
386
390
path_str : & ' path str ,
391
+ item_id : ItemId ,
387
392
module_id : DefId ,
388
393
) -> Result < ( Res , Option < ItemFragment > ) , ErrorKind < ' path > > {
389
394
let tcx = self . cx . tcx ;
390
395
let no_res = || ResolutionFailure :: NotResolved {
396
+ item_id,
391
397
module_id,
392
398
partial_res : None ,
393
399
unresolved : path_str. into ( ) ,
@@ -410,13 +416,7 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
410
416
// If there's no third component, we saw `[a::b]` before and it failed to resolve.
411
417
// So there's no partial res.
412
418
. ok_or_else ( no_res) ?;
413
- let ty_res = self
414
- . cx
415
- . enter_resolver ( |resolver| {
416
- resolver. resolve_str_path_error ( DUMMY_SP , & path, TypeNS , module_id)
417
- } )
418
- . and_then ( |( _, res) | res. try_into ( ) )
419
- . map_err ( |( ) | no_res ( ) ) ?;
419
+ let ty_res = self . resolve_path ( & path, TypeNS , item_id, module_id) . ok_or_else ( no_res) ?;
420
420
421
421
match ty_res {
422
422
Res :: Def ( DefKind :: Enum , did) => {
@@ -437,6 +437,7 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
437
437
Ok ( ( ty_res, Some ( ItemFragment ( FragmentKind :: VariantField , field. did ) ) ) )
438
438
} else {
439
439
Err ( ResolutionFailure :: NotResolved {
440
+ item_id,
440
441
module_id,
441
442
partial_res : Some ( Res :: Def ( DefKind :: Enum , def. did ) ) ,
442
443
unresolved : variant_field_name. to_string ( ) . into ( ) ,
@@ -448,6 +449,7 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
448
449
}
449
450
}
450
451
_ => Err ( ResolutionFailure :: NotResolved {
452
+ item_id,
451
453
module_id,
452
454
partial_res : Some ( ty_res) ,
453
455
unresolved : variant_name. to_string ( ) . into ( ) ,
@@ -481,6 +483,7 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
481
483
fn resolve_macro (
482
484
& self ,
483
485
path_str : & ' a str ,
486
+ item_id : ItemId ,
484
487
module_id : DefId ,
485
488
) -> Result < Res , ResolutionFailure < ' a > > {
486
489
self . cx . enter_resolver ( |resolver| {
@@ -499,19 +502,67 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
499
502
return Ok ( res. try_into ( ) . unwrap ( ) ) ;
500
503
}
501
504
Err ( ResolutionFailure :: NotResolved {
505
+ item_id,
502
506
module_id,
503
507
partial_res : None ,
504
508
unresolved : path_str. into ( ) ,
505
509
} )
506
510
} )
507
511
}
508
512
513
+ fn resolve_self_ty ( & self , path_str : & str , ns : Namespace , item_id : ItemId ) -> Option < Res > {
514
+ if ns != TypeNS || path_str != "Self" {
515
+ return None ;
516
+ }
517
+
518
+ let self_id = match item_id. as_def_id ( ) {
519
+ None => None ,
520
+ Some ( did)
521
+ if ( matches ! ( self . cx. tcx. def_kind( did) , DefKind :: Field )
522
+ && matches ! (
523
+ self . cx. tcx. def_kind( self . cx. tcx. parent( did) . unwrap( ) ) ,
524
+ DefKind :: Variant
525
+ ) ) =>
526
+ {
527
+ self . cx . tcx . parent ( did) . and_then ( |item_id| self . cx . tcx . parent ( item_id) )
528
+ }
529
+ Some ( did)
530
+ if matches ! (
531
+ self . cx. tcx. def_kind( did) ,
532
+ DefKind :: AssocConst
533
+ | DefKind :: AssocFn
534
+ | DefKind :: AssocTy
535
+ | DefKind :: Variant
536
+ | DefKind :: Field
537
+ ) =>
538
+ {
539
+ self . cx . tcx . parent ( did)
540
+ }
541
+ Some ( did) => Some ( did) ,
542
+ } ;
543
+
544
+ self_id. and_then ( |self_id| match self . cx . tcx . def_kind ( self_id) {
545
+ DefKind :: Impl => self . def_id_to_res ( self_id) ,
546
+ def_kind => Some ( Res :: Def ( def_kind, self_id) ) ,
547
+ } )
548
+ }
549
+
509
550
/// Convenience wrapper around `resolve_str_path_error`.
510
551
///
511
552
/// This also handles resolving `true` and `false` as booleans.
512
553
/// NOTE: `resolve_str_path_error` knows only about paths, not about types.
513
554
/// Associated items will never be resolved by this function.
514
- fn resolve_path ( & self , path_str : & str , ns : Namespace , module_id : DefId ) -> Option < Res > {
555
+ fn resolve_path (
556
+ & self ,
557
+ path_str : & str ,
558
+ ns : Namespace ,
559
+ item_id : ItemId ,
560
+ module_id : DefId ,
561
+ ) -> Option < Res > {
562
+ if let res @ Some ( ..) = self . resolve_self_ty ( path_str, ns, item_id) {
563
+ return res;
564
+ }
565
+
515
566
let result = self . cx . enter_resolver ( |resolver| {
516
567
resolver
517
568
. resolve_str_path_error ( DUMMY_SP , path_str, ns, module_id)
@@ -532,10 +583,11 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
532
583
& mut self ,
533
584
path_str : & ' path str ,
534
585
ns : Namespace ,
586
+ item_id : ItemId ,
535
587
module_id : DefId ,
536
588
user_fragment : & Option < String > ,
537
589
) -> Result < ( Res , Option < UrlFragment > ) , ErrorKind < ' path > > {
538
- let ( res, rustdoc_fragment) = self . resolve_inner ( path_str, ns, module_id) ?;
590
+ let ( res, rustdoc_fragment) = self . resolve_inner ( path_str, ns, item_id , module_id) ?;
539
591
let chosen_fragment = match ( user_fragment, rustdoc_fragment) {
540
592
( Some ( _) , Some ( r_frag) ) => {
541
593
let diag_res = match r_frag {
@@ -555,9 +607,10 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
555
607
& mut self ,
556
608
path_str : & ' path str ,
557
609
ns : Namespace ,
610
+ item_id : ItemId ,
558
611
module_id : DefId ,
559
612
) -> Result < ( Res , Option < ItemFragment > ) , ErrorKind < ' path > > {
560
- if let Some ( res) = self . resolve_path ( path_str, ns, module_id) {
613
+ if let Some ( res) = self . resolve_path ( path_str, ns, item_id , module_id) {
561
614
match res {
562
615
// FIXME(#76467): make this fallthrough to lookup the associated
563
616
// item a separate function.
@@ -585,6 +638,7 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
585
638
. ok_or_else ( || {
586
639
debug ! ( "found no `::`, assumming {} was correctly not in scope" , item_name) ;
587
640
ResolutionFailure :: NotResolved {
641
+ item_id,
588
642
module_id,
589
643
partial_res : None ,
590
644
unresolved : item_str. into ( ) ,
@@ -596,7 +650,7 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
596
650
// error instead and special case *only* modules with `#[doc(primitive)]`, not all
597
651
// primitives.
598
652
resolve_primitive ( & path_root, TypeNS )
599
- . or_else ( || self . resolve_path ( & path_root, TypeNS , module_id) )
653
+ . or_else ( || self . resolve_path ( & path_root, TypeNS , item_id , module_id) )
600
654
. and_then ( |ty_res| {
601
655
let ( res, fragment) =
602
656
self . resolve_associated_item ( ty_res, item_name, ns, module_id) ?;
@@ -605,9 +659,10 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
605
659
} )
606
660
. unwrap_or_else ( || {
607
661
if ns == Namespace :: ValueNS {
608
- self . variant_field ( path_str, module_id)
662
+ self . variant_field ( path_str, item_id , module_id)
609
663
} else {
610
664
Err ( ResolutionFailure :: NotResolved {
665
+ item_id,
611
666
module_id,
612
667
partial_res : None ,
613
668
unresolved : path_root. into ( ) ,
@@ -730,7 +785,7 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
730
785
// Checks if item_name is a variant of the `SomeItem` enum
731
786
if ns == TypeNS && def_kind == DefKind :: Enum {
732
787
match tcx. type_of ( did) . kind ( ) {
733
- TyKind :: Adt ( adt_def, _) => {
788
+ ty :: Adt ( adt_def, _) => {
734
789
for variant in & adt_def. variants {
735
790
if variant. name == item_name {
736
791
return Some ( (
@@ -830,17 +885,18 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
830
885
& mut self ,
831
886
ns : Namespace ,
832
887
path_str : & str ,
888
+ item_id : ItemId ,
833
889
module_id : DefId ,
834
890
extra_fragment : & Option < String > ,
835
891
) -> Option < Res > {
836
892
// resolve() can't be used for macro namespace
837
893
let result = match ns {
838
894
Namespace :: MacroNS => self
839
- . resolve_macro ( path_str, module_id)
895
+ . resolve_macro ( path_str, item_id , module_id)
840
896
. map ( |res| ( res, None ) )
841
897
. map_err ( ErrorKind :: from) ,
842
898
Namespace :: TypeNS | Namespace :: ValueNS => {
843
- self . resolve ( path_str, ns, module_id, extra_fragment)
899
+ self . resolve ( path_str, ns, item_id , module_id, extra_fragment)
844
900
}
845
901
} ;
846
902
@@ -987,53 +1043,6 @@ impl<'a, 'tcx> DocVisitor for LinkCollector<'a, 'tcx> {
987
1043
trace ! ( "got parent node for {:?} {:?}, id {:?}" , item. type_( ) , item. name, item. def_id) ;
988
1044
}
989
1045
990
- // find item's parent to resolve `Self` in item's docs below
991
- debug ! ( "looking for the `Self` type" ) ;
992
- let self_id = match item. def_id . as_def_id ( ) {
993
- None => None ,
994
- Some ( did)
995
- if ( matches ! ( self . cx. tcx. def_kind( did) , DefKind :: Field )
996
- && matches ! (
997
- self . cx. tcx. def_kind( self . cx. tcx. parent( did) . unwrap( ) ) ,
998
- DefKind :: Variant
999
- ) ) =>
1000
- {
1001
- self . cx . tcx . parent ( did) . and_then ( |item_id| self . cx . tcx . parent ( item_id) )
1002
- }
1003
- Some ( did)
1004
- if matches ! (
1005
- self . cx. tcx. def_kind( did) ,
1006
- DefKind :: AssocConst
1007
- | DefKind :: AssocFn
1008
- | DefKind :: AssocTy
1009
- | DefKind :: Variant
1010
- | DefKind :: Field
1011
- ) =>
1012
- {
1013
- self . cx . tcx . parent ( did)
1014
- }
1015
- Some ( did) => Some ( did) ,
1016
- } ;
1017
-
1018
- // FIXME(jynelson): this shouldn't go through stringification, rustdoc should just use the DefId directly
1019
- let self_name = self_id. and_then ( |self_id| {
1020
- if matches ! ( self . cx. tcx. def_kind( self_id) , DefKind :: Impl ) {
1021
- // using `ty.to_string()` (or any variant) has issues with raw idents
1022
- let ty = self . cx . tcx . type_of ( self_id) ;
1023
- let name = match ty. kind ( ) {
1024
- ty:: Adt ( def, _) => Some ( self . cx . tcx . item_name ( def. did ) . to_string ( ) ) ,
1025
- other if other. is_primitive ( ) => Some ( ty. to_string ( ) ) ,
1026
- _ => None ,
1027
- } ;
1028
- debug ! ( "using type_of(): {:?}" , name) ;
1029
- name
1030
- } else {
1031
- let name = self . cx . tcx . opt_item_name ( self_id) . map ( |sym| sym. to_string ( ) ) ;
1032
- debug ! ( "using item_name(): {:?}" , name) ;
1033
- name
1034
- }
1035
- } ) ;
1036
-
1037
1046
let inner_docs = item. inner_docs ( self . cx . tcx ) ;
1038
1047
1039
1048
if item. is_mod ( ) && inner_docs {
@@ -1055,7 +1064,7 @@ impl<'a, 'tcx> DocVisitor for LinkCollector<'a, 'tcx> {
1055
1064
// NOTE: if there are links that start in one crate and end in another, this will not resolve them.
1056
1065
// This is a degenerate case and it's not supported by rustdoc.
1057
1066
for md_link in markdown_links ( & doc) {
1058
- let link = self . resolve_link ( & item, & doc, & self_name , parent_node, krate, md_link) ;
1067
+ let link = self . resolve_link ( & item, & doc, parent_node, krate, md_link) ;
1059
1068
if let Some ( link) = link {
1060
1069
self . cx . cache . intra_doc_links . entry ( item. def_id ) . or_default ( ) . push ( link) ;
1061
1070
}
@@ -1189,7 +1198,6 @@ impl LinkCollector<'_, '_> {
1189
1198
& mut self ,
1190
1199
item : & Item ,
1191
1200
dox : & str ,
1192
- self_name : & Option < String > ,
1193
1201
parent_node : Option < DefId > ,
1194
1202
krate : CrateNum ,
1195
1203
ori_link : MarkdownLink ,
@@ -1259,19 +1267,8 @@ impl LinkCollector<'_, '_> {
1259
1267
} ;
1260
1268
1261
1269
let resolved_self;
1262
- // replace `Self` with suitable item's parent name
1263
- let is_lone_self = path_str == "Self" ;
1264
1270
let is_lone_crate = path_str == "crate" ;
1265
- if path_str. starts_with ( "Self::" ) || is_lone_self {
1266
- if let Some ( ref name) = self_name {
1267
- if is_lone_self {
1268
- path_str = name;
1269
- } else {
1270
- resolved_self = format ! ( "{}::{}" , name, & path_str[ 6 ..] ) ;
1271
- path_str = & resolved_self;
1272
- }
1273
- }
1274
- } else if path_str. starts_with ( "crate::" ) || is_lone_crate {
1271
+ if path_str. starts_with ( "crate::" ) || is_lone_crate {
1275
1272
use rustc_span:: def_id:: CRATE_DEF_INDEX ;
1276
1273
1277
1274
// HACK(jynelson): rustc_resolve thinks that `crate` is the crate currently being documented.
@@ -1291,6 +1288,7 @@ impl LinkCollector<'_, '_> {
1291
1288
1292
1289
let ( mut res, fragment) = self . resolve_with_disambiguator_cached (
1293
1290
ResolutionInfo {
1291
+ item_id : item. def_id ,
1294
1292
module_id,
1295
1293
dis : disambiguator,
1296
1294
path_str : path_str. to_owned ( ) ,
@@ -1533,12 +1531,13 @@ impl LinkCollector<'_, '_> {
1533
1531
) -> Option < ( Res , Option < UrlFragment > ) > {
1534
1532
let disambiguator = key. dis ;
1535
1533
let path_str = & key. path_str ;
1534
+ let item_id = key. item_id ;
1536
1535
let base_node = key. module_id ;
1537
1536
let extra_fragment = & key. extra_fragment ;
1538
1537
1539
1538
match disambiguator. map ( Disambiguator :: ns) {
1540
1539
Some ( expected_ns @ ( ValueNS | TypeNS ) ) => {
1541
- match self . resolve ( path_str, expected_ns, base_node, extra_fragment) {
1540
+ match self . resolve ( path_str, expected_ns, item_id , base_node, extra_fragment) {
1542
1541
Ok ( res) => Some ( res) ,
1543
1542
Err ( ErrorKind :: Resolve ( box mut kind) ) => {
1544
1543
// We only looked in one namespace. Try to give a better error if possible.
@@ -1547,9 +1546,13 @@ impl LinkCollector<'_, '_> {
1547
1546
// FIXME: really it should be `resolution_failure` that does this, not `resolve_with_disambiguator`
1548
1547
// See https://github.com/rust-lang/rust/pull/76955#discussion_r493953382 for a good approach
1549
1548
for new_ns in [ other_ns, MacroNS ] {
1550
- if let Some ( res) =
1551
- self . check_full_res ( new_ns, path_str, base_node, extra_fragment)
1552
- {
1549
+ if let Some ( res) = self . check_full_res (
1550
+ new_ns,
1551
+ path_str,
1552
+ item_id,
1553
+ base_node,
1554
+ extra_fragment,
1555
+ ) {
1553
1556
kind = ResolutionFailure :: WrongNamespace { res, expected_ns } ;
1554
1557
break ;
1555
1558
}
@@ -1571,9 +1574,15 @@ impl LinkCollector<'_, '_> {
1571
1574
// Try everything!
1572
1575
let mut candidates = PerNS {
1573
1576
macro_ns : self
1574
- . resolve_macro ( path_str, base_node)
1577
+ . resolve_macro ( path_str, item_id , base_node)
1575
1578
. map ( |res| ( res, extra_fragment. clone ( ) . map ( UrlFragment :: UserWritten ) ) ) ,
1576
- type_ns : match self . resolve ( path_str, TypeNS , base_node, extra_fragment) {
1579
+ type_ns : match self . resolve (
1580
+ path_str,
1581
+ TypeNS ,
1582
+ item_id,
1583
+ base_node,
1584
+ extra_fragment,
1585
+ ) {
1577
1586
Ok ( res) => {
1578
1587
debug ! ( "got res in TypeNS: {:?}" , res) ;
1579
1588
Ok ( res)
@@ -1584,7 +1593,13 @@ impl LinkCollector<'_, '_> {
1584
1593
}
1585
1594
Err ( ErrorKind :: Resolve ( box kind) ) => Err ( kind) ,
1586
1595
} ,
1587
- value_ns : match self . resolve ( path_str, ValueNS , base_node, extra_fragment) {
1596
+ value_ns : match self . resolve (
1597
+ path_str,
1598
+ ValueNS ,
1599
+ item_id,
1600
+ base_node,
1601
+ extra_fragment,
1602
+ ) {
1588
1603
Ok ( res) => Ok ( res) ,
1589
1604
Err ( ErrorKind :: AnchorFailure ( msg) ) => {
1590
1605
anchor_failure ( self . cx , diag, msg) ;
@@ -1643,14 +1658,18 @@ impl LinkCollector<'_, '_> {
1643
1658
}
1644
1659
}
1645
1660
Some ( MacroNS ) => {
1646
- match self . resolve_macro ( path_str, base_node) {
1661
+ match self . resolve_macro ( path_str, item_id , base_node) {
1647
1662
Ok ( res) => Some ( ( res, extra_fragment. clone ( ) . map ( UrlFragment :: UserWritten ) ) ) ,
1648
1663
Err ( mut kind) => {
1649
1664
// `resolve_macro` only looks in the macro namespace. Try to give a better error if possible.
1650
1665
for ns in [ TypeNS , ValueNS ] {
1651
- if let Some ( res) =
1652
- self . check_full_res ( ns, path_str, base_node, extra_fragment)
1653
- {
1666
+ if let Some ( res) = self . check_full_res (
1667
+ ns,
1668
+ path_str,
1669
+ item_id,
1670
+ base_node,
1671
+ extra_fragment,
1672
+ ) {
1654
1673
kind =
1655
1674
ResolutionFailure :: WrongNamespace { res, expected_ns : MacroNS } ;
1656
1675
break ;
@@ -1977,11 +1996,16 @@ fn resolution_failure(
1977
1996
}
1978
1997
variants_seen. push ( variant) ;
1979
1998
1980
- if let ResolutionFailure :: NotResolved { module_id, partial_res, unresolved } =
1981
- & mut failure
1999
+ if let ResolutionFailure :: NotResolved {
2000
+ item_id,
2001
+ module_id,
2002
+ partial_res,
2003
+ unresolved,
2004
+ } = & mut failure
1982
2005
{
1983
2006
use DefKind :: * ;
1984
2007
2008
+ let item_id = * item_id;
1985
2009
let module_id = * module_id;
1986
2010
// FIXME(jynelson): this might conflict with my `Self` fix in #76467
1987
2011
// FIXME: maybe use itertools `collect_tuple` instead?
@@ -2005,7 +2029,8 @@ fn resolution_failure(
2005
2029
} ;
2006
2030
name = start;
2007
2031
for ns in [ TypeNS , ValueNS , MacroNS ] {
2008
- if let Some ( res) = collector. check_full_res ( ns, start, module_id, & None )
2032
+ if let Some ( res) =
2033
+ collector. check_full_res ( ns, start, item_id, module_id, & None )
2009
2034
{
2010
2035
debug ! ( "found partial_res={:?}" , res) ;
2011
2036
* partial_res = Some ( res) ;
0 commit comments