11use errors:: Applicability ;
2- use rustc:: hir:: def:: Def ;
2+ use rustc:: hir:: def:: { Def , Namespace :: { self , * } , PerNS } ;
33use rustc:: hir:: def_id:: DefId ;
44use rustc:: hir;
55use rustc:: lint as lint;
@@ -36,46 +36,24 @@ pub fn collect_intra_doc_links(krate: Crate, cx: &DocContext<'_>) -> Crate {
3636 }
3737}
3838
39- #[ derive( Debug ) ]
40- enum PathKind {
41- /// Either a value or type, but not a macro
42- Unknown ,
43- /// Macro
44- Macro ,
45- /// Values, functions, consts, statics (everything in the value namespace)
46- Value ,
47- /// Types, traits (everything in the type namespace)
48- Type ,
49- }
50-
5139struct LinkCollector < ' a , ' tcx > {
5240 cx : & ' a DocContext < ' tcx > ,
5341 mod_ids : Vec < ast:: NodeId > ,
54- is_nightly_build : bool ,
55- }
56-
57- #[ derive( Debug , Copy , Clone ) ]
58- enum Namespace {
59- Type ,
60- Value ,
61- Macro ,
6242}
6343
6444impl < ' a , ' tcx > LinkCollector < ' a , ' tcx > {
6545 fn new ( cx : & ' a DocContext < ' tcx > ) -> Self {
6646 LinkCollector {
6747 cx,
6848 mod_ids : Vec :: new ( ) ,
69- is_nightly_build : UnstableFeatures :: from_environment ( ) . is_nightly_build ( ) ,
7049 }
7150 }
7251
73- /// Resolves a given string as a path, along with whether or not it is
74- /// in the value namespace. Also returns an optional URL fragment in the case
75- /// of variants and methods.
52+ /// Resolves a string as a path within a particular namespace. Also returns an optional
53+ /// URL fragment in the case of variants and methods.
7654 fn resolve ( & self ,
7755 path_str : & str ,
78- is_val : bool ,
56+ ns : Namespace ,
7957 current_item : & Option < String > ,
8058 parent_id : Option < ast:: NodeId > )
8159 -> Result < ( Def , Option < String > ) , ( ) >
@@ -86,11 +64,11 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
8664 // path.
8765 if let Some ( id) = parent_id. or ( self . mod_ids . last ( ) . cloned ( ) ) {
8866 // FIXME: `with_scope` requires the `NodeId` of a module.
89- let result = cx. enter_resolver ( |resolver| resolver . with_scope ( id ,
90- |resolver| {
91- resolver. resolve_str_path_error ( DUMMY_SP ,
92- & path_str , is_val )
93- } ) ) ;
67+ let result = cx. enter_resolver ( |resolver| {
68+ resolver . with_scope ( id , |resolver| {
69+ resolver. resolve_str_path_error ( DUMMY_SP , & path_str , ns == ValueNS )
70+ } )
71+ } ) ;
9472
9573 if let Ok ( result) = result {
9674 // In case this is a trait item, skip the
@@ -103,16 +81,16 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
10381 _ => return Ok ( ( result. def , None ) )
10482 } ;
10583
106- if value != is_val {
84+ if value != ( ns == ValueNS ) {
10785 return Err ( ( ) )
10886 }
109- } else if let Some ( prim) = is_primitive ( path_str, is_val ) {
87+ } else if let Some ( prim) = is_primitive ( path_str, ns ) {
11088 return Ok ( ( prim, Some ( path_str. to_owned ( ) ) ) )
11189 } else {
11290 // If resolution failed, it may still be a method
11391 // because methods are not handled by the resolver
11492 // If so, bail when we're not looking for a value.
115- if !is_val {
93+ if ns != ValueNS {
11694 return Err ( ( ) )
11795 }
11896 }
@@ -136,7 +114,7 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
136114 path = name. clone ( ) ;
137115 }
138116 }
139- if let Some ( prim) = is_primitive ( & path, false ) {
117+ if let Some ( prim) = is_primitive ( & path, TypeNS ) {
140118 let did = primitive_impl ( cx, & path) . ok_or ( ( ) ) ?;
141119 return cx. tcx . associated_items ( did)
142120 . find ( |item| item. ident . name == item_name)
@@ -160,8 +138,8 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
160138 . find ( |item| item. ident . name == item_name) ;
161139 if let Some ( item) = item {
162140 let out = match item. kind {
163- ty:: AssociatedKind :: Method if is_val => "method" ,
164- ty:: AssociatedKind :: Const if is_val => "associatedconstant" ,
141+ ty:: AssociatedKind :: Method if ns == ValueNS => "method" ,
142+ ty:: AssociatedKind :: Const if ns == ValueNS => "associatedconstant" ,
165143 _ => return Err ( ( ) )
166144 } ;
167145 Ok ( ( ty. def , Some ( format ! ( "{}.{}" , out, item_name) ) ) )
@@ -198,9 +176,9 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
198176 . find ( |item| item. ident . name == item_name) ;
199177 if let Some ( item) = item {
200178 let kind = match item. kind {
201- ty:: AssociatedKind :: Const if is_val => "associatedconstant" ,
202- ty:: AssociatedKind :: Type if !is_val => "associatedtype" ,
203- ty:: AssociatedKind :: Method if is_val => {
179+ ty:: AssociatedKind :: Const if ns == ValueNS => "associatedconstant" ,
180+ ty:: AssociatedKind :: Type if ns == TypeNS => "associatedtype" ,
181+ ty:: AssociatedKind :: Method if ns == ValueNS => {
204182 if item. defaultness . has_value ( ) {
205183 "method"
206184 } else {
@@ -287,39 +265,35 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> {
287265
288266 look_for_tests ( & cx, & dox, & item, true ) ;
289267
290- if !self . is_nightly_build {
291- return None ;
292- }
293-
294268 for ( ori_link, link_range) in markdown_links ( & dox) {
295269 // Bail early for real links.
296270 if ori_link. contains ( '/' ) {
297271 continue ;
298272 }
299273 let link = ori_link. replace ( "`" , "" ) ;
300274 let ( def, fragment) = {
301- let mut kind = PathKind :: Unknown ;
275+ let mut kind = None ;
302276 let path_str = if let Some ( prefix) =
303277 [ "struct@" , "enum@" , "type@" ,
304278 "trait@" , "union@" ] . iter ( )
305279 . find ( |p| link. starts_with ( * * p) ) {
306- kind = PathKind :: Type ;
280+ kind = Some ( TypeNS ) ;
307281 link. trim_start_matches ( prefix)
308282 } else if let Some ( prefix) =
309283 [ "const@" , "static@" ,
310284 "value@" , "function@" , "mod@" ,
311285 "fn@" , "module@" , "method@" ]
312286 . iter ( ) . find ( |p| link. starts_with ( * * p) ) {
313- kind = PathKind :: Value ;
287+ kind = Some ( ValueNS ) ;
314288 link. trim_start_matches ( prefix)
315289 } else if link. ends_with ( "()" ) {
316- kind = PathKind :: Value ;
290+ kind = Some ( ValueNS ) ;
317291 link. trim_end_matches ( "()" )
318292 } else if link. starts_with ( "macro@" ) {
319- kind = PathKind :: Macro ;
293+ kind = Some ( MacroNS ) ;
320294 link. trim_start_matches ( "macro@" )
321295 } else if link. ends_with ( '!' ) {
322- kind = PathKind :: Macro ;
296+ kind = Some ( MacroNS ) ;
323297 link. trim_end_matches ( '!' )
324298 } else {
325299 & link[ ..]
@@ -331,8 +305,8 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> {
331305 }
332306
333307 match kind {
334- PathKind :: Value => {
335- if let Ok ( def) = self . resolve ( path_str, true , & current_item, parent_node) {
308+ Some ( ns @ ValueNS ) => {
309+ if let Ok ( def) = self . resolve ( path_str, ns , & current_item, parent_node) {
336310 def
337311 } else {
338312 resolution_failure ( cx, & item. attrs , path_str, & dox, link_range) ;
@@ -342,66 +316,58 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> {
342316 continue ;
343317 }
344318 }
345- PathKind :: Type => {
346- if let Ok ( def) = self . resolve ( path_str, false , & current_item, parent_node) {
319+ Some ( ns @ TypeNS ) => {
320+ if let Ok ( def) = self . resolve ( path_str, ns , & current_item, parent_node) {
347321 def
348322 } else {
349323 resolution_failure ( cx, & item. attrs , path_str, & dox, link_range) ;
350324 // This could just be a normal link.
351325 continue ;
352326 }
353327 }
354- PathKind :: Unknown => {
328+ None => {
355329 // Try everything!
356- let mut candidates = vec ! [ ] ;
357-
358- if let Some ( macro_def) = macro_resolve ( cx, path_str) {
359- candidates. push ( ( ( macro_def, None ) , Namespace :: Macro ) ) ;
360- }
361-
362- if let Ok ( type_def) =
363- self . resolve ( path_str, false , & current_item, parent_node)
364- {
365- candidates. push ( ( type_def, Namespace :: Type ) ) ;
366- }
367-
368- if let Ok ( value_def) =
369- self . resolve ( path_str, true , & current_item, parent_node)
370- {
371- // Structs, variants, and mods exist in both namespaces, skip them.
372- match value_def. 0 {
373- Def :: StructCtor ( ..)
374- | Def :: Mod ( ..)
375- | Def :: Variant ( ..)
376- | Def :: VariantCtor ( ..)
377- | Def :: SelfCtor ( ..) => ( ) ,
378- _ => candidates. push ( ( value_def, Namespace :: Value ) ) ,
379- }
380- }
330+ let candidates = PerNS {
331+ macro_ns : macro_resolve ( cx, path_str) . map ( |def| ( def, None ) ) ,
332+ type_ns : self
333+ . resolve ( path_str, TypeNS , & current_item, parent_node)
334+ . ok ( ) ,
335+ value_ns : self
336+ . resolve ( path_str, ValueNS , & current_item, parent_node)
337+ . ok ( )
338+ . and_then ( |( def, fragment) | {
339+ // Constructors are picked up in the type namespace.
340+ match def {
341+ Def :: StructCtor ( ..)
342+ | Def :: VariantCtor ( ..)
343+ | Def :: SelfCtor ( ..) => None ,
344+ _ => Some ( ( def, fragment) )
345+ }
346+ } ) ,
347+ } ;
381348
382- if candidates. len ( ) == 1 {
383- candidates. remove ( 0 ) . 0
384- } else if candidates. is_empty ( ) {
349+ if candidates. is_empty ( ) {
385350 resolution_failure ( cx, & item. attrs , path_str, & dox, link_range) ;
386351 // this could just be a normal link
387352 continue ;
388- } else {
389- let candidates = candidates. into_iter ( ) . map ( |( ( def, _) , ns) | {
390- ( def, ns)
391- } ) . collect :: < Vec < _ > > ( ) ;
353+ }
392354
355+ let is_unambiguous = candidates. clone ( ) . present_items ( ) . count ( ) == 1 ;
356+ if is_unambiguous {
357+ candidates. present_items ( ) . next ( ) . unwrap ( )
358+ } else {
393359 ambiguity_error (
394360 cx,
395361 & item. attrs ,
396362 path_str,
397363 & dox,
398364 link_range,
399- & candidates,
365+ candidates. map ( |candidate| candidate . map ( | ( def , _ ) | def ) ) ,
400366 ) ;
401367 continue ;
402368 }
403369 }
404- PathKind :: Macro => {
370+ Some ( MacroNS ) => {
405371 if let Some ( def) = macro_resolve ( cx, path_str) {
406372 ( def, None )
407373 } else {
@@ -514,13 +480,16 @@ fn ambiguity_error(
514480 path_str : & str ,
515481 dox : & str ,
516482 link_range : Option < Range < usize > > ,
517- candidates : & [ ( Def , Namespace ) ] ,
483+ candidates : PerNS < Option < Def > > ,
518484) {
519485 let sp = span_of_attrs ( attrs) ;
520486
521487 let mut msg = format ! ( "`{}` is " , path_str) ;
522488
523- match candidates {
489+ let candidates = [ TypeNS , ValueNS , MacroNS ] . iter ( ) . filter_map ( |& ns| {
490+ candidates[ ns] . map ( |def| ( def, ns) )
491+ } ) . collect :: < Vec < _ > > ( ) ;
492+ match candidates. as_slice ( ) {
524493 [ ( first_def, _) , ( second_def, _) ] => {
525494 msg += & format ! (
526495 "both {} {} and {} {}" ,
@@ -568,9 +537,9 @@ fn ambiguity_error(
568537 ( Def :: Union ( ..) , _) => "union" ,
569538 ( Def :: Trait ( ..) , _) => "trait" ,
570539 ( Def :: Mod ( ..) , _) => "module" ,
571- ( _, Namespace :: Type ) => "type" ,
572- ( _, Namespace :: Value ) => "value" ,
573- ( _, Namespace :: Macro ) => "macro" ,
540+ ( _, TypeNS ) => "type" ,
541+ ( _, ValueNS ) => "value" ,
542+ ( _, MacroNS ) => "macro" ,
574543 } ;
575544
576545 // FIXME: if this is an implied shortcut link, it's bad style to suggest `@`
@@ -646,11 +615,11 @@ const PRIMITIVES: &[(&str, Def)] = &[
646615 ( "char" , Def :: PrimTy ( hir:: PrimTy :: Char ) ) ,
647616] ;
648617
649- fn is_primitive ( path_str : & str , is_val : bool ) -> Option < Def > {
650- if is_val {
651- None
652- } else {
618+ fn is_primitive ( path_str : & str , ns : Namespace ) -> Option < Def > {
619+ if ns == TypeNS {
653620 PRIMITIVES . iter ( ) . find ( |x| x. 0 == path_str) . map ( |x| x. 1 )
621+ } else {
622+ None
654623 }
655624}
656625
0 commit comments