@@ -461,60 +461,20 @@ impl Item {
461461 . map_or ( & [ ] [ ..] , |v| v. as_slice ( ) )
462462 . iter ( )
463463 . filter_map ( |ItemLink { link : s, link_text, did, ref fragment } | {
464- match did {
465- Some ( did) => {
466- if let Ok ( ( mut href, ..) ) = href ( did. clone ( ) , cx) {
467- if let Some ( ref fragment) = * fragment {
468- href. push ( '#' ) ;
469- href. push_str ( fragment) ;
470- }
471- Some ( RenderedLink {
472- original_text : s. clone ( ) ,
473- new_text : link_text. clone ( ) ,
474- href,
475- } )
476- } else {
477- None
478- }
479- }
480- // FIXME(83083): using fragments as a side-channel for
481- // primitive names is very unfortunate
482- None => {
483- let relative_to = & cx. current ;
484- if let Some ( ref fragment) = * fragment {
485- let url = match cx. cache ( ) . extern_locations . get ( & self . def_id . krate ( ) ) {
486- Some ( & ExternalLocation :: Local ) => {
487- if relative_to[ 0 ] == "std" {
488- let depth = relative_to. len ( ) - 1 ;
489- "../" . repeat ( depth)
490- } else {
491- let depth = relative_to. len ( ) ;
492- format ! ( "{}std/" , "../" . repeat( depth) )
493- }
494- }
495- Some ( ExternalLocation :: Remote ( ref s) ) => {
496- format ! ( "{}/std/" , s. trim_end_matches( '/' ) )
497- }
498- Some ( ExternalLocation :: Unknown ) | None => {
499- format ! ( "{}/std/" , crate :: DOC_RUST_LANG_ORG_CHANNEL )
500- }
501- } ;
502- // This is a primitive so the url is done "by hand".
503- let tail = fragment. find ( '#' ) . unwrap_or_else ( || fragment. len ( ) ) ;
504- Some ( RenderedLink {
505- original_text : s. clone ( ) ,
506- new_text : link_text. clone ( ) ,
507- href : format ! (
508- "{}primitive.{}.html{}" ,
509- url,
510- & fragment[ ..tail] ,
511- & fragment[ tail..]
512- ) ,
513- } )
514- } else {
515- panic ! ( "This isn't a primitive?!" ) ;
516- }
464+ debug ! ( ?did) ;
465+ if let Ok ( ( mut href, ..) ) = href ( did. clone ( ) , cx) {
466+ debug ! ( ?href) ;
467+ if let Some ( ref fragment) = * fragment {
468+ href. push ( '#' ) ;
469+ href. push_str ( fragment) ;
517470 }
471+ Some ( RenderedLink {
472+ original_text : s. clone ( ) ,
473+ new_text : link_text. clone ( ) ,
474+ href,
475+ } )
476+ } else {
477+ None
518478 }
519479 } )
520480 . collect ( )
@@ -531,18 +491,10 @@ impl Item {
531491 . get ( & self . def_id )
532492 . map_or ( & [ ] [ ..] , |v| v. as_slice ( ) )
533493 . iter ( )
534- . filter_map ( |ItemLink { link : s, link_text, did, fragment } | {
535- // FIXME(83083): using fragments as a side-channel for
536- // primitive names is very unfortunate
537- if did. is_some ( ) || fragment. is_some ( ) {
538- Some ( RenderedLink {
539- original_text : s. clone ( ) ,
540- new_text : link_text. clone ( ) ,
541- href : String :: new ( ) ,
542- } )
543- } else {
544- None
545- }
494+ . map ( |ItemLink { link : s, link_text, .. } | RenderedLink {
495+ original_text : s. clone ( ) ,
496+ new_text : link_text. clone ( ) ,
497+ href : String :: new ( ) ,
546498 } )
547499 . collect ( )
548500 }
@@ -962,7 +914,7 @@ crate struct Attributes {
962914 crate other_attrs : Vec < ast:: Attribute > ,
963915}
964916
965- #[ derive( Clone , Debug , Default , PartialEq , Eq , Hash ) ]
917+ #[ derive( Clone , Debug , PartialEq , Eq , Hash ) ]
966918/// A link that has not yet been rendered.
967919///
968920/// This link will be turned into a rendered link by [`Item::links`].
@@ -974,7 +926,7 @@ crate struct ItemLink {
974926 /// This may not be the same as `link` if there was a disambiguator
975927 /// in an intra-doc link (e.g. \[`fn@f`\])
976928 pub ( crate ) link_text : String ,
977- pub ( crate ) did : Option < DefId > ,
929+ pub ( crate ) did : DefId ,
978930 /// The url fragment to append to the link
979931 pub ( crate ) fragment : Option < String > ,
980932}
@@ -1799,6 +1751,39 @@ impl PrimitiveType {
17991751 Never => sym:: never,
18001752 }
18011753 }
1754+
1755+ /// Returns the DefId of the module with `doc(primitive)` for this primitive type.
1756+ /// Panics if there is no such module.
1757+ ///
1758+ /// This gives precedence to primitives defined in the current crate, and deprioritizes primitives defined in `core`,
1759+ /// but otherwise, if multiple crates define the same primitive, there is no guarantee of which will be picked.
1760+ /// In particular, if a crate depends on both `std` and another crate that also defines `doc(primitive)`, then
1761+ /// it's entirely random whether `std` or the other crate is picked. (no_std crates are usually fine unless multiple dependencies define a primitive.)
1762+ crate fn primitive_locations ( tcx : TyCtxt < ' _ > ) -> & FxHashMap < PrimitiveType , DefId > {
1763+ static PRIMITIVE_LOCATIONS : OnceCell < FxHashMap < PrimitiveType , DefId > > = OnceCell :: new ( ) ;
1764+ PRIMITIVE_LOCATIONS . get_or_init ( || {
1765+ let mut primitive_locations = FxHashMap :: default ( ) ;
1766+ // NOTE: technically this misses crates that are only passed with `--extern` and not loaded when checking the crate.
1767+ // This is a degenerate case that I don't plan to support.
1768+ for & crate_num in tcx. crates ( ( ) ) {
1769+ let e = ExternalCrate { crate_num } ;
1770+ let crate_name = e. name ( tcx) ;
1771+ debug ! ( ?crate_num, ?crate_name) ;
1772+ for & ( def_id, prim) in & e. primitives ( tcx) {
1773+ // HACK: try to link to std instead where possible
1774+ if crate_name == sym:: core && primitive_locations. get ( & prim) . is_some ( ) {
1775+ continue ;
1776+ }
1777+ primitive_locations. insert ( prim, def_id) ;
1778+ }
1779+ }
1780+ let local_primitives = ExternalCrate { crate_num : LOCAL_CRATE } . primitives ( tcx) ;
1781+ for ( def_id, prim) in local_primitives {
1782+ primitive_locations. insert ( prim, def_id) ;
1783+ }
1784+ primitive_locations
1785+ } )
1786+ }
18021787}
18031788
18041789impl From < ast:: IntTy > for PrimitiveType {
0 commit comments