@@ -777,19 +777,15 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
777777 } else {
778778 "items from traits can only be used if the trait is implemented and in scope"
779779 } ) ;
780- let mut msg = format ! (
780+ let message = |action| format ! (
781781 "the following {traits_define} an item `{name}`, perhaps you need to {action} \
782782 {one_of_them}:",
783783 traits_define = if candidates. len( ) == 1 {
784784 "trait defines"
785785 } else {
786786 "traits define"
787787 } ,
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,
793789 one_of_them = if candidates. len( ) == 1 {
794790 "it"
795791 } else {
@@ -809,50 +805,81 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
809805 // Get the `hir::Param` to verify whether it already has any bounds.
810806 // We do this to avoid suggesting code that ends up as `T: FooBar`,
811807 // 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 ;
825870 }
871+ _ => { }
826872 }
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 ;
851873 }
852874 } ;
853875 }
854876
855877 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+ } ) ;
856883 for ( i, trait_info) in candidates. iter ( ) . enumerate ( ) {
857884 msg. push_str ( & format ! (
858885 "\n candidate #{}: `{}`" ,
0 commit comments