@@ -47,13 +47,13 @@ pub enum ReborrowHints {
4747pub enum InlayKind {
4848 BindingModeHint ,
4949 ChainingHint ,
50+ ClosingBraceHint ,
5051 ClosureReturnTypeHint ,
5152 GenericParamListHint ,
5253 ImplicitReborrowHint ,
5354 LifetimeHint ,
5455 ParameterHint ,
5556 TypeHint ,
56- ClosingBraceHint ,
5757}
5858
5959#[ derive( Debug ) ]
@@ -127,28 +127,33 @@ fn hints(
127127 } ;
128128
129129 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 ( ( ) ) ,
148155 }
149- } else if let Some ( it) = ast:: Fn :: cast ( node) {
150- lifetime_hints ( hints, config, it) ;
151- }
156+ } ;
152157}
153158
154159fn closing_brace_hints (
@@ -249,7 +254,7 @@ fn closing_brace_hints(
249254 None
250255}
251256
252- fn lifetime_hints (
257+ fn lifetime_fn_hints (
253258 acc : & mut Vec < InlayHint > ,
254259 config : & InlayHintsConfig ,
255260 func : ast:: Fn ,
@@ -262,80 +267,75 @@ fn lifetime_hints(
262267 let ret_type = func. ret_type ( ) ;
263268 let self_param = param_list. self_param ( ) . filter ( |it| it. amp_token ( ) . is_some ( ) ) ;
264269
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 ,
280273 } ;
281274
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) | {
292283 // FIXME: check path types
293284 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+ }
301298 _ => ( ) ,
302299 } )
303300 } ) ;
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
322302 } ;
323303
324304 // 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+ }
333335 }
334- }
335- potential_lt_refs. iter ( ) . for_each ( |( name, it) | {
336- if is_elided ( it. lifetime ( ) ) {
336+ potential_lt_refs. for_each ( |( name, ..) | {
337337 let name = match name {
338- Some ( it) => {
338+ Some ( it) if config . param_names_for_lifetime_elision_hints => {
339339 if let Some ( c) = used_names. get_mut ( it. text ( ) . as_str ( ) ) {
340340 * c += 1 ;
341341 SmolStr :: from ( format ! ( "'{text}{c}" , text = it. text( ) . as_str( ) ) )
@@ -347,26 +347,22 @@ fn lifetime_hints(
347347 _ => gen_idx_name ( ) ,
348348 } ;
349349 allocated_lifetimes. push ( name) ;
350- }
351- } ) ;
350+ } ) ;
351+ }
352352
353353 // 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+ }
369364 }
365+ [ ..] => None ,
370366 } ;
371367
372368 if allocated_lifetimes. is_empty ( ) && output. is_none ( ) {
@@ -398,27 +394,12 @@ fn lifetime_hints(
398394 return None ;
399395 }
400396
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 ( ) ;
420402 acc. push ( InlayHint { range : t. text_range ( ) , kind : InlayKind :: LifetimeHint , label : lt } ) ;
421- idx += 1 ;
422403 }
423404 }
424405
0 commit comments