@@ -1034,101 +1034,125 @@ impl<'tcx> LifetimeContext<'_, 'tcx> {
10341034 lifetime_names : & FxHashSet < ast:: Ident > ,
10351035 params : & [ ElisionFailureInfo ] ,
10361036 ) {
1037- if count > 1 {
1038- err. span_label ( span, format ! ( "expected {} lifetime parameters" , count) ) ;
1039- } else {
1040- let snippet = self . tcx . sess . source_map ( ) . span_to_snippet ( span) . ok ( ) ;
1041- let suggest_existing = |err : & mut DiagnosticBuilder < ' _ > , sugg| {
1042- err. span_suggestion (
1043- span,
1044- "consider using the named lifetime" ,
1045- sugg,
1046- Applicability :: MaybeIncorrect ,
1047- ) ;
1048- } ;
1049- let suggest_new = |err : & mut DiagnosticBuilder < ' _ > , sugg : & str | {
1050- err. span_label ( span, "expected named lifetime parameter" ) ;
1037+ let snippet = self . tcx . sess . source_map ( ) . span_to_snippet ( span) . ok ( ) ;
10511038
1052- for missing in self . missing_named_lifetime_spots . iter ( ) . rev ( ) {
1053- let mut introduce_suggestion = vec ! [ ] ;
1054- let msg;
1055- let should_break;
1056- introduce_suggestion. push ( match missing {
1057- MissingLifetimeSpot :: Generics ( generics) => {
1058- msg = "consider introducing a named lifetime parameter" . to_string ( ) ;
1059- should_break = true ;
1060- if let Some ( param) = generics. params . iter ( ) . find ( |p| match p. kind {
1061- hir:: GenericParamKind :: Type {
1062- synthetic : Some ( hir:: SyntheticTyParamKind :: ImplTrait ) ,
1063- ..
1064- } => false ,
1065- _ => true ,
1066- } ) {
1067- ( param. span . shrink_to_lo ( ) , "'a, " . to_string ( ) )
1068- } else {
1069- ( generics. span , "<'a>" . to_string ( ) )
1070- }
1071- }
1072- MissingLifetimeSpot :: HigherRanked { span, span_type } => {
1073- msg = format ! (
1074- "consider making the {} lifetime-generic with a new `'a` lifetime" ,
1075- span_type. descr( ) ,
1076- ) ;
1077- should_break = false ;
1078- err. note (
1079- "for more information on higher-ranked polymorphism, visit \
1080- https://doc.rust-lang.org/nomicon/hrtb.html",
1081- ) ;
1082- ( * span, span_type. suggestion ( "'a" ) )
1083- }
1084- } ) ;
1085- for param in params {
1086- if let Ok ( snippet) = self . tcx . sess . source_map ( ) . span_to_snippet ( param. span )
1087- {
1088- if snippet. starts_with ( '&' ) && !snippet. starts_with ( "&'" ) {
1089- introduce_suggestion
1090- . push ( ( param. span , format ! ( "&'a {}" , & snippet[ 1 ..] ) ) ) ;
1091- } else if snippet. starts_with ( "&'_ " ) {
1092- introduce_suggestion
1093- . push ( ( param. span , format ! ( "&'a {}" , & snippet[ 4 ..] ) ) ) ;
1094- }
1039+ err. span_label (
1040+ span,
1041+ & format ! (
1042+ "expected {} lifetime parameter{}" ,
1043+ if count == 1 { "named" . to_string( ) } else { count. to_string( ) } ,
1044+ pluralize!( count)
1045+ ) ,
1046+ ) ;
1047+
1048+ let suggest_existing = |err : & mut DiagnosticBuilder < ' _ > , sugg| {
1049+ err. span_suggestion_verbose (
1050+ span,
1051+ & format ! ( "consider using the `{}` lifetime" , lifetime_names. iter( ) . next( ) . unwrap( ) ) ,
1052+ sugg,
1053+ Applicability :: MaybeIncorrect ,
1054+ ) ;
1055+ } ;
1056+ let suggest_new = |err : & mut DiagnosticBuilder < ' _ > , sugg : & str | {
1057+ for missing in self . missing_named_lifetime_spots . iter ( ) . rev ( ) {
1058+ let mut introduce_suggestion = vec ! [ ] ;
1059+ let msg;
1060+ let should_break;
1061+ introduce_suggestion. push ( match missing {
1062+ MissingLifetimeSpot :: Generics ( generics) => {
1063+ msg = "consider introducing a named lifetime parameter" . to_string ( ) ;
1064+ should_break = true ;
1065+ if let Some ( param) = generics. params . iter ( ) . find ( |p| match p. kind {
1066+ hir:: GenericParamKind :: Type {
1067+ synthetic : Some ( hir:: SyntheticTyParamKind :: ImplTrait ) ,
1068+ ..
1069+ } => false ,
1070+ _ => true ,
1071+ } ) {
1072+ ( param. span . shrink_to_lo ( ) , "'a, " . to_string ( ) )
1073+ } else {
1074+ ( generics. span , "<'a>" . to_string ( ) )
10951075 }
10961076 }
1097- introduce_suggestion. push ( ( span, sugg. to_string ( ) ) ) ;
1098- err. multipart_suggestion (
1099- & msg,
1100- introduce_suggestion,
1101- Applicability :: MaybeIncorrect ,
1102- ) ;
1103- if should_break {
1104- break ;
1077+ MissingLifetimeSpot :: HigherRanked { span, span_type } => {
1078+ msg = format ! (
1079+ "consider making the {} lifetime-generic with a new `'a` lifetime" ,
1080+ span_type. descr( ) ,
1081+ ) ;
1082+ should_break = false ;
1083+ err. note (
1084+ "for more information on higher-ranked polymorphism, visit \
1085+ https://doc.rust-lang.org/nomicon/hrtb.html",
1086+ ) ;
1087+ ( * span, span_type. suggestion ( "'a" ) )
1088+ }
1089+ } ) ;
1090+ for param in params {
1091+ if let Ok ( snippet) = self . tcx . sess . source_map ( ) . span_to_snippet ( param. span ) {
1092+ if snippet. starts_with ( '&' ) && !snippet. starts_with ( "&'" ) {
1093+ introduce_suggestion
1094+ . push ( ( param. span , format ! ( "&'a {}" , & snippet[ 1 ..] ) ) ) ;
1095+ } else if snippet. starts_with ( "&'_ " ) {
1096+ introduce_suggestion
1097+ . push ( ( param. span , format ! ( "&'a {}" , & snippet[ 4 ..] ) ) ) ;
1098+ }
11051099 }
11061100 }
1107- } ;
1108-
1109- match ( lifetime_names. len ( ) , lifetime_names. iter ( ) . next ( ) , snippet. as_deref ( ) ) {
1110- ( 1 , Some ( name) , Some ( "&" ) ) => {
1111- suggest_existing ( err, format ! ( "&{} " , name) ) ;
1112- }
1113- ( 1 , Some ( name) , Some ( "'_" ) ) => {
1114- suggest_existing ( err, name. to_string ( ) ) ;
1115- }
1116- ( 1 , Some ( name) , Some ( snippet) ) if !snippet. ends_with ( '>' ) => {
1117- suggest_existing ( err, format ! ( "{}<{}>" , snippet, name) ) ;
1118- }
1119- ( 0 , _, Some ( "&" ) ) => {
1120- suggest_new ( err, "&'a " ) ;
1121- }
1122- ( 0 , _, Some ( "'_" ) ) => {
1123- suggest_new ( err, "'a" ) ;
1124- }
1125- ( 0 , _, Some ( snippet) ) if !snippet. ends_with ( '>' ) => {
1126- suggest_new ( err, & format ! ( "{}<'a>" , snippet) ) ;
1101+ introduce_suggestion. push ( ( span, sugg. to_string ( ) ) ) ;
1102+ err. multipart_suggestion ( & msg, introduce_suggestion, Applicability :: MaybeIncorrect ) ;
1103+ if should_break {
1104+ break ;
11271105 }
1128- _ => {
1129- err. span_label ( span, "expected lifetime parameter" ) ;
1106+ }
1107+ } ;
1108+
1109+ match ( lifetime_names. len ( ) , lifetime_names. iter ( ) . next ( ) , snippet. as_deref ( ) ) {
1110+ ( 1 , Some ( name) , Some ( "&" ) ) => {
1111+ suggest_existing ( err, format ! ( "&{} " , name) ) ;
1112+ }
1113+ ( 1 , Some ( name) , Some ( "'_" ) ) => {
1114+ suggest_existing ( err, name. to_string ( ) ) ;
1115+ }
1116+ ( 1 , Some ( name) , Some ( "" ) ) => {
1117+ suggest_existing ( err, format ! ( "{}, " , name) . repeat ( count) ) ;
1118+ }
1119+ ( 1 , Some ( name) , Some ( snippet) ) if !snippet. ends_with ( '>' ) => {
1120+ suggest_existing (
1121+ err,
1122+ format ! (
1123+ "{}<{}>" ,
1124+ snippet,
1125+ std:: iter:: repeat( name. to_string( ) )
1126+ . take( count)
1127+ . collect:: <Vec <_>>( )
1128+ . join( ", " )
1129+ ) ,
1130+ ) ;
1131+ }
1132+ ( 0 , _, Some ( "&" ) ) if count == 1 => {
1133+ suggest_new ( err, "&'a " ) ;
1134+ }
1135+ ( 0 , _, Some ( "'_" ) ) if count == 1 => {
1136+ suggest_new ( err, "'a" ) ;
1137+ }
1138+ ( 0 , _, Some ( snippet) ) if !snippet. ends_with ( '>' ) && count == 1 => {
1139+ suggest_new ( err, & format ! ( "{}<'a>" , snippet) ) ;
1140+ }
1141+ ( n, ..) if n > 1 => {
1142+ let spans: Vec < Span > = lifetime_names. iter ( ) . map ( |lt| lt. span ) . collect ( ) ;
1143+ err. span_note ( spans, "these named lifetimes are available to use" ) ;
1144+ if Some ( "" ) == snippet. as_deref ( ) {
1145+ // This happens when we have `Foo<T>` where we point at the space before `T`,
1146+ // but this can be confusing so we give a suggestion with placeholders.
1147+ err. span_suggestion_verbose (
1148+ span,
1149+ "consider using one of the available lifetimes here" ,
1150+ "'lifetime, " . repeat ( count) ,
1151+ Applicability :: HasPlaceholders ,
1152+ ) ;
11301153 }
11311154 }
1155+ _ => { }
11321156 }
11331157 }
11341158}
0 commit comments