@@ -239,6 +239,7 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
239
239
// If resolution failed, it may still be a method
240
240
// because methods are not handled by the resolver
241
241
// If so, bail when we're not looking for a value.
242
+ // TODO: is this correct? What about associated types?
242
243
if ns != ValueNS {
243
244
return Err ( ErrorKind :: ResolutionFailure ) ;
244
245
}
@@ -305,7 +306,8 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
305
306
// To handle that properly resolve() would have to support
306
307
// something like [`ambi_fn`](<SomeStruct as SomeTrait>::ambi_fn)
307
308
if kind. is_none ( ) {
308
- kind = resolve_associated_trait_item ( did, item_name, & self . cx ) ?;
309
+ kind = resolve_associated_trait_item ( did, item_name, ns, & self . cx ) ?;
310
+ debug ! ( "got associated item kind {:?}" , kind) ;
309
311
}
310
312
311
313
if let Some ( kind) = kind {
@@ -405,23 +407,27 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
405
407
}
406
408
}
407
409
408
- fn resolve_associated_trait_item ( did : DefId , item_name : Symbol , cx : & DocContext < ' _ > ) -> Result < Option < ty:: AssocKind > , ErrorKind > {
410
+ fn resolve_associated_trait_item ( did : DefId , item_name : Symbol , ns : Namespace , cx : & DocContext < ' _ > ) -> Result < Option < ty:: AssocKind > , ErrorKind > {
411
+ use rustc_hir:: def_id:: LOCAL_CRATE ;
412
+
409
413
let ty = cx. tcx . type_of ( did) ;
410
- // Checks if item_name belongs to `impl SomeItem`
411
- // `def_id` should be a trait
412
- let associated_items_for_def_id = |tcx : ty:: TyCtxt < ' _ > , def_id : DefId | -> Vec < _ > {
413
- tcx. associated_items ( def_id)
414
- . filter_by_name ( tcx, Ident :: with_dummy_span ( item_name) , def_id)
414
+ // Checks if item_name belongs to this `impl_`
415
+ // `impl_` should be a trait or trait implementation.
416
+ let associated_items_for_impl = |tcx : ty:: TyCtxt < ' _ > , impl_ : DefId | -> Vec < _ > {
417
+ tcx. associated_items ( impl_)
418
+ // TODO: should this be unhygienic?
419
+ . filter_by_name ( tcx, Ident :: with_dummy_span ( item_name) , impl_)
415
420
. map ( |assoc| ( assoc. def_id , assoc. kind ) )
416
421
// TODO: this collect seems a shame
417
422
. collect ( )
418
423
} ;
419
- let impls = crate :: clean:: get_auto_trait_and_blanket_impls ( cx, ty, did) ;
420
- let candidates: Vec < _ > = impls
424
+ // First consider automatic impls: `impl From<T> for T`
425
+ let implicit_impls = crate :: clean:: get_auto_trait_and_blanket_impls ( cx, ty, did) ;
426
+ let mut candidates: Vec < _ > = implicit_impls
421
427
. flat_map ( |impl_outer| {
422
428
match impl_outer. inner {
423
429
ImplItem ( impl_) => {
424
- debug ! ( "considering trait {:?}" , impl_. trait_) ;
430
+ debug ! ( "considering auto or blanket impl for trait {:?}" , impl_. trait_) ;
425
431
// Give precedence to methods that were overridden
426
432
if !impl_. provided_trait_methods . contains ( & * item_name. as_str ( ) ) {
427
433
impl_. items . into_iter ( )
@@ -449,22 +455,60 @@ fn resolve_associated_trait_item(did: DefId, item_name: Symbol, cx: &DocContext<
449
455
// }
450
456
// ```
451
457
// TODO: this is wrong, it should look at the trait, not the impl
452
- associated_items_for_def_id ( cx. tcx , impl_outer. def_id )
458
+ associated_items_for_impl ( cx. tcx , impl_outer. def_id )
453
459
}
454
460
}
455
461
_ => panic ! ( "get_impls returned something that wasn't an impl" ) ,
456
462
}
457
463
} )
458
- . chain ( cx. tcx . all_impls ( did) . flat_map ( |impl_| associated_items_for_def_id ( cx. tcx , impl_) ) )
459
- //.chain(cx.tcx.all_local_trait_impls(did).flat_map(|impl_| associated_items_for_def_id(cx.tcx, impl_)))
460
464
. collect ( ) ;
465
+ // Next consider explicit impls: `impl MyTrait for MyType`
466
+ // There isn't a cheap way to do this. Just look at every trait!
467
+ for & trait_ in cx. tcx . all_traits ( LOCAL_CRATE ) {
468
+ debug ! ( "considering explicit impl for trait {:?}" , trait_) ;
469
+ // We can skip the trait if it doesn't have the associated item `item_name`
470
+ let assoc_item = cx. tcx
471
+ . associated_items ( trait_)
472
+ . find_by_name_and_namespace ( cx. tcx , Ident :: with_dummy_span ( item_name) , ns, trait_)
473
+ . map ( |assoc| ( assoc. def_id , assoc. kind ) ) ;
474
+ if let Some ( assoc_item) = assoc_item {
475
+ debug ! ( "considering item {:?}" , assoc_item) ;
476
+ // Look at each trait implementation to see if it's an impl for `did`
477
+ cx. tcx . for_each_relevant_impl ( trait_, ty, |impl_| {
478
+ use ty:: TyKind ;
479
+
480
+ let trait_ref = cx. tcx . impl_trait_ref ( impl_) . expect ( "this is not an inherent impl" ) ;
481
+ // Check if these are the same type.
482
+ let impl_type = trait_ref. self_ty ( ) ;
483
+ debug ! ( "comparing type {} with kind {:?} against def_id {:?}" , impl_type, impl_type. kind, did) ;
484
+ // Fast path: if this is a primitive simple `==` will work
485
+ let same_type = impl_type == ty || match impl_type. kind {
486
+ // Check if these are the same def_id
487
+ TyKind :: Adt ( def, _) => {
488
+ debug ! ( "adt did: {:?}" , def. did) ;
489
+ def. did == did
490
+ }
491
+ TyKind :: Foreign ( def_id) => def_id == did,
492
+ _ => false ,
493
+ } ;
494
+ if same_type {
495
+ // We found it!
496
+ debug ! ( "found a match!" ) ;
497
+ candidates. push ( assoc_item) ;
498
+ }
499
+ } ) ;
500
+ }
501
+ }
502
+
461
503
if candidates. len ( ) > 1 {
504
+ debug ! ( "ambiguous" ) ;
462
505
let candidates = candidates. into_iter ( )
463
506
. map ( |( def_id, kind) | Res :: Def ( kind. as_def_kind ( ) , def_id) )
464
507
. collect ( ) ;
465
508
return Err ( ErrorKind :: Ambiguous { candidates } ) ;
466
509
}
467
- Ok ( candidates. into_iter ( ) . next ( ) . map ( |( _, kind) | kind) )
510
+ // Cleanup and go home
511
+ Ok ( candidates. pop ( ) . map ( |( _, kind) | kind) )
468
512
}
469
513
470
514
/// Check for resolve collisions between a trait and its derive
@@ -718,6 +762,7 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> {
718
762
continue ;
719
763
}
720
764
Err ( ErrorKind :: Ambiguous { candidates } ) => {
765
+ debug ! ( "got ambiguity error: {:?}" , candidates) ;
721
766
ambiguity_error (
722
767
cx,
723
768
& item,
@@ -776,11 +821,23 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> {
776
821
base_node,
777
822
& extra_fragment,
778
823
) {
824
+ Ok ( res) => Some ( res) ,
779
825
Err ( ErrorKind :: AnchorFailure ( msg) ) => {
780
826
anchor_failure ( cx, & item, & ori_link, & dox, link_range, msg) ;
781
827
continue ;
782
828
}
783
- x => x. ok ( ) ,
829
+ Err ( ErrorKind :: ResolutionFailure ) => None ,
830
+ Err ( ErrorKind :: Ambiguous { candidates } ) => {
831
+ ambiguity_error (
832
+ cx,
833
+ & item,
834
+ path_str,
835
+ & dox,
836
+ link_range,
837
+ candidates. into_iter ( ) . map ( |res| ( res, TypeNS ) ) . collect ( ) ,
838
+ ) ;
839
+ continue ;
840
+ }
784
841
} ,
785
842
value_ns : match self . resolve (
786
843
path_str,
@@ -790,11 +847,23 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> {
790
847
base_node,
791
848
& extra_fragment,
792
849
) {
850
+ Ok ( res) => Some ( res) ,
793
851
Err ( ErrorKind :: AnchorFailure ( msg) ) => {
794
852
anchor_failure ( cx, & item, & ori_link, & dox, link_range, msg) ;
795
853
continue ;
796
854
}
797
- x => x. ok ( ) ,
855
+ Err ( ErrorKind :: ResolutionFailure ) => None ,
856
+ Err ( ErrorKind :: Ambiguous { candidates } ) => {
857
+ ambiguity_error (
858
+ cx,
859
+ & item,
860
+ path_str,
861
+ & dox,
862
+ link_range,
863
+ candidates. into_iter ( ) . map ( |res| ( res, TypeNS ) ) . collect ( ) ,
864
+ ) ;
865
+ continue ;
866
+ }
798
867
}
799
868
. and_then ( |( res, fragment) | {
800
869
// Constructors are picked up in the type namespace.
@@ -1028,9 +1097,11 @@ fn ambiguity_error(
1028
1097
link_range : Option < Range < usize > > ,
1029
1098
candidates : Vec < ( Res , Namespace ) > ,
1030
1099
) {
1100
+ assert ! ( candidates. len( ) >= 2 ) ;
1031
1101
let hir_id = match cx. as_local_hir_id ( item. def_id ) {
1032
1102
Some ( hir_id) => hir_id,
1033
1103
None => {
1104
+ debug ! ( "ignoring ambiguity error for non-local item" ) ;
1034
1105
// If non-local, no need to check anything.
1035
1106
return ;
1036
1107
}
0 commit comments