1
1
use std:: fmt;
2
2
3
3
use 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
+ } ;
5
8
use ide_db:: {
6
9
base_db:: FileRange , famous_defs:: FamousDefs , syntax_helpers:: node_ext:: walk_ty, FxHashMap ,
7
10
RootDatabase ,
@@ -22,7 +25,7 @@ pub struct InlayHintsConfig {
22
25
pub type_hints : bool ,
23
26
pub parameter_hints : bool ,
24
27
pub chaining_hints : bool ,
25
- pub reborrow_hints : ReborrowHints ,
28
+ pub adjustment_hints : AdjustmentHints ,
26
29
pub closure_return_type_hints : ClosureReturnTypeHints ,
27
30
pub binding_mode_hints : bool ,
28
31
pub lifetime_elision_hints : LifetimeElisionHints ,
@@ -48,7 +51,7 @@ pub enum LifetimeElisionHints {
48
51
}
49
52
50
53
#[ derive( Clone , Debug , PartialEq , Eq ) ]
51
- pub enum ReborrowHints {
54
+ pub enum AdjustmentHints {
52
55
Always ,
53
56
MutableOnly ,
54
57
Never ,
@@ -61,7 +64,8 @@ pub enum InlayKind {
61
64
ClosingBraceHint ,
62
65
ClosureReturnTypeHint ,
63
66
GenericParamListHint ,
64
- ImplicitReborrowHint ,
67
+ AdjustmentHint ,
68
+ AdjustmentHintClosingParenthesis ,
65
69
LifetimeHint ,
66
70
ParameterHint ,
67
71
TypeHint ,
@@ -115,6 +119,12 @@ impl From<String> for InlayHintLabel {
115
119
}
116
120
}
117
121
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
+
118
128
impl fmt:: Display for InlayHintLabel {
119
129
fn fmt ( & self , f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
120
130
write ! ( f, "{}" , self . parts. iter( ) . map( |part| & part. text) . format( "" ) )
@@ -221,6 +231,7 @@ fn hints(
221
231
match node {
222
232
ast:: Expr ( expr) => {
223
233
chaining_hints( hints, sema, & famous_defs, config, file_id, & expr) ;
234
+ adjustment_hints( hints, sema, config, & expr) ;
224
235
match expr {
225
236
ast:: Expr :: CallExpr ( it) => param_name_hints( hints, sema, config, ast:: Expr :: from( it) ) ,
226
237
ast:: Expr :: MethodCallExpr ( it) => {
@@ -229,7 +240,7 @@ fn hints(
229
240
ast:: Expr :: ClosureExpr ( it) => closure_ret_hints( hints, sema, & famous_defs, config, file_id, it) ,
230
241
// We could show reborrows for all expressions, but usually that is just noise to the user
231
242
// 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),
233
244
_ => None ,
234
245
}
235
246
} ,
@@ -617,30 +628,83 @@ fn closure_ret_hints(
617
628
Some ( ( ) )
618
629
}
619
630
620
- fn reborrow_hints (
631
+ fn adjustment_hints (
621
632
acc : & mut Vec < InlayHint > ,
622
633
sema : & Semantics < ' _ , RootDatabase > ,
623
634
config : & InlayHintsConfig ,
624
635
expr : & ast:: Expr ,
625
636
) -> Option < ( ) > {
626
- if config. reborrow_hints == ReborrowHints :: Never {
627
- return None ;
637
+ if config. adjustment_hints == AdjustmentHints :: Never {
638
+ // return None;
628
639
}
629
640
641
+ let parent = expr. syntax ( ) . parent ( ) . and_then ( ast:: Expr :: cast) ;
630
642
let descended = sema. descend_node_into_attributes ( expr. clone ( ) ) . pop ( ) ;
631
643
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 ,
637
661
} ;
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
+ }
644
708
Some ( ( ) )
645
709
}
646
710
@@ -785,23 +849,23 @@ fn binding_mode_hints(
785
849
tooltip : Some ( InlayTooltip :: String ( "Inferred binding mode" . into ( ) ) ) ,
786
850
} ) ;
787
851
} ) ;
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
+ // }
805
869
806
870
Some ( ( ) )
807
871
}
@@ -1218,7 +1282,7 @@ mod tests {
1218
1282
use syntax:: { TextRange , TextSize } ;
1219
1283
use test_utils:: extract_annotations;
1220
1284
1221
- use crate :: inlay_hints:: ReborrowHints ;
1285
+ use crate :: inlay_hints:: AdjustmentHints ;
1222
1286
use crate :: { fixture, inlay_hints:: InlayHintsConfig , LifetimeElisionHints } ;
1223
1287
1224
1288
use super :: ClosureReturnTypeHints ;
@@ -1230,7 +1294,7 @@ mod tests {
1230
1294
chaining_hints : false ,
1231
1295
lifetime_elision_hints : LifetimeElisionHints :: Never ,
1232
1296
closure_return_type_hints : ClosureReturnTypeHints :: Never ,
1233
- reborrow_hints : ReborrowHints :: Always ,
1297
+ adjustment_hints : AdjustmentHints :: Always ,
1234
1298
binding_mode_hints : false ,
1235
1299
hide_named_constructor_hints : false ,
1236
1300
hide_closure_initialization_hints : false ,
@@ -1242,7 +1306,7 @@ mod tests {
1242
1306
type_hints : true ,
1243
1307
parameter_hints : true ,
1244
1308
chaining_hints : true ,
1245
- reborrow_hints : ReborrowHints :: Always ,
1309
+ adjustment_hints : AdjustmentHints :: Always ,
1246
1310
closure_return_type_hints : ClosureReturnTypeHints :: WithBlock ,
1247
1311
binding_mode_hints : true ,
1248
1312
lifetime_elision_hints : LifetimeElisionHints :: Always ,
@@ -2849,7 +2913,7 @@ impl () {
2849
2913
fn hints_implicit_reborrow ( ) {
2850
2914
check_with_config (
2851
2915
InlayHintsConfig {
2852
- reborrow_hints : ReborrowHints :: Always ,
2916
+ adjustment_hints : AdjustmentHints :: Always ,
2853
2917
parameter_hints : true ,
2854
2918
..DISABLED_CONFIG
2855
2919
} ,
0 commit comments