@@ -217,7 +217,7 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
217
217
let kind = if let Some ( intermediate) = self . check_full_res (
218
218
TypeNS ,
219
219
& intermediate_path,
220
- Some ( module_id) ,
220
+ module_id,
221
221
current_item,
222
222
extra_fragment,
223
223
) {
@@ -235,7 +235,7 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
235
235
fn macro_resolve (
236
236
& self ,
237
237
path_str : & ' a str ,
238
- parent_id : Option < DefId > ,
238
+ module_id : DefId ,
239
239
) -> Result < Res , ResolutionFailure < ' a > > {
240
240
let cx = self . cx ;
241
241
let path = ast:: Path :: from_ident ( Ident :: from_str ( path_str) ) ;
@@ -254,28 +254,23 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
254
254
if let Some ( res) = resolver. all_macros ( ) . get ( & Symbol :: intern ( path_str) ) {
255
255
return Some ( Ok ( res. map_id ( |_| panic ! ( "unexpected id" ) ) ) ) ;
256
256
}
257
- if let Some ( module_id) = parent_id {
258
- debug ! ( "resolving {} as a macro in the module {:?}" , path_str, module_id) ;
259
- if let Ok ( ( _, res) ) =
260
- resolver. resolve_str_path_error ( DUMMY_SP , path_str, MacroNS , module_id)
261
- {
262
- // don't resolve builtins like `#[derive]`
263
- if let Res :: Def ( ..) = res {
264
- let res = res. map_id ( |_| panic ! ( "unexpected node_id" ) ) ;
265
- return Some ( Ok ( res) ) ;
266
- }
257
+ debug ! ( "resolving {} as a macro in the module {:?}" , path_str, module_id) ;
258
+ if let Ok ( ( _, res) ) =
259
+ resolver. resolve_str_path_error ( DUMMY_SP , path_str, MacroNS , module_id)
260
+ {
261
+ // don't resolve builtins like `#[derive]`
262
+ if let Res :: Def ( ..) = res {
263
+ let res = res. map_id ( |_| panic ! ( "unexpected node_id" ) ) ;
264
+ return Some ( Ok ( res) ) ;
267
265
}
268
- } else {
269
- debug ! ( "attempting to resolve item without parent module: {}" , path_str) ;
270
- return Some ( Err ( ResolutionFailure :: NoParentItem ) ) ;
271
266
}
272
267
None
273
268
} )
274
269
// This weird control flow is so we don't borrow the resolver more than once at a time
275
270
. unwrap_or_else ( || {
276
271
let mut split = path_str. rsplitn ( 2 , "::" ) ;
277
272
if let Some ( ( parent, base) ) = split. next ( ) . and_then ( |x| Some ( ( split. next ( ) ?, x) ) ) {
278
- if let Some ( res) = self . check_full_res ( TypeNS , parent, parent_id , & None , & None ) {
273
+ if let Some ( res) = self . check_full_res ( TypeNS , parent, module_id , & None , & None ) {
279
274
return Err ( if matches ! ( res, Res :: PrimTy ( _) ) {
280
275
ResolutionFailure :: NoPrimitiveAssocItem {
281
276
res,
@@ -287,306 +282,282 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
287
282
} ) ;
288
283
}
289
284
}
290
- Err ( ResolutionFailure :: NotInScope {
291
- module_id : parent_id. expect ( "already saw `Some` when resolving as a macro" ) ,
292
- name : path_str. into ( ) ,
293
- } )
285
+ Err ( ResolutionFailure :: NotInScope { module_id, name : path_str. into ( ) } )
294
286
} )
295
287
}
288
+
296
289
/// Resolves a string as a path within a particular namespace. Also returns an optional
297
290
/// URL fragment in the case of variants and methods.
298
291
fn resolve < ' path > (
299
292
& self ,
300
293
path_str : & ' path str ,
301
294
ns : Namespace ,
302
295
current_item : & Option < String > ,
303
- parent_id : Option < DefId > ,
296
+ module_id : DefId ,
304
297
extra_fragment : & Option < String > ,
305
298
) -> Result < ( Res , Option < String > ) , ErrorKind < ' path > > {
306
299
let cx = self . cx ;
307
300
308
- // In case we're in a module, try to resolve the relative path.
309
- if let Some ( module_id) = parent_id {
310
- let result = cx. enter_resolver ( |resolver| {
311
- resolver. resolve_str_path_error ( DUMMY_SP , & path_str, ns, module_id)
312
- } ) ;
313
- debug ! ( "{} resolved to {:?} in namespace {:?}" , path_str, result, ns) ;
314
- let result = match result {
315
- Ok ( ( _, Res :: Err ) ) => Err ( ( ) ) ,
316
- x => x,
317
- } ;
301
+ let result = cx. enter_resolver ( |resolver| {
302
+ resolver. resolve_str_path_error ( DUMMY_SP , & path_str, ns, module_id)
303
+ } ) ;
304
+ debug ! ( "{} resolved to {:?} in namespace {:?}" , path_str, result, ns) ;
305
+ let result = match result {
306
+ Ok ( ( _, Res :: Err ) ) => Err ( ( ) ) ,
307
+ x => x,
308
+ } ;
318
309
319
- if let Ok ( ( _, res) ) = result {
320
- let res = res. map_id ( |_| panic ! ( "unexpected node_id" ) ) ;
321
- // In case this is a trait item, skip the
322
- // early return and try looking for the trait.
323
- let value = match res {
324
- Res :: Def ( DefKind :: AssocFn | DefKind :: AssocConst , _) => true ,
325
- Res :: Def ( DefKind :: AssocTy , _) => false ,
326
- Res :: Def ( DefKind :: Variant , _) => {
327
- return handle_variant ( cx, res, extra_fragment) ;
328
- }
329
- // Not a trait item; just return what we found.
330
- Res :: PrimTy ( ..) => {
331
- if extra_fragment. is_some ( ) {
332
- return Err ( ErrorKind :: AnchorFailure (
333
- AnchorFailure :: RustdocAnchorConflict ( res) ,
334
- ) ) ;
335
- }
336
- return Ok ( ( res, Some ( path_str. to_owned ( ) ) ) ) ;
337
- }
338
- Res :: Def ( DefKind :: Mod , _) => {
339
- return Ok ( ( res, extra_fragment. clone ( ) ) ) ;
340
- }
341
- _ => {
342
- return Ok ( ( res, extra_fragment. clone ( ) ) ) ;
310
+ if let Ok ( ( _, res) ) = result {
311
+ let res = res. map_id ( |_| panic ! ( "unexpected node_id" ) ) ;
312
+ // In case this is a trait item, skip the
313
+ // early return and try looking for the trait.
314
+ let value = match res {
315
+ Res :: Def ( DefKind :: AssocFn | DefKind :: AssocConst , _) => true ,
316
+ Res :: Def ( DefKind :: AssocTy , _) => false ,
317
+ Res :: Def ( DefKind :: Variant , _) => {
318
+ return handle_variant ( cx, res, extra_fragment) ;
319
+ }
320
+ // Not a trait item; just return what we found.
321
+ Res :: PrimTy ( ..) => {
322
+ if extra_fragment. is_some ( ) {
323
+ return Err ( ErrorKind :: AnchorFailure (
324
+ AnchorFailure :: RustdocAnchorConflict ( res) ,
325
+ ) ) ;
343
326
}
344
- } ;
345
-
346
- if value != ( ns == ValueNS ) {
347
- return Err ( ResolutionFailure :: WrongNamespace ( res, ns ) . into ( ) ) ;
327
+ return Ok ( ( res , Some ( path_str . to_owned ( ) ) ) ) ;
328
+ }
329
+ Res :: Def ( DefKind :: Mod , _ ) => {
330
+ return Ok ( ( res, extra_fragment . clone ( ) ) ) ;
348
331
}
349
- } else if let Some ( ( path, prim) ) = is_primitive ( path_str, ns) {
350
- if extra_fragment. is_some ( ) {
351
- return Err ( ErrorKind :: AnchorFailure ( AnchorFailure :: RustdocAnchorConflict (
352
- prim,
353
- ) ) ) ;
332
+ _ => {
333
+ return Ok ( ( res, extra_fragment. clone ( ) ) ) ;
354
334
}
355
- return Ok ( ( prim, Some ( path. to_owned ( ) ) ) ) ;
335
+ } ;
336
+
337
+ if value != ( ns == ValueNS ) {
338
+ return Err ( ResolutionFailure :: WrongNamespace ( res, ns) . into ( ) ) ;
356
339
}
340
+ } else if let Some ( ( path, prim) ) = is_primitive ( path_str, ns) {
341
+ if extra_fragment. is_some ( ) {
342
+ return Err ( ErrorKind :: AnchorFailure ( AnchorFailure :: RustdocAnchorConflict ( prim) ) ) ;
343
+ }
344
+ return Ok ( ( prim, Some ( path. to_owned ( ) ) ) ) ;
345
+ }
357
346
358
- // Try looking for methods and associated items.
359
- let mut split = path_str. rsplitn ( 2 , "::" ) ;
360
- // this can be an `unwrap()` because we ensure the link is never empty
361
- let item_name = Symbol :: intern ( split. next ( ) . unwrap ( ) ) ;
362
- let path_root = split
363
- . next ( )
364
- . map ( |f| {
365
- if f == "self" || f == "Self" {
366
- if let Some ( name) = current_item. as_ref ( ) {
367
- return name. clone ( ) ;
368
- }
369
- }
370
- f. to_owned ( )
371
- } )
372
- // If there's no `::`, it's not an associated item.
373
- // So we can be sure that `rustc_resolve` was accurate when it said it wasn't resolved.
374
- . ok_or_else ( || {
375
- debug ! ( "found no `::`, assumming {} was correctly not in scope" , item_name) ;
376
- ResolutionFailure :: NotInScope { module_id, name : item_name. to_string ( ) . into ( ) }
377
- } ) ?;
378
-
379
- if let Some ( ( path, prim) ) = is_primitive ( & path_root, TypeNS ) {
380
- let impls = primitive_impl ( cx, & path)
381
- . ok_or_else ( || ResolutionFailure :: NoPrimitiveImpl ( prim, path_root. into ( ) ) ) ?;
382
- for & impl_ in impls {
383
- let link = cx
384
- . tcx
385
- . associated_items ( impl_)
386
- . find_by_name_and_namespace (
387
- cx. tcx ,
388
- Ident :: with_dummy_span ( item_name) ,
389
- ns,
390
- impl_,
391
- )
392
- . map ( |item| match item. kind {
393
- ty:: AssocKind :: Fn => "method" ,
394
- ty:: AssocKind :: Const => "associatedconstant" ,
395
- ty:: AssocKind :: Type => "associatedtype" ,
396
- } )
397
- . map ( |out| ( prim, Some ( format ! ( "{}#{}.{}" , path, out, item_name) ) ) ) ;
398
- if let Some ( link) = link {
399
- return Ok ( link) ;
347
+ // Try looking for methods and associated items.
348
+ let mut split = path_str. rsplitn ( 2 , "::" ) ;
349
+ // this can be an `unwrap()` because we ensure the link is never empty
350
+ let item_name = Symbol :: intern ( split. next ( ) . unwrap ( ) ) ;
351
+ let path_root = split
352
+ . next ( )
353
+ . map ( |f| {
354
+ if f == "self" || f == "Self" {
355
+ if let Some ( name) = current_item. as_ref ( ) {
356
+ return name. clone ( ) ;
400
357
}
401
358
}
402
- debug ! (
403
- "returning primitive error for {}::{} in {} namespace" ,
404
- path,
405
- item_name,
406
- ns. descr( )
407
- ) ;
408
- return Err ( ResolutionFailure :: NoPrimitiveAssocItem {
409
- res : prim,
410
- prim_name : path,
411
- assoc_item : item_name,
359
+ f. to_owned ( )
360
+ } )
361
+ // If there's no `::`, it's not an associated item.
362
+ // So we can be sure that `rustc_resolve` was accurate when it said it wasn't resolved.
363
+ . ok_or_else ( || {
364
+ debug ! ( "found no `::`, assumming {} was correctly not in scope" , item_name) ;
365
+ ResolutionFailure :: NotInScope { module_id, name : item_name. to_string ( ) . into ( ) }
366
+ } ) ?;
367
+
368
+ if let Some ( ( path, prim) ) = is_primitive ( & path_root, TypeNS ) {
369
+ let impls = primitive_impl ( cx, & path)
370
+ . ok_or_else ( || ResolutionFailure :: NoPrimitiveImpl ( prim, path_root. into ( ) ) ) ?;
371
+ for & impl_ in impls {
372
+ let link = cx
373
+ . tcx
374
+ . associated_items ( impl_)
375
+ . find_by_name_and_namespace (
376
+ cx. tcx ,
377
+ Ident :: with_dummy_span ( item_name) ,
378
+ ns,
379
+ impl_,
380
+ )
381
+ . map ( |item| match item. kind {
382
+ ty:: AssocKind :: Fn => "method" ,
383
+ ty:: AssocKind :: Const => "associatedconstant" ,
384
+ ty:: AssocKind :: Type => "associatedtype" ,
385
+ } )
386
+ . map ( |out| ( prim, Some ( format ! ( "{}#{}.{}" , path, out, item_name) ) ) ) ;
387
+ if let Some ( link) = link {
388
+ return Ok ( link) ;
412
389
}
413
- . into ( ) ) ;
414
390
}
391
+ debug ! (
392
+ "returning primitive error for {}::{} in {} namespace" ,
393
+ path,
394
+ item_name,
395
+ ns. descr( )
396
+ ) ;
397
+ return Err ( ResolutionFailure :: NoPrimitiveAssocItem {
398
+ res : prim,
399
+ prim_name : path,
400
+ assoc_item : item_name,
401
+ }
402
+ . into ( ) ) ;
403
+ }
415
404
416
- let ty_res = cx
417
- . enter_resolver ( |resolver| {
418
- // only types can have associated items
419
- resolver. resolve_str_path_error ( DUMMY_SP , & path_root, TypeNS , module_id)
420
- } )
421
- . map ( |( _, res) | res) ;
422
- let ty_res = match ty_res {
423
- Err ( ( ) ) | Ok ( Res :: Err ) => {
424
- return if ns == Namespace :: ValueNS {
425
- self . variant_field ( path_str, current_item, module_id, extra_fragment)
426
- } else {
427
- // See if it only broke because of the namespace.
428
- let kind = cx. enter_resolver ( |resolver| {
429
- // NOTE: this doesn't use `check_full_res` because we explicitly want to ignore `TypeNS` (we already checked it)
430
- for & ns in & [ MacroNS , ValueNS ] {
431
- match resolver
432
- . resolve_str_path_error ( DUMMY_SP , & path_root, ns, module_id)
433
- {
434
- Ok ( ( _, Res :: Err ) ) | Err ( ( ) ) => { }
435
- Ok ( ( _, res) ) => {
436
- let res = res. map_id ( |_| panic ! ( "unexpected node_id" ) ) ;
437
- return ResolutionFailure :: CannotHaveAssociatedItems (
438
- res, ns,
439
- ) ;
440
- }
405
+ let ty_res = cx
406
+ . enter_resolver ( |resolver| {
407
+ // only types can have associated items
408
+ resolver. resolve_str_path_error ( DUMMY_SP , & path_root, TypeNS , module_id)
409
+ } )
410
+ . map ( |( _, res) | res) ;
411
+ let ty_res = match ty_res {
412
+ Err ( ( ) ) | Ok ( Res :: Err ) => {
413
+ return if ns == Namespace :: ValueNS {
414
+ self . variant_field ( path_str, current_item, module_id, extra_fragment)
415
+ } else {
416
+ // See if it only broke because of the namespace.
417
+ let kind = cx. enter_resolver ( |resolver| {
418
+ // NOTE: this doesn't use `check_full_res` because we explicitly want to ignore `TypeNS` (we already checked it)
419
+ for & ns in & [ MacroNS , ValueNS ] {
420
+ match resolver
421
+ . resolve_str_path_error ( DUMMY_SP , & path_root, ns, module_id)
422
+ {
423
+ Ok ( ( _, Res :: Err ) ) | Err ( ( ) ) => { }
424
+ Ok ( ( _, res) ) => {
425
+ let res = res. map_id ( |_| panic ! ( "unexpected node_id" ) ) ;
426
+ return ResolutionFailure :: CannotHaveAssociatedItems ( res, ns) ;
441
427
}
442
428
}
443
- ResolutionFailure :: NotInScope { module_id, name : path_root. into ( ) }
444
- } ) ;
445
- Err ( kind. into ( ) )
446
- } ;
447
- }
448
- Ok ( res) => res,
449
- } ;
450
- let ty_res = ty_res. map_id ( |_| panic ! ( "unexpected node_id" ) ) ;
451
- let res = match ty_res {
452
- Res :: Def (
453
- DefKind :: Struct | DefKind :: Union | DefKind :: Enum | DefKind :: TyAlias ,
454
- did,
455
- ) => {
456
- debug ! ( "looking for associated item named {} for item {:?}" , item_name, did) ;
457
- // Checks if item_name belongs to `impl SomeItem`
458
- let assoc_item = cx
459
- . tcx
460
- . inherent_impls ( did)
461
- . iter ( )
462
- . flat_map ( |& imp| {
463
- cx. tcx . associated_items ( imp) . find_by_name_and_namespace (
464
- cx. tcx ,
465
- Ident :: with_dummy_span ( item_name) ,
466
- ns,
467
- imp,
468
- )
469
- } )
470
- . map ( |item| ( item. kind , item. def_id ) )
471
- // There should only ever be one associated item that matches from any inherent impl
472
- . next ( )
473
- // Check if item_name belongs to `impl SomeTrait for SomeItem`
474
- // This gives precedence to `impl SomeItem`:
475
- // Although having both would be ambiguous, use impl version for compat. sake.
476
- // To handle that properly resolve() would have to support
477
- // something like [`ambi_fn`](<SomeStruct as SomeTrait>::ambi_fn)
478
- . or_else ( || {
479
- let kind = resolve_associated_trait_item (
480
- did, module_id, item_name, ns, & self . cx ,
481
- ) ;
482
- debug ! ( "got associated item kind {:?}" , kind) ;
483
- kind
484
- } ) ;
485
-
486
- if let Some ( ( kind, id) ) = assoc_item {
487
- let out = match kind {
488
- ty:: AssocKind :: Fn => "method" ,
489
- ty:: AssocKind :: Const => "associatedconstant" ,
490
- ty:: AssocKind :: Type => "associatedtype" ,
491
- } ;
492
- Some ( if extra_fragment. is_some ( ) {
493
- Err ( ErrorKind :: AnchorFailure ( AnchorFailure :: RustdocAnchorConflict (
494
- ty_res,
495
- ) ) )
496
- } else {
497
- // HACK(jynelson): `clean` expects the type, not the associated item.
498
- // but the disambiguator logic expects the associated item.
499
- // Store the kind in a side channel so that only the disambiguator logic looks at it.
500
- self . kind_side_channel . set ( Some ( ( kind. as_def_kind ( ) , id) ) ) ;
501
- Ok ( ( ty_res, Some ( format ! ( "{}.{}" , out, item_name) ) ) )
502
- } )
503
- } else if ns == Namespace :: ValueNS {
504
- debug ! ( "looking for variants or fields named {} for {:?}" , item_name, did) ;
505
- match cx. tcx . type_of ( did) . kind ( ) {
506
- ty:: Adt ( def, _) => {
507
- let field = if def. is_enum ( ) {
508
- def. all_fields ( ) . find ( |item| item. ident . name == item_name)
509
- } else {
510
- def. non_enum_variant ( )
511
- . fields
512
- . iter ( )
513
- . find ( |item| item. ident . name == item_name)
514
- } ;
515
- field. map ( |item| {
516
- if extra_fragment. is_some ( ) {
517
- let res = Res :: Def (
518
- if def. is_enum ( ) {
519
- DefKind :: Variant
520
- } else {
521
- DefKind :: Field
522
- } ,
523
- item. did ,
524
- ) ;
525
- Err ( ErrorKind :: AnchorFailure (
526
- AnchorFailure :: RustdocAnchorConflict ( res) ,
527
- ) )
528
- } else {
529
- Ok ( (
530
- ty_res,
531
- Some ( format ! (
532
- "{}.{}" ,
533
- if def. is_enum( ) {
534
- "variant"
535
- } else {
536
- "structfield"
537
- } ,
538
- item. ident
539
- ) ) ,
540
- ) )
541
- }
542
- } )
543
- }
544
- _ => None ,
545
429
}
546
- } else {
547
- // We already know this isn't in ValueNS, so no need to check variant_field
548
- return Err ( ResolutionFailure :: NoAssocItem ( ty_res, item_name) . into ( ) ) ;
549
- }
550
- }
551
- Res :: Def ( DefKind :: Trait , did) => cx
430
+ ResolutionFailure :: NotInScope { module_id, name : path_root. into ( ) }
431
+ } ) ;
432
+ Err ( kind. into ( ) )
433
+ } ;
434
+ }
435
+ Ok ( res) => res,
436
+ } ;
437
+ let ty_res = ty_res. map_id ( |_| panic ! ( "unexpected node_id" ) ) ;
438
+ let res = match ty_res {
439
+ Res :: Def ( DefKind :: Struct | DefKind :: Union | DefKind :: Enum | DefKind :: TyAlias , did) => {
440
+ debug ! ( "looking for associated item named {} for item {:?}" , item_name, did) ;
441
+ // Checks if item_name belongs to `impl SomeItem`
442
+ let assoc_item = cx
552
443
. tcx
553
- . associated_items ( did)
554
- . find_by_name_and_namespace ( cx. tcx , Ident :: with_dummy_span ( item_name) , ns, did)
555
- . map ( |item| {
556
- let kind = match item. kind {
557
- ty:: AssocKind :: Const => "associatedconstant" ,
558
- ty:: AssocKind :: Type => "associatedtype" ,
559
- ty:: AssocKind :: Fn => {
560
- if item. defaultness . has_value ( ) {
561
- "method"
444
+ . inherent_impls ( did)
445
+ . iter ( )
446
+ . flat_map ( |& imp| {
447
+ cx. tcx . associated_items ( imp) . find_by_name_and_namespace (
448
+ cx. tcx ,
449
+ Ident :: with_dummy_span ( item_name) ,
450
+ ns,
451
+ imp,
452
+ )
453
+ } )
454
+ . map ( |item| ( item. kind , item. def_id ) )
455
+ // There should only ever be one associated item that matches from any inherent impl
456
+ . next ( )
457
+ // Check if item_name belongs to `impl SomeTrait for SomeItem`
458
+ // This gives precedence to `impl SomeItem`:
459
+ // Although having both would be ambiguous, use impl version for compat. sake.
460
+ // To handle that properly resolve() would have to support
461
+ // something like [`ambi_fn`](<SomeStruct as SomeTrait>::ambi_fn)
462
+ . or_else ( || {
463
+ let kind =
464
+ resolve_associated_trait_item ( did, module_id, item_name, ns, & self . cx ) ;
465
+ debug ! ( "got associated item kind {:?}" , kind) ;
466
+ kind
467
+ } ) ;
468
+
469
+ if let Some ( ( kind, id) ) = assoc_item {
470
+ let out = match kind {
471
+ ty:: AssocKind :: Fn => "method" ,
472
+ ty:: AssocKind :: Const => "associatedconstant" ,
473
+ ty:: AssocKind :: Type => "associatedtype" ,
474
+ } ;
475
+ Some ( if extra_fragment. is_some ( ) {
476
+ Err ( ErrorKind :: AnchorFailure ( AnchorFailure :: RustdocAnchorConflict ( ty_res) ) )
477
+ } else {
478
+ // HACK(jynelson): `clean` expects the type, not the associated item.
479
+ // but the disambiguator logic expects the associated item.
480
+ // Store the kind in a side channel so that only the disambiguator logic looks at it.
481
+ self . kind_side_channel . set ( Some ( ( kind. as_def_kind ( ) , id) ) ) ;
482
+ Ok ( ( ty_res, Some ( format ! ( "{}.{}" , out, item_name) ) ) )
483
+ } )
484
+ } else if ns == Namespace :: ValueNS {
485
+ debug ! ( "looking for variants or fields named {} for {:?}" , item_name, did) ;
486
+ match cx. tcx . type_of ( did) . kind ( ) {
487
+ ty:: Adt ( def, _) => {
488
+ let field = if def. is_enum ( ) {
489
+ def. all_fields ( ) . find ( |item| item. ident . name == item_name)
490
+ } else {
491
+ def. non_enum_variant ( )
492
+ . fields
493
+ . iter ( )
494
+ . find ( |item| item. ident . name == item_name)
495
+ } ;
496
+ field. map ( |item| {
497
+ if extra_fragment. is_some ( ) {
498
+ let res = Res :: Def (
499
+ if def. is_enum ( ) {
500
+ DefKind :: Variant
501
+ } else {
502
+ DefKind :: Field
503
+ } ,
504
+ item. did ,
505
+ ) ;
506
+ Err ( ErrorKind :: AnchorFailure (
507
+ AnchorFailure :: RustdocAnchorConflict ( res) ,
508
+ ) )
562
509
} else {
563
- "tymethod"
510
+ Ok ( (
511
+ ty_res,
512
+ Some ( format ! (
513
+ "{}.{}" ,
514
+ if def. is_enum( ) { "variant" } else { "structfield" } ,
515
+ item. ident
516
+ ) ) ,
517
+ ) )
564
518
}
565
- }
566
- } ;
567
-
568
- if extra_fragment. is_some ( ) {
569
- Err ( ErrorKind :: AnchorFailure ( AnchorFailure :: RustdocAnchorConflict (
570
- ty_res,
571
- ) ) )
572
- } else {
573
- let res = Res :: Def ( item. kind . as_def_kind ( ) , item. def_id ) ;
574
- Ok ( ( res, Some ( format ! ( "{}.{}" , kind, item_name) ) ) )
519
+ } )
575
520
}
576
- } ) ,
577
- _ => None ,
578
- } ;
579
- res. unwrap_or_else ( || {
580
- if ns == Namespace :: ValueNS {
581
- self . variant_field ( path_str, current_item, module_id, extra_fragment)
521
+ _ => None ,
522
+ }
582
523
} else {
583
- Err ( ResolutionFailure :: NoAssocItem ( ty_res, item_name) . into ( ) )
524
+ // We already know this isn't in ValueNS, so no need to check variant_field
525
+ return Err ( ResolutionFailure :: NoAssocItem ( ty_res, item_name) . into ( ) ) ;
584
526
}
585
- } )
586
- } else {
587
- debug ! ( "attempting to resolve item without parent module: {}" , path_str) ;
588
- Err ( ResolutionFailure :: NoParentItem . into ( ) )
589
- }
527
+ }
528
+ Res :: Def ( DefKind :: Trait , did) => cx
529
+ . tcx
530
+ . associated_items ( did)
531
+ . find_by_name_and_namespace ( cx. tcx , Ident :: with_dummy_span ( item_name) , ns, did)
532
+ . map ( |item| {
533
+ let kind = match item. kind {
534
+ ty:: AssocKind :: Const => "associatedconstant" ,
535
+ ty:: AssocKind :: Type => "associatedtype" ,
536
+ ty:: AssocKind :: Fn => {
537
+ if item. defaultness . has_value ( ) {
538
+ "method"
539
+ } else {
540
+ "tymethod"
541
+ }
542
+ }
543
+ } ;
544
+
545
+ if extra_fragment. is_some ( ) {
546
+ Err ( ErrorKind :: AnchorFailure ( AnchorFailure :: RustdocAnchorConflict ( ty_res) ) )
547
+ } else {
548
+ let res = Res :: Def ( item. kind . as_def_kind ( ) , item. def_id ) ;
549
+ Ok ( ( res, Some ( format ! ( "{}.{}" , kind, item_name) ) ) )
550
+ }
551
+ } ) ,
552
+ _ => None ,
553
+ } ;
554
+ res. unwrap_or_else ( || {
555
+ if ns == Namespace :: ValueNS {
556
+ self . variant_field ( path_str, current_item, module_id, extra_fragment)
557
+ } else {
558
+ Err ( ResolutionFailure :: NoAssocItem ( ty_res, item_name) . into ( ) )
559
+ }
560
+ } )
590
561
}
591
562
592
563
/// Used for reporting better errors.
@@ -599,7 +570,7 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
599
570
& self ,
600
571
ns : Namespace ,
601
572
path_str : & str ,
602
- base_node : Option < DefId > ,
573
+ module_id : DefId ,
603
574
current_item : & Option < String > ,
604
575
extra_fragment : & Option < String > ,
605
576
) -> Option < Res > {
@@ -616,11 +587,11 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
616
587
} ;
617
588
// cannot be used for macro namespace
618
589
let check_full_res = |this : & Self , ns| {
619
- let result = this. resolve ( path_str, ns, current_item, base_node , extra_fragment) ;
590
+ let result = this. resolve ( path_str, ns, current_item, module_id , extra_fragment) ;
620
591
check_full_res_inner ( this, result. map ( |( res, _) | res) )
621
592
} ;
622
593
let check_full_res_macro = |this : & Self | {
623
- let result = this. macro_resolve ( path_str, base_node ) ;
594
+ let result = this. macro_resolve ( path_str, module_id ) ;
624
595
check_full_res_inner ( this, result. map_err ( ErrorKind :: from) )
625
596
} ;
626
597
match ns {
@@ -843,7 +814,6 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> {
843
814
self . mod_ids . push ( item. def_id ) ;
844
815
}
845
816
846
- let cx = self . cx ;
847
817
let dox = item. attrs . collapsed_doc_value ( ) . unwrap_or_else ( String :: new) ;
848
818
trace ! ( "got documentation '{}'" , dox) ;
849
819
@@ -885,377 +855,439 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> {
885
855
} ) ;
886
856
887
857
for ( ori_link, link_range) in markdown_links ( & dox) {
888
- trace ! ( "considering link '{}'" , ori_link) ;
858
+ self . resolve_link (
859
+ & mut item,
860
+ & dox,
861
+ & current_item,
862
+ parent_node,
863
+ & parent_name,
864
+ ori_link,
865
+ link_range,
866
+ ) ;
867
+ }
868
+
869
+ if item. is_mod ( ) && !item. attrs . inner_docs {
870
+ self . mod_ids . push ( item. def_id ) ;
871
+ }
872
+
873
+ if item. is_mod ( ) {
874
+ let ret = self . fold_item_recur ( item) ;
875
+
876
+ self . mod_ids . pop ( ) ;
889
877
890
- // Bail early for real links.
891
- if ori_link. contains ( '/' ) {
892
- continue ;
878
+ ret
879
+ } else {
880
+ self . fold_item_recur ( item)
881
+ }
882
+ }
883
+ }
884
+
885
+ impl LinkCollector < ' _ , ' _ > {
886
+ fn resolve_link (
887
+ & self ,
888
+ item : & mut Item ,
889
+ dox : & str ,
890
+ current_item : & Option < String > ,
891
+ parent_node : Option < DefId > ,
892
+ parent_name : & Option < String > ,
893
+ ori_link : String ,
894
+ link_range : Option < Range < usize > > ,
895
+ ) {
896
+ trace ! ( "considering link '{}'" , ori_link) ;
897
+
898
+ // Bail early for real links.
899
+ if ori_link. contains ( '/' ) {
900
+ return ;
901
+ }
902
+
903
+ // [] is mostly likely not supposed to be a link
904
+ if ori_link. is_empty ( ) {
905
+ return ;
906
+ }
907
+
908
+ let cx = self . cx ;
909
+ let link = ori_link. replace ( "`" , "" ) ;
910
+ let parts = link. split ( '#' ) . collect :: < Vec < _ > > ( ) ;
911
+ let ( link, extra_fragment) = if parts. len ( ) > 2 {
912
+ anchor_failure ( cx, & item, & link, dox, link_range, AnchorFailure :: MultipleAnchors ) ;
913
+ return ;
914
+ } else if parts. len ( ) == 2 {
915
+ if parts[ 0 ] . trim ( ) . is_empty ( ) {
916
+ // This is an anchor to an element of the current page, nothing to do in here!
917
+ return ;
893
918
}
919
+ ( parts[ 0 ] , Some ( parts[ 1 ] . to_owned ( ) ) )
920
+ } else {
921
+ ( parts[ 0 ] , None )
922
+ } ;
923
+ let resolved_self;
924
+ let link_text;
925
+ let mut path_str;
926
+ let disambiguator;
927
+ let ( mut res, mut fragment) = {
928
+ path_str = if let Ok ( ( d, path) ) = Disambiguator :: from_str ( & link) {
929
+ disambiguator = Some ( d) ;
930
+ path
931
+ } else {
932
+ disambiguator = None ;
933
+ & link
934
+ }
935
+ . trim ( ) ;
894
936
895
- // [] is mostly likely not supposed to be a link
896
- if ori_link. is_empty ( ) {
897
- continue ;
937
+ if path_str. contains ( |ch : char | !( ch. is_alphanumeric ( ) || ch == ':' || ch == '_' ) ) {
938
+ return ;
898
939
}
899
940
900
- let link = ori_link. replace ( "`" , "" ) ;
901
- let parts = link. split ( '#' ) . collect :: < Vec < _ > > ( ) ;
902
- let ( link, extra_fragment) = if parts. len ( ) > 2 {
903
- anchor_failure ( cx, & item, & link, & dox, link_range, AnchorFailure :: MultipleAnchors ) ;
904
- continue ;
905
- } else if parts. len ( ) == 2 {
906
- if parts[ 0 ] . trim ( ) . is_empty ( ) {
907
- // This is an anchor to an element of the current page, nothing to do in here!
908
- continue ;
909
- }
910
- ( parts[ 0 ] , Some ( parts[ 1 ] . to_owned ( ) ) )
941
+ // We stripped `()` and `!` when parsing the disambiguator.
942
+ // Add them back to be displayed, but not prefix disambiguators.
943
+ link_text = disambiguator
944
+ . map ( |d| d. display_for ( path_str) )
945
+ . unwrap_or_else ( || path_str. to_owned ( ) ) ;
946
+
947
+ // In order to correctly resolve intra-doc-links we need to
948
+ // pick a base AST node to work from. If the documentation for
949
+ // this module came from an inner comment (//!) then we anchor
950
+ // our name resolution *inside* the module. If, on the other
951
+ // hand it was an outer comment (///) then we anchor the name
952
+ // resolution in the parent module on the basis that the names
953
+ // used are more likely to be intended to be parent names. For
954
+ // this, we set base_node to None for inner comments since
955
+ // we've already pushed this node onto the resolution stack but
956
+ // for outer comments we explicitly try and resolve against the
957
+ // parent_node first.
958
+ let base_node = if item. is_mod ( ) && item. attrs . inner_docs {
959
+ self . mod_ids . last ( ) . copied ( )
911
960
} else {
912
- ( parts [ 0 ] , None )
961
+ parent_node
913
962
} ;
914
- let resolved_self;
915
- let link_text;
916
- let mut path_str;
917
- let disambiguator;
918
- let ( mut res, mut fragment) = {
919
- path_str = if let Ok ( ( d, path) ) = Disambiguator :: from_str ( & link) {
920
- disambiguator = Some ( d) ;
921
- path
922
- } else {
923
- disambiguator = None ;
924
- & link
925
- }
926
- . trim ( ) ;
927
963
928
- if path_str. contains ( |ch : char | !( ch. is_alphanumeric ( ) || ch == ':' || ch == '_' ) ) {
929
- continue ;
964
+ let module_id = if let Some ( id) = base_node {
965
+ id
966
+ } else {
967
+ debug ! ( "attempting to resolve item without parent module: {}" , path_str) ;
968
+ let err_kind = ResolutionFailure :: NoParentItem . into ( ) ;
969
+ resolution_failure (
970
+ self ,
971
+ & item,
972
+ path_str,
973
+ disambiguator,
974
+ dox,
975
+ link_range,
976
+ smallvec ! [ err_kind] ,
977
+ ) ;
978
+ return ;
979
+ } ;
980
+
981
+ // replace `Self` with suitable item's parent name
982
+ if path_str. starts_with ( "Self::" ) {
983
+ if let Some ( ref name) = parent_name {
984
+ resolved_self = format ! ( "{}::{}" , name, & path_str[ 6 ..] ) ;
985
+ path_str = & resolved_self;
930
986
}
987
+ }
931
988
932
- // We stripped `()` and `!` when parsing the disambiguator.
933
- // Add them back to be displayed, but not prefix disambiguators.
934
- link_text = disambiguator
935
- . map ( |d| d. display_for ( path_str) )
936
- . unwrap_or_else ( || path_str. to_owned ( ) ) ;
937
-
938
- // In order to correctly resolve intra-doc-links we need to
939
- // pick a base AST node to work from. If the documentation for
940
- // this module came from an inner comment (//!) then we anchor
941
- // our name resolution *inside* the module. If, on the other
942
- // hand it was an outer comment (///) then we anchor the name
943
- // resolution in the parent module on the basis that the names
944
- // used are more likely to be intended to be parent names. For
945
- // this, we set base_node to None for inner comments since
946
- // we've already pushed this node onto the resolution stack but
947
- // for outer comments we explicitly try and resolve against the
948
- // parent_node first.
949
- let base_node = if item. is_mod ( ) && item. attrs . inner_docs {
950
- self . mod_ids . last ( ) . copied ( )
951
- } else {
952
- parent_node
953
- } ;
989
+ match self . resolve_with_disambiguator (
990
+ disambiguator,
991
+ item,
992
+ dox,
993
+ path_str,
994
+ current_item,
995
+ module_id,
996
+ extra_fragment,
997
+ & ori_link,
998
+ link_range. clone ( ) ,
999
+ ) {
1000
+ Some ( x) => x,
1001
+ None => return ,
1002
+ }
1003
+ } ;
954
1004
955
- // replace `Self` with suitable item's parent name
956
- if path_str. starts_with ( "Self::" ) {
957
- if let Some ( ref name) = parent_name {
958
- resolved_self = format ! ( "{}::{}" , name, & path_str[ 6 ..] ) ;
959
- path_str = & resolved_self;
1005
+ // Check for a primitive which might conflict with a module
1006
+ // Report the ambiguity and require that the user specify which one they meant.
1007
+ // FIXME: could there ever be a primitive not in the type namespace?
1008
+ if matches ! (
1009
+ disambiguator,
1010
+ None | Some ( Disambiguator :: Namespace ( Namespace :: TypeNS ) | Disambiguator :: Primitive )
1011
+ ) && !matches ! ( res, Res :: PrimTy ( _) )
1012
+ {
1013
+ if let Some ( ( path, prim) ) = is_primitive ( path_str, TypeNS ) {
1014
+ // `prim@char`
1015
+ if matches ! ( disambiguator, Some ( Disambiguator :: Primitive ) ) {
1016
+ if fragment. is_some ( ) {
1017
+ anchor_failure (
1018
+ cx,
1019
+ & item,
1020
+ path_str,
1021
+ dox,
1022
+ link_range,
1023
+ AnchorFailure :: RustdocAnchorConflict ( prim) ,
1024
+ ) ;
1025
+ return ;
960
1026
}
1027
+ res = prim;
1028
+ fragment = Some ( path. to_owned ( ) ) ;
1029
+ } else {
1030
+ // `[char]` when a `char` module is in scope
1031
+ let candidates = vec ! [ res, prim] ;
1032
+ ambiguity_error ( cx, & item, path_str, dox, link_range, candidates) ;
1033
+ return ;
961
1034
}
1035
+ }
1036
+ }
962
1037
963
- match disambiguator. map ( Disambiguator :: ns) {
964
- Some ( ns @ ( ValueNS | TypeNS ) ) => {
965
- match self . resolve ( path_str, ns, & current_item, base_node, & extra_fragment)
966
- {
967
- Ok ( res) => res,
968
- Err ( ErrorKind :: Resolve ( box mut kind) ) => {
969
- // We only looked in one namespace. Try to give a better error if possible.
970
- if kind. full_res ( ) . is_none ( ) {
971
- let other_ns = if ns == ValueNS { TypeNS } else { ValueNS } ;
972
- for & new_ns in & [ other_ns, MacroNS ] {
973
- if let Some ( res) = self . check_full_res (
974
- new_ns,
975
- path_str,
976
- base_node,
977
- & current_item,
978
- & extra_fragment,
979
- ) {
980
- kind = ResolutionFailure :: WrongNamespace ( res, ns) ;
981
- break ;
982
- }
983
- }
984
- }
985
- resolution_failure (
986
- self ,
987
- & item,
988
- path_str,
989
- disambiguator,
990
- & dox,
991
- link_range,
992
- smallvec ! [ kind] ,
993
- ) ;
994
- // This could just be a normal link or a broken link
995
- // we could potentially check if something is
996
- // "intra-doc-link-like" and warn in that case.
997
- continue ;
998
- }
999
- Err ( ErrorKind :: AnchorFailure ( msg) ) => {
1000
- anchor_failure ( cx, & item, & ori_link, & dox, link_range, msg) ;
1001
- continue ;
1002
- }
1003
- }
1038
+ let report_mismatch = |specified : Disambiguator , resolved : Disambiguator | {
1039
+ // The resolved item did not match the disambiguator; give a better error than 'not found'
1040
+ let msg = format ! ( "incompatible link kind for `{}`" , path_str) ;
1041
+ report_diagnostic ( cx, & msg, & item, dox, & link_range, |diag, sp| {
1042
+ let note = format ! (
1043
+ "this link resolved to {} {}, which is not {} {}" ,
1044
+ resolved. article( ) ,
1045
+ resolved. descr( ) ,
1046
+ specified. article( ) ,
1047
+ specified. descr( )
1048
+ ) ;
1049
+ diag. note ( & note) ;
1050
+ suggest_disambiguator ( resolved, diag, path_str, dox, sp, & link_range) ;
1051
+ } ) ;
1052
+ } ;
1053
+ if let Res :: PrimTy ( _) = res {
1054
+ match disambiguator {
1055
+ Some ( Disambiguator :: Primitive | Disambiguator :: Namespace ( _) ) | None => {
1056
+ item. attrs . links . push ( ItemLink {
1057
+ link : ori_link,
1058
+ link_text : path_str. to_owned ( ) ,
1059
+ did : None ,
1060
+ fragment,
1061
+ } ) ;
1062
+ }
1063
+ Some ( other) => {
1064
+ report_mismatch ( other, Disambiguator :: Primitive ) ;
1065
+ return ;
1066
+ }
1067
+ }
1068
+ } else {
1069
+ debug ! ( "intra-doc link to {} resolved to {:?}" , path_str, res) ;
1070
+
1071
+ // Disallow e.g. linking to enums with `struct@`
1072
+ if let Res :: Def ( kind, _) = res {
1073
+ debug ! ( "saw kind {:?} with disambiguator {:?}" , kind, disambiguator) ;
1074
+ match ( self . kind_side_channel . take ( ) . map ( |( kind, _) | kind) . unwrap_or ( kind) , disambiguator) {
1075
+ | ( DefKind :: Const | DefKind :: ConstParam | DefKind :: AssocConst | DefKind :: AnonConst , Some ( Disambiguator :: Kind ( DefKind :: Const ) ) )
1076
+ // NOTE: this allows 'method' to mean both normal functions and associated functions
1077
+ // This can't cause ambiguity because both are in the same namespace.
1078
+ | ( DefKind :: Fn | DefKind :: AssocFn , Some ( Disambiguator :: Kind ( DefKind :: Fn ) ) )
1079
+ // These are namespaces; allow anything in the namespace to match
1080
+ | ( _, Some ( Disambiguator :: Namespace ( _) ) )
1081
+ // If no disambiguator given, allow anything
1082
+ | ( _, None )
1083
+ // All of these are valid, so do nothing
1084
+ => { }
1085
+ ( actual, Some ( Disambiguator :: Kind ( expected) ) ) if actual == expected => { }
1086
+ ( _, Some ( specified @ Disambiguator :: Kind ( _) | specified @ Disambiguator :: Primitive ) ) => {
1087
+ report_mismatch ( specified, Disambiguator :: Kind ( kind) ) ;
1088
+ return ;
1004
1089
}
1005
- None => {
1006
- // Try everything!
1007
- let mut candidates = PerNS {
1008
- macro_ns : self
1009
- . macro_resolve ( path_str, base_node)
1010
- . map ( |res| ( res, extra_fragment. clone ( ) ) ) ,
1011
- type_ns : match self . resolve (
1012
- path_str,
1013
- TypeNS ,
1014
- & current_item,
1015
- base_node,
1016
- & extra_fragment,
1017
- ) {
1018
- Ok ( res) => {
1019
- debug ! ( "got res in TypeNS: {:?}" , res) ;
1020
- Ok ( res)
1021
- }
1022
- Err ( ErrorKind :: AnchorFailure ( msg) ) => {
1023
- anchor_failure ( cx, & item, & ori_link, & dox, link_range, msg) ;
1024
- continue ;
1025
- }
1026
- Err ( ErrorKind :: Resolve ( box kind) ) => Err ( kind) ,
1027
- } ,
1028
- value_ns : match self . resolve (
1029
- path_str,
1030
- ValueNS ,
1031
- & current_item,
1032
- base_node,
1033
- & extra_fragment,
1034
- ) {
1035
- Ok ( res) => Ok ( res) ,
1036
- Err ( ErrorKind :: AnchorFailure ( msg) ) => {
1037
- anchor_failure ( cx, & item, & ori_link, & dox, link_range, msg) ;
1038
- continue ;
1039
- }
1040
- Err ( ErrorKind :: Resolve ( box kind) ) => Err ( kind) ,
1041
- }
1042
- . and_then ( |( res, fragment) | {
1043
- // Constructors are picked up in the type namespace.
1044
- match res {
1045
- Res :: Def ( DefKind :: Ctor ( ..) , _) | Res :: SelfCtor ( ..) => {
1046
- Err ( ResolutionFailure :: WrongNamespace ( res, TypeNS ) )
1047
- }
1048
- _ => match ( fragment, extra_fragment) {
1049
- ( Some ( fragment) , Some ( _) ) => {
1050
- // Shouldn't happen but who knows?
1051
- Ok ( ( res, Some ( fragment) ) )
1052
- }
1053
- ( fragment, None ) | ( None , fragment) => Ok ( ( res, fragment) ) ,
1054
- } ,
1055
- }
1056
- } ) ,
1057
- } ;
1090
+ }
1091
+ }
1058
1092
1059
- let len = candidates. iter ( ) . filter ( |res| res. is_ok ( ) ) . count ( ) ;
1093
+ // item can be non-local e.g. when using #[doc(primitive = "pointer")]
1094
+ if let Some ( ( src_id, dst_id) ) = res
1095
+ . opt_def_id ( )
1096
+ . and_then ( |def_id| def_id. as_local ( ) )
1097
+ . and_then ( |dst_id| item. def_id . as_local ( ) . map ( |src_id| ( src_id, dst_id) ) )
1098
+ {
1099
+ use rustc_hir:: def_id:: LOCAL_CRATE ;
1060
1100
1061
- if len == 0 {
1062
- resolution_failure (
1063
- self ,
1064
- & item,
1065
- path_str,
1066
- disambiguator,
1067
- & dox,
1068
- link_range,
1069
- candidates. into_iter ( ) . filter_map ( |res| res. err ( ) ) . collect ( ) ,
1070
- ) ;
1071
- // this could just be a normal link
1072
- continue ;
1073
- }
1101
+ let hir_src = self . cx . tcx . hir ( ) . local_def_id_to_hir_id ( src_id) ;
1102
+ let hir_dst = self . cx . tcx . hir ( ) . local_def_id_to_hir_id ( dst_id) ;
1074
1103
1075
- if len == 1 {
1076
- candidates. into_iter ( ) . filter_map ( |res| res. ok ( ) ) . next ( ) . unwrap ( )
1077
- } else if len == 2 && is_derive_trait_collision ( & candidates) {
1078
- candidates. type_ns . unwrap ( )
1079
- } else {
1080
- if is_derive_trait_collision ( & candidates) {
1081
- candidates. macro_ns = Err ( ResolutionFailure :: Dummy ) ;
1082
- }
1083
- // If we're reporting an ambiguity, don't mention the namespaces that failed
1084
- let candidates =
1085
- candidates. map ( |candidate| candidate. ok ( ) . map ( |( res, _) | res) ) ;
1086
- ambiguity_error (
1087
- cx,
1088
- & item,
1089
- path_str,
1090
- & dox,
1091
- link_range,
1092
- candidates. present_items ( ) . collect ( ) ,
1093
- ) ;
1094
- continue ;
1095
- }
1096
- }
1097
- Some ( MacroNS ) => {
1098
- match self . macro_resolve ( path_str, base_node) {
1099
- Ok ( res) => ( res, extra_fragment) ,
1100
- Err ( mut kind) => {
1101
- // `macro_resolve` only looks in the macro namespace. Try to give a better error if possible.
1102
- for & ns in & [ TypeNS , ValueNS ] {
1103
- if let Some ( res) = self . check_full_res (
1104
- ns,
1105
- path_str,
1106
- base_node,
1107
- & current_item,
1108
- & extra_fragment,
1109
- ) {
1110
- kind = ResolutionFailure :: WrongNamespace ( res, MacroNS ) ;
1111
- break ;
1112
- }
1113
- }
1114
- resolution_failure (
1115
- self ,
1116
- & item,
1104
+ if self . cx . tcx . privacy_access_levels ( LOCAL_CRATE ) . is_exported ( hir_src)
1105
+ && !self . cx . tcx . privacy_access_levels ( LOCAL_CRATE ) . is_exported ( hir_dst)
1106
+ {
1107
+ privacy_error ( cx, & item, & path_str, dox, link_range) ;
1108
+ return ;
1109
+ }
1110
+ }
1111
+ let id = register_res ( cx, res) ;
1112
+ item. attrs . links . push ( ItemLink { link : ori_link, link_text, did : Some ( id) , fragment } ) ;
1113
+ }
1114
+ }
1115
+
1116
+ fn resolve_with_disambiguator (
1117
+ & self ,
1118
+ disambiguator : Option < Disambiguator > ,
1119
+ item : & mut Item ,
1120
+ dox : & str ,
1121
+ path_str : & str ,
1122
+ current_item : & Option < String > ,
1123
+ base_node : DefId ,
1124
+ extra_fragment : Option < String > ,
1125
+ ori_link : & str ,
1126
+ link_range : Option < Range < usize > > ,
1127
+ ) -> Option < ( Res , Option < String > ) > {
1128
+ match disambiguator. map ( Disambiguator :: ns) {
1129
+ Some ( ns @ ( ValueNS | TypeNS ) ) => {
1130
+ match self . resolve ( path_str, ns, & current_item, base_node, & extra_fragment) {
1131
+ Ok ( res) => Some ( res) ,
1132
+ Err ( ErrorKind :: Resolve ( box mut kind) ) => {
1133
+ // We only looked in one namespace. Try to give a better error if possible.
1134
+ if kind. full_res ( ) . is_none ( ) {
1135
+ let other_ns = if ns == ValueNS { TypeNS } else { ValueNS } ;
1136
+ for & new_ns in & [ other_ns, MacroNS ] {
1137
+ if let Some ( res) = self . check_full_res (
1138
+ new_ns,
1117
1139
path_str,
1118
- disambiguator,
1119
- & dox,
1120
- link_range,
1121
- smallvec ! [ kind] ,
1122
- ) ;
1123
- continue ;
1140
+ base_node,
1141
+ & current_item,
1142
+ & extra_fragment,
1143
+ ) {
1144
+ kind = ResolutionFailure :: WrongNamespace ( res, ns) ;
1145
+ break ;
1146
+ }
1124
1147
}
1125
1148
}
1149
+ resolution_failure (
1150
+ self ,
1151
+ & item,
1152
+ path_str,
1153
+ disambiguator,
1154
+ dox,
1155
+ link_range,
1156
+ smallvec ! [ kind] ,
1157
+ ) ;
1158
+ // This could just be a normal link or a broken link
1159
+ // we could potentially check if something is
1160
+ // "intra-doc-link-like" and warn in that case.
1161
+ return None ;
1126
1162
}
1127
- }
1128
- } ;
1129
-
1130
- // Check for a primitive which might conflict with a module
1131
- // Report the ambiguity and require that the user specify which one they meant.
1132
- // FIXME: could there ever be a primitive not in the type namespace?
1133
- if matches ! (
1134
- disambiguator,
1135
- None | Some ( Disambiguator :: Namespace ( Namespace :: TypeNS ) | Disambiguator :: Primitive )
1136
- ) && !matches ! ( res, Res :: PrimTy ( _) )
1137
- {
1138
- if let Some ( ( path, prim) ) = is_primitive ( path_str, TypeNS ) {
1139
- // `prim@char`
1140
- if matches ! ( disambiguator, Some ( Disambiguator :: Primitive ) ) {
1141
- if fragment. is_some ( ) {
1142
- anchor_failure (
1143
- cx,
1144
- & item,
1145
- path_str,
1146
- & dox,
1147
- link_range,
1148
- AnchorFailure :: RustdocAnchorConflict ( prim) ,
1149
- ) ;
1150
- continue ;
1151
- }
1152
- res = prim;
1153
- fragment = Some ( path. to_owned ( ) ) ;
1154
- } else {
1155
- // `[char]` when a `char` module is in scope
1156
- let candidates = vec ! [ res, prim] ;
1157
- ambiguity_error ( cx, & item, path_str, & dox, link_range, candidates) ;
1158
- continue ;
1163
+ Err ( ErrorKind :: AnchorFailure ( msg) ) => {
1164
+ anchor_failure ( self . cx , & item, & ori_link, dox, link_range, msg) ;
1165
+ return None ;
1159
1166
}
1160
1167
}
1161
1168
}
1169
+ None => {
1170
+ // Try everything!
1171
+ let mut candidates = PerNS {
1172
+ macro_ns : self
1173
+ . macro_resolve ( path_str, base_node)
1174
+ . map ( |res| ( res, extra_fragment. clone ( ) ) ) ,
1175
+ type_ns : match self . resolve (
1176
+ path_str,
1177
+ TypeNS ,
1178
+ & current_item,
1179
+ base_node,
1180
+ & extra_fragment,
1181
+ ) {
1182
+ Ok ( res) => {
1183
+ debug ! ( "got res in TypeNS: {:?}" , res) ;
1184
+ Ok ( res)
1185
+ }
1186
+ Err ( ErrorKind :: AnchorFailure ( msg) ) => {
1187
+ anchor_failure ( self . cx , & item, ori_link, dox, link_range, msg) ;
1188
+ return None ;
1189
+ }
1190
+ Err ( ErrorKind :: Resolve ( box kind) ) => Err ( kind) ,
1191
+ } ,
1192
+ value_ns : match self . resolve (
1193
+ path_str,
1194
+ ValueNS ,
1195
+ & current_item,
1196
+ base_node,
1197
+ & extra_fragment,
1198
+ ) {
1199
+ Ok ( res) => Ok ( res) ,
1200
+ Err ( ErrorKind :: AnchorFailure ( msg) ) => {
1201
+ anchor_failure ( self . cx , & item, ori_link, dox, link_range, msg) ;
1202
+ return None ;
1203
+ }
1204
+ Err ( ErrorKind :: Resolve ( box kind) ) => Err ( kind) ,
1205
+ }
1206
+ . and_then ( |( res, fragment) | {
1207
+ // Constructors are picked up in the type namespace.
1208
+ match res {
1209
+ Res :: Def ( DefKind :: Ctor ( ..) , _) | Res :: SelfCtor ( ..) => {
1210
+ Err ( ResolutionFailure :: WrongNamespace ( res, TypeNS ) )
1211
+ }
1212
+ _ => match ( fragment, extra_fragment) {
1213
+ ( Some ( fragment) , Some ( _) ) => {
1214
+ // Shouldn't happen but who knows?
1215
+ Ok ( ( res, Some ( fragment) ) )
1216
+ }
1217
+ ( fragment, None ) | ( None , fragment) => Ok ( ( res, fragment) ) ,
1218
+ } ,
1219
+ }
1220
+ } ) ,
1221
+ } ;
1162
1222
1163
- let report_mismatch = |specified : Disambiguator , resolved : Disambiguator | {
1164
- // The resolved item did not match the disambiguator; give a better error than 'not found'
1165
- let msg = format ! ( "incompatible link kind for `{}`" , path_str) ;
1166
- report_diagnostic ( cx, & msg, & item, & dox, & link_range, |diag, sp| {
1167
- let note = format ! (
1168
- "this link resolved to {} {}, which is not {} {}" ,
1169
- resolved. article( ) ,
1170
- resolved. descr( ) ,
1171
- specified. article( ) ,
1172
- specified. descr( )
1223
+ let len = candidates. iter ( ) . filter ( |res| res. is_ok ( ) ) . count ( ) ;
1224
+
1225
+ if len == 0 {
1226
+ resolution_failure (
1227
+ self ,
1228
+ & item,
1229
+ path_str,
1230
+ disambiguator,
1231
+ dox,
1232
+ link_range,
1233
+ candidates. into_iter ( ) . filter_map ( |res| res. err ( ) ) . collect ( ) ,
1173
1234
) ;
1174
- diag. note ( & note) ;
1175
- suggest_disambiguator ( resolved, diag, path_str, & dox, sp, & link_range) ;
1176
- } ) ;
1177
- } ;
1178
- if let Res :: PrimTy ( _) = res {
1179
- match disambiguator {
1180
- Some ( Disambiguator :: Primitive | Disambiguator :: Namespace ( _) ) | None => {
1181
- item. attrs . links . push ( ItemLink {
1182
- link : ori_link,
1183
- link_text : path_str. to_owned ( ) ,
1184
- did : None ,
1185
- fragment,
1186
- } ) ;
1187
- }
1188
- Some ( other) => {
1189
- report_mismatch ( other, Disambiguator :: Primitive ) ;
1190
- continue ;
1191
- }
1235
+ // this could just be a normal link
1236
+ return None ;
1192
1237
}
1193
- } else {
1194
- debug ! ( "intra-doc link to {} resolved to {:?}" , path_str, res) ;
1195
-
1196
- // Disallow e.g. linking to enums with `struct@`
1197
- if let Res :: Def ( kind, _) = res {
1198
- debug ! ( "saw kind {:?} with disambiguator {:?}" , kind, disambiguator) ;
1199
- match ( self . kind_side_channel . take ( ) . map ( |( kind, _) | kind) . unwrap_or ( kind) , disambiguator) {
1200
- | ( DefKind :: Const | DefKind :: ConstParam | DefKind :: AssocConst | DefKind :: AnonConst , Some ( Disambiguator :: Kind ( DefKind :: Const ) ) )
1201
- // NOTE: this allows 'method' to mean both normal functions and associated functions
1202
- // This can't cause ambiguity because both are in the same namespace.
1203
- | ( DefKind :: Fn | DefKind :: AssocFn , Some ( Disambiguator :: Kind ( DefKind :: Fn ) ) )
1204
- // These are namespaces; allow anything in the namespace to match
1205
- | ( _, Some ( Disambiguator :: Namespace ( _) ) )
1206
- // If no disambiguator given, allow anything
1207
- | ( _, None )
1208
- // All of these are valid, so do nothing
1209
- => { }
1210
- ( actual, Some ( Disambiguator :: Kind ( expected) ) ) if actual == expected => { }
1211
- ( _, Some ( specified @ Disambiguator :: Kind ( _) | specified @ Disambiguator :: Primitive ) ) => {
1212
- report_mismatch ( specified, Disambiguator :: Kind ( kind) ) ;
1213
- continue ;
1214
- }
1238
+
1239
+ if len == 1 {
1240
+ Some ( candidates. into_iter ( ) . filter_map ( |res| res. ok ( ) ) . next ( ) . unwrap ( ) )
1241
+ } else if len == 2 && is_derive_trait_collision ( & candidates) {
1242
+ Some ( candidates. type_ns . unwrap ( ) )
1243
+ } else {
1244
+ if is_derive_trait_collision ( & candidates) {
1245
+ candidates. macro_ns = Err ( ResolutionFailure :: Dummy ) ;
1215
1246
}
1247
+ // If we're reporting an ambiguity, don't mention the namespaces that failed
1248
+ let candidates = candidates. map ( |candidate| candidate. ok ( ) . map ( |( res, _) | res) ) ;
1249
+ ambiguity_error (
1250
+ self . cx ,
1251
+ & item,
1252
+ path_str,
1253
+ dox,
1254
+ link_range,
1255
+ candidates. present_items ( ) . collect ( ) ,
1256
+ ) ;
1257
+ return None ;
1216
1258
}
1217
-
1218
- // item can be non-local e.g. when using #[doc(primitive = "pointer")]
1219
- if let Some ( ( src_id, dst_id) ) = res
1220
- . opt_def_id ( )
1221
- . and_then ( |def_id| def_id. as_local ( ) )
1222
- . and_then ( |dst_id| item. def_id . as_local ( ) . map ( |src_id| ( src_id, dst_id) ) )
1223
- {
1224
- use rustc_hir:: def_id:: LOCAL_CRATE ;
1225
-
1226
- let hir_src = self . cx . tcx . hir ( ) . local_def_id_to_hir_id ( src_id) ;
1227
- let hir_dst = self . cx . tcx . hir ( ) . local_def_id_to_hir_id ( dst_id) ;
1228
-
1229
- if self . cx . tcx . privacy_access_levels ( LOCAL_CRATE ) . is_exported ( hir_src)
1230
- && !self . cx . tcx . privacy_access_levels ( LOCAL_CRATE ) . is_exported ( hir_dst)
1231
- {
1232
- privacy_error ( cx, & item, & path_str, & dox, link_range) ;
1233
- continue ;
1259
+ }
1260
+ Some ( MacroNS ) => {
1261
+ match self . macro_resolve ( path_str, base_node) {
1262
+ Ok ( res) => Some ( ( res, extra_fragment) ) ,
1263
+ Err ( mut kind) => {
1264
+ // `macro_resolve` only looks in the macro namespace. Try to give a better error if possible.
1265
+ for & ns in & [ TypeNS , ValueNS ] {
1266
+ if let Some ( res) = self . check_full_res (
1267
+ ns,
1268
+ path_str,
1269
+ base_node,
1270
+ & current_item,
1271
+ & extra_fragment,
1272
+ ) {
1273
+ kind = ResolutionFailure :: WrongNamespace ( res, MacroNS ) ;
1274
+ break ;
1275
+ }
1276
+ }
1277
+ resolution_failure (
1278
+ self ,
1279
+ & item,
1280
+ path_str,
1281
+ disambiguator,
1282
+ dox,
1283
+ link_range,
1284
+ smallvec ! [ kind] ,
1285
+ ) ;
1286
+ return None ;
1234
1287
}
1235
1288
}
1236
- let id = register_res ( cx, res) ;
1237
- item. attrs . links . push ( ItemLink {
1238
- link : ori_link,
1239
- link_text,
1240
- did : Some ( id) ,
1241
- fragment,
1242
- } ) ;
1243
1289
}
1244
1290
}
1245
-
1246
- if item. is_mod ( ) && !item. attrs . inner_docs {
1247
- self . mod_ids . push ( item. def_id ) ;
1248
- }
1249
-
1250
- if item. is_mod ( ) {
1251
- let ret = self . fold_item_recur ( item) ;
1252
-
1253
- self . mod_ids . pop ( ) ;
1254
-
1255
- ret
1256
- } else {
1257
- self . fold_item_recur ( item)
1258
- }
1259
1291
}
1260
1292
}
1261
1293
@@ -1536,13 +1568,9 @@ fn resolution_failure(
1536
1568
break ;
1537
1569
}
1538
1570
} ;
1539
- if let Some ( res) = collector. check_full_res (
1540
- TypeNS ,
1541
- & current,
1542
- Some ( * module_id) ,
1543
- & None ,
1544
- & None ,
1545
- ) {
1571
+ if let Some ( res) =
1572
+ collector. check_full_res ( TypeNS , & current, * module_id, & None , & None )
1573
+ {
1546
1574
failure = ResolutionFailure :: NoAssocItem ( res, Symbol :: intern ( current) ) ;
1547
1575
break ;
1548
1576
}
0 commit comments