1
1
use hir:: HirDisplay ;
2
- use syntax:: {
3
- ast:: { self , AstNode , LetStmt } ,
4
- TextRange ,
5
- } ;
2
+ use syntax:: ast:: { self , AstNode , LetStmt , Param } ;
6
3
7
4
use crate :: { AssistContext , AssistId , AssistKind , Assists } ;
8
5
@@ -22,40 +19,46 @@ use crate::{AssistContext, AssistId, AssistKind, Assists};
22
19
// }
23
20
// ```
24
21
pub ( crate ) fn add_explicit_type ( acc : & mut Assists , ctx : & AssistContext ) -> Option < ( ) > {
25
- let let_stmt = ctx. find_node_at_offset :: < LetStmt > ( ) ? ;
26
- let module = ctx . sema . scope ( let_stmt . syntax ( ) ) . module ( ) ? ;
27
- let expr = let_stmt. initializer ( ) ?;
28
- // Must be a binding
29
- let pat = match let_stmt . pat ( ) ? {
30
- ast :: Pat :: IdentPat ( bind_pat ) => bind_pat ,
31
- _ => return None ,
32
- } ;
33
- let pat_range = pat . syntax ( ) . text_range ( ) ;
22
+ let ( ascribed_ty , expr , pat ) = if let Some ( let_stmt) = ctx. find_node_at_offset :: < LetStmt > ( ) {
23
+ let cursor_in_range = {
24
+ let eq_range = let_stmt. eq_token ( ) ?. text_range ( ) ;
25
+ ctx . offset ( ) < eq_range . start ( )
26
+ } ;
27
+ if !cursor_in_range {
28
+ cov_mark :: hit! ( add_explicit_type_not_applicable_if_cursor_after_equals ) ;
29
+ return None ;
30
+ }
34
31
35
- // Assist should only be applicable if cursor is between 'let' and '='
36
- let cursor_in_range = {
37
- let stmt_range = let_stmt. syntax ( ) . text_range ( ) ;
38
- let eq_range = let_stmt. eq_token ( ) ?. text_range ( ) ;
39
- let let_range = TextRange :: new ( stmt_range. start ( ) , eq_range. start ( ) ) ;
40
- let_range. contains_range ( ctx. frange . range )
41
- } ;
42
- if !cursor_in_range {
43
- cov_mark:: hit!( add_explicit_type_not_applicable_if_cursor_after_equals) ;
32
+ ( let_stmt. ty ( ) , let_stmt. initializer ( ) , let_stmt. pat ( ) ?)
33
+ } else if let Some ( param) = ctx. find_node_at_offset :: < Param > ( ) {
34
+ if param. syntax ( ) . ancestors ( ) . nth ( 2 ) . and_then ( ast:: ClosureExpr :: cast) . is_none ( ) {
35
+ cov_mark:: hit!( add_explicit_type_not_applicable_in_fn_param) ;
36
+ return None ;
37
+ }
38
+ ( param. ty ( ) , None , param. pat ( ) ?)
39
+ } else {
44
40
return None ;
45
- }
41
+ } ;
42
+
43
+ let module = ctx. sema . scope ( pat. syntax ( ) ) . module ( ) ?;
44
+ let pat_range = pat. syntax ( ) . text_range ( ) ;
46
45
47
- // Assist not applicable if the type has already been specified
48
- // and it has no placeholders
49
- let ascribed_ty = let_stmt. ty ( ) ;
46
+ // Don't enable the assist if there is a type ascription without any placeholders
50
47
if let Some ( ty) = & ascribed_ty {
51
- if ty. syntax ( ) . descendants ( ) . find_map ( ast:: InferType :: cast) . is_none ( ) {
48
+ let mut contains_infer_ty = false ;
49
+ ty. walk ( & mut |ty| contains_infer_ty |= matches ! ( ty, ast:: Type :: InferType ( _) ) ) ;
50
+ if !contains_infer_ty {
52
51
cov_mark:: hit!( add_explicit_type_not_applicable_if_ty_already_specified) ;
53
52
return None ;
54
53
}
55
54
}
56
55
57
- // Infer type
58
- let ( ty, _) = ctx. sema . type_of_expr_with_coercion ( & expr) ?;
56
+ let ty = match ( pat, expr) {
57
+ ( ast:: Pat :: IdentPat ( _) , Some ( expr) ) => ctx. sema . type_of_expr_with_coercion ( & expr) ?. 0 ,
58
+ ( pat, _) => ctx. sema . type_of_pat ( & pat) ?,
59
+ } ;
60
+
61
+ // Unresolved or unnameable types can't be annotated
59
62
if ty. contains_unknown ( ) || ty. is_closure ( ) {
60
63
cov_mark:: hit!( add_explicit_type_not_applicable_if_ty_not_inferred) ;
61
64
return None ;
@@ -89,7 +92,7 @@ mod tests {
89
92
}
90
93
91
94
#[ test]
92
- fn add_explicit_type_works_for_simple_expr ( ) {
95
+ fn add_explicit_type_simple ( ) {
93
96
check_assist (
94
97
add_explicit_type,
95
98
r#"fn f() { let a$0 = 1; }"# ,
@@ -98,7 +101,7 @@ mod tests {
98
101
}
99
102
100
103
#[ test]
101
- fn add_explicit_type_works_for_underscore ( ) {
104
+ fn add_explicit_type_simple_on_infer_ty ( ) {
102
105
check_assist (
103
106
add_explicit_type,
104
107
r#"fn f() { let a$0: _ = 1; }"# ,
@@ -107,19 +110,16 @@ mod tests {
107
110
}
108
111
109
112
#[ test]
110
- fn add_explicit_type_works_for_nested_underscore ( ) {
113
+ fn add_explicit_type_simple_nested_infer_ty ( ) {
111
114
check_assist (
112
115
add_explicit_type,
113
116
r#"
114
- enum Option<T> { Some(T), None }
115
-
117
+ //- minicore: option
116
118
fn f() {
117
119
let a$0: Option<_> = Option::Some(1);
118
120
}
119
121
"# ,
120
122
r#"
121
- enum Option<T> { Some(T), None }
122
-
123
123
fn f() {
124
124
let a: Option<i32> = Option::Some(1);
125
125
}
@@ -128,7 +128,7 @@ fn f() {
128
128
}
129
129
130
130
#[ test]
131
- fn add_explicit_type_works_for_macro_call ( ) {
131
+ fn add_explicit_type_macro_call_expr ( ) {
132
132
check_assist (
133
133
add_explicit_type,
134
134
r"macro_rules! v { () => {0u64} } fn f() { let a$0 = v!(); }" ,
@@ -137,64 +137,31 @@ fn f() {
137
137
}
138
138
139
139
#[ test]
140
- fn add_explicit_type_works_for_macro_call_recursive ( ) {
141
- check_assist (
142
- add_explicit_type,
143
- r#"macro_rules! u { () => {0u64} } macro_rules! v { () => {u!()} } fn f() { let a$0 = v!(); }"# ,
144
- r#"macro_rules! u { () => {0u64} } macro_rules! v { () => {u!()} } fn f() { let a: u64 = v!(); }"# ,
145
- ) ;
146
- }
147
-
148
- #[ test]
149
- fn add_explicit_type_not_applicable_if_ty_not_inferred ( ) {
140
+ fn add_explicit_type_not_applicable_unresolved ( ) {
150
141
cov_mark:: check!( add_explicit_type_not_applicable_if_ty_not_inferred) ;
151
142
check_assist_not_applicable ( add_explicit_type, r#"fn f() { let a$0 = None; }"# ) ;
152
143
}
153
144
154
145
#[ test]
155
- fn add_explicit_type_not_applicable_if_ty_already_specified ( ) {
156
- cov_mark:: check!( add_explicit_type_not_applicable_if_ty_already_specified) ;
157
- check_assist_not_applicable ( add_explicit_type, r#"fn f() { let a$0: i32 = 1; }"# ) ;
146
+ fn add_explicit_type_not_applicable_closure_expr ( ) {
147
+ check_assist_not_applicable ( add_explicit_type, r#"fn f() { let a$0 = || {}; }"# ) ;
158
148
}
159
149
160
150
#[ test]
161
- fn add_explicit_type_not_applicable_if_specified_ty_is_tuple ( ) {
162
- check_assist_not_applicable (
163
- add_explicit_type,
164
- r#"fn f() { let a$0: (i32, i32) = (3, 4); }"# ,
165
- ) ;
151
+ fn add_explicit_type_not_applicable_ty_already_specified ( ) {
152
+ cov_mark:: check!( add_explicit_type_not_applicable_if_ty_already_specified) ;
153
+ check_assist_not_applicable ( add_explicit_type, r#"fn f() { let a$0: i32 = 1; }"# ) ;
166
154
}
167
155
168
156
#[ test]
169
- fn add_explicit_type_not_applicable_if_cursor_after_equals ( ) {
157
+ fn add_explicit_type_not_applicable_cursor_after_equals_of_let ( ) {
170
158
cov_mark:: check!( add_explicit_type_not_applicable_if_cursor_after_equals) ;
171
159
check_assist_not_applicable (
172
160
add_explicit_type,
173
161
r#"fn f() {let a =$0 match 1 {2 => 3, 3 => 5};}"# ,
174
162
)
175
163
}
176
164
177
- #[ test]
178
- fn add_explicit_type_not_applicable_if_cursor_before_let ( ) {
179
- check_assist_not_applicable (
180
- add_explicit_type,
181
- r#"fn f() $0{let a = match 1 {2 => 3, 3 => 5};}"# ,
182
- )
183
- }
184
-
185
- #[ test]
186
- fn closure_parameters_are_not_added ( ) {
187
- check_assist_not_applicable (
188
- add_explicit_type,
189
- r#"
190
- fn main() {
191
- let multiply_by_two$0 = |i| i * 3;
192
- let six = multiply_by_two(2);
193
- }
194
- "# ,
195
- )
196
- }
197
-
198
165
/// https://github.com/rust-analyzer/rust-analyzer/issues/2922
199
166
#[ test]
200
167
fn regression_issue_2922 ( ) {
@@ -276,6 +243,55 @@ fn f() {
276
243
fn f() {
277
244
let x: *const [i32] = &[3];
278
245
}
246
+ "# ,
247
+ ) ;
248
+ }
249
+
250
+ #[ test]
251
+ fn add_explicit_type_not_applicable_fn_param ( ) {
252
+ cov_mark:: check!( add_explicit_type_not_applicable_in_fn_param) ;
253
+ check_assist_not_applicable ( add_explicit_type, r#"fn f(x$0: ()) {}"# ) ;
254
+ }
255
+
256
+ #[ test]
257
+ fn add_explicit_type_ascribes_closure_param ( ) {
258
+ check_assist (
259
+ add_explicit_type,
260
+ r#"
261
+ fn f() {
262
+ |y$0| {
263
+ let x: i32 = y;
264
+ };
265
+ }
266
+ "# ,
267
+ r#"
268
+ fn f() {
269
+ |y: i32| {
270
+ let x: i32 = y;
271
+ };
272
+ }
273
+ "# ,
274
+ ) ;
275
+ }
276
+
277
+ #[ test]
278
+ fn add_explicit_type_ascribes_closure_param_already_ascribed ( ) {
279
+ check_assist (
280
+ add_explicit_type,
281
+ r#"
282
+ //- minicore: option
283
+ fn f() {
284
+ |mut y$0: Option<_>| {
285
+ y = Some(3);
286
+ };
287
+ }
288
+ "# ,
289
+ r#"
290
+ fn f() {
291
+ |mut y: Option<i32>| {
292
+ y = Some(3);
293
+ };
294
+ }
279
295
"# ,
280
296
) ;
281
297
}
0 commit comments