@@ -531,7 +531,12 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
531531 s : ROOT_SCOPE ,
532532 } ;
533533 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+ ) ;
535540 intravisit:: walk_item ( this, item) ;
536541 } ) ;
537542 }
@@ -574,7 +579,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
574579 self . with ( scope, |old_scope, this| {
575580 // a bare fn has no bounds, so everything
576581 // 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 , & [ ] ) ;
578583 intravisit:: walk_ty ( this, ty) ;
579584 } ) ;
580585 self . is_in_fn_syntax = was_in_fn_syntax;
@@ -871,7 +876,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
871876 abstract_type_parent : false ,
872877 } ;
873878 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 , & [ ] ) ;
875880 this. visit_ty ( & bounded_ty) ;
876881 walk_list ! ( this, visit_ty_param_bound, bounds) ;
877882 } ) ;
@@ -938,7 +943,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
938943 abstract_type_parent : false ,
939944 } ;
940945 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 , & [ ] ) ;
942947 walk_list ! ( this, visit_generic_param, & trait_ref. bound_generic_params) ;
943948 this. visit_trait_ref ( & trait_ref. trait_ref )
944949 } )
@@ -1441,6 +1446,18 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
14411446 . collect ( ) ;
14421447
14431448 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+
14441461
14451462 let scope = Scope :: Binder {
14461463 lifetimes,
@@ -1450,7 +1467,12 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
14501467 track_lifetime_uses : false ,
14511468 } ;
14521469 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+ ) ;
14541476 this. hack ( walk) ; // FIXME(#37666) workaround in place of `walk(this)`
14551477 } ) ;
14561478 }
@@ -2031,7 +2053,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
20312053
20322054 if let Some ( params) = error {
20332055 if lifetime_refs. len ( ) == 1 {
2034- self . report_elision_failure ( & mut err, params) ;
2056+ self . report_elision_failure ( & mut err, params, span ) ;
20352057 }
20362058 }
20372059
@@ -2042,6 +2064,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
20422064 & mut self ,
20432065 db : & mut DiagnosticBuilder ,
20442066 params : & [ ElisionFailureInfo ] ,
2067+ span : Span ,
20452068 ) {
20462069 let mut m = String :: new ( ) ;
20472070 let len = params. len ( ) ;
@@ -2097,18 +2120,22 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
20972120 "this function's return type contains a borrowed value, but \
20982121 there is no value for it to be borrowed from"
20992122 ) ;
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+ ) ;
21012128 } else if elided_len == 0 {
21022129 help ! (
21032130 db,
21042131 "this function's return type contains a borrowed value with \
21052132 an elided lifetime, but the lifetime cannot be derived from \
21062133 the arguments"
21072134 ) ;
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 ( ) ,
21122139 ) ;
21132140 } else if elided_len == 1 {
21142141 help ! (
@@ -2149,82 +2176,131 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
21492176 self . insert_lifetime ( lifetime_ref, lifetime. shifted ( late_depth) ) ;
21502177 }
21512178
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 ( ) ;
21972192 let mut err = struct_span_err ! (
21982193 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) ,
22022202 ) ;
2203- err. span_label ( bound. span , "`'_` is a reserved lifetime name" ) ;
22042203 err. emit ( ) ;
22052204 }
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,
22122247 & format ! (
22132248 "unnecessary lifetime parameter `{}`" ,
22142249 lifetime_i. lifetime. name. name( )
22152250 ) ,
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+ }
22282304 }
22292305 }
22302306 }
0 commit comments