11use hir:: HirDisplay ;
2- use syntax:: {
3- ast:: { self , AstNode , LetStmt } ,
4- TextRange ,
5- } ;
2+ use syntax:: ast:: { self , AstNode , LetStmt , Param } ;
63
74use crate :: { AssistContext , AssistId , AssistKind , Assists } ;
85
@@ -22,40 +19,46 @@ use crate::{AssistContext, AssistId, AssistKind, Assists};
2219// }
2320// ```
2421pub ( 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+ }
3431
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 {
4440 return None ;
45- }
41+ } ;
42+
43+ let module = ctx. sema . scope ( pat. syntax ( ) ) . module ( ) ?;
44+ let pat_range = pat. syntax ( ) . text_range ( ) ;
4645
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
5047 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 {
5251 cov_mark:: hit!( add_explicit_type_not_applicable_if_ty_already_specified) ;
5352 return None ;
5453 }
5554 }
5655
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
5962 if ty. contains_unknown ( ) || ty. is_closure ( ) {
6063 cov_mark:: hit!( add_explicit_type_not_applicable_if_ty_not_inferred) ;
6164 return None ;
@@ -89,7 +92,7 @@ mod tests {
8992 }
9093
9194 #[ test]
92- fn add_explicit_type_works_for_simple_expr ( ) {
95+ fn add_explicit_type_simple ( ) {
9396 check_assist (
9497 add_explicit_type,
9598 r#"fn f() { let a$0 = 1; }"# ,
@@ -98,7 +101,7 @@ mod tests {
98101 }
99102
100103 #[ test]
101- fn add_explicit_type_works_for_underscore ( ) {
104+ fn add_explicit_type_simple_on_infer_ty ( ) {
102105 check_assist (
103106 add_explicit_type,
104107 r#"fn f() { let a$0: _ = 1; }"# ,
@@ -107,19 +110,16 @@ mod tests {
107110 }
108111
109112 #[ test]
110- fn add_explicit_type_works_for_nested_underscore ( ) {
113+ fn add_explicit_type_simple_nested_infer_ty ( ) {
111114 check_assist (
112115 add_explicit_type,
113116 r#"
114- enum Option<T> { Some(T), None }
115-
117+ //- minicore: option
116118fn f() {
117119 let a$0: Option<_> = Option::Some(1);
118120}
119121"# ,
120122 r#"
121- enum Option<T> { Some(T), None }
122-
123123fn f() {
124124 let a: Option<i32> = Option::Some(1);
125125}
@@ -128,7 +128,7 @@ fn f() {
128128 }
129129
130130 #[ test]
131- fn add_explicit_type_works_for_macro_call ( ) {
131+ fn add_explicit_type_macro_call_expr ( ) {
132132 check_assist (
133133 add_explicit_type,
134134 r"macro_rules! v { () => {0u64} } fn f() { let a$0 = v!(); }" ,
@@ -137,64 +137,31 @@ fn f() {
137137 }
138138
139139 #[ 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 ( ) {
150141 cov_mark:: check!( add_explicit_type_not_applicable_if_ty_not_inferred) ;
151142 check_assist_not_applicable ( add_explicit_type, r#"fn f() { let a$0 = None; }"# ) ;
152143 }
153144
154145 #[ 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 = || {}; }"# ) ;
158148 }
159149
160150 #[ 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; }"# ) ;
166154 }
167155
168156 #[ test]
169- fn add_explicit_type_not_applicable_if_cursor_after_equals ( ) {
157+ fn add_explicit_type_not_applicable_cursor_after_equals_of_let ( ) {
170158 cov_mark:: check!( add_explicit_type_not_applicable_if_cursor_after_equals) ;
171159 check_assist_not_applicable (
172160 add_explicit_type,
173161 r#"fn f() {let a =$0 match 1 {2 => 3, 3 => 5};}"# ,
174162 )
175163 }
176164
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-
198165 /// https://github.com/rust-analyzer/rust-analyzer/issues/2922
199166 #[ test]
200167 fn regression_issue_2922 ( ) {
@@ -276,6 +243,55 @@ fn f() {
276243fn f() {
277244 let x: *const [i32] = &[3];
278245}
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+ }
279295"# ,
280296 ) ;
281297 }
0 commit comments