@@ -829,16 +829,13 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> {
829
829
}
830
830
let candidates =
831
831
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) ) ) ;
835
832
ambiguity_error (
836
833
cx,
837
834
& item,
838
835
path_str,
839
836
& dox,
840
837
link_range,
841
- candidates. collect ( ) ,
838
+ candidates. present_items ( ) . collect ( ) ,
842
839
) ;
843
840
continue ;
844
841
}
@@ -880,7 +877,7 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> {
880
877
fragment = Some ( path. to_owned ( ) ) ;
881
878
} else {
882
879
// `[char]` when a `char` module is in scope
883
- let candidates = vec ! [ ( res, TypeNS ) , ( prim, TypeNS ) ] ;
880
+ let candidates = vec ! [ res, prim] ;
884
881
ambiguity_error ( cx, & item, path_str, & dox, link_range, candidates) ;
885
882
continue ;
886
883
}
@@ -898,20 +895,8 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> {
898
895
specified. article( ) ,
899
896
specified. descr( )
900
897
) ;
901
- let suggestion = resolved. display_for ( path_str) ;
902
- let help_msg =
903
- format ! ( "to link to the {}, use its disambiguator" , resolved. descr( ) ) ;
904
898
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) ;
915
900
} ) ;
916
901
} ;
917
902
if let Res :: PrimTy ( _) = res {
@@ -1047,17 +1032,32 @@ impl Disambiguator {
1047
1032
}
1048
1033
}
1049
1034
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
+
1051
1050
let kind = match self {
1052
- Disambiguator :: Primitive => return format ! ( "prim@{}" , path_str) ,
1051
+ Disambiguator :: Primitive => return ( PREFIX , format ! ( "prim@{}" , path_str) ) ,
1053
1052
Disambiguator :: Kind ( kind) => kind,
1054
1053
Disambiguator :: Namespace ( _) => panic ! ( "display_for cannot be used on namespaces" ) ,
1055
1054
} ;
1056
1055
if kind == DefKind :: Macro ( MacroKind :: Bang ) {
1057
- return format ! ( "{}!" , path_str) ;
1056
+ return ( MACRO , format ! ( "{}!" , path_str) ) ;
1058
1057
} else if kind == DefKind :: Fn || kind == DefKind :: AssocFn {
1059
- return format ! ( "{}()" , path_str) ;
1058
+ return ( FUNCTION , format ! ( "{}()" , path_str) ) ;
1060
1059
}
1060
+
1061
1061
let prefix = match kind {
1062
1062
DefKind :: Struct => "struct" ,
1063
1063
DefKind :: Enum => "enum" ,
@@ -1079,7 +1079,9 @@ impl Disambiguator {
1079
1079
Namespace :: MacroNS => "macro" ,
1080
1080
} ,
1081
1081
} ;
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) )
1083
1085
}
1084
1086
1085
1087
fn ns ( self ) -> Namespace {
@@ -1247,12 +1249,12 @@ fn ambiguity_error(
1247
1249
path_str : & str ,
1248
1250
dox : & str ,
1249
1251
link_range : Option < Range < usize > > ,
1250
- candidates : Vec < ( Res , Namespace ) > ,
1252
+ candidates : Vec < Res > ,
1251
1253
) {
1252
1254
let mut msg = format ! ( "`{}` is " , path_str) ;
1253
1255
1254
1256
match candidates. as_slice ( ) {
1255
- [ ( first_def, _ ) , ( second_def, _ ) ] => {
1257
+ [ first_def, second_def] => {
1256
1258
msg += & format ! (
1257
1259
"both {} {} and {} {}" ,
1258
1260
first_def. article( ) ,
@@ -1263,7 +1265,7 @@ fn ambiguity_error(
1263
1265
}
1264
1266
_ => {
1265
1267
let mut candidates = candidates. iter ( ) . peekable ( ) ;
1266
- while let Some ( ( res, _ ) ) = candidates. next ( ) {
1268
+ while let Some ( res) = candidates. next ( ) {
1267
1269
if candidates. peek ( ) . is_some ( ) {
1268
1270
msg += & format ! ( "{} {}, " , res. article( ) , res. descr( ) ) ;
1269
1271
} else {
@@ -1276,52 +1278,38 @@ fn ambiguity_error(
1276
1278
report_diagnostic ( cx, & msg, item, dox, link_range. clone ( ) , |diag, sp| {
1277
1279
if let Some ( sp) = sp {
1278
1280
diag. span_label ( sp, "ambiguous link" ) ;
1281
+ } else {
1282
+ diag. note ( "ambiguous link" ) ;
1283
+ }
1279
1284
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
+ }
1310
1291
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) ;
1314
1302
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) ;
1323
1307
}
1324
- } ) ;
1308
+
1309
+ diag. span_suggestion ( sp, & help, suggestion, Applicability :: MaybeIncorrect ) ;
1310
+ } else {
1311
+ diag. help ( & format ! ( "{}: {}" , help, suggestion) ) ;
1312
+ }
1325
1313
}
1326
1314
1327
1315
fn privacy_error (
0 commit comments