@@ -47,13 +47,13 @@ pub enum ReborrowHints {
47
47
pub enum InlayKind {
48
48
BindingModeHint ,
49
49
ChainingHint ,
50
+ ClosingBraceHint ,
50
51
ClosureReturnTypeHint ,
51
52
GenericParamListHint ,
52
53
ImplicitReborrowHint ,
53
54
LifetimeHint ,
54
55
ParameterHint ,
55
56
TypeHint ,
56
- ClosingBraceHint ,
57
57
}
58
58
59
59
#[ derive( Debug ) ]
@@ -127,28 +127,33 @@ fn hints(
127
127
} ;
128
128
129
129
closing_brace_hints ( hints, sema, config, node. clone ( ) ) ;
130
-
131
- if let Some ( expr) = ast:: Expr :: cast ( node. clone ( ) ) {
132
- chaining_hints ( hints, sema, & famous_defs, config, & expr) ;
133
- match expr {
134
- ast:: Expr :: CallExpr ( it) => param_name_hints ( hints, sema, config, ast:: Expr :: from ( it) ) ,
135
- ast:: Expr :: MethodCallExpr ( it) => {
136
- param_name_hints ( hints, sema, config, ast:: Expr :: from ( it) )
137
- }
138
- ast:: Expr :: ClosureExpr ( it) => closure_ret_hints ( hints, sema, & famous_defs, config, it) ,
139
- // We could show reborrows for all expressions, but usually that is just noise to the user
140
- // and the main point here is to show why "moving" a mutable reference doesn't necessarily move it
141
- ast:: Expr :: PathExpr ( _) => reborrow_hints ( hints, sema, config, & expr) ,
142
- _ => None ,
143
- } ;
144
- } else if let Some ( it) = ast:: Pat :: cast ( node. clone ( ) ) {
145
- binding_mode_hints ( hints, sema, config, & it) ;
146
- if let ast:: Pat :: IdentPat ( it) = it {
147
- bind_pat_hints ( hints, sema, config, & it) ;
130
+ match_ast ! {
131
+ match node {
132
+ ast:: Expr ( expr) => {
133
+ chaining_hints( hints, sema, & famous_defs, config, & expr) ;
134
+ match expr {
135
+ ast:: Expr :: CallExpr ( it) => param_name_hints( hints, sema, config, ast:: Expr :: from( it) ) ,
136
+ ast:: Expr :: MethodCallExpr ( it) => {
137
+ param_name_hints( hints, sema, config, ast:: Expr :: from( it) )
138
+ }
139
+ ast:: Expr :: ClosureExpr ( it) => closure_ret_hints( hints, sema, & famous_defs, config, it) ,
140
+ // We could show reborrows for all expressions, but usually that is just noise to the user
141
+ // and the main point here is to show why "moving" a mutable reference doesn't necessarily move it
142
+ ast:: Expr :: PathExpr ( _) => reborrow_hints( hints, sema, config, & expr) ,
143
+ _ => None ,
144
+ }
145
+ } ,
146
+ ast:: Pat ( it) => {
147
+ binding_mode_hints( hints, sema, config, & it) ;
148
+ if let ast:: Pat :: IdentPat ( it) = it {
149
+ bind_pat_hints( hints, sema, config, & it) ;
150
+ }
151
+ Some ( ( ) )
152
+ } ,
153
+ ast:: Fn ( it) => lifetime_fn_hints( hints, config, it) ,
154
+ _ => Some ( ( ) ) ,
148
155
}
149
- } else if let Some ( it) = ast:: Fn :: cast ( node) {
150
- lifetime_hints ( hints, config, it) ;
151
- }
156
+ } ;
152
157
}
153
158
154
159
fn closing_brace_hints (
@@ -249,7 +254,7 @@ fn closing_brace_hints(
249
254
None
250
255
}
251
256
252
- fn lifetime_hints (
257
+ fn lifetime_fn_hints (
253
258
acc : & mut Vec < InlayHint > ,
254
259
config : & InlayHintsConfig ,
255
260
func : ast:: Fn ,
@@ -262,80 +267,75 @@ fn lifetime_hints(
262
267
let ret_type = func. ret_type ( ) ;
263
268
let self_param = param_list. self_param ( ) . filter ( |it| it. amp_token ( ) . is_some ( ) ) ;
264
269
265
- let mut used_names: FxHashMap < SmolStr , usize > = generic_param_list
266
- . iter ( )
267
- . filter ( |_| config. param_names_for_lifetime_elision_hints )
268
- . flat_map ( |gpl| gpl. lifetime_params ( ) )
269
- . filter_map ( |param| param. lifetime ( ) )
270
- . filter_map ( |lt| Some ( ( SmolStr :: from ( lt. text ( ) . as_str ( ) . get ( 1 ..) ?) , 0 ) ) )
271
- . collect ( ) ;
272
-
273
- let mut allocated_lifetimes = vec ! [ ] ;
274
- let mut gen_idx_name = {
275
- let mut gen = ( 0u8 ..) . map ( |idx| match idx {
276
- idx if idx < 10 => SmolStr :: from_iter ( [ '\'' , ( idx + 48 ) as char ] ) ,
277
- idx => format ! ( "'{idx}" ) . into ( ) ,
278
- } ) ;
279
- move || gen. next ( ) . unwrap_or_default ( )
270
+ let is_elided = |lt : & Option < ast:: Lifetime > | match lt {
271
+ Some ( lt) => matches ! ( lt. text( ) . as_str( ) , "'_" ) ,
272
+ None => true ,
280
273
} ;
281
274
282
- let mut potential_lt_refs: Vec < _ > = vec ! [ ] ;
283
- param_list
284
- . params ( )
285
- . filter_map ( |it| {
286
- Some ( (
287
- config. param_names_for_lifetime_elision_hints . then ( || it. pat ( ) ) . flatten ( ) ,
288
- it. ty ( ) ?,
289
- ) )
290
- } )
291
- . for_each ( |( pat, ty) | {
275
+ let potential_lt_refs = {
276
+ let mut acc: Vec < _ > = vec ! [ ] ;
277
+ if let Some ( self_param) = & self_param {
278
+ let lifetime = self_param. lifetime ( ) ;
279
+ let is_elided = is_elided ( & lifetime) ;
280
+ acc. push ( ( None , self_param. amp_token ( ) , lifetime, is_elided) ) ;
281
+ }
282
+ param_list. params ( ) . filter_map ( |it| Some ( ( it. pat ( ) , it. ty ( ) ?) ) ) . for_each ( |( pat, ty) | {
292
283
// FIXME: check path types
293
284
walk_ty ( & ty, & mut |ty| match ty {
294
- ast:: Type :: RefType ( r) => potential_lt_refs. push ( (
295
- pat. as_ref ( ) . and_then ( |it| match it {
296
- ast:: Pat :: IdentPat ( p) => p. name ( ) ,
297
- _ => None ,
298
- } ) ,
299
- r,
300
- ) ) ,
285
+ ast:: Type :: RefType ( r) => {
286
+ let lifetime = r. lifetime ( ) ;
287
+ let is_elided = is_elided ( & lifetime) ;
288
+ acc. push ( (
289
+ pat. as_ref ( ) . and_then ( |it| match it {
290
+ ast:: Pat :: IdentPat ( p) => p. name ( ) ,
291
+ _ => None ,
292
+ } ) ,
293
+ r. amp_token ( ) ,
294
+ lifetime,
295
+ is_elided,
296
+ ) )
297
+ }
301
298
_ => ( ) ,
302
299
} )
303
300
} ) ;
304
-
305
- enum LifetimeKind {
306
- Elided ,
307
- Named ( SmolStr ) ,
308
- Static ,
309
- }
310
-
311
- let fetch_lt_text = |lt : Option < ast:: Lifetime > | match lt {
312
- Some ( lt) => match lt. text ( ) . as_str ( ) {
313
- "'_" => LifetimeKind :: Elided ,
314
- "'static" => LifetimeKind :: Static ,
315
- name => LifetimeKind :: Named ( name. into ( ) ) ,
316
- } ,
317
- None => LifetimeKind :: Elided ,
318
- } ;
319
- let is_elided = |lt : Option < ast:: Lifetime > | match lt {
320
- Some ( lt) => matches ! ( lt. text( ) . as_str( ) , "'_" ) ,
321
- None => true ,
301
+ acc
322
302
} ;
323
303
324
304
// allocate names
325
- if let Some ( self_param) = & self_param {
326
- if is_elided ( self_param. lifetime ( ) ) {
327
- allocated_lifetimes. push ( if config. param_names_for_lifetime_elision_hints {
328
- // self can't be used as a lifetime, so no need to check for collisions
329
- "'self" . into ( )
330
- } else {
331
- gen_idx_name ( )
332
- } ) ;
305
+ let mut gen_idx_name = {
306
+ let mut gen = ( 0u8 ..) . map ( |idx| match idx {
307
+ idx if idx < 10 => SmolStr :: from_iter ( [ '\'' , ( idx + 48 ) as char ] ) ,
308
+ idx => format ! ( "'{idx}" ) . into ( ) ,
309
+ } ) ;
310
+ move || gen. next ( ) . unwrap_or_default ( )
311
+ } ;
312
+ let mut allocated_lifetimes = vec ! [ ] ;
313
+
314
+ let mut used_names: FxHashMap < SmolStr , usize > =
315
+ match config. param_names_for_lifetime_elision_hints {
316
+ true => generic_param_list
317
+ . iter ( )
318
+ . flat_map ( |gpl| gpl. lifetime_params ( ) )
319
+ . filter_map ( |param| param. lifetime ( ) )
320
+ . filter_map ( |lt| Some ( ( SmolStr :: from ( lt. text ( ) . as_str ( ) . get ( 1 ..) ?) , 0 ) ) )
321
+ . collect ( ) ,
322
+ false => Default :: default ( ) ,
323
+ } ;
324
+ {
325
+ let mut potential_lt_refs = potential_lt_refs. iter ( ) . filter ( |& & ( .., is_elided) | is_elided) ;
326
+ if let Some ( _) = & self_param {
327
+ if let Some ( _) = potential_lt_refs. next ( ) {
328
+ allocated_lifetimes. push ( if config. param_names_for_lifetime_elision_hints {
329
+ // self can't be used as a lifetime, so no need to check for collisions
330
+ "'self" . into ( )
331
+ } else {
332
+ gen_idx_name ( )
333
+ } ) ;
334
+ }
333
335
}
334
- }
335
- potential_lt_refs. iter ( ) . for_each ( |( name, it) | {
336
- if is_elided ( it. lifetime ( ) ) {
336
+ potential_lt_refs. for_each ( |( name, ..) | {
337
337
let name = match name {
338
- Some ( it) => {
338
+ Some ( it) if config . param_names_for_lifetime_elision_hints => {
339
339
if let Some ( c) = used_names. get_mut ( it. text ( ) . as_str ( ) ) {
340
340
* c += 1 ;
341
341
SmolStr :: from ( format ! ( "'{text}{c}" , text = it. text( ) . as_str( ) ) )
@@ -347,26 +347,22 @@ fn lifetime_hints(
347
347
_ => gen_idx_name ( ) ,
348
348
} ;
349
349
allocated_lifetimes. push ( name) ;
350
- }
351
- } ) ;
350
+ } ) ;
351
+ }
352
352
353
353
// fetch output lifetime if elision rule applies
354
-
355
- let output = if let Some ( self_param) = & self_param {
356
- match fetch_lt_text ( self_param. lifetime ( ) ) {
357
- LifetimeKind :: Elided => allocated_lifetimes. get ( 0 ) . cloned ( ) ,
358
- LifetimeKind :: Named ( name) => Some ( name) ,
359
- LifetimeKind :: Static => None ,
360
- }
361
- } else {
362
- match potential_lt_refs. as_slice ( ) {
363
- [ ( _, r) ] => match fetch_lt_text ( r. lifetime ( ) ) {
364
- LifetimeKind :: Elided => allocated_lifetimes. get ( 0 ) . cloned ( ) ,
365
- LifetimeKind :: Named ( name) => Some ( name) ,
366
- LifetimeKind :: Static => None ,
367
- } ,
368
- [ ..] => None ,
354
+ let output = match potential_lt_refs. as_slice ( ) {
355
+ [ ( _, _, lifetime, _) , ..] if self_param. is_some ( ) || potential_lt_refs. len ( ) == 1 => {
356
+ match lifetime {
357
+ Some ( lt) => match lt. text ( ) . as_str ( ) {
358
+ "'_" => allocated_lifetimes. get ( 0 ) . cloned ( ) ,
359
+ "'static" => None ,
360
+ name => Some ( name. into ( ) ) ,
361
+ } ,
362
+ None => allocated_lifetimes. get ( 0 ) . cloned ( ) ,
363
+ }
369
364
}
365
+ [ ..] => None ,
370
366
} ;
371
367
372
368
if allocated_lifetimes. is_empty ( ) && output. is_none ( ) {
@@ -398,27 +394,12 @@ fn lifetime_hints(
398
394
return None ;
399
395
}
400
396
401
- let mut idx = match & self_param {
402
- Some ( self_param) if is_elided ( self_param. lifetime ( ) ) => {
403
- if let Some ( amp) = self_param. amp_token ( ) {
404
- let lt = allocated_lifetimes[ 0 ] . clone ( ) ;
405
- acc. push ( InlayHint {
406
- range : amp. text_range ( ) ,
407
- kind : InlayKind :: LifetimeHint ,
408
- label : lt,
409
- } ) ;
410
- }
411
- 1
412
- }
413
- _ => 0 ,
414
- } ;
415
-
416
- for ( _, p) in potential_lt_refs. iter ( ) {
417
- if is_elided ( p. lifetime ( ) ) {
418
- let t = p. amp_token ( ) ?;
419
- let lt = allocated_lifetimes[ idx] . clone ( ) ;
397
+ let mut a = allocated_lifetimes. iter ( ) ;
398
+ for ( _, amp_token, _, is_elided) in potential_lt_refs {
399
+ if is_elided {
400
+ let t = amp_token?;
401
+ let lt = a. next ( ) ?. clone ( ) ;
420
402
acc. push ( InlayHint { range : t. text_range ( ) , kind : InlayKind :: LifetimeHint , label : lt } ) ;
421
- idx += 1 ;
422
403
}
423
404
}
424
405
0 commit comments