@@ -181,7 +181,6 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
181
181
fn resolve (
182
182
& self ,
183
183
path_str : & str ,
184
- disambiguator : Option < Disambiguator > ,
185
184
ns : Namespace ,
186
185
current_item : & Option < String > ,
187
186
parent_id : Option < DefId > ,
@@ -218,18 +217,6 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
218
217
return Ok ( ( res, Some ( path_str. to_owned ( ) ) ) ) ;
219
218
}
220
219
Res :: Def ( DefKind :: Mod , _) => {
221
- // This resolved to a module, but we want primitive types to take precedence instead.
222
- if matches ! (
223
- disambiguator,
224
- None | Some ( Disambiguator :: Namespace ( Namespace :: TypeNS ) )
225
- ) {
226
- if let Some ( ( path, prim) ) = is_primitive ( path_str, ns) {
227
- if extra_fragment. is_some ( ) {
228
- return Err ( ErrorKind :: AnchorFailure ( AnchorFailure :: Primitive ) ) ;
229
- }
230
- return Ok ( ( prim, Some ( path. to_owned ( ) ) ) ) ;
231
- }
232
- }
233
220
return Ok ( ( res, extra_fragment. clone ( ) ) ) ;
234
221
}
235
222
_ => {
@@ -713,7 +700,7 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> {
713
700
let resolved_self;
714
701
let mut path_str;
715
702
let disambiguator;
716
- let ( res, fragment) = {
703
+ let ( mut res, mut fragment) = {
717
704
path_str = if let Ok ( ( d, path) ) = Disambiguator :: from_str ( & link) {
718
705
disambiguator = Some ( d) ;
719
706
path
@@ -756,7 +743,6 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> {
756
743
Some ( ns @ ( ValueNS | TypeNS ) ) => {
757
744
match self . resolve (
758
745
path_str,
759
- disambiguator,
760
746
ns,
761
747
& current_item,
762
748
base_node,
@@ -784,7 +770,6 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> {
784
770
. map ( |res| ( res, extra_fragment. clone ( ) ) ) ,
785
771
type_ns : match self . resolve (
786
772
path_str,
787
- disambiguator,
788
773
TypeNS ,
789
774
& current_item,
790
775
base_node,
@@ -802,7 +787,6 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> {
802
787
} ,
803
788
value_ns : match self . resolve (
804
789
path_str,
805
- disambiguator,
806
790
ValueNS ,
807
791
& current_item,
808
792
base_node,
@@ -848,13 +832,18 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> {
848
832
if is_derive_trait_collision ( & candidates) {
849
833
candidates. macro_ns = None ;
850
834
}
835
+ let candidates =
836
+ candidates. map ( |candidate| candidate. map ( |( res, _) | res) ) ;
837
+ let candidates = [ TypeNS , ValueNS , MacroNS ]
838
+ . iter ( )
839
+ . filter_map ( |& ns| candidates[ ns] . map ( |res| ( res, ns) ) ) ;
851
840
ambiguity_error (
852
841
cx,
853
842
& item,
854
843
path_str,
855
844
& dox,
856
845
link_range,
857
- candidates. map ( |candidate| candidate . map ( | ( res , _ ) | res ) ) ,
846
+ candidates. collect ( ) ,
858
847
) ;
859
848
continue ;
860
849
}
@@ -870,13 +859,81 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> {
870
859
}
871
860
} ;
872
861
862
+ // Check for a primitive which might conflict with a module
863
+ // Report the ambiguity and require that the user specify which one they meant.
864
+ // FIXME: could there ever be a primitive not in the type namespace?
865
+ if matches ! (
866
+ disambiguator,
867
+ None | Some ( Disambiguator :: Namespace ( Namespace :: TypeNS ) | Disambiguator :: Primitive )
868
+ ) && !matches ! ( res, Res :: PrimTy ( _) )
869
+ {
870
+ if let Some ( ( path, prim) ) = is_primitive ( path_str, TypeNS ) {
871
+ // `prim@char`
872
+ if matches ! ( disambiguator, Some ( Disambiguator :: Primitive ) ) {
873
+ if fragment. is_some ( ) {
874
+ anchor_failure (
875
+ cx,
876
+ & item,
877
+ path_str,
878
+ & dox,
879
+ link_range,
880
+ AnchorFailure :: Primitive ,
881
+ ) ;
882
+ continue ;
883
+ }
884
+ res = prim;
885
+ fragment = Some ( path. to_owned ( ) ) ;
886
+ } else {
887
+ // `[char]` when a `char` module is in scope
888
+ let candidates = vec ! [ ( res, TypeNS ) , ( prim, TypeNS ) ] ;
889
+ ambiguity_error ( cx, & item, path_str, & dox, link_range, candidates) ;
890
+ continue ;
891
+ }
892
+ }
893
+ }
894
+
895
+ let report_mismatch = |specified : Disambiguator , resolved : Disambiguator | {
896
+ // The resolved item did not match the disambiguator; give a better error than 'not found'
897
+ let msg = format ! ( "incompatible link kind for `{}`" , path_str) ;
898
+ report_diagnostic ( cx, & msg, & item, & dox, link_range. clone ( ) , |diag, sp| {
899
+ let note = format ! (
900
+ "this link resolved to {} {}, which is not {} {}" ,
901
+ resolved. article( ) ,
902
+ resolved. descr( ) ,
903
+ specified. article( ) ,
904
+ specified. descr( )
905
+ ) ;
906
+ let suggestion = resolved. display_for ( path_str) ;
907
+ let help_msg =
908
+ format ! ( "to link to the {}, use its disambiguator" , resolved. descr( ) ) ;
909
+ diag. note ( & note) ;
910
+ if let Some ( sp) = sp {
911
+ diag. span_suggestion (
912
+ sp,
913
+ & help_msg,
914
+ suggestion,
915
+ Applicability :: MaybeIncorrect ,
916
+ ) ;
917
+ } else {
918
+ diag. help ( & format ! ( "{}: {}" , help_msg, suggestion) ) ;
919
+ }
920
+ } ) ;
921
+ } ;
873
922
if let Res :: PrimTy ( _) = res {
874
- item. attrs . links . push ( ( ori_link, None , fragment) ) ;
923
+ match disambiguator {
924
+ Some ( Disambiguator :: Primitive | Disambiguator :: Namespace ( _) ) | None => {
925
+ item. attrs . links . push ( ( ori_link, None , fragment) )
926
+ }
927
+ Some ( other) => {
928
+ report_mismatch ( other, Disambiguator :: Primitive ) ;
929
+ continue ;
930
+ }
931
+ }
875
932
} else {
876
933
debug ! ( "intra-doc link to {} resolved to {:?}" , path_str, res) ;
877
934
878
935
// Disallow e.g. linking to enums with `struct@`
879
- if let Res :: Def ( kind, id ) = res {
936
+ if let Res :: Def ( kind, _ ) = res {
880
937
debug ! ( "saw kind {:?} with disambiguator {:?}" , kind, disambiguator) ;
881
938
match ( self . kind_side_channel . take ( ) . unwrap_or ( kind) , disambiguator) {
882
939
| ( DefKind :: Const | DefKind :: ConstParam | DefKind :: AssocConst | DefKind :: AnonConst , Some ( Disambiguator :: Kind ( DefKind :: Const ) ) )
@@ -890,22 +947,8 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> {
890
947
// All of these are valid, so do nothing
891
948
=> { }
892
949
( actual, Some ( Disambiguator :: Kind ( expected) ) ) if actual == expected => { }
893
- ( _, Some ( Disambiguator :: Kind ( expected) ) ) => {
894
- // The resolved item did not match the disambiguator; give a better error than 'not found'
895
- let msg = format ! ( "incompatible link kind for `{}`" , path_str) ;
896
- report_diagnostic ( cx, & msg, & item, & dox, link_range, |diag, sp| {
897
- // HACK(jynelson): by looking at the source I saw the DefId we pass
898
- // for `expected.descr()` doesn't matter, since it's not a crate
899
- let note = format ! ( "this link resolved to {} {}, which is not {} {}" , kind. article( ) , kind. descr( id) , expected. article( ) , expected. descr( id) ) ;
900
- let suggestion = Disambiguator :: display_for ( kind, path_str) ;
901
- let help_msg = format ! ( "to link to the {}, use its disambiguator" , kind. descr( id) ) ;
902
- diag. note ( & note) ;
903
- if let Some ( sp) = sp {
904
- diag. span_suggestion ( sp, & help_msg, suggestion, Applicability :: MaybeIncorrect ) ;
905
- } else {
906
- diag. help ( & format ! ( "{}: {}" , help_msg, suggestion) ) ;
907
- }
908
- } ) ;
950
+ ( _, Some ( specified @ Disambiguator :: Kind ( _) | specified @ Disambiguator :: Primitive ) ) => {
951
+ report_mismatch ( specified, Disambiguator :: Kind ( kind) ) ;
909
952
continue ;
910
953
}
911
954
}
@@ -961,14 +1004,15 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> {
961
1004
962
1005
#[ derive( Copy , Clone , Debug , PartialEq , Eq ) ]
963
1006
enum Disambiguator {
1007
+ Primitive ,
964
1008
Kind ( DefKind ) ,
965
1009
Namespace ( Namespace ) ,
966
1010
}
967
1011
968
1012
impl Disambiguator {
969
1013
/// (disambiguator, path_str)
970
1014
fn from_str ( link : & str ) -> Result < ( Self , & str ) , ( ) > {
971
- use Disambiguator :: { Kind , Namespace as NS } ;
1015
+ use Disambiguator :: { Kind , Namespace as NS , Primitive } ;
972
1016
973
1017
let find_suffix = || {
974
1018
let suffixes = [
@@ -999,6 +1043,7 @@ impl Disambiguator {
999
1043
"type" => NS ( Namespace :: TypeNS ) ,
1000
1044
"value" => NS ( Namespace :: ValueNS ) ,
1001
1045
"macro" => NS ( Namespace :: MacroNS ) ,
1046
+ "prim" | "primitive" => Primitive ,
1002
1047
_ => return find_suffix ( ) ,
1003
1048
} ;
1004
1049
Ok ( ( d, & rest[ 1 ..] ) )
@@ -1007,7 +1052,12 @@ impl Disambiguator {
1007
1052
}
1008
1053
}
1009
1054
1010
- fn display_for ( kind : DefKind , path_str : & str ) -> String {
1055
+ fn display_for ( self , path_str : & str ) -> String {
1056
+ let kind = match self {
1057
+ Disambiguator :: Primitive => return format ! ( "prim@{}" , path_str) ,
1058
+ Disambiguator :: Kind ( kind) => kind,
1059
+ Disambiguator :: Namespace ( _) => panic ! ( "display_for cannot be used on namespaces" ) ,
1060
+ } ;
1011
1061
if kind == DefKind :: Macro ( MacroKind :: Bang ) {
1012
1062
return format ! ( "{}!" , path_str) ;
1013
1063
} else if kind == DefKind :: Fn || kind == DefKind :: AssocFn {
@@ -1043,6 +1093,25 @@ impl Disambiguator {
1043
1093
Self :: Kind ( k) => {
1044
1094
k. ns ( ) . expect ( "only DefKinds with a valid namespace can be disambiguators" )
1045
1095
}
1096
+ Self :: Primitive => TypeNS ,
1097
+ }
1098
+ }
1099
+
1100
+ fn article ( self ) -> & ' static str {
1101
+ match self {
1102
+ Self :: Namespace ( _) => panic ! ( "article() doesn't make sense for namespaces" ) ,
1103
+ Self :: Kind ( k) => k. article ( ) ,
1104
+ Self :: Primitive => "a" ,
1105
+ }
1106
+ }
1107
+
1108
+ fn descr ( self ) -> & ' static str {
1109
+ match self {
1110
+ Self :: Namespace ( n) => n. descr ( ) ,
1111
+ // HACK(jynelson): by looking at the source I saw the DefId we pass
1112
+ // for `expected.descr()` doesn't matter, since it's not a crate
1113
+ Self :: Kind ( k) => k. descr ( DefId :: local ( hir:: def_id:: DefIndex :: from_usize ( 0 ) ) ) ,
1114
+ Self :: Primitive => "builtin type" ,
1046
1115
}
1047
1116
}
1048
1117
}
@@ -1183,14 +1252,10 @@ fn ambiguity_error(
1183
1252
path_str : & str ,
1184
1253
dox : & str ,
1185
1254
link_range : Option < Range < usize > > ,
1186
- candidates : PerNS < Option < Res > > ,
1255
+ candidates : Vec < ( Res , Namespace ) > ,
1187
1256
) {
1188
1257
let mut msg = format ! ( "`{}` is " , path_str) ;
1189
1258
1190
- let candidates = [ TypeNS , ValueNS , MacroNS ]
1191
- . iter ( )
1192
- . filter_map ( |& ns| candidates[ ns] . map ( |res| ( res, ns) ) )
1193
- . collect :: < Vec < _ > > ( ) ;
1194
1259
match candidates. as_slice ( ) {
1195
1260
[ ( first_def, _) , ( second_def, _) ] => {
1196
1261
msg += & format ! (
@@ -1229,6 +1294,7 @@ fn ambiguity_error(
1229
1294
}
1230
1295
_ => {
1231
1296
let type_ = match ( res, ns) {
1297
+ ( Res :: PrimTy ( _) , _) => "prim" ,
1232
1298
( Res :: Def ( DefKind :: Const , _) , _) => "const" ,
1233
1299
( Res :: Def ( DefKind :: Static , _) , _) => "static" ,
1234
1300
( Res :: Def ( DefKind :: Struct , _) , _) => "struct" ,
0 commit comments