@@ -5,7 +5,7 @@ use rustc_errors::Applicability::{MachineApplicable, MaybeIncorrect};
55use rustc_errors:: { pluralize, DiagnosticBuilder } ;
66use rustc_hir as hir;
77use rustc_hir:: def_id:: DefId ;
8- use rustc_span:: symbol:: sym;
8+ use rustc_span:: symbol:: { sym, Symbol } ;
99use rustc_span:: { BytePos , MultiSpan , Span } ;
1010use rustc_target:: spec:: abi;
1111
@@ -616,26 +616,11 @@ impl<T> Trait<T> for X {
616616 // We don't want to suggest calling an assoc fn in a scope where that isn't feasible.
617617 let callable_scope = match body_owner {
618618 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 ,
639624 } ;
640625 let impl_comparison = matches ! (
641626 cause_code,
@@ -649,112 +634,20 @@ impl<T> Trait<T> for X {
649634 // type error is a comparison of an `impl` with its `trait` or when the
650635 // scope is outside of a `Body`.
651636 } 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+ ) ;
696644 // Possibly suggest constraining the associated type to conform to the
697645 // found type.
698646 suggested |=
699647 self . suggest_constraint ( db, & msg, body_owner_def_id, proj_ty, values. found ) ;
700648 }
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 ) ;
758651 }
759652 if let ty:: Opaque ( def_id, _) = proj_ty. self_ty ( ) . kind {
760653 // 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() }
800693 }
801694 }
802695
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+
803811 /// Given a slice of `hir::GenericBound`s, if any of them corresponds to the `trait_ref`
804812 /// requirement, provide a strucuted suggestion to constrain it to a given type `ty`.
805813 fn constrain_generic_bound_associated_type_structured_suggestion (
@@ -812,22 +820,16 @@ fn foo(&self) -> Self::T { String::new() }
812820 msg : & str ,
813821 ) -> bool {
814822 // 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+ )
828830 }
829- }
830- false
831+ _ => false ,
832+ } )
831833 }
832834
833835 /// Given a span corresponding to a bound, provide a structured suggestion to set an
0 commit comments