@@ -181,7 +181,6 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
181181 fn resolve (
182182 & self ,
183183 path_str : & str ,
184- disambiguator : Option < Disambiguator > ,
185184 ns : Namespace ,
186185 current_item : & Option < String > ,
187186 parent_id : Option < DefId > ,
@@ -218,18 +217,6 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
218217 return Ok ( ( res, Some ( path_str. to_owned ( ) ) ) ) ;
219218 }
220219 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- }
233220 return Ok ( ( res, extra_fragment. clone ( ) ) ) ;
234221 }
235222 _ => {
@@ -713,7 +700,7 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> {
713700 let resolved_self;
714701 let mut path_str;
715702 let disambiguator;
716- let ( res, fragment) = {
703+ let ( mut res, mut fragment) = {
717704 path_str = if let Ok ( ( d, path) ) = Disambiguator :: from_str ( & link) {
718705 disambiguator = Some ( d) ;
719706 path
@@ -756,7 +743,6 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> {
756743 Some ( ns @ ( ValueNS | TypeNS ) ) => {
757744 match self . resolve (
758745 path_str,
759- disambiguator,
760746 ns,
761747 & current_item,
762748 base_node,
@@ -784,7 +770,6 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> {
784770 . map ( |res| ( res, extra_fragment. clone ( ) ) ) ,
785771 type_ns : match self . resolve (
786772 path_str,
787- disambiguator,
788773 TypeNS ,
789774 & current_item,
790775 base_node,
@@ -802,7 +787,6 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> {
802787 } ,
803788 value_ns : match self . resolve (
804789 path_str,
805- disambiguator,
806790 ValueNS ,
807791 & current_item,
808792 base_node,
@@ -848,13 +832,18 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> {
848832 if is_derive_trait_collision ( & candidates) {
849833 candidates. macro_ns = None ;
850834 }
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) ) ) ;
851840 ambiguity_error (
852841 cx,
853842 & item,
854843 path_str,
855844 & dox,
856845 link_range,
857- candidates. map ( |candidate| candidate . map ( | ( res , _ ) | res ) ) ,
846+ candidates. collect ( ) ,
858847 ) ;
859848 continue ;
860849 }
@@ -870,13 +859,81 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> {
870859 }
871860 } ;
872861
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+ } ;
873922 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+ }
875932 } else {
876933 debug ! ( "intra-doc link to {} resolved to {:?}" , path_str, res) ;
877934
878935 // Disallow e.g. linking to enums with `struct@`
879- if let Res :: Def ( kind, id ) = res {
936+ if let Res :: Def ( kind, _ ) = res {
880937 debug ! ( "saw kind {:?} with disambiguator {:?}" , kind, disambiguator) ;
881938 match ( self . kind_side_channel . take ( ) . unwrap_or ( kind) , disambiguator) {
882939 | ( 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> {
890947 // All of these are valid, so do nothing
891948 => { }
892949 ( 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) ) ;
909952 continue ;
910953 }
911954 }
@@ -961,14 +1004,15 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> {
9611004
9621005#[ derive( Copy , Clone , Debug , PartialEq , Eq ) ]
9631006enum Disambiguator {
1007+ Primitive ,
9641008 Kind ( DefKind ) ,
9651009 Namespace ( Namespace ) ,
9661010}
9671011
9681012impl Disambiguator {
9691013 /// (disambiguator, path_str)
9701014 fn from_str ( link : & str ) -> Result < ( Self , & str ) , ( ) > {
971- use Disambiguator :: { Kind , Namespace as NS } ;
1015+ use Disambiguator :: { Kind , Namespace as NS , Primitive } ;
9721016
9731017 let find_suffix = || {
9741018 let suffixes = [
@@ -999,6 +1043,7 @@ impl Disambiguator {
9991043 "type" => NS ( Namespace :: TypeNS ) ,
10001044 "value" => NS ( Namespace :: ValueNS ) ,
10011045 "macro" => NS ( Namespace :: MacroNS ) ,
1046+ "prim" | "primitive" => Primitive ,
10021047 _ => return find_suffix ( ) ,
10031048 } ;
10041049 Ok ( ( d, & rest[ 1 ..] ) )
@@ -1007,7 +1052,12 @@ impl Disambiguator {
10071052 }
10081053 }
10091054
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+ } ;
10111061 if kind == DefKind :: Macro ( MacroKind :: Bang ) {
10121062 return format ! ( "{}!" , path_str) ;
10131063 } else if kind == DefKind :: Fn || kind == DefKind :: AssocFn {
@@ -1043,6 +1093,25 @@ impl Disambiguator {
10431093 Self :: Kind ( k) => {
10441094 k. ns ( ) . expect ( "only DefKinds with a valid namespace can be disambiguators" )
10451095 }
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" ,
10461115 }
10471116 }
10481117}
@@ -1183,14 +1252,10 @@ fn ambiguity_error(
11831252 path_str : & str ,
11841253 dox : & str ,
11851254 link_range : Option < Range < usize > > ,
1186- candidates : PerNS < Option < Res > > ,
1255+ candidates : Vec < ( Res , Namespace ) > ,
11871256) {
11881257 let mut msg = format ! ( "`{}` is " , path_str) ;
11891258
1190- let candidates = [ TypeNS , ValueNS , MacroNS ]
1191- . iter ( )
1192- . filter_map ( |& ns| candidates[ ns] . map ( |res| ( res, ns) ) )
1193- . collect :: < Vec < _ > > ( ) ;
11941259 match candidates. as_slice ( ) {
11951260 [ ( first_def, _) , ( second_def, _) ] => {
11961261 msg += & format ! (
@@ -1229,6 +1294,7 @@ fn ambiguity_error(
12291294 }
12301295 _ => {
12311296 let type_ = match ( res, ns) {
1297+ ( Res :: PrimTy ( _) , _) => "prim" ,
12321298 ( Res :: Def ( DefKind :: Const , _) , _) => "const" ,
12331299 ( Res :: Def ( DefKind :: Static , _) , _) => "static" ,
12341300 ( Res :: Def ( DefKind :: Struct , _) , _) => "struct" ,
0 commit comments