@@ -772,6 +772,120 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
772772 static_candidates
773773 }
774774
775+ fn suggest_unsatisfied_ty_or_trait (
776+ & self ,
777+ err : & mut Diag < ' _ > ,
778+ span : Span ,
779+ rcvr_ty : Ty < ' tcx > ,
780+ item_ident : Ident ,
781+ item_kind : & str ,
782+ source : SelfSource < ' tcx > ,
783+ unsatisfied_predicates : & UnsatisfiedPredicates < ' tcx > ,
784+ static_candidates : & [ CandidateSource ] ,
785+ ) -> Result < ( bool , bool , bool , bool , SortedMap < Span , Vec < String > > ) , ( ) > {
786+ let mut restrict_type_params = false ;
787+ let mut suggested_derive = false ;
788+ let mut unsatisfied_bounds = false ;
789+ let mut custom_span_label = !static_candidates. is_empty ( ) ;
790+ let mut bound_spans: SortedMap < Span , Vec < String > > = Default :: default ( ) ;
791+ let tcx = self . tcx ;
792+
793+ if item_ident. name == sym:: count && self . is_slice_ty ( rcvr_ty, span) {
794+ let msg = "consider using `len` instead" ;
795+ if let SelfSource :: MethodCall ( _expr) = source {
796+ err. span_suggestion_short ( span, msg, "len" , Applicability :: MachineApplicable ) ;
797+ } else {
798+ err. span_label ( span, msg) ;
799+ }
800+ if let Some ( iterator_trait) = self . tcx . get_diagnostic_item ( sym:: Iterator ) {
801+ let iterator_trait = self . tcx . def_path_str ( iterator_trait) ;
802+ err. note ( format ! (
803+ "`count` is defined on `{iterator_trait}`, which `{rcvr_ty}` does not implement"
804+ ) ) ;
805+ }
806+ } else if self . impl_into_iterator_should_be_iterator ( rcvr_ty, span, unsatisfied_predicates)
807+ {
808+ err. span_label ( span, format ! ( "`{rcvr_ty}` is not an iterator" ) ) ;
809+ if !span. in_external_macro ( self . tcx . sess . source_map ( ) ) {
810+ err. multipart_suggestion_verbose (
811+ "call `.into_iter()` first" ,
812+ vec ! [ ( span. shrink_to_lo( ) , format!( "into_iter()." ) ) ] ,
813+ Applicability :: MaybeIncorrect ,
814+ ) ;
815+ }
816+ // Report to emit the diagnostic
817+ return Err ( ( ) ) ;
818+ } else if !unsatisfied_predicates. is_empty ( ) {
819+ if matches ! ( rcvr_ty. kind( ) , ty:: Param ( _) ) {
820+ // We special case the situation where we are looking for `_` in
821+ // `<TypeParam as _>::method` because otherwise the machinery will look for blanket
822+ // implementations that have unsatisfied trait bounds to suggest, leading us to claim
823+ // things like "we're looking for a trait with method `cmp`, both `Iterator` and `Ord`
824+ // have one, in order to implement `Ord` you need to restrict `TypeParam: FnPtr` so
825+ // that `impl<T: FnPtr> Ord for T` can apply", which is not what we want. We have a type
826+ // parameter, we want to directly say "`Ord::cmp` and `Iterator::cmp` exist, restrict
827+ // `TypeParam: Ord` or `TypeParam: Iterator`"". That is done further down when calling
828+ // `self.suggest_traits_to_import`, so we ignore the `unsatisfied_predicates`
829+ // suggestions.
830+ } else {
831+ self . handle_unsatisfied_predicates (
832+ err,
833+ rcvr_ty,
834+ item_ident,
835+ item_kind,
836+ span,
837+ unsatisfied_predicates,
838+ & mut restrict_type_params,
839+ & mut suggested_derive,
840+ & mut unsatisfied_bounds,
841+ & mut custom_span_label,
842+ & mut bound_spans,
843+ ) ;
844+ }
845+ } else if let ty:: Adt ( def, targs) = rcvr_ty. kind ( )
846+ && let SelfSource :: MethodCall ( rcvr_expr) = source
847+ {
848+ // This is useful for methods on arbitrary self types that might have a simple
849+ // mutability difference, like calling a method on `Pin<&mut Self>` that is on
850+ // `Pin<&Self>`.
851+ if targs. len ( ) == 1 {
852+ let mut item_segment = hir:: PathSegment :: invalid ( ) ;
853+ item_segment. ident = item_ident;
854+ for t in [ Ty :: new_mut_ref, Ty :: new_imm_ref, |_, _, t| t] {
855+ let new_args =
856+ tcx. mk_args_from_iter ( targs. iter ( ) . map ( |arg| match arg. as_type ( ) {
857+ Some ( ty) => ty:: GenericArg :: from ( t (
858+ tcx,
859+ tcx. lifetimes . re_erased ,
860+ ty. peel_refs ( ) ,
861+ ) ) ,
862+ _ => arg,
863+ } ) ) ;
864+ let rcvr_ty = Ty :: new_adt ( tcx, * def, new_args) ;
865+ if let Ok ( method) = self . lookup_method_for_diagnostic (
866+ rcvr_ty,
867+ & item_segment,
868+ span,
869+ tcx. parent_hir_node ( rcvr_expr. hir_id ) . expect_expr ( ) ,
870+ rcvr_expr,
871+ ) {
872+ err. span_note (
873+ tcx. def_span ( method. def_id ) ,
874+ format ! ( "{item_kind} is available for `{rcvr_ty}`" ) ,
875+ ) ;
876+ }
877+ }
878+ }
879+ }
880+ Ok ( (
881+ restrict_type_params,
882+ suggested_derive,
883+ unsatisfied_bounds,
884+ custom_span_label,
885+ bound_spans,
886+ ) )
887+ }
888+
775889 fn report_no_match_method_error (
776890 & self ,
777891 mut span : Span ,
@@ -874,12 +988,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
874988 sugg_span,
875989 & no_match_data,
876990 ) ;
877- let mut custom_span_label = !static_candidates. is_empty ( ) ;
878991
879- let mut bound_spans: SortedMap < Span , Vec < String > > = Default :: default ( ) ;
880- let mut restrict_type_params = false ;
881- let mut suggested_derive = false ;
882- let mut unsatisfied_bounds = false ;
883992 let mut ty_span = match rcvr_ty. kind ( ) {
884993 ty:: Param ( param_type) => {
885994 Some ( param_type. span_from_generics ( self . tcx , self . body_id . to_def_id ( ) ) )
@@ -888,92 +997,25 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
888997 _ => None ,
889998 } ;
890999
891- if item_ident. name == sym:: count && self . is_slice_ty ( rcvr_ty, span) {
892- let msg = "consider using `len` instead" ;
893- if let SelfSource :: MethodCall ( _expr) = source {
894- err. span_suggestion_short ( span, msg, "len" , Applicability :: MachineApplicable ) ;
895- } else {
896- err. span_label ( span, msg) ;
897- }
898- if let Some ( iterator_trait) = self . tcx . get_diagnostic_item ( sym:: Iterator ) {
899- let iterator_trait = self . tcx . def_path_str ( iterator_trait) ;
900- err. note ( format ! (
901- "`count` is defined on `{iterator_trait}`, which `{rcvr_ty}` does not implement"
902- ) ) ;
903- }
904- } else if self . impl_into_iterator_should_be_iterator ( rcvr_ty, span, unsatisfied_predicates)
905- {
906- err. span_label ( span, format ! ( "`{rcvr_ty}` is not an iterator" ) ) ;
907- if !span. in_external_macro ( self . tcx . sess . source_map ( ) ) {
908- err. multipart_suggestion_verbose (
909- "call `.into_iter()` first" ,
910- vec ! [ ( span. shrink_to_lo( ) , format!( "into_iter()." ) ) ] ,
911- Applicability :: MaybeIncorrect ,
912- ) ;
913- }
1000+ let Ok ( (
1001+ restrict_type_params,
1002+ suggested_derive,
1003+ unsatisfied_bounds,
1004+ custom_span_label,
1005+ bound_spans,
1006+ ) ) = self . suggest_unsatisfied_ty_or_trait (
1007+ & mut err,
1008+ span,
1009+ rcvr_ty,
1010+ item_ident,
1011+ item_kind,
1012+ source,
1013+ unsatisfied_predicates,
1014+ & static_candidates,
1015+ )
1016+ else {
9141017 return err. emit ( ) ;
915- } else if !unsatisfied_predicates. is_empty ( ) {
916- if matches ! ( rcvr_ty. kind( ) , ty:: Param ( _) ) {
917- // We special case the situation where we are looking for `_` in
918- // `<TypeParam as _>::method` because otherwise the machinery will look for blanket
919- // implementations that have unsatisfied trait bounds to suggest, leading us to claim
920- // things like "we're looking for a trait with method `cmp`, both `Iterator` and `Ord`
921- // have one, in order to implement `Ord` you need to restrict `TypeParam: FnPtr` so
922- // that `impl<T: FnPtr> Ord for T` can apply", which is not what we want. We have a type
923- // parameter, we want to directly say "`Ord::cmp` and `Iterator::cmp` exist, restrict
924- // `TypeParam: Ord` or `TypeParam: Iterator`"". That is done further down when calling
925- // `self.suggest_traits_to_import`, so we ignore the `unsatisfied_predicates`
926- // suggestions.
927- } else {
928- self . handle_unsatisfied_predicates (
929- & mut err,
930- rcvr_ty,
931- item_ident,
932- item_kind,
933- span,
934- unsatisfied_predicates,
935- & mut restrict_type_params,
936- & mut suggested_derive,
937- & mut unsatisfied_bounds,
938- & mut custom_span_label,
939- & mut bound_spans,
940- ) ;
941- }
942- } else if let ty:: Adt ( def, targs) = rcvr_ty. kind ( )
943- && let SelfSource :: MethodCall ( rcvr_expr) = source
944- {
945- // This is useful for methods on arbitrary self types that might have a simple
946- // mutability difference, like calling a method on `Pin<&mut Self>` that is on
947- // `Pin<&Self>`.
948- if targs. len ( ) == 1 {
949- let mut item_segment = hir:: PathSegment :: invalid ( ) ;
950- item_segment. ident = item_ident;
951- for t in [ Ty :: new_mut_ref, Ty :: new_imm_ref, |_, _, t| t] {
952- let new_args =
953- tcx. mk_args_from_iter ( targs. iter ( ) . map ( |arg| match arg. as_type ( ) {
954- Some ( ty) => ty:: GenericArg :: from ( t (
955- tcx,
956- tcx. lifetimes . re_erased ,
957- ty. peel_refs ( ) ,
958- ) ) ,
959- _ => arg,
960- } ) ) ;
961- let rcvr_ty = Ty :: new_adt ( tcx, * def, new_args) ;
962- if let Ok ( method) = self . lookup_method_for_diagnostic (
963- rcvr_ty,
964- & item_segment,
965- span,
966- tcx. parent_hir_node ( rcvr_expr. hir_id ) . expect_expr ( ) ,
967- rcvr_expr,
968- ) {
969- err. span_note (
970- tcx. def_span ( method. def_id ) ,
971- format ! ( "{item_kind} is available for `{rcvr_ty}`" ) ,
972- ) ;
973- }
974- }
975- }
976- }
1018+ } ;
9771019
9781020 let mut find_candidate_for_method = false ;
9791021 let should_label_not_found = match source {
0 commit comments