@@ -531,7 +531,12 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
531
531
s : ROOT_SCOPE ,
532
532
} ;
533
533
self . with ( scope, |old_scope, this| {
534
- this. check_lifetime_params ( old_scope, & generics. params ) ;
534
+ this. check_lifetime_params (
535
+ old_scope,
536
+ & generics. params ,
537
+ Some ( generics. span ) ,
538
+ & [ ] ,
539
+ ) ;
535
540
intravisit:: walk_item ( this, item) ;
536
541
} ) ;
537
542
}
@@ -574,7 +579,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
574
579
self . with ( scope, |old_scope, this| {
575
580
// a bare fn has no bounds, so everything
576
581
// contained within is scoped within its binder.
577
- this. check_lifetime_params ( old_scope, & c. generic_params ) ;
582
+ this. check_lifetime_params ( old_scope, & c. generic_params , None , & [ ] ) ;
578
583
intravisit:: walk_ty ( this, ty) ;
579
584
} ) ;
580
585
self . is_in_fn_syntax = was_in_fn_syntax;
@@ -871,7 +876,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
871
876
abstract_type_parent : false ,
872
877
} ;
873
878
let result = self . with ( scope, |old_scope, this| {
874
- this. check_lifetime_params ( old_scope, & bound_generic_params) ;
879
+ this. check_lifetime_params ( old_scope, & bound_generic_params, None , & [ ] ) ;
875
880
this. visit_ty ( & bounded_ty) ;
876
881
walk_list ! ( this, visit_ty_param_bound, bounds) ;
877
882
} ) ;
@@ -938,7 +943,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
938
943
abstract_type_parent : false ,
939
944
} ;
940
945
self . with ( scope, |old_scope, this| {
941
- this. check_lifetime_params ( old_scope, & trait_ref. bound_generic_params ) ;
946
+ this. check_lifetime_params ( old_scope, & trait_ref. bound_generic_params , None , & [ ] ) ;
942
947
walk_list ! ( this, visit_generic_param, & trait_ref. bound_generic_params) ;
943
948
this. visit_trait_ref ( & trait_ref. trait_ref )
944
949
} )
@@ -1441,6 +1446,18 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
1441
1446
. collect ( ) ;
1442
1447
1443
1448
let next_early_index = index + generics. ty_params ( ) . count ( ) as u32 ;
1449
+ let mut arg_lifetimes = vec ! [ ] ;
1450
+ for input in & decl. inputs {
1451
+ for lt in input. lifetimes ( ) {
1452
+ arg_lifetimes. push ( lt) ;
1453
+ }
1454
+ }
1455
+ if let hir:: FunctionRetTy :: Return ( ref output) = decl. output {
1456
+ for lt in output. lifetimes ( ) {
1457
+ arg_lifetimes. push ( lt) ;
1458
+ }
1459
+ }
1460
+
1444
1461
1445
1462
let scope = Scope :: Binder {
1446
1463
lifetimes,
@@ -1450,7 +1467,12 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
1450
1467
track_lifetime_uses : false ,
1451
1468
} ;
1452
1469
self . with ( scope, move |old_scope, this| {
1453
- this. check_lifetime_params ( old_scope, & generics. params ) ;
1470
+ this. check_lifetime_params (
1471
+ old_scope,
1472
+ & generics. params ,
1473
+ Some ( generics. span ) ,
1474
+ & arg_lifetimes,
1475
+ ) ;
1454
1476
this. hack ( walk) ; // FIXME(#37666) workaround in place of `walk(this)`
1455
1477
} ) ;
1456
1478
}
@@ -2031,7 +2053,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
2031
2053
2032
2054
if let Some ( params) = error {
2033
2055
if lifetime_refs. len ( ) == 1 {
2034
- self . report_elision_failure ( & mut err, params) ;
2056
+ self . report_elision_failure ( & mut err, params, span ) ;
2035
2057
}
2036
2058
}
2037
2059
@@ -2042,6 +2064,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
2042
2064
& mut self ,
2043
2065
db : & mut DiagnosticBuilder ,
2044
2066
params : & [ ElisionFailureInfo ] ,
2067
+ span : Span ,
2045
2068
) {
2046
2069
let mut m = String :: new ( ) ;
2047
2070
let len = params. len ( ) ;
@@ -2097,18 +2120,22 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
2097
2120
"this function's return type contains a borrowed value, but \
2098
2121
there is no value for it to be borrowed from"
2099
2122
) ;
2100
- help ! ( db, "consider giving it a 'static lifetime" ) ;
2123
+ db. span_suggestion (
2124
+ span,
2125
+ "consider giving it a `'static` lifetime" ,
2126
+ "&'static " . to_owned ( ) ,
2127
+ ) ;
2101
2128
} else if elided_len == 0 {
2102
2129
help ! (
2103
2130
db,
2104
2131
"this function's return type contains a borrowed value with \
2105
2132
an elided lifetime, but the lifetime cannot be derived from \
2106
2133
the arguments"
2107
2134
) ;
2108
- help ! (
2109
- db ,
2110
- "consider giving it an explicit bounded or 'static \
2111
- lifetime"
2135
+ db . span_suggestion (
2136
+ span ,
2137
+ "consider giving it an explicit bound or ` 'static` lifetime" ,
2138
+ "&'static " . to_owned ( ) ,
2112
2139
) ;
2113
2140
} else if elided_len == 1 {
2114
2141
help ! (
@@ -2149,82 +2176,131 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
2149
2176
self . insert_lifetime ( lifetime_ref, lifetime. shifted ( late_depth) ) ;
2150
2177
}
2151
2178
2152
- fn check_lifetime_params ( & mut self , old_scope : ScopeRef , params : & ' tcx [ hir:: GenericParam ] ) {
2153
- for ( i, lifetime_i) in params. lifetimes ( ) . enumerate ( ) {
2154
- match lifetime_i. lifetime . name {
2155
- hir:: LifetimeName :: Static | hir:: LifetimeName :: Underscore => {
2156
- let lifetime = lifetime_i. lifetime ;
2157
- let name = lifetime. name . name ( ) ;
2158
- let mut err = struct_span_err ! (
2159
- self . tcx. sess,
2160
- lifetime. span,
2161
- E0262 ,
2162
- "invalid lifetime parameter name: `{}`" ,
2163
- name
2164
- ) ;
2165
- err. span_label (
2166
- lifetime. span ,
2167
- format ! ( "{} is a reserved lifetime name" , name) ,
2168
- ) ;
2169
- err. emit ( ) ;
2170
- }
2171
- hir:: LifetimeName :: Fresh ( _)
2172
- | hir:: LifetimeName :: Implicit
2173
- | hir:: LifetimeName :: Name ( _) => { }
2174
- }
2175
-
2176
- // It is a hard error to shadow a lifetime within the same scope.
2177
- for lifetime_j in params. lifetimes ( ) . skip ( i + 1 ) {
2178
- if lifetime_i. lifetime . name == lifetime_j. lifetime . name {
2179
- struct_span_err ! (
2180
- self . tcx. sess,
2181
- lifetime_j. lifetime. span,
2182
- E0263 ,
2183
- "lifetime name `{}` declared twice in the same scope" ,
2184
- lifetime_j. lifetime. name. name( )
2185
- ) . span_label ( lifetime_j. lifetime . span , "declared twice" )
2186
- . span_label ( lifetime_i. lifetime . span , "previous declaration here" )
2187
- . emit ( ) ;
2188
- }
2189
- }
2190
-
2191
- // It is a soft error to shadow a lifetime within a parent scope.
2192
- self . check_lifetime_def_for_shadowing ( old_scope, & lifetime_i. lifetime ) ;
2193
-
2194
- for bound in & lifetime_i. bounds {
2195
- match bound. name {
2196
- hir:: LifetimeName :: Underscore => {
2179
+ fn check_lifetime_params (
2180
+ & mut self ,
2181
+ old_scope : ScopeRef ,
2182
+ params : & ' tcx [ hir:: GenericParam ] ,
2183
+ generics_span : Option < Span > ,
2184
+ arg_lifetimes : & [ hir:: Lifetime ] ,
2185
+ ) {
2186
+ for ( i, param_i) in params. iter ( ) . enumerate ( ) {
2187
+ if let hir:: GenericParam :: Lifetime ( lifetime_i) = param_i {
2188
+ match lifetime_i. lifetime . name {
2189
+ hir:: LifetimeName :: Static | hir:: LifetimeName :: Underscore => {
2190
+ let lifetime = lifetime_i. lifetime ;
2191
+ let name = lifetime. name . name ( ) ;
2197
2192
let mut err = struct_span_err ! (
2198
2193
self . tcx. sess,
2199
- bound. span,
2200
- E0637 ,
2201
- "invalid lifetime bound name: `'_`"
2194
+ lifetime. span,
2195
+ E0262 ,
2196
+ "invalid lifetime parameter name: `{}`" ,
2197
+ name
2198
+ ) ;
2199
+ err. span_label (
2200
+ lifetime. span ,
2201
+ format ! ( "{} is a reserved lifetime name" , name) ,
2202
2202
) ;
2203
- err. span_label ( bound. span , "`'_` is a reserved lifetime name" ) ;
2204
2203
err. emit ( ) ;
2205
2204
}
2206
- hir:: LifetimeName :: Static => {
2207
- self . insert_lifetime ( bound, Region :: Static ) ;
2208
- self . tcx
2209
- . sess
2210
- . struct_span_warn (
2211
- lifetime_i. lifetime . span . to ( bound. span ) ,
2205
+ hir:: LifetimeName :: Fresh ( _)
2206
+ | hir:: LifetimeName :: Implicit
2207
+ | hir:: LifetimeName :: Name ( _) => { }
2208
+ }
2209
+
2210
+ // It is a hard error to shadow a lifetime within the same scope.
2211
+ for param_j in params. iter ( ) . skip ( i + 1 ) {
2212
+ if let hir:: GenericParam :: Lifetime ( lifetime_j) = param_j {
2213
+ if lifetime_i. lifetime . name == lifetime_j. lifetime . name {
2214
+ struct_span_err ! (
2215
+ self . tcx. sess,
2216
+ lifetime_j. lifetime. span,
2217
+ E0263 ,
2218
+ "lifetime name `{}` declared twice in the same scope" ,
2219
+ lifetime_j. lifetime. name. name( )
2220
+ ) . span_label ( lifetime_j. lifetime . span , "declared twice" )
2221
+ . span_label ( lifetime_i. lifetime . span , "previous declaration here" )
2222
+ . emit ( ) ;
2223
+ }
2224
+ }
2225
+ }
2226
+
2227
+ // It is a soft error to shadow a lifetime within a parent scope.
2228
+ self . check_lifetime_def_for_shadowing ( old_scope, & lifetime_i. lifetime ) ;
2229
+
2230
+ for bound in & lifetime_i. bounds {
2231
+ match bound. name {
2232
+ hir:: LifetimeName :: Underscore => {
2233
+ let mut err = struct_span_err ! (
2234
+ self . tcx. sess,
2235
+ bound. span,
2236
+ E0637 ,
2237
+ "invalid lifetime bound name: `'_`"
2238
+ ) ;
2239
+ err. span_label ( bound. span , "`'_` is a reserved lifetime name" ) ;
2240
+ err. emit ( ) ;
2241
+ }
2242
+ hir:: LifetimeName :: Static => {
2243
+ self . insert_lifetime ( bound, Region :: Static ) ;
2244
+ let sp = lifetime_i. lifetime . span . to ( bound. span ) ;
2245
+ let mut warn = self . tcx . sess . struct_span_warn (
2246
+ sp,
2212
2247
& format ! (
2213
2248
"unnecessary lifetime parameter `{}`" ,
2214
2249
lifetime_i. lifetime. name. name( )
2215
2250
) ,
2216
- )
2217
- . help ( & format ! (
2218
- "you can use the `'static` lifetime directly, in place \
2219
- of `{}`",
2220
- lifetime_i. lifetime. name. name( )
2221
- ) )
2222
- . emit ( ) ;
2223
- }
2224
- hir:: LifetimeName :: Fresh ( _)
2225
- | hir:: LifetimeName :: Implicit
2226
- | hir:: LifetimeName :: Name ( _) => {
2227
- self . resolve_lifetime_ref ( bound) ;
2251
+ ) ;
2252
+ let mut spans_to_replace = arg_lifetimes. iter ( ) . filter_map ( |lifetime| {
2253
+ if lifetime. name . name ( ) == lifetime_i. lifetime . name . name ( ) {
2254
+ Some ( ( lifetime. span , "'static" . to_owned ( ) ) )
2255
+ } else {
2256
+ None
2257
+ }
2258
+ } ) . collect :: < Vec < _ > > ( ) ;
2259
+ if let ( 1 , Some ( sp) ) = ( params. len ( ) , generics_span) {
2260
+ spans_to_replace. push ( ( sp, "" . into ( ) ) ) ;
2261
+ warn. multipart_suggestion (
2262
+ & format ! (
2263
+ "you can use the `'static` lifetime directly, \
2264
+ in place of `{}`",
2265
+ lifetime_i. lifetime. name. name( ) ,
2266
+ ) ,
2267
+ spans_to_replace,
2268
+ ) ;
2269
+ } else if params. len ( ) > 1 {
2270
+ let sp = if let Some ( next_param) = params. iter ( ) . nth ( i + 1 ) {
2271
+ // we'll remove everything until the next parameter
2272
+ lifetime_i. lifetime . span . until ( next_param. span ( ) )
2273
+ } else if let Some ( prev_param) = params. iter ( ) . nth ( i - 1 ) {
2274
+ // this must be the last argument, include the previous comma
2275
+ self . tcx . sess . codemap ( )
2276
+ . next_point ( prev_param. span ( ) )
2277
+ . to ( sp)
2278
+ } else { // THIS SHOULDN'T HAPPEN :|
2279
+ sp
2280
+ } ;
2281
+
2282
+ spans_to_replace. push ( ( sp, "" . into ( ) ) ) ;
2283
+ warn. multipart_suggestion (
2284
+ & format ! (
2285
+ "you can use the `'static` lifetime directly, \
2286
+ in place of `{}`",
2287
+ lifetime_i. lifetime. name. name( ) ,
2288
+ ) ,
2289
+ spans_to_replace,
2290
+ ) ;
2291
+ } else {
2292
+ warn. help ( & format ! (
2293
+ "you can use the `'static` lifetime directly, in place of `{}`" ,
2294
+ lifetime_i. lifetime. name. name( ) ,
2295
+ ) ) ;
2296
+ }
2297
+ warn. emit ( ) ;
2298
+ }
2299
+ hir:: LifetimeName :: Fresh ( _)
2300
+ | hir:: LifetimeName :: Implicit
2301
+ | hir:: LifetimeName :: Name ( _) => {
2302
+ self . resolve_lifetime_ref ( bound) ;
2303
+ }
2228
2304
}
2229
2305
}
2230
2306
}
0 commit comments