11use std:: {
22 fmt:: { self , Write } ,
3- mem:: take,
3+ mem:: { self , take} ,
44} ;
55
66use either:: Either ;
@@ -297,6 +297,17 @@ pub struct InlayHintsConfig {
297297 pub closing_brace_hints_min_lines : Option < usize > ,
298298 pub fields_to_resolve : InlayFieldsToResolve ,
299299}
300+ impl InlayHintsConfig {
301+ fn lazy_text_edit ( & self , finish : impl FnOnce ( ) -> TextEdit ) -> Lazy < TextEdit > {
302+ if self . fields_to_resolve . resolve_text_edits {
303+ Lazy :: Lazy
304+ } else {
305+ let edit = finish ( ) ;
306+ never ! ( edit. is_empty( ) , "inlay hint produced an empty text edit" ) ;
307+ Lazy :: Computed ( edit)
308+ }
309+ }
310+ }
300311
301312#[ derive( Copy , Clone , Debug , PartialEq , Eq ) ]
302313pub struct InlayFieldsToResolve {
@@ -408,12 +419,32 @@ pub struct InlayHint {
408419 /// The actual label to show in the inlay hint.
409420 pub label : InlayHintLabel ,
410421 /// Text edit to apply when "accepting" this inlay hint.
411- pub text_edit : Option < TextEdit > ,
422+ pub text_edit : Option < Lazy < TextEdit > > ,
412423 /// Range to recompute inlay hints when trying to resolve for this hint. If this is none, the
413424 /// hint does not support resolving.
414425 pub resolve_parent : Option < TextRange > ,
415426}
416427
428+ /// A type signaling that a value is either computed, or is available for computation.
429+ #[ derive( Clone , Debug ) ]
430+ pub enum Lazy < T > {
431+ Computed ( T ) ,
432+ Lazy ,
433+ }
434+
435+ impl < T > Lazy < T > {
436+ pub fn computed ( self ) -> Option < T > {
437+ match self {
438+ Lazy :: Computed ( it) => Some ( it) ,
439+ _ => None ,
440+ }
441+ }
442+
443+ pub fn is_lazy ( & self ) -> bool {
444+ matches ! ( self , Self :: Lazy )
445+ }
446+ }
447+
417448impl std:: hash:: Hash for InlayHint {
418449 fn hash < H : std:: hash:: Hasher > ( & self , state : & mut H ) {
419450 self . range . hash ( state) ;
@@ -422,7 +453,7 @@ impl std::hash::Hash for InlayHint {
422453 self . pad_right . hash ( state) ;
423454 self . kind . hash ( state) ;
424455 self . label . hash ( state) ;
425- self . text_edit . is_some ( ) . hash ( state) ;
456+ mem :: discriminant ( & self . text_edit ) . hash ( state) ;
426457 }
427458}
428459
@@ -439,10 +470,6 @@ impl InlayHint {
439470 resolve_parent : None ,
440471 }
441472 }
442-
443- pub fn needs_resolve ( & self ) -> Option < TextRange > {
444- self . resolve_parent . filter ( |_| self . text_edit . is_some ( ) || self . label . needs_resolve ( ) )
445- }
446473}
447474
448475#[ derive( Debug , Hash ) ]
@@ -503,10 +530,6 @@ impl InlayHintLabel {
503530 }
504531 self . parts . push ( part) ;
505532 }
506-
507- pub fn needs_resolve ( & self ) -> bool {
508- self . parts . iter ( ) . any ( |part| part. linked_location . is_some ( ) || part. tooltip . is_some ( ) )
509- }
510533}
511534
512535impl From < String > for InlayHintLabel {
@@ -725,19 +748,22 @@ fn hint_iterator(
725748
726749fn ty_to_text_edit (
727750 sema : & Semantics < ' _ , RootDatabase > ,
751+ config : & InlayHintsConfig ,
728752 node_for_hint : & SyntaxNode ,
729753 ty : & hir:: Type ,
730754 offset_to_insert : TextSize ,
731- prefix : String ,
732- ) -> Option < TextEdit > {
733- let scope = sema. scope ( node_for_hint) ?;
755+ prefix : impl Into < String > ,
756+ ) -> Option < Lazy < TextEdit > > {
734757 // FIXME: Limit the length and bail out on excess somehow?
735- let rendered = ty. display_source_code ( scope. db , scope. module ( ) . into ( ) , false ) . ok ( ) ?;
736-
737- let mut builder = TextEdit :: builder ( ) ;
738- builder. insert ( offset_to_insert, prefix) ;
739- builder. insert ( offset_to_insert, rendered) ;
740- Some ( builder. finish ( ) )
758+ let rendered = sema
759+ . scope ( node_for_hint)
760+ . and_then ( |scope| ty. display_source_code ( scope. db , scope. module ( ) . into ( ) , false ) . ok ( ) ) ?;
761+ Some ( config. lazy_text_edit ( || {
762+ let mut builder = TextEdit :: builder ( ) ;
763+ builder. insert ( offset_to_insert, prefix. into ( ) ) ;
764+ builder. insert ( offset_to_insert, rendered) ;
765+ builder. finish ( )
766+ } ) )
741767}
742768
743769fn closure_has_block_body ( closure : & ast:: ClosureExpr ) -> bool {
@@ -847,7 +873,7 @@ mod tests {
847873
848874 let edits = inlay_hints
849875 . into_iter ( )
850- . filter_map ( |hint| hint. text_edit )
876+ . filter_map ( |hint| hint. text_edit ? . computed ( ) )
851877 . reduce ( |mut acc, next| {
852878 acc. union ( next) . expect ( "merging text edits failed" ) ;
853879 acc
@@ -867,7 +893,8 @@ mod tests {
867893 let ( analysis, file_id) = fixture:: file ( ra_fixture) ;
868894 let inlay_hints = analysis. inlay_hints ( & config, file_id, None ) . unwrap ( ) ;
869895
870- let edits: Vec < _ > = inlay_hints. into_iter ( ) . filter_map ( |hint| hint. text_edit ) . collect ( ) ;
896+ let edits: Vec < _ > =
897+ inlay_hints. into_iter ( ) . filter_map ( |hint| hint. text_edit ?. computed ( ) ) . collect ( ) ;
871898
872899 assert ! ( edits. is_empty( ) , "unexpected edits: {edits:?}" ) ;
873900 }
0 commit comments