11use std:: fmt;
22
33use either:: Either ;
4- use hir:: { known, Callable , HasVisibility , HirDisplay , Mutability , Semantics , TypeInfo } ;
4+ use hir:: {
5+ known, Adjust , AutoBorrow , Callable , HasVisibility , HirDisplay , Mutability , OverloadedDeref ,
6+ PointerCast , Safety , Semantics , TypeInfo ,
7+ } ;
58use ide_db:: {
69 base_db:: FileRange , famous_defs:: FamousDefs , syntax_helpers:: node_ext:: walk_ty, FxHashMap ,
710 RootDatabase ,
@@ -22,7 +25,7 @@ pub struct InlayHintsConfig {
2225 pub type_hints : bool ,
2326 pub parameter_hints : bool ,
2427 pub chaining_hints : bool ,
25- pub reborrow_hints : ReborrowHints ,
28+ pub adjustment_hints : AdjustmentHints ,
2629 pub closure_return_type_hints : ClosureReturnTypeHints ,
2730 pub binding_mode_hints : bool ,
2831 pub lifetime_elision_hints : LifetimeElisionHints ,
@@ -48,7 +51,7 @@ pub enum LifetimeElisionHints {
4851}
4952
5053#[ derive( Clone , Debug , PartialEq , Eq ) ]
51- pub enum ReborrowHints {
54+ pub enum AdjustmentHints {
5255 Always ,
5356 MutableOnly ,
5457 Never ,
@@ -61,7 +64,8 @@ pub enum InlayKind {
6164 ClosingBraceHint ,
6265 ClosureReturnTypeHint ,
6366 GenericParamListHint ,
64- ImplicitReborrowHint ,
67+ AdjustmentHint ,
68+ AdjustmentHintClosingParenthesis ,
6569 LifetimeHint ,
6670 ParameterHint ,
6771 TypeHint ,
@@ -115,6 +119,12 @@ impl From<String> for InlayHintLabel {
115119 }
116120}
117121
122+ impl From < & str > for InlayHintLabel {
123+ fn from ( s : & str ) -> Self {
124+ Self { parts : vec ! [ InlayHintLabelPart { text: s. into( ) , linked_location: None } ] }
125+ }
126+ }
127+
118128impl fmt:: Display for InlayHintLabel {
119129 fn fmt ( & self , f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
120130 write ! ( f, "{}" , self . parts. iter( ) . map( |part| & part. text) . format( "" ) )
@@ -221,6 +231,7 @@ fn hints(
221231 match node {
222232 ast:: Expr ( expr) => {
223233 chaining_hints( hints, sema, & famous_defs, config, file_id, & expr) ;
234+ adjustment_hints( hints, sema, config, & expr) ;
224235 match expr {
225236 ast:: Expr :: CallExpr ( it) => param_name_hints( hints, sema, config, ast:: Expr :: from( it) ) ,
226237 ast:: Expr :: MethodCallExpr ( it) => {
@@ -229,7 +240,7 @@ fn hints(
229240 ast:: Expr :: ClosureExpr ( it) => closure_ret_hints( hints, sema, & famous_defs, config, file_id, it) ,
230241 // We could show reborrows for all expressions, but usually that is just noise to the user
231242 // and the main point here is to show why "moving" a mutable reference doesn't necessarily move it
232- ast:: Expr :: PathExpr ( _) => reborrow_hints( hints, sema, config, & expr) ,
243+ // ast::Expr::PathExpr(_) => reborrow_hints(hints, sema, config, &expr),
233244 _ => None ,
234245 }
235246 } ,
@@ -617,30 +628,83 @@ fn closure_ret_hints(
617628 Some ( ( ) )
618629}
619630
620- fn reborrow_hints (
631+ fn adjustment_hints (
621632 acc : & mut Vec < InlayHint > ,
622633 sema : & Semantics < ' _ , RootDatabase > ,
623634 config : & InlayHintsConfig ,
624635 expr : & ast:: Expr ,
625636) -> Option < ( ) > {
626- if config. reborrow_hints == ReborrowHints :: Never {
627- return None ;
637+ if config. adjustment_hints == AdjustmentHints :: Never {
638+ // return None;
628639 }
629640
641+ let parent = expr. syntax ( ) . parent ( ) . and_then ( ast:: Expr :: cast) ;
630642 let descended = sema. descend_node_into_attributes ( expr. clone ( ) ) . pop ( ) ;
631643 let desc_expr = descended. as_ref ( ) . unwrap_or ( expr) ;
632- let mutability = sema. is_implicit_reborrow ( desc_expr) ?;
633- let label = match mutability {
634- hir:: Mutability :: Shared if config. reborrow_hints != ReborrowHints :: MutableOnly => "&*" ,
635- hir:: Mutability :: Mut => "&mut *" ,
636- _ => return None ,
644+ let adjustments = sema. expr_adjustments ( desc_expr) . filter ( |it| !it. is_empty ( ) ) ?;
645+ let needs_parens = match parent {
646+ Some ( parent) => {
647+ match parent {
648+ ast:: Expr :: AwaitExpr ( _)
649+ | ast:: Expr :: CallExpr ( _)
650+ | ast:: Expr :: CastExpr ( _)
651+ | ast:: Expr :: FieldExpr ( _)
652+ | ast:: Expr :: MethodCallExpr ( _)
653+ | ast:: Expr :: TryExpr ( _) => true ,
654+ // FIXME: shorthands need special casing, though not sure if adjustments are even valid there
655+ ast:: Expr :: RecordExpr ( _) => false ,
656+ ast:: Expr :: IndexExpr ( index) => index. base ( ) . as_ref ( ) == Some ( expr) ,
657+ _ => false ,
658+ }
659+ }
660+ None => false ,
637661 } ;
638- acc. push ( InlayHint {
639- range : expr. syntax ( ) . text_range ( ) ,
640- kind : InlayKind :: ImplicitReborrowHint ,
641- label : label. to_string ( ) . into ( ) ,
642- tooltip : Some ( InlayTooltip :: String ( "Compiler inserted reborrow" . into ( ) ) ) ,
643- } ) ;
662+ if needs_parens {
663+ acc. push ( InlayHint {
664+ range : expr. syntax ( ) . text_range ( ) ,
665+ kind : InlayKind :: AdjustmentHint ,
666+ label : "(" . into ( ) ,
667+ tooltip : None ,
668+ } ) ;
669+ }
670+ for adjustment in adjustments. into_iter ( ) . rev ( ) {
671+ // FIXME: Add some nicer tooltips to each of these
672+ let text = match adjustment {
673+ Adjust :: NeverToAny => "<never-to-any>" ,
674+ Adjust :: Deref ( None ) => "*" ,
675+ Adjust :: Deref ( Some ( OverloadedDeref ( Mutability :: Mut ) ) ) => "*" ,
676+ Adjust :: Deref ( Some ( OverloadedDeref ( Mutability :: Shared ) ) ) => "*" ,
677+ Adjust :: Borrow ( AutoBorrow :: Ref ( Mutability :: Shared ) ) => "&" ,
678+ Adjust :: Borrow ( AutoBorrow :: Ref ( Mutability :: Mut ) ) => "&mut " ,
679+ Adjust :: Borrow ( AutoBorrow :: RawPtr ( Mutability :: Shared ) ) => "&raw const " ,
680+ Adjust :: Borrow ( AutoBorrow :: RawPtr ( Mutability :: Mut ) ) => "&raw mut " ,
681+ // some of these could be represented via `as` casts, but that's not too nice and
682+ // handling everything as a prefix expr makes the `(` and `)` insertion easier
683+ Adjust :: Pointer ( cast) => match cast {
684+ PointerCast :: ReifyFnPointer => "<fn-item-to-fn-pointer>" ,
685+ PointerCast :: UnsafeFnPointer => "<safe-fn-pointer-to-unsafe-fn-pointer>" ,
686+ PointerCast :: ClosureFnPointer ( Safety :: Unsafe ) => "<closure-to-unsafe-fn-pointer>" ,
687+ PointerCast :: ClosureFnPointer ( Safety :: Safe ) => "<closure-to-fn-pointer>" ,
688+ PointerCast :: MutToConstPointer => "<mut-ptr-to-const-ptr>" ,
689+ PointerCast :: ArrayToPointer => "<array-ptr-to-element-ptr>" ,
690+ PointerCast :: Unsize => "<unsize>" ,
691+ } ,
692+ } ;
693+ acc. push ( InlayHint {
694+ range : expr. syntax ( ) . text_range ( ) ,
695+ kind : InlayKind :: AdjustmentHint ,
696+ label : text. into ( ) ,
697+ tooltip : None ,
698+ } ) ;
699+ }
700+ if needs_parens {
701+ acc. push ( InlayHint {
702+ range : expr. syntax ( ) . text_range ( ) ,
703+ kind : InlayKind :: AdjustmentHintClosingParenthesis ,
704+ label : ")" . into ( ) ,
705+ tooltip : None ,
706+ } ) ;
707+ }
644708 Some ( ( ) )
645709}
646710
@@ -785,23 +849,23 @@ fn binding_mode_hints(
785849 tooltip : Some ( InlayTooltip :: String ( "Inferred binding mode" . into ( ) ) ) ,
786850 } ) ;
787851 } ) ;
788- match pat {
789- ast:: Pat :: IdentPat ( pat) if pat. ref_token ( ) . is_none ( ) && pat. mut_token ( ) . is_none ( ) => {
790- let bm = sema. binding_mode_of_pat ( pat) ?;
791- let bm = match bm {
792- hir:: BindingMode :: Move => return None ,
793- hir:: BindingMode :: Ref ( Mutability :: Mut ) => "ref mut" ,
794- hir:: BindingMode :: Ref ( Mutability :: Shared ) => "ref" ,
795- } ;
796- acc. push ( InlayHint {
797- range,
798- kind : InlayKind :: BindingModeHint ,
799- label : bm. to_string ( ) . into ( ) ,
800- tooltip : Some ( InlayTooltip :: String ( "Inferred binding mode" . into ( ) ) ) ,
801- } ) ;
802- }
803- _ => ( ) ,
804- }
852+ // match pat {
853+ // ast::Pat::IdentPat(pat) if pat.ref_token().is_none() && pat.mut_token().is_none() => {
854+ // let bm = sema.binding_mode_of_pat(pat)?;
855+ // let bm = match bm {
856+ // hir::BindingMode::Move => return None,
857+ // hir::BindingMode::Ref(Mutability::Mut) => "ref mut",
858+ // hir::BindingMode::Ref(Mutability::Shared) => "ref",
859+ // };
860+ // acc.push(InlayHint {
861+ // range,
862+ // kind: InlayKind::BindingModeHint,
863+ // label: bm.to_string().into(),
864+ // tooltip: Some(InlayTooltip::String("Inferred binding mode".into())),
865+ // });
866+ // }
867+ // _ => (),
868+ // }
805869
806870 Some ( ( ) )
807871}
@@ -1218,7 +1282,7 @@ mod tests {
12181282 use syntax:: { TextRange , TextSize } ;
12191283 use test_utils:: extract_annotations;
12201284
1221- use crate :: inlay_hints:: ReborrowHints ;
1285+ use crate :: inlay_hints:: AdjustmentHints ;
12221286 use crate :: { fixture, inlay_hints:: InlayHintsConfig , LifetimeElisionHints } ;
12231287
12241288 use super :: ClosureReturnTypeHints ;
@@ -1230,7 +1294,7 @@ mod tests {
12301294 chaining_hints : false ,
12311295 lifetime_elision_hints : LifetimeElisionHints :: Never ,
12321296 closure_return_type_hints : ClosureReturnTypeHints :: Never ,
1233- reborrow_hints : ReborrowHints :: Always ,
1297+ adjustment_hints : AdjustmentHints :: Always ,
12341298 binding_mode_hints : false ,
12351299 hide_named_constructor_hints : false ,
12361300 hide_closure_initialization_hints : false ,
@@ -1242,7 +1306,7 @@ mod tests {
12421306 type_hints : true ,
12431307 parameter_hints : true ,
12441308 chaining_hints : true ,
1245- reborrow_hints : ReborrowHints :: Always ,
1309+ adjustment_hints : AdjustmentHints :: Always ,
12461310 closure_return_type_hints : ClosureReturnTypeHints :: WithBlock ,
12471311 binding_mode_hints : true ,
12481312 lifetime_elision_hints : LifetimeElisionHints :: Always ,
@@ -2849,7 +2913,7 @@ impl () {
28492913 fn hints_implicit_reborrow ( ) {
28502914 check_with_config (
28512915 InlayHintsConfig {
2852- reborrow_hints : ReborrowHints :: Always ,
2916+ adjustment_hints : AdjustmentHints :: Always ,
28532917 parameter_hints : true ,
28542918 ..DISABLED_CONFIG
28552919 } ,
0 commit comments