1
1
use hir:: { db:: HirDatabase , HirDisplay } ;
2
2
use ra_syntax:: {
3
- ast:: { self , AstNode , LetStmt , NameOwner } ,
4
- TextRange , T ,
3
+ ast:: { self , AstNode , LetStmt , NameOwner , TypeAscriptionOwner } ,
4
+ TextRange ,
5
5
} ;
6
6
7
7
use crate :: { Assist , AssistCtx , AssistId } ;
@@ -34,17 +34,21 @@ pub(crate) fn add_explicit_type(ctx: AssistCtx<impl HirDatabase>) -> Option<Assi
34
34
// The binding must have a name
35
35
let name = pat. name ( ) ?;
36
36
let name_range = name. syntax ( ) . text_range ( ) ;
37
- // Assist should only be applicable if cursor is between 'let' and '='
38
37
let stmt_range = stmt. syntax ( ) . text_range ( ) ;
39
38
let eq_range = stmt. eq_token ( ) ?. text_range ( ) ;
39
+ // Assist should only be applicable if cursor is between 'let' and '='
40
40
let let_range = TextRange :: from_to ( stmt_range. start ( ) , eq_range. start ( ) ) ;
41
41
let cursor_in_range = ctx. frange . range . is_subrange ( & let_range) ;
42
42
if !cursor_in_range {
43
43
return None ;
44
44
}
45
45
// Assist not applicable if the type has already been specified
46
- if stmt. syntax ( ) . children_with_tokens ( ) . any ( |child| child. kind ( ) == T ! [ : ] ) {
47
- return None ;
46
+ // and it has no placeholders
47
+ let ascribed_ty = stmt. ascribed_type ( ) ;
48
+ if let Some ( ref ty) = ascribed_ty {
49
+ if ty. syntax ( ) . descendants ( ) . find_map ( ast:: PlaceholderType :: cast) . is_none ( ) {
50
+ return None ;
51
+ }
48
52
}
49
53
// Infer type
50
54
let db = ctx. db ;
@@ -60,7 +64,11 @@ pub(crate) fn add_explicit_type(ctx: AssistCtx<impl HirDatabase>) -> Option<Assi
60
64
format ! ( "Insert explicit type '{}'" , ty. display( db) ) ,
61
65
|edit| {
62
66
edit. target ( pat_range) ;
63
- edit. insert ( name_range. end ( ) , format ! ( ": {}" , ty. display( db) ) ) ;
67
+ if let Some ( ascribed_ty) = ascribed_ty {
68
+ edit. replace ( ascribed_ty. syntax ( ) . text_range ( ) , format ! ( "{}" , ty. display( db) ) ) ;
69
+ } else {
70
+ edit. insert ( name_range. end ( ) , format ! ( ": {}" , ty. display( db) ) ) ;
71
+ }
64
72
} ,
65
73
)
66
74
}
@@ -85,6 +93,40 @@ mod tests {
85
93
) ;
86
94
}
87
95
96
+ #[ test]
97
+ fn add_explicit_type_works_for_underscore ( ) {
98
+ check_assist (
99
+ add_explicit_type,
100
+ "fn f() { let a<|>: _ = 1; }" ,
101
+ "fn f() { let a<|>: i32 = 1; }" ,
102
+ ) ;
103
+ }
104
+
105
+ #[ test]
106
+ fn add_explicit_type_works_for_nested_underscore ( ) {
107
+ check_assist (
108
+ add_explicit_type,
109
+ r#"
110
+ enum Option<T> {
111
+ Some(T),
112
+ None
113
+ }
114
+
115
+ fn f() {
116
+ let a<|>: Option<_> = Option::Some(1);
117
+ }"# ,
118
+ r#"
119
+ enum Option<T> {
120
+ Some(T),
121
+ None
122
+ }
123
+
124
+ fn f() {
125
+ let a<|>: Option<i32> = Option::Some(1);
126
+ }"# ,
127
+ ) ;
128
+ }
129
+
88
130
#[ test]
89
131
fn add_explicit_type_works_for_macro_call ( ) {
90
132
check_assist (
0 commit comments