@@ -829,16 +829,13 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> {
829829 }
830830 let candidates =
831831 candidates. map ( |candidate| candidate. map ( |( res, _) | res) ) ;
832- let candidates = [ TypeNS , ValueNS , MacroNS ]
833- . iter ( )
834- . filter_map ( |& ns| candidates[ ns] . map ( |res| ( res, ns) ) ) ;
835832 ambiguity_error (
836833 cx,
837834 & item,
838835 path_str,
839836 & dox,
840837 link_range,
841- candidates. collect ( ) ,
838+ candidates. present_items ( ) . collect ( ) ,
842839 ) ;
843840 continue ;
844841 }
@@ -880,7 +877,7 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> {
880877 fragment = Some ( path. to_owned ( ) ) ;
881878 } else {
882879 // `[char]` when a `char` module is in scope
883- let candidates = vec ! [ ( res, TypeNS ) , ( prim, TypeNS ) ] ;
880+ let candidates = vec ! [ res, prim] ;
884881 ambiguity_error ( cx, & item, path_str, & dox, link_range, candidates) ;
885882 continue ;
886883 }
@@ -898,20 +895,8 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> {
898895 specified. article( ) ,
899896 specified. descr( )
900897 ) ;
901- let suggestion = resolved. display_for ( path_str) ;
902- let help_msg =
903- format ! ( "to link to the {}, use its disambiguator" , resolved. descr( ) ) ;
904898 diag. note ( & note) ;
905- if let Some ( sp) = sp {
906- diag. span_suggestion (
907- sp,
908- & help_msg,
909- suggestion,
910- Applicability :: MaybeIncorrect ,
911- ) ;
912- } else {
913- diag. help ( & format ! ( "{}: {}" , help_msg, suggestion) ) ;
914- }
899+ suggest_disambiguator ( resolved, diag, path_str, & dox, sp, & link_range) ;
915900 } ) ;
916901 } ;
917902 if let Res :: PrimTy ( _) = res {
@@ -1047,17 +1032,32 @@ impl Disambiguator {
10471032 }
10481033 }
10491034
1050- fn display_for ( self , path_str : & str ) -> String {
1035+ /// WARNING: panics on `Res::Err`
1036+ fn from_res ( res : Res ) -> Self {
1037+ match res {
1038+ Res :: Def ( kind, _) => Disambiguator :: Kind ( kind) ,
1039+ Res :: PrimTy ( _) => Disambiguator :: Primitive ,
1040+ _ => Disambiguator :: Namespace ( res. ns ( ) . expect ( "can't call `from_res` on Res::err" ) ) ,
1041+ }
1042+ }
1043+
1044+ /// Return (description of the change, suggestion)
1045+ fn display_for ( self , path_str : & str ) -> ( & ' static str , String ) {
1046+ const PREFIX : & str = "prefix with the item kind" ;
1047+ const FUNCTION : & str = "add parentheses" ;
1048+ const MACRO : & str = "add an exclamation mark" ;
1049+
10511050 let kind = match self {
1052- Disambiguator :: Primitive => return format ! ( "prim@{}" , path_str) ,
1051+ Disambiguator :: Primitive => return ( PREFIX , format ! ( "prim@{}" , path_str) ) ,
10531052 Disambiguator :: Kind ( kind) => kind,
10541053 Disambiguator :: Namespace ( _) => panic ! ( "display_for cannot be used on namespaces" ) ,
10551054 } ;
10561055 if kind == DefKind :: Macro ( MacroKind :: Bang ) {
1057- return format ! ( "{}!" , path_str) ;
1056+ return ( MACRO , format ! ( "{}!" , path_str) ) ;
10581057 } else if kind == DefKind :: Fn || kind == DefKind :: AssocFn {
1059- return format ! ( "{}()" , path_str) ;
1058+ return ( FUNCTION , format ! ( "{}()" , path_str) ) ;
10601059 }
1060+
10611061 let prefix = match kind {
10621062 DefKind :: Struct => "struct" ,
10631063 DefKind :: Enum => "enum" ,
@@ -1079,7 +1079,9 @@ impl Disambiguator {
10791079 Namespace :: MacroNS => "macro" ,
10801080 } ,
10811081 } ;
1082- format ! ( "{}@{}" , prefix, path_str)
1082+
1083+ // FIXME: if this is an implied shortcut link, it's bad style to suggest `@`
1084+ ( PREFIX , format ! ( "{}@{}" , prefix, path_str) )
10831085 }
10841086
10851087 fn ns ( self ) -> Namespace {
@@ -1247,12 +1249,12 @@ fn ambiguity_error(
12471249 path_str : & str ,
12481250 dox : & str ,
12491251 link_range : Option < Range < usize > > ,
1250- candidates : Vec < ( Res , Namespace ) > ,
1252+ candidates : Vec < Res > ,
12511253) {
12521254 let mut msg = format ! ( "`{}` is " , path_str) ;
12531255
12541256 match candidates. as_slice ( ) {
1255- [ ( first_def, _ ) , ( second_def, _ ) ] => {
1257+ [ first_def, second_def] => {
12561258 msg += & format ! (
12571259 "both {} {} and {} {}" ,
12581260 first_def. article( ) ,
@@ -1263,7 +1265,7 @@ fn ambiguity_error(
12631265 }
12641266 _ => {
12651267 let mut candidates = candidates. iter ( ) . peekable ( ) ;
1266- while let Some ( ( res, _ ) ) = candidates. next ( ) {
1268+ while let Some ( res) = candidates. next ( ) {
12671269 if candidates. peek ( ) . is_some ( ) {
12681270 msg += & format ! ( "{} {}, " , res. article( ) , res. descr( ) ) ;
12691271 } else {
@@ -1276,52 +1278,38 @@ fn ambiguity_error(
12761278 report_diagnostic ( cx, & msg, item, dox, link_range. clone ( ) , |diag, sp| {
12771279 if let Some ( sp) = sp {
12781280 diag. span_label ( sp, "ambiguous link" ) ;
1281+ } else {
1282+ diag. note ( "ambiguous link" ) ;
1283+ }
12791284
1280- let link_range = link_range. expect ( "must have a link range if we have a span" ) ;
1281-
1282- for ( res, ns) in candidates {
1283- let ( action, mut suggestion) = match res {
1284- Res :: Def ( DefKind :: AssocFn | DefKind :: Fn , _) => {
1285- ( "add parentheses" , format ! ( "{}()" , path_str) )
1286- }
1287- Res :: Def ( DefKind :: Macro ( MacroKind :: Bang ) , _) => {
1288- ( "add an exclamation mark" , format ! ( "{}!" , path_str) )
1289- }
1290- _ => {
1291- let type_ = match ( res, ns) {
1292- ( Res :: PrimTy ( _) , _) => "prim" ,
1293- ( Res :: Def ( DefKind :: Const , _) , _) => "const" ,
1294- ( Res :: Def ( DefKind :: Static , _) , _) => "static" ,
1295- ( Res :: Def ( DefKind :: Struct , _) , _) => "struct" ,
1296- ( Res :: Def ( DefKind :: Enum , _) , _) => "enum" ,
1297- ( Res :: Def ( DefKind :: Union , _) , _) => "union" ,
1298- ( Res :: Def ( DefKind :: Trait , _) , _) => "trait" ,
1299- ( Res :: Def ( DefKind :: Mod , _) , _) => "module" ,
1300- ( _, TypeNS ) => "type" ,
1301- ( _, ValueNS ) => "value" ,
1302- ( Res :: Def ( DefKind :: Macro ( MacroKind :: Derive ) , _) , MacroNS ) => "derive" ,
1303- ( _, MacroNS ) => "macro" ,
1304- } ;
1305-
1306- // FIXME: if this is an implied shortcut link, it's bad style to suggest `@`
1307- ( "prefix with the item type" , format ! ( "{}@{}" , type_, path_str) )
1308- }
1309- } ;
1285+ for res in candidates {
1286+ let disambiguator = Disambiguator :: from_res ( res) ;
1287+ suggest_disambiguator ( disambiguator, diag, path_str, dox, sp, & link_range) ;
1288+ }
1289+ } ) ;
1290+ }
13101291
1311- if dox. bytes ( ) . nth ( link_range. start ) == Some ( b'`' ) {
1312- suggestion = format ! ( "`{}`" , suggestion) ;
1313- }
1292+ fn suggest_disambiguator (
1293+ disambiguator : Disambiguator ,
1294+ diag : & mut DiagnosticBuilder < ' _ > ,
1295+ path_str : & str ,
1296+ dox : & str ,
1297+ sp : Option < rustc_span:: Span > ,
1298+ link_range : & Option < Range < usize > > ,
1299+ ) {
1300+ let ( action, mut suggestion) = disambiguator. display_for ( path_str) ;
1301+ let help = format ! ( "to link to the {}, {}" , disambiguator. descr( ) , action) ;
13141302
1315- // FIXME: Create a version of this suggestion for when we don't have the span.
1316- diag. span_suggestion (
1317- sp,
1318- & format ! ( "to link to the {}, {}" , res. descr( ) , action) ,
1319- suggestion,
1320- Applicability :: MaybeIncorrect ,
1321- ) ;
1322- }
1303+ if let Some ( sp) = sp {
1304+ let link_range = link_range. as_ref ( ) . expect ( "must have a link range if we have a span" ) ;
1305+ if dox. bytes ( ) . nth ( link_range. start ) == Some ( b'`' ) {
1306+ suggestion = format ! ( "`{}`" , suggestion) ;
13231307 }
1324- } ) ;
1308+
1309+ diag. span_suggestion ( sp, & help, suggestion, Applicability :: MaybeIncorrect ) ;
1310+ } else {
1311+ diag. help ( & format ! ( "{}: {}" , help, suggestion) ) ;
1312+ }
13251313}
13261314
13271315fn privacy_error (
0 commit comments