@@ -140,43 +140,115 @@ fn report_mismatches<'tcx>(
140
140
}
141
141
}
142
142
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
+ }
148
149
149
- for info in input_info. iter ( ) . chain ( output_info) {
150
+ impl LifetimeSyntaxCategory {
151
+ fn new ( syntax_source : ( hir:: LifetimeSyntax , LifetimeSource ) ) -> Option < Self > {
150
152
use LifetimeSource :: * ;
151
153
use hir:: LifetimeSyntax :: * ;
152
154
153
- let syntax_source = ( info. lifetime . syntax , info. lifetime . source ) ;
154
-
155
155
match syntax_source {
156
- // Ignore any other kind of lifetime.
157
- ( _, Other ) => continue ,
158
-
159
156
// E.g. `&T`.
160
- ( Implicit , Reference | OutlivesBound | PreciseCapturing ) |
157
+ ( Implicit , Reference ) |
161
158
// E.g. `&'_ T`.
162
- ( ExplicitAnonymous , Reference | OutlivesBound | PreciseCapturing ) |
159
+ ( ExplicitAnonymous , Reference ) |
163
160
// 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
+ }
165
166
166
167
// E.g. `ContainsLifetime`.
167
- ( Implicit , Path { .. } ) => n_hidden += 1 ,
168
+ ( Implicit , Path { .. } ) => {
169
+ Some ( Self :: Hidden )
170
+ }
168
171
169
172
// E.g. `&'a T`.
170
- ( ExplicitBound , Reference | OutlivesBound | PreciseCapturing ) |
173
+ ( ExplicitBound , Reference ) |
171
174
// 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
+ }
174
242
}
175
243
176
- let syntax_counts = ( n_hidden, n_elided, n_named) ;
177
244
tracing:: debug!( ?syntax_counts) ;
178
245
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
+ )
180
252
}
181
253
182
254
fn emit_mismatch_diagnostic < ' tcx > (
@@ -238,7 +310,7 @@ fn emit_mismatch_diagnostic<'tcx>(
238
310
use LifetimeSource :: * ;
239
311
use hir:: LifetimeSyntax :: * ;
240
312
241
- let syntax_source = ( info. lifetime . syntax , info . lifetime . source ) ;
313
+ let syntax_source = info. syntax_source ( ) ;
242
314
243
315
if let ( _, Other ) = syntax_source {
244
316
// Ignore any other kind of lifetime.
@@ -259,7 +331,6 @@ fn emit_mismatch_diagnostic<'tcx>(
259
331
// E.g. `&'_ T`.
260
332
( ExplicitAnonymous , Reference ) => {
261
333
suggest_change_to_implicit. push ( info) ;
262
- suggest_change_to_mixed_implicit. push ( info) ;
263
334
suggest_change_to_explicit_bound. push ( info) ;
264
335
}
265
336
@@ -319,12 +390,22 @@ fn emit_mismatch_diagnostic<'tcx>(
319
390
}
320
391
}
321
392
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
+
322
406
let make_implicit_suggestions =
323
407
|infos : & [ & Info < ' _ > ] | infos. iter ( ) . map ( |i| i. removing_span ( ) ) . collect :: < Vec < _ > > ( ) ;
324
408
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
-
328
409
let explicit_bound_suggestion = bound_lifetime. map ( |info| {
329
410
build_mismatch_suggestion ( info. lifetime_name ( ) , & suggest_change_to_explicit_bound)
330
411
} ) ;
@@ -399,8 +480,6 @@ fn emit_mismatch_diagnostic<'tcx>(
399
480
?explicit_anonymous_suggestion,
400
481
) ;
401
482
402
- let lifetime_name = bound_lifetime. map ( |info| info. lifetime_name ( ) ) . unwrap_or ( "'_" ) . to_owned ( ) ;
403
-
404
483
// We can produce a number of suggestions which may overwhelm
405
484
// the user. Instead, we order the suggestions based on Rust
406
485
// idioms. The "best" choice is shown to the user and the
@@ -413,21 +492,21 @@ fn emit_mismatch_diagnostic<'tcx>(
413
492
414
493
cx. emit_span_lint (
415
494
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 } ,
418
497
) ;
419
498
}
420
499
421
500
fn build_mismatch_suggestion (
422
501
lifetime_name : & str ,
423
502
infos : & [ & Info < ' _ > ] ,
424
503
) -> lints:: MismatchedLifetimeSyntaxesSuggestion {
425
- let lifetime_name_sugg = lifetime_name. to_owned ( ) ;
504
+ let lifetime_name = lifetime_name. to_owned ( ) ;
426
505
427
506
let suggestions = infos. iter ( ) . map ( |info| info. suggestion ( & lifetime_name) ) . collect ( ) ;
428
507
429
508
lints:: MismatchedLifetimeSyntaxesSuggestion :: Explicit {
430
- lifetime_name_sugg ,
509
+ lifetime_name ,
431
510
suggestions,
432
511
tool_only : false ,
433
512
}
@@ -441,6 +520,14 @@ struct Info<'tcx> {
441
520
}
442
521
443
522
impl < ' 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
+
444
531
fn lifetime_name ( & self ) -> & str {
445
532
self . lifetime . ident . as_str ( )
446
533
}
0 commit comments