@@ -5,7 +5,7 @@ use rustc_errors::Applicability::{MachineApplicable, MaybeIncorrect};
5
5
use rustc_errors:: { pluralize, DiagnosticBuilder } ;
6
6
use rustc_hir as hir;
7
7
use rustc_hir:: def_id:: DefId ;
8
- use rustc_span:: symbol:: sym;
8
+ use rustc_span:: symbol:: { sym, Symbol } ;
9
9
use rustc_span:: { BytePos , MultiSpan , Span } ;
10
10
use rustc_target:: spec:: abi;
11
11
@@ -616,26 +616,11 @@ impl<T> Trait<T> for X {
616
616
// We don't want to suggest calling an assoc fn in a scope where that isn't feasible.
617
617
let callable_scope = match body_owner {
618
618
Some (
619
- hir:: Node :: Item ( hir:: Item {
620
- kind :
621
- hir:: ItemKind :: Trait ( ..)
622
- | hir:: ItemKind :: Impl { .. }
623
- | hir:: ItemKind :: Const ( ..)
624
- | hir:: ItemKind :: Enum ( ..)
625
- | hir:: ItemKind :: Struct ( ..)
626
- | hir:: ItemKind :: Union ( ..) ,
627
- ..
628
- } )
629
- | hir:: Node :: TraitItem ( hir:: TraitItem {
630
- kind : hir:: TraitItemKind :: Const ( ..) | hir:: TraitItemKind :: Type ( ..) ,
631
- ..
632
- } )
633
- | hir:: Node :: ImplItem ( hir:: ImplItem {
634
- kind : hir:: ImplItemKind :: Const ( ..) | hir:: ImplItemKind :: TyAlias ( ..) ,
635
- ..
636
- } ) ,
637
- ) => false ,
638
- _ => true ,
619
+ hir:: Node :: Item ( hir:: Item { kind : hir:: ItemKind :: Fn ( ..) , .. } )
620
+ | hir:: Node :: TraitItem ( hir:: TraitItem { kind : hir:: TraitItemKind :: Fn ( ..) , .. } )
621
+ | hir:: Node :: ImplItem ( hir:: ImplItem { kind : hir:: ImplItemKind :: Fn ( ..) , .. } ) ,
622
+ ) => true ,
623
+ _ => false ,
639
624
} ;
640
625
let impl_comparison = matches ! (
641
626
cause_code,
@@ -649,112 +634,20 @@ impl<T> Trait<T> for X {
649
634
// type error is a comparison of an `impl` with its `trait` or when the
650
635
// scope is outside of a `Body`.
651
636
} else {
652
- let items = self . associated_items ( assoc. container . id ( ) ) ;
653
- // Find all the methods in the trait that could be called to construct the
654
- // expected associated type.
655
- // FIXME: consider suggesting the use of associated `const`s.
656
- let methods: Vec < ( Span , String ) > = items
657
- . items
658
- . iter ( )
659
- . filter ( |( name, item) | {
660
- ty:: AssocKind :: Fn == item. kind && Some ( * * name) != current_method_ident
661
- } )
662
- . filter_map ( |( _, item) | {
663
- let method = self . fn_sig ( item. def_id ) ;
664
- match method. output ( ) . skip_binder ( ) . kind {
665
- ty:: Projection ( ty:: ProjectionTy { item_def_id, .. } )
666
- if item_def_id == proj_ty. item_def_id =>
667
- {
668
- Some ( (
669
- self . sess . source_map ( ) . guess_head_span ( self . def_span ( item. def_id ) ) ,
670
- format ! ( "consider calling `{}`" , self . def_path_str( item. def_id) ) ,
671
- ) )
672
- }
673
- _ => None ,
674
- }
675
- } )
676
- . collect ( ) ;
677
- if !methods. is_empty ( ) {
678
- // Use a single `help:` to show all the methods in the trait that can
679
- // be used to construct the expected associated type.
680
- let mut span: MultiSpan =
681
- methods. iter ( ) . map ( |( sp, _) | * sp) . collect :: < Vec < Span > > ( ) . into ( ) ;
682
- let msg = format ! (
683
- "{some} method{s} {are} available that return{r} `{ty}`" ,
684
- some = if methods. len( ) == 1 { "a" } else { "some" } ,
685
- s = pluralize!( methods. len( ) ) ,
686
- are = if methods. len( ) == 1 { "is" } else { "are" } ,
687
- r = if methods. len( ) == 1 { "s" } else { "" } ,
688
- ty = values. expected
689
- ) ;
690
- for ( sp, label) in methods. into_iter ( ) {
691
- span. push_span_label ( sp, label) ;
692
- }
693
- db. span_help ( span, & msg) ;
694
- suggested = true ;
695
- }
637
+ suggested |= self . point_at_methods_that_satisfy_associated_type (
638
+ db,
639
+ assoc. container . id ( ) ,
640
+ current_method_ident,
641
+ proj_ty. item_def_id ,
642
+ values. expected ,
643
+ ) ;
696
644
// Possibly suggest constraining the associated type to conform to the
697
645
// found type.
698
646
suggested |=
699
647
self . suggest_constraint ( db, & msg, body_owner_def_id, proj_ty, values. found ) ;
700
648
}
701
- if let ( Some ( hir_id) , false ) =
702
- ( body_owner_def_id. as_local ( ) . map ( |id| self . hir ( ) . as_local_hir_id ( id) ) , suggested)
703
- {
704
- // When `body_owner` is an `impl` or `trait` item, look in its associated types for
705
- // `expected` and point at it.
706
- let parent_id = self . hir ( ) . get_parent_item ( hir_id) ;
707
- let item = self . hir ( ) . find ( parent_id) ;
708
- debug ! ( "expected_projection parent item {:?}" , item) ;
709
- match item {
710
- Some ( hir:: Node :: Item ( hir:: Item {
711
- kind : hir:: ItemKind :: Trait ( .., items) , ..
712
- } ) ) => {
713
- // FIXME: account for `#![feature(specialization)]`
714
- for item in & items[ ..] {
715
- match item. kind {
716
- hir:: AssocItemKind :: Type | hir:: AssocItemKind :: OpaqueTy => {
717
- if self . type_of ( self . hir ( ) . local_def_id ( item. id . hir_id ) )
718
- == values. found
719
- {
720
- if let hir:: Defaultness :: Default { has_value : true } =
721
- item. defaultness
722
- {
723
- db. span_label (
724
- item. span ,
725
- "associated type defaults can't be assumed inside the \
726
- trait defining them",
727
- ) ;
728
- } else {
729
- db. span_label ( item. span , "expected this associated type" ) ;
730
- }
731
- suggested = true ;
732
- }
733
- }
734
- _ => { }
735
- }
736
- }
737
- }
738
- Some ( hir:: Node :: Item ( hir:: Item {
739
- kind : hir:: ItemKind :: Impl { items, .. } ,
740
- ..
741
- } ) ) => {
742
- for item in & items[ ..] {
743
- match item. kind {
744
- hir:: AssocItemKind :: Type | hir:: AssocItemKind :: OpaqueTy => {
745
- if self . type_of ( self . hir ( ) . local_def_id ( item. id . hir_id ) )
746
- == values. found
747
- {
748
- db. span_label ( item. span , "expected this associated type" ) ;
749
- suggested = true ;
750
- }
751
- }
752
- _ => { }
753
- }
754
- }
755
- }
756
- _ => { }
757
- }
649
+ if !suggested {
650
+ suggested = self . point_at_associated_type ( db, body_owner_def_id, values. found ) ;
758
651
}
759
652
if let ty:: Opaque ( def_id, _) = proj_ty. self_ty ( ) . kind {
760
653
// When the expected `impl Trait` is not defined in the current item, it will come from
@@ -800,6 +693,121 @@ fn foo(&self) -> Self::T { String::new() }
800
693
}
801
694
}
802
695
696
+ fn point_at_methods_that_satisfy_associated_type (
697
+ & self ,
698
+ db : & mut DiagnosticBuilder < ' _ > ,
699
+ assoc_container_id : DefId ,
700
+ current_method_ident : Option < Symbol > ,
701
+ proj_ty_item_def_id : DefId ,
702
+ expected : Ty < ' tcx > ,
703
+ ) -> bool {
704
+ let items = self . associated_items ( assoc_container_id) ;
705
+ // Find all the methods in the trait that could be called to construct the
706
+ // expected associated type.
707
+ // FIXME: consider suggesting the use of associated `const`s.
708
+ let methods: Vec < ( Span , String ) > = items
709
+ . items
710
+ . iter ( )
711
+ . filter ( |( name, item) | {
712
+ ty:: AssocKind :: Fn == item. kind && Some ( * * name) != current_method_ident
713
+ } )
714
+ . filter_map ( |( _, item) | {
715
+ let method = self . fn_sig ( item. def_id ) ;
716
+ match method. output ( ) . skip_binder ( ) . kind {
717
+ ty:: Projection ( ty:: ProjectionTy { item_def_id, .. } )
718
+ if item_def_id == proj_ty_item_def_id =>
719
+ {
720
+ Some ( (
721
+ self . sess . source_map ( ) . guess_head_span ( self . def_span ( item. def_id ) ) ,
722
+ format ! ( "consider calling `{}`" , self . def_path_str( item. def_id) ) ,
723
+ ) )
724
+ }
725
+ _ => None ,
726
+ }
727
+ } )
728
+ . collect ( ) ;
729
+ if !methods. is_empty ( ) {
730
+ // Use a single `help:` to show all the methods in the trait that can
731
+ // be used to construct the expected associated type.
732
+ let mut span: MultiSpan =
733
+ methods. iter ( ) . map ( |( sp, _) | * sp) . collect :: < Vec < Span > > ( ) . into ( ) ;
734
+ let msg = format ! (
735
+ "{some} method{s} {are} available that return{r} `{ty}`" ,
736
+ some = if methods. len( ) == 1 { "a" } else { "some" } ,
737
+ s = pluralize!( methods. len( ) ) ,
738
+ are = if methods. len( ) == 1 { "is" } else { "are" } ,
739
+ r = if methods. len( ) == 1 { "s" } else { "" } ,
740
+ ty = expected
741
+ ) ;
742
+ for ( sp, label) in methods. into_iter ( ) {
743
+ span. push_span_label ( sp, label) ;
744
+ }
745
+ db. span_help ( span, & msg) ;
746
+ return true ;
747
+ }
748
+ false
749
+ }
750
+
751
+ fn point_at_associated_type (
752
+ & self ,
753
+ db : & mut DiagnosticBuilder < ' _ > ,
754
+ body_owner_def_id : DefId ,
755
+ found : Ty < ' tcx > ,
756
+ ) -> bool {
757
+ let hir_id = match body_owner_def_id. as_local ( ) . map ( |id| self . hir ( ) . as_local_hir_id ( id) ) {
758
+ Some ( hir_id) => hir_id,
759
+ None => return false ,
760
+ } ;
761
+ // When `body_owner` is an `impl` or `trait` item, look in its associated types for
762
+ // `expected` and point at it.
763
+ let parent_id = self . hir ( ) . get_parent_item ( hir_id) ;
764
+ let item = self . hir ( ) . find ( parent_id) ;
765
+ debug ! ( "expected_projection parent item {:?}" , item) ;
766
+ match item {
767
+ Some ( hir:: Node :: Item ( hir:: Item { kind : hir:: ItemKind :: Trait ( .., items) , .. } ) ) => {
768
+ // FIXME: account for `#![feature(specialization)]`
769
+ for item in & items[ ..] {
770
+ match item. kind {
771
+ hir:: AssocItemKind :: Type | hir:: AssocItemKind :: OpaqueTy => {
772
+ if self . type_of ( self . hir ( ) . local_def_id ( item. id . hir_id ) ) == found {
773
+ if let hir:: Defaultness :: Default { has_value : true } =
774
+ item. defaultness
775
+ {
776
+ db. span_label (
777
+ item. span ,
778
+ "associated type defaults can't be assumed inside the \
779
+ trait defining them",
780
+ ) ;
781
+ } else {
782
+ db. span_label ( item. span , "expected this associated type" ) ;
783
+ }
784
+ return true ;
785
+ }
786
+ }
787
+ _ => { }
788
+ }
789
+ }
790
+ }
791
+ Some ( hir:: Node :: Item ( hir:: Item {
792
+ kind : hir:: ItemKind :: Impl { items, .. } , ..
793
+ } ) ) => {
794
+ for item in & items[ ..] {
795
+ match item. kind {
796
+ hir:: AssocItemKind :: Type | hir:: AssocItemKind :: OpaqueTy => {
797
+ if self . type_of ( self . hir ( ) . local_def_id ( item. id . hir_id ) ) == found {
798
+ db. span_label ( item. span , "expected this associated type" ) ;
799
+ return true ;
800
+ }
801
+ }
802
+ _ => { }
803
+ }
804
+ }
805
+ }
806
+ _ => { }
807
+ }
808
+ false
809
+ }
810
+
803
811
/// Given a slice of `hir::GenericBound`s, if any of them corresponds to the `trait_ref`
804
812
/// requirement, provide a strucuted suggestion to constrain it to a given type `ty`.
805
813
fn constrain_generic_bound_associated_type_structured_suggestion (
@@ -812,22 +820,16 @@ fn foo(&self) -> Self::T { String::new() }
812
820
msg : & str ,
813
821
) -> bool {
814
822
// FIXME: we would want to call `resolve_vars_if_possible` on `ty` before suggesting.
815
- for bound in bounds {
816
- match bound {
817
- hir:: GenericBound :: Trait ( ptr, hir:: TraitBoundModifier :: None ) => {
818
- // Relate the type param against `T` in `<A as T>::Foo`.
819
- if ptr. trait_ref . trait_def_id ( ) == Some ( trait_ref. def_id )
820
- && self . constrain_associated_type_structured_suggestion (
821
- db, ptr. span , assoc, ty, msg,
822
- )
823
- {
824
- return true ;
825
- }
826
- }
827
- _ => { }
823
+ bounds. iter ( ) . any ( |bound| match bound {
824
+ hir:: GenericBound :: Trait ( ptr, hir:: TraitBoundModifier :: None ) => {
825
+ // Relate the type param against `T` in `<A as T>::Foo`.
826
+ ptr. trait_ref . trait_def_id ( ) == Some ( trait_ref. def_id )
827
+ && self . constrain_associated_type_structured_suggestion (
828
+ db, ptr. span , assoc, ty, msg,
829
+ )
828
830
}
829
- }
830
- false
831
+ _ => false ,
832
+ } )
831
833
}
832
834
833
835
/// Given a span corresponding to a bound, provide a structured suggestion to set an
0 commit comments