1
1
use rustc_ast as ast;
2
+ use rustc_data_structures:: stable_set:: FxHashSet ;
2
3
use rustc_errors:: { Applicability , DiagnosticBuilder } ;
3
4
use rustc_expand:: base:: SyntaxExtensionKind ;
4
5
use rustc_feature:: UnstableFeatures ;
@@ -9,7 +10,7 @@ use rustc_hir::def::{
9
10
PerNS , Res ,
10
11
} ;
11
12
use rustc_hir:: def_id:: DefId ;
12
- use rustc_middle:: ty;
13
+ use rustc_middle:: ty:: { self , TyCtxt } ;
13
14
use rustc_resolve:: ParentScope ;
14
15
use rustc_session:: lint;
15
16
use rustc_span:: hygiene:: MacroKind ;
@@ -347,7 +348,7 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
347
348
// HACK(jynelson): `clean` expects the type, not the associated item.
348
349
// but the disambiguator logic expects the associated item.
349
350
// Store the kind in a side channel so that only the disambiguator logic looks at it.
350
- self . kind_side_channel . replace ( Some ( item . kind . as_def_kind ( ) ) ) ;
351
+ self . kind_side_channel . set ( Some ( kind. as_def_kind ( ) ) ) ;
351
352
Ok ( ( ty_res, Some ( format ! ( "{}.{}" , out, item_name) ) ) )
352
353
} )
353
354
} else if ns == Namespace :: ValueNS {
@@ -443,8 +444,6 @@ fn resolve_associated_trait_item(
443
444
ns : Namespace ,
444
445
cx : & DocContext < ' _ > ,
445
446
) -> Option < ty:: AssocKind > {
446
- use rustc_hir:: def_id:: LOCAL_CRATE ;
447
-
448
447
let ty = cx. tcx . type_of ( did) ;
449
448
// First consider automatic impls: `impl From<T> for T`
450
449
let implicit_impls = crate :: clean:: get_auto_trait_and_blanket_impls ( cx, ty, did) ;
@@ -501,54 +500,69 @@ fn resolve_associated_trait_item(
501
500
}
502
501
} )
503
502
. collect ( ) ;
503
+
504
504
// Next consider explicit impls: `impl MyTrait for MyType`
505
- // There isn't a cheap way to do this. Just look at every trait!
506
- for & trait_ in cx. tcx . all_traits ( LOCAL_CRATE ) {
507
- trace ! ( "considering explicit impl for trait {:?}" , trait_) ;
508
- // We can skip the trait if it doesn't have the associated item `item_name`
509
- let assoc_item = cx
510
- . tcx
511
- . associated_items ( trait_)
512
- . find_by_name_and_namespace ( cx. tcx , Ident :: with_dummy_span ( item_name) , ns, trait_)
513
- . map ( |assoc| ( assoc. def_id , assoc. kind ) ) ;
514
- if let Some ( assoc_item) = assoc_item {
515
- debug ! ( "considering item {:?}" , assoc_item) ;
516
- // Look at each trait implementation to see if it's an impl for `did`
517
- cx. tcx . for_each_relevant_impl ( trait_, ty, |impl_| {
518
- use ty:: TyKind ;
519
-
520
- let trait_ref = cx. tcx . impl_trait_ref ( impl_) . expect ( "this is not an inherent impl" ) ;
521
- // Check if these are the same type.
522
- let impl_type = trait_ref. self_ty ( ) ;
523
- debug ! (
524
- "comparing type {} with kind {:?} against def_id {:?}" ,
525
- impl_type, impl_type. kind, did
526
- ) ;
527
- // Fast path: if this is a primitive simple `==` will work
528
- let same_type = impl_type == ty
529
- || match impl_type. kind {
530
- // Check if these are the same def_id
531
- TyKind :: Adt ( def, _) => {
532
- debug ! ( "adt did: {:?}" , def. did) ;
533
- def. did == did
534
- }
535
- TyKind :: Foreign ( def_id) => def_id == did,
536
- _ => false ,
537
- } ;
538
- if same_type {
539
- // We found it!
540
- debug ! ( "found a match!" ) ;
541
- candidates. push ( assoc_item) ;
542
- }
543
- } ) ;
544
- }
505
+ // Give precedence to inherent impls.
506
+ if candidates. is_empty ( ) {
507
+ let mut cache = cx. type_trait_cache . borrow_mut ( ) ;
508
+ let traits = cache. entry ( did) . or_insert_with ( || traits_implemented_by ( cx. tcx , did) ) ;
509
+ debug ! ( "considering traits {:?}" , traits) ;
510
+ candidates. extend ( traits. iter ( ) . filter_map ( |& trait_| {
511
+ cx. tcx
512
+ . associated_items ( trait_)
513
+ . find_by_name_and_namespace ( cx. tcx , Ident :: with_dummy_span ( item_name) , ns, trait_)
514
+ . map ( |assoc| ( assoc. def_id , assoc. kind ) )
515
+ } ) ) ;
545
516
}
546
-
547
517
// FIXME: warn about ambiguity
548
518
debug ! ( "the candidates were {:?}" , candidates) ;
549
519
candidates. pop ( ) . map ( |( _, kind) | kind)
550
520
}
551
521
522
+ /// Given a type, return all traits implemented by that type.
523
+ ///
524
+ /// NOTE: this cannot be a query because more traits could be available when more crates are compiled!
525
+ /// So it is not stable to serialize cross-crate.
526
+ /// FIXME: this should only search traits in scope
527
+ fn traits_implemented_by < ' a > ( tcx : TyCtxt < ' a > , type_ : DefId ) -> FxHashSet < DefId > {
528
+ use rustc_hir:: def_id:: LOCAL_CRATE ;
529
+
530
+ let all_traits = tcx. all_traits ( LOCAL_CRATE ) . iter ( ) . copied ( ) ;
531
+ let ty = tcx. type_of ( type_) ;
532
+ let iter = all_traits. flat_map ( |trait_| {
533
+ trace ! ( "considering explicit impl for trait {:?}" , trait_) ;
534
+ let mut saw_impl = false ;
535
+ // Look at each trait implementation to see if it's an impl for `did`
536
+ tcx. for_each_relevant_impl ( trait_, ty, |impl_| {
537
+ // FIXME: this is inefficient, find a way to short-circuit for_each_* so this doesn't take as long
538
+ if saw_impl {
539
+ return ;
540
+ }
541
+
542
+ let trait_ref = tcx. impl_trait_ref ( impl_) . expect ( "this is not an inherent impl" ) ;
543
+ // Check if these are the same type.
544
+ let impl_type = trait_ref. self_ty ( ) ;
545
+ debug ! (
546
+ "comparing type {} with kind {:?} against type {:?}" ,
547
+ impl_type, impl_type. kind, type_
548
+ ) ;
549
+ // Fast path: if this is a primitive simple `==` will work
550
+ saw_impl = impl_type == ty
551
+ || match impl_type. kind {
552
+ // Check if these are the same def_id
553
+ ty:: Adt ( def, _) => {
554
+ debug ! ( "adt def_id: {:?}" , def. did) ;
555
+ def. did == type_
556
+ }
557
+ ty:: Foreign ( def_id) => def_id == type_,
558
+ _ => false ,
559
+ } ;
560
+ } ) ;
561
+ if saw_impl { Some ( trait_) } else { None }
562
+ } ) ;
563
+ iter. collect ( )
564
+ }
565
+
552
566
/// Check for resolve collisions between a trait and its derive
553
567
///
554
568
/// These are common and we should just resolve to the trait in that case
0 commit comments