@@ -140,43 +140,115 @@ fn report_mismatches<'tcx>(
140140    } 
141141} 
142142
143- fn  lifetimes_use_matched_syntax ( input_info :  & [ Info < ' _ > ] ,  output_info :  & [ Info < ' _ > ] )  -> bool  { 
144-     // Categorize lifetimes into source/syntax buckets. 
145-     let  mut  n_hidden = 0 ; 
146-     let  mut  n_elided = 0 ; 
147-     let  mut  n_named = 0 ; 
143+ #[ derive( Debug ,  Copy ,  Clone ,  PartialEq ) ]  
144+ enum  LifetimeSyntaxCategory  { 
145+     Hidden , 
146+     Elided , 
147+     Named , 
148+ } 
148149
149-     for  info in  input_info. iter ( ) . chain ( output_info)  { 
150+ impl  LifetimeSyntaxCategory  { 
151+     fn  new ( syntax_source :  ( hir:: LifetimeSyntax ,  LifetimeSource ) )  -> Option < Self >  { 
150152        use  LifetimeSource :: * ; 
151153        use  hir:: LifetimeSyntax :: * ; 
152154
153-         let  syntax_source = ( info. lifetime . syntax ,  info. lifetime . source ) ; 
154- 
155155        match  syntax_source { 
156-             // Ignore any other kind of lifetime. 
157-             ( _,  Other )  => continue , 
158- 
159156            // E.g. `&T`. 
160-             ( Implicit ,  Reference  |  OutlivesBound  |  PreciseCapturing )  |
157+             ( Implicit ,  Reference )  |
161158            // E.g. `&'_ T`. 
162-             ( ExplicitAnonymous ,  Reference  |  OutlivesBound  |  PreciseCapturing )  |
159+             ( ExplicitAnonymous ,  Reference )  |
163160            // E.g. `ContainsLifetime<'_>`. 
164-             ( ExplicitAnonymous ,  Path  {  .. } )  => n_elided += 1 , 
161+             ( ExplicitAnonymous ,  Path  {  .. } )  |
162+             // E.g. `+ '_`, `+ use<'_>`. 
163+             ( ExplicitAnonymous ,  OutlivesBound  | PreciseCapturing )  => { 
164+                 Some ( Self :: Elided ) 
165+             } 
165166
166167            // E.g. `ContainsLifetime`. 
167-             ( Implicit ,  Path  {  .. } )  => n_hidden += 1 , 
168+             ( Implicit ,  Path  {  .. } )  => { 
169+                 Some ( Self :: Hidden ) 
170+             } 
168171
169172            // E.g. `&'a T`. 
170-             ( ExplicitBound ,  Reference  |  OutlivesBound  |  PreciseCapturing )  |
173+             ( ExplicitBound ,  Reference )  |
171174            // E.g. `ContainsLifetime<'a>`. 
172-             ( ExplicitBound ,  Path  {  .. } )  => n_named += 1 , 
173-         } ; 
175+             ( ExplicitBound ,  Path  {  .. } )  |
176+             // E.g. `+ 'a`, `+ use<'a>`. 
177+             ( ExplicitBound ,  OutlivesBound  | PreciseCapturing )  => { 
178+                 Some ( Self :: Named ) 
179+             } 
180+ 
181+             ( Implicit ,  OutlivesBound  | PreciseCapturing )  |
182+             ( _,  Other )  => { 
183+                 None 
184+             } 
185+         } 
186+     } 
187+ } 
188+ 
189+ #[ derive( Debug ,  Default ) ]  
190+ pub  struct  LifetimeSyntaxCategories < T >  { 
191+     pub  hidden :  T , 
192+     pub  elided :  T , 
193+     pub  named :  T , 
194+ } 
195+ 
196+ impl < T >  LifetimeSyntaxCategories < T >  { 
197+     fn  select ( & mut  self ,  category :  LifetimeSyntaxCategory )  -> & mut  T  { 
198+         use  LifetimeSyntaxCategory :: * ; 
199+ 
200+         match  category { 
201+             Elided  => & mut  self . elided , 
202+             Hidden  => & mut  self . hidden , 
203+             Named  => & mut  self . named , 
204+         } 
205+     } 
206+ } 
207+ 
208+ impl < T >  LifetimeSyntaxCategories < Vec < T > >  { 
209+     pub  fn  len ( & self )  -> LifetimeSyntaxCategories < usize >  { 
210+         LifetimeSyntaxCategories  { 
211+             hidden :  self . hidden . len ( ) , 
212+             elided :  self . elided . len ( ) , 
213+             named :  self . named . len ( ) , 
214+         } 
215+     } 
216+ 
217+     pub  fn  flatten ( & self )  -> impl  Iterator < Item  = & T >  { 
218+         let  Self  {  hidden,  elided,  named }  = self ; 
219+         [ hidden. iter ( ) ,  elided. iter ( ) ,  named. iter ( ) ] . into_iter ( ) . flatten ( ) 
220+     } 
221+ } 
222+ 
223+ impl  std:: ops:: Add  for  LifetimeSyntaxCategories < usize >  { 
224+     type  Output  = Self ; 
225+ 
226+     fn  add ( self ,  rhs :  Self )  -> Self :: Output  { 
227+         Self  { 
228+             hidden :  self . hidden  + rhs. hidden , 
229+             elided :  self . elided  + rhs. elided , 
230+             named :  self . named  + rhs. named , 
231+         } 
232+     } 
233+ } 
234+ 
235+ fn  lifetimes_use_matched_syntax ( input_info :  & [ Info < ' _ > ] ,  output_info :  & [ Info < ' _ > ] )  -> bool  { 
236+     let  mut  syntax_counts = LifetimeSyntaxCategories :: < usize > :: default ( ) ; 
237+ 
238+     for  info in  input_info. iter ( ) . chain ( output_info)  { 
239+         if  let  Some ( category)  = info. lifetime_syntax_category ( )  { 
240+             * syntax_counts. select ( category)  += 1 ; 
241+         } 
174242    } 
175243
176-     let  syntax_counts = ( n_hidden,  n_elided,  n_named) ; 
177244    tracing:: debug!( ?syntax_counts) ; 
178245
179-     matches ! ( syntax_counts,  ( _,  0 ,  0 )  | ( 0 ,  _,  0 )  | ( 0 ,  0 ,  _) ) 
246+     matches ! ( 
247+         syntax_counts, 
248+         LifetimeSyntaxCategories  {  hidden:  _,  elided:  0 ,  named:  0  } 
249+             | LifetimeSyntaxCategories  {  hidden:  0 ,  elided:  _,  named:  0  } 
250+             | LifetimeSyntaxCategories  {  hidden:  0 ,  elided:  0 ,  named:  _ } 
251+     ) 
180252} 
181253
182254fn  emit_mismatch_diagnostic < ' tcx > ( 
@@ -238,7 +310,7 @@ fn emit_mismatch_diagnostic<'tcx>(
238310        use  LifetimeSource :: * ; 
239311        use  hir:: LifetimeSyntax :: * ; 
240312
241-         let  syntax_source = ( info. lifetime . syntax ,  info . lifetime . source ) ; 
313+         let  syntax_source = info. syntax_source ( ) ; 
242314
243315        if  let  ( _,  Other )  = syntax_source { 
244316            // Ignore any other kind of lifetime. 
@@ -259,7 +331,6 @@ fn emit_mismatch_diagnostic<'tcx>(
259331            // E.g. `&'_ T`. 
260332            ( ExplicitAnonymous ,  Reference )  => { 
261333                suggest_change_to_implicit. push ( info) ; 
262-                 suggest_change_to_mixed_implicit. push ( info) ; 
263334                suggest_change_to_explicit_bound. push ( info) ; 
264335            } 
265336
@@ -319,12 +390,22 @@ fn emit_mismatch_diagnostic<'tcx>(
319390        } 
320391    } 
321392
393+     let  categorize = |infos :  & [ Info < ' _ > ] | { 
394+         let  mut  categories = LifetimeSyntaxCategories :: < Vec < _ > > :: default ( ) ; 
395+         for  info in  infos { 
396+             if  let  Some ( category)  = info. lifetime_syntax_category ( )  { 
397+                 categories. select ( category) . push ( info. reporting_span ( ) ) ; 
398+             } 
399+         } 
400+         categories
401+     } ; 
402+ 
403+     let  inputs = categorize ( input_info) ; 
404+     let  outputs = categorize ( output_info) ; 
405+ 
322406    let  make_implicit_suggestions =
323407        |infos :  & [ & Info < ' _ > ] | infos. iter ( ) . map ( |i| i. removing_span ( ) ) . collect :: < Vec < _ > > ( ) ; 
324408
325-     let  inputs = input_info. iter ( ) . map ( |info| info. reporting_span ( ) ) . collect ( ) ; 
326-     let  outputs = output_info. iter ( ) . map ( |info| info. reporting_span ( ) ) . collect ( ) ; 
327- 
328409    let  explicit_bound_suggestion = bound_lifetime. map ( |info| { 
329410        build_mismatch_suggestion ( info. lifetime_name ( ) ,  & suggest_change_to_explicit_bound) 
330411    } ) ; 
@@ -399,8 +480,6 @@ fn emit_mismatch_diagnostic<'tcx>(
399480        ?explicit_anonymous_suggestion, 
400481    ) ; 
401482
402-     let  lifetime_name = bound_lifetime. map ( |info| info. lifetime_name ( ) ) . unwrap_or ( "'_" ) . to_owned ( ) ; 
403- 
404483    // We can produce a number of suggestions which may overwhelm 
405484    // the user. Instead, we order the suggestions based on Rust 
406485    // idioms. The "best" choice is shown to the user and the 
@@ -413,21 +492,21 @@ fn emit_mismatch_diagnostic<'tcx>(
413492
414493    cx. emit_span_lint ( 
415494        MISMATCHED_LIFETIME_SYNTAXES , 
416-         Vec :: clone ( & inputs ) , 
417-         lints:: MismatchedLifetimeSyntaxes  {  lifetime_name ,   inputs,  outputs,  suggestions } , 
495+         inputs . flatten ( ) . copied ( ) . collect :: < Vec < _ > > ( ) , 
496+         lints:: MismatchedLifetimeSyntaxes  {  inputs,  outputs,  suggestions } , 
418497    ) ; 
419498} 
420499
421500fn  build_mismatch_suggestion ( 
422501    lifetime_name :  & str , 
423502    infos :  & [ & Info < ' _ > ] , 
424503)  -> lints:: MismatchedLifetimeSyntaxesSuggestion  { 
425-     let  lifetime_name_sugg  = lifetime_name. to_owned ( ) ; 
504+     let  lifetime_name  = lifetime_name. to_owned ( ) ; 
426505
427506    let  suggestions = infos. iter ( ) . map ( |info| info. suggestion ( & lifetime_name) ) . collect ( ) ; 
428507
429508    lints:: MismatchedLifetimeSyntaxesSuggestion :: Explicit  { 
430-         lifetime_name_sugg , 
509+         lifetime_name , 
431510        suggestions, 
432511        tool_only :  false , 
433512    } 
@@ -441,6 +520,14 @@ struct Info<'tcx> {
441520} 
442521
443522impl < ' tcx >  Info < ' tcx >  { 
523+     fn  syntax_source ( & self )  -> ( hir:: LifetimeSyntax ,  LifetimeSource )  { 
524+         ( self . lifetime . syntax ,  self . lifetime . source ) 
525+     } 
526+ 
527+     fn  lifetime_syntax_category ( & self )  -> Option < LifetimeSyntaxCategory >  { 
528+         LifetimeSyntaxCategory :: new ( self . syntax_source ( ) ) 
529+     } 
530+ 
444531    fn  lifetime_name ( & self )  -> & str  { 
445532        self . lifetime . ident . as_str ( ) 
446533    } 
0 commit comments