@@ -1999,3 +1999,233 @@ impl EarlyLintPass for KeywordIdents {
19991999        lint. emit ( ) 
20002000    } 
20012001} 
2002+ 
2003+ 
2004+ pub  struct  ExplicitOutlivesRequirements ; 
2005+ 
2006+ impl  LintPass  for  ExplicitOutlivesRequirements  { 
2007+     fn  get_lints ( & self )  -> LintArray  { 
2008+         lint_array ! [ EXPLICIT_OUTLIVES_REQUIREMENTS ] 
2009+     } 
2010+ } 
2011+ 
2012+ impl  ExplicitOutlivesRequirements  { 
2013+     fn  collect_outlives_bound_spans ( 
2014+         & self , 
2015+         cx :  & LateContext , 
2016+         item_def_id :  DefId , 
2017+         param_name :  & str , 
2018+         bounds :  & hir:: GenericBounds , 
2019+         infer_static :  bool 
2020+     )  -> Vec < ( usize ,  Span ) >  { 
2021+         // For lack of a more elegant strategy for comparing the `ty::Predicate`s 
2022+         // returned by this query with the params/bounds grabbed from the HIR—and 
2023+         // with some regrets—we're going to covert the param/lifetime names to 
2024+         // strings 
2025+         let  inferred_outlives = cx. tcx . inferred_outlives_of ( item_def_id) ; 
2026+ 
2027+         let  ty_lt_names = inferred_outlives. iter ( ) . filter_map ( |pred| { 
2028+             let  binder = match  pred { 
2029+                 ty:: Predicate :: TypeOutlives ( binder)  => binder, 
2030+                 _ => {  return  None ;  } 
2031+             } ; 
2032+             let  ty_outlives_pred = binder. skip_binder ( ) ; 
2033+             let  ty_name = match  ty_outlives_pred. 0 . sty  { 
2034+                 ty:: Param ( param)  => param. name . to_string ( ) , 
2035+                 _ => {  return  None ;  } 
2036+             } ; 
2037+             let  lt_name = match  ty_outlives_pred. 1  { 
2038+                 ty:: RegionKind :: ReEarlyBound ( region)  => { 
2039+                     region. name . to_string ( ) 
2040+                 } , 
2041+                 _ => {  return  None ;  } 
2042+             } ; 
2043+             Some ( ( ty_name,  lt_name) ) 
2044+         } ) . collect :: < Vec < _ > > ( ) ; 
2045+ 
2046+         let  mut  bound_spans = Vec :: new ( ) ; 
2047+         for  ( i,  bound)  in  bounds. iter ( ) . enumerate ( )  { 
2048+             if  let  hir:: GenericBound :: Outlives ( lifetime)  = bound { 
2049+                 let  is_static = match  lifetime. name  { 
2050+                     hir:: LifetimeName :: Static  => true , 
2051+                     _ => false 
2052+                 } ; 
2053+                 if  is_static && !infer_static { 
2054+                     // infer-outlives for 'static is still feature-gated (tracking issue #44493) 
2055+                     continue ; 
2056+                 } 
2057+ 
2058+                 let  lt_name = & lifetime. name . ident ( ) . to_string ( ) ; 
2059+                 if  ty_lt_names. contains ( & ( param_name. to_owned ( ) ,  lt_name. to_owned ( ) ) )  { 
2060+                     bound_spans. push ( ( i,  bound. span ( ) ) ) ; 
2061+                 } 
2062+             } 
2063+         } 
2064+         bound_spans
2065+     } 
2066+ 
2067+     fn  consolidate_outlives_bound_spans ( 
2068+         & self , 
2069+         lo :  Span , 
2070+         bounds :  & hir:: GenericBounds , 
2071+         bound_spans :  Vec < ( usize ,  Span ) > 
2072+     )  -> Vec < Span >  { 
2073+         if  bounds. is_empty ( )  { 
2074+             return  Vec :: new ( ) ; 
2075+         } 
2076+         if  bound_spans. len ( )  == bounds. len ( )  { 
2077+             let  ( _,  last_bound_span)  = bound_spans[ bound_spans. len ( ) -1 ] ; 
2078+             // If all bounds are inferable, we want to delete the colon, so 
2079+             // start from just after the parameter (span passed as argument) 
2080+             vec ! [ lo. to( last_bound_span) ] 
2081+         }  else  { 
2082+             let  mut  merged = Vec :: new ( ) ; 
2083+             let  mut  last_merged_i = None ; 
2084+ 
2085+             let  mut  from_start = true ; 
2086+             for  ( i,  bound_span)  in  bound_spans { 
2087+                 match  last_merged_i { 
2088+                     // If the first bound is inferable, our span should also eat the trailing `+` 
2089+                     None  if  i == 0  => { 
2090+                         merged. push ( bound_span. to ( bounds[ 1 ] . span ( ) . shrink_to_lo ( ) ) ) ; 
2091+                         last_merged_i = Some ( 0 ) ; 
2092+                     } , 
2093+                     // If consecutive bounds are inferable, merge their spans 
2094+                     Some ( h)  if  i == h+1  => { 
2095+                         if  let  Some ( tail)  = merged. last_mut ( )  { 
2096+                             // Also eat the trailing `+` if the first 
2097+                             // more-than-one bound is inferable 
2098+                             let  to_span = if  from_start && i < bounds. len ( )  { 
2099+                                 bounds[ i+1 ] . span ( ) . shrink_to_lo ( ) 
2100+                             }  else  { 
2101+                                 bound_span
2102+                             } ; 
2103+                             * tail = tail. to ( to_span) ; 
2104+                             last_merged_i = Some ( i) ; 
2105+                         }  else  { 
2106+                             bug ! ( "another bound-span visited earlier" ) ; 
2107+                         } 
2108+                     } , 
2109+                     _ => { 
2110+                         // When we find a non-inferable bound, subsequent inferable bounds 
2111+                         // won't be consecutive from the start (and we'll eat the leading 
2112+                         // `+` rather than the trailing one) 
2113+                         from_start = false ; 
2114+                         merged. push ( bounds[ i-1 ] . span ( ) . shrink_to_hi ( ) . to ( bound_span) ) ; 
2115+                         last_merged_i = Some ( i) ; 
2116+                     } 
2117+                 } 
2118+             } 
2119+             merged
2120+         } 
2121+     } 
2122+ } 
2123+ 
2124+ impl < ' a ,  ' tcx >  LateLintPass < ' a ,  ' tcx >  for  ExplicitOutlivesRequirements  { 
2125+     fn  check_item ( & mut  self ,  cx :  & LateContext < ' a ,  ' tcx > ,  item :  & ' tcx  hir:: Item )  { 
2126+         let  infer_static = cx. tcx . features ( ) . infer_static_outlives_requirements ; 
2127+         let  def_id = cx. tcx . hir . local_def_id ( item. id ) ; 
2128+         if  let  hir:: ItemKind :: Struct ( _,  ref  generics)  = item. node  { 
2129+             let  mut  bound_count = 0 ; 
2130+             let  mut  lint_spans = Vec :: new ( ) ; 
2131+ 
2132+             for  param in  & generics. params  { 
2133+                 let  param_name = match  param. kind  { 
2134+                     hir:: GenericParamKind :: Lifetime  {  .. }  => {  continue ;  } , 
2135+                     hir:: GenericParamKind :: Type  {  .. }  => { 
2136+                         match  param. name  { 
2137+                             hir:: ParamName :: Fresh ( _)  => {  continue ;  } , 
2138+                             hir:: ParamName :: Plain ( name)  => name. to_string ( ) 
2139+                         } 
2140+                     } 
2141+                 } ; 
2142+                 let  bound_spans = self . collect_outlives_bound_spans ( 
2143+                     cx,  def_id,  & param_name,  & param. bounds ,  infer_static
2144+                 ) ; 
2145+                 bound_count += bound_spans. len ( ) ; 
2146+                 lint_spans. extend ( 
2147+                     self . consolidate_outlives_bound_spans ( 
2148+                         param. span . shrink_to_hi ( ) ,  & param. bounds ,  bound_spans
2149+                     ) 
2150+                 ) ; 
2151+             } 
2152+ 
2153+             let  mut  where_lint_spans = Vec :: new ( ) ; 
2154+             let  mut  dropped_predicate_count = 0 ; 
2155+             let  num_predicates = generics. where_clause . predicates . len ( ) ; 
2156+             for  ( i,  where_predicate)  in  generics. where_clause . predicates . iter ( ) . enumerate ( )  { 
2157+                 if  let  hir:: WherePredicate :: BoundPredicate ( predicate)  = where_predicate { 
2158+                     let  param_name = match  predicate. bounded_ty . node  { 
2159+                         hir:: TyKind :: Path ( ref  qpath)  => { 
2160+                             if  let  hir:: QPath :: Resolved ( None ,  ty_param_path)  = qpath { 
2161+                                 ty_param_path. segments [ 0 ] . ident . to_string ( ) 
2162+                             }  else  { 
2163+                                 continue ; 
2164+                             } 
2165+                         } , 
2166+                         _ => {  continue ;  } 
2167+                     } ; 
2168+                     let  bound_spans = self . collect_outlives_bound_spans ( 
2169+                         cx,  def_id,  & param_name,  & predicate. bounds ,  infer_static
2170+                     ) ; 
2171+                     bound_count += bound_spans. len ( ) ; 
2172+ 
2173+                     let  drop_predicate = bound_spans. len ( )  == predicate. bounds . len ( ) ; 
2174+                     if  drop_predicate { 
2175+                         dropped_predicate_count += 1 ; 
2176+                     } 
2177+ 
2178+                     // If all the bounds on a predicate were inferable and there are 
2179+                     // further predicates, we want to eat the trailing comma 
2180+                     if  drop_predicate && i + 1  < num_predicates { 
2181+                         let  next_predicate_span = generics. where_clause . predicates [ i+1 ] . span ( ) ; 
2182+                         where_lint_spans. push ( 
2183+                             predicate. span . to ( next_predicate_span. shrink_to_lo ( ) ) 
2184+                         ) ; 
2185+                     }  else  { 
2186+                         where_lint_spans. extend ( 
2187+                             self . consolidate_outlives_bound_spans ( 
2188+                                 predicate. span . shrink_to_lo ( ) , 
2189+                                 & predicate. bounds , 
2190+                                 bound_spans
2191+                             ) 
2192+                         ) ; 
2193+                     } 
2194+                 } 
2195+             } 
2196+ 
2197+             // If all predicates are inferable, drop the entire clause 
2198+             // (including the `where`) 
2199+             if  num_predicates > 0  && dropped_predicate_count == num_predicates { 
2200+                 let  full_where_span = generics. span . shrink_to_hi ( ) 
2201+                     . to ( generics. where_clause . span ( ) 
2202+                     . expect ( "span of (nonempty) where clause should exist" ) ) ; 
2203+                 lint_spans. push ( 
2204+                     full_where_span
2205+                 ) ; 
2206+             }  else  { 
2207+                 lint_spans. extend ( where_lint_spans) ; 
2208+             } 
2209+ 
2210+             if  !lint_spans. is_empty ( )  { 
2211+                 let  mut  err = cx. struct_span_lint ( 
2212+                     EXPLICIT_OUTLIVES_REQUIREMENTS , 
2213+                     lint_spans. clone ( ) , 
2214+                     "outlives requirements can be inferred" 
2215+                 ) ; 
2216+                 err. multipart_suggestion_with_applicability ( 
2217+                     if  bound_count == 1  { 
2218+                         "remove this bound" 
2219+                     }  else  { 
2220+                         "remove these bounds" 
2221+                     } , 
2222+                     lint_spans. into_iter ( ) . map ( |span| ( span,  "" . to_owned ( ) ) ) . collect :: < Vec < _ > > ( ) , 
2223+                     Applicability :: MachineApplicable 
2224+                 ) ; 
2225+                 err. emit ( ) ; 
2226+             } 
2227+ 
2228+         } 
2229+     } 
2230+ 
2231+ } 
0 commit comments