@@ -7,7 +7,10 @@ use crate::infer::error_reporting::nice_region_error::NiceRegionError;
7
7
use crate :: infer:: lexical_region_resolve:: RegionResolutionError ;
8
8
use crate :: infer:: SubregionOrigin ;
9
9
10
- use rustc_errors:: { struct_span_err, ErrorReported } ;
10
+ use rustc_errors:: { struct_span_err, Applicability , DiagnosticBuilder , ErrorReported } ;
11
+ use rustc_hir as hir;
12
+ use rustc_hir:: { GenericParamKind , Ty } ;
13
+ use rustc_middle:: ty:: Region ;
11
14
12
15
impl < ' a , ' tcx > NiceRegionError < ' a , ' tcx > {
13
16
/// Print the error message for lifetime errors when both the concerned regions are anonymous.
@@ -160,11 +163,13 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
160
163
}
161
164
} ;
162
165
163
- let mut e = struct_span_err ! ( self . tcx( ) . sess, span, E0623 , "lifetime mismatch" ) ;
166
+ let mut err = struct_span_err ! ( self . tcx( ) . sess, span, E0623 , "lifetime mismatch" ) ;
164
167
165
- e. span_label ( span_1, main_label) ;
166
- e. span_label ( span_2, String :: new ( ) ) ;
167
- e. span_label ( span, span_label) ;
168
+ err. span_label ( span_1, main_label) ;
169
+ err. span_label ( span_2, String :: new ( ) ) ;
170
+ err. span_label ( span, span_label) ;
171
+
172
+ self . suggest_adding_lifetime_params ( sub, ty_sup, ty_sub, & mut err) ;
168
173
169
174
if let Some ( t) = future_return_type {
170
175
let snip = self
@@ -178,14 +183,87 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
178
183
( _, "" ) => None ,
179
184
_ => Some ( s) ,
180
185
} )
181
- . unwrap_or ( "{unnamed_type}" . to_string ( ) ) ;
186
+ . unwrap_or_else ( || "{unnamed_type}" . to_string ( ) ) ;
182
187
183
- e . span_label (
188
+ err . span_label (
184
189
t. span ,
185
190
& format ! ( "this `async fn` implicitly returns an `impl Future<Output = {}>`" , snip) ,
186
191
) ;
187
192
}
188
- e . emit ( ) ;
193
+ err . emit ( ) ;
189
194
Some ( ErrorReported )
190
195
}
196
+
197
+ fn suggest_adding_lifetime_params (
198
+ & self ,
199
+ sub : Region < ' tcx > ,
200
+ ty_sup : & Ty < ' _ > ,
201
+ ty_sub : & Ty < ' _ > ,
202
+ err : & mut DiagnosticBuilder < ' _ > ,
203
+ ) {
204
+ if let (
205
+ hir:: Ty { kind : hir:: TyKind :: Rptr ( lifetime_sub, _) , .. } ,
206
+ hir:: Ty { kind : hir:: TyKind :: Rptr ( lifetime_sup, _) , .. } ,
207
+ ) = ( ty_sub, ty_sup)
208
+ {
209
+ if lifetime_sub. name . is_elided ( ) && lifetime_sup. name . is_elided ( ) {
210
+ if let Some ( anon_reg) = self . tcx ( ) . is_suitable_region ( sub) {
211
+ let hir_id = self . tcx ( ) . hir ( ) . local_def_id_to_hir_id ( anon_reg. def_id ) ;
212
+ if let hir:: Node :: Item ( & hir:: Item {
213
+ kind : hir:: ItemKind :: Fn ( _, ref generics, ..) ,
214
+ ..
215
+ } ) = self . tcx ( ) . hir ( ) . get ( hir_id)
216
+ {
217
+ let ( suggestion_param_name, introduce_new) = generics
218
+ . params
219
+ . iter ( )
220
+ . find ( |p| matches ! ( p. kind, GenericParamKind :: Lifetime { .. } ) )
221
+ . and_then ( |p| self . tcx ( ) . sess . source_map ( ) . span_to_snippet ( p. span ) . ok ( ) )
222
+ . map ( |name| ( name, false ) )
223
+ . unwrap_or_else ( || ( "'a" . to_string ( ) , true ) ) ;
224
+
225
+ let mut suggestions = vec ! [
226
+ if let hir:: LifetimeName :: Underscore = lifetime_sub. name {
227
+ ( lifetime_sub. span, suggestion_param_name. clone( ) )
228
+ } else {
229
+ (
230
+ lifetime_sub. span. shrink_to_hi( ) ,
231
+ suggestion_param_name. clone( ) + " " ,
232
+ )
233
+ } ,
234
+ if let hir:: LifetimeName :: Underscore = lifetime_sup. name {
235
+ ( lifetime_sup. span, suggestion_param_name. clone( ) )
236
+ } else {
237
+ (
238
+ lifetime_sup. span. shrink_to_hi( ) ,
239
+ suggestion_param_name. clone( ) + " " ,
240
+ )
241
+ } ,
242
+ ] ;
243
+
244
+ if introduce_new {
245
+ let new_param_suggestion = match & generics. params {
246
+ [ ] => ( generics. span , format ! ( "<{}>" , suggestion_param_name) ) ,
247
+ [ first, ..] => (
248
+ first. span . shrink_to_lo ( ) ,
249
+ format ! ( "{}, " , suggestion_param_name) ,
250
+ ) ,
251
+ } ;
252
+
253
+ suggestions. push ( new_param_suggestion) ;
254
+ }
255
+
256
+ err. multipart_suggestion (
257
+ "consider introducing a named lifetime parameter" ,
258
+ suggestions,
259
+ Applicability :: MaybeIncorrect ,
260
+ ) ;
261
+ err. note (
262
+ "each elided lifetime in input position becomes a distinct lifetime" ,
263
+ ) ;
264
+ }
265
+ }
266
+ }
267
+ }
268
+ }
191
269
}
0 commit comments