@@ -777,19 +777,15 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
777
777
} else {
778
778
"items from traits can only be used if the trait is implemented and in scope"
779
779
} ) ;
780
- let mut msg = format ! (
780
+ let message = |action| format ! (
781
781
"the following {traits_define} an item `{name}`, perhaps you need to {action} \
782
782
{one_of_them}:",
783
783
traits_define = if candidates. len( ) == 1 {
784
784
"trait defines"
785
785
} else {
786
786
"traits define"
787
787
} ,
788
- action = if let Some ( param) = param_type {
789
- format!( "restrict type parameter `{}` with" , param)
790
- } else {
791
- "implement" . to_string( )
792
- } ,
788
+ action = action,
793
789
one_of_them = if candidates. len( ) == 1 {
794
790
"it"
795
791
} else {
@@ -809,50 +805,81 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
809
805
// Get the `hir::Param` to verify whether it already has any bounds.
810
806
// We do this to avoid suggesting code that ends up as `T: FooBar`,
811
807
// instead we suggest `T: Foo + Bar` in that case.
812
- let mut has_bounds = None ;
813
- let mut impl_trait = false ;
814
- if let Node :: GenericParam ( ref param) = hir. get ( id) {
815
- let kind = & param. kind ;
816
- if let hir:: GenericParamKind :: Type { synthetic : Some ( _) , .. } = kind {
817
- // We've found `fn foo(x: impl Trait)` instead of
818
- // `fn foo<T>(x: T)`. We want to suggest the correct
819
- // `fn foo(x: impl Trait + TraitBound)` instead of
820
- // `fn foo<T: TraitBound>(x: T)`. (See #63706.)
821
- impl_trait = true ;
822
- has_bounds = param. bounds . get ( 1 ) ;
823
- } else {
824
- has_bounds = param. bounds . get ( 0 ) ;
808
+ match hir. get ( id) {
809
+ Node :: GenericParam ( ref param) => {
810
+ let mut impl_trait = false ;
811
+ let has_bounds = if let hir:: GenericParamKind :: Type {
812
+ synthetic : Some ( _) , ..
813
+ } = & param. kind {
814
+ // We've found `fn foo(x: impl Trait)` instead of
815
+ // `fn foo<T>(x: T)`. We want to suggest the correct
816
+ // `fn foo(x: impl Trait + TraitBound)` instead of
817
+ // `fn foo<T: TraitBound>(x: T)`. (#63706)
818
+ impl_trait = true ;
819
+ param. bounds . get ( 1 )
820
+ } else {
821
+ param. bounds . get ( 0 )
822
+ } ;
823
+ let sp = hir. span ( id) ;
824
+ let sp = if let Some ( first_bound) = has_bounds {
825
+ // `sp` only covers `T`, change it so that it covers
826
+ // `T:` when appropriate
827
+ sp. until ( first_bound. span ( ) )
828
+ } else {
829
+ sp
830
+ } ;
831
+ // FIXME: contrast `t.def_id` against `param.bounds` to not suggest
832
+ // traits already there. That can happen when the cause is that
833
+ // we're in a const scope or associated function used as a method.
834
+ err. span_suggestions (
835
+ sp,
836
+ & message ( format ! (
837
+ "restrict type parameter `{}` with" ,
838
+ param. name. ident( ) . as_str( ) ,
839
+ ) ) ,
840
+ candidates. iter ( ) . map ( |t| format ! (
841
+ "{}{} {}{}" ,
842
+ param. name. ident( ) . as_str( ) ,
843
+ if impl_trait { " +" } else { ":" } ,
844
+ self . tcx. def_path_str( t. def_id) ,
845
+ if has_bounds. is_some( ) { " + " } else { "" } ,
846
+ ) ) ,
847
+ Applicability :: MaybeIncorrect ,
848
+ ) ;
849
+ suggested = true ;
850
+ }
851
+ Node :: Item ( hir:: Item {
852
+ kind : hir:: ItemKind :: Trait ( .., bounds, _) , ident, ..
853
+ } ) => {
854
+ let ( sp, sep, article) = if bounds. is_empty ( ) {
855
+ ( ident. span . shrink_to_hi ( ) , ":" , "a" )
856
+ } else {
857
+ ( bounds. last ( ) . unwrap ( ) . span ( ) . shrink_to_hi ( ) , " +" , "another" )
858
+ } ;
859
+ err. span_suggestions (
860
+ sp,
861
+ & message ( format ! ( "add {} supertrait for" , article) ) ,
862
+ candidates. iter ( ) . map ( |t| format ! (
863
+ "{} {}" ,
864
+ sep,
865
+ self . tcx. def_path_str( t. def_id) ,
866
+ ) ) ,
867
+ Applicability :: MaybeIncorrect ,
868
+ ) ;
869
+ suggested = true ;
825
870
}
871
+ _ => { }
826
872
}
827
- let sp = hir. span ( id) ;
828
- // `sp` only covers `T`, change it so that it covers `T:` when appropriate.
829
- let sp = if let Some ( first_bound) = has_bounds {
830
- sp. until ( first_bound. span ( ) )
831
- } else {
832
- sp
833
- } ;
834
-
835
- // FIXME: contrast `t.def_id` against `param.bounds` to not suggest traits
836
- // already there. That can happen when the cause is that we're in a const
837
- // scope or associated function used as a method.
838
- err. span_suggestions (
839
- sp,
840
- & msg[ ..] ,
841
- candidates. iter ( ) . map ( |t| format ! (
842
- "{}{} {}{}" ,
843
- param,
844
- if impl_trait { " +" } else { ":" } ,
845
- self . tcx. def_path_str( t. def_id) ,
846
- if has_bounds. is_some( ) { " + " } else { "" } ,
847
- ) ) ,
848
- Applicability :: MaybeIncorrect ,
849
- ) ;
850
- suggested = true ;
851
873
}
852
874
} ;
853
875
}
854
876
855
877
if !suggested {
878
+ let mut msg = message ( if let Some ( param) = param_type {
879
+ format ! ( "restrict type parameter `{}` with" , param)
880
+ } else {
881
+ "implement" . to_string ( )
882
+ } ) ;
856
883
for ( i, trait_info) in candidates. iter ( ) . enumerate ( ) {
857
884
msg. push_str ( & format ! (
858
885
"\n candidate #{}: `{}`" ,
0 commit comments