1
+ use hir:: HirDisplay ;
1
2
use syntax:: {
2
3
ast:: { Expr , GenericArg } ,
3
4
ast:: { LetStmt , Type :: InferType } ,
@@ -65,7 +66,16 @@ pub(crate) fn replace_turbofish_with_explicit_type(
65
66
66
67
// An improvement would be to check that this is correctly part of the return value of the
67
68
// function call, or sub in the actual return type.
68
- let turbofish_type = & turbofish_args[ 0 ] ;
69
+ let returned_type = match ctx. sema . type_of_expr ( & initializer) {
70
+ Some ( returned_type) if !returned_type. original . contains_unknown ( ) => {
71
+ let module = ctx. sema . scope ( let_stmt. syntax ( ) ) ?. module ( ) ;
72
+ returned_type. original . display_source_code ( ctx. db ( ) , module. into ( ) ) . ok ( ) ?
73
+ }
74
+ _ => {
75
+ cov_mark:: hit!( fallback_to_turbofish_type_if_type_info_not_available) ;
76
+ turbofish_args[ 0 ] . to_string ( )
77
+ }
78
+ } ;
69
79
70
80
let initializer_start = initializer. syntax ( ) . text_range ( ) . start ( ) ;
71
81
if ctx. offset ( ) > turbofish_range. end ( ) || ctx. offset ( ) < initializer_start {
@@ -83,7 +93,7 @@ pub(crate) fn replace_turbofish_with_explicit_type(
83
93
"Replace turbofish with explicit type" ,
84
94
TextRange :: new ( initializer_start, turbofish_range. end ( ) ) ,
85
95
|builder| {
86
- builder. insert ( ident_range. end ( ) , format ! ( ": {}" , turbofish_type ) ) ;
96
+ builder. insert ( ident_range. end ( ) , format ! ( ": {}" , returned_type ) ) ;
87
97
builder. delete ( turbofish_range) ;
88
98
} ,
89
99
) ;
@@ -98,7 +108,7 @@ pub(crate) fn replace_turbofish_with_explicit_type(
98
108
"Replace `_` with turbofish type" ,
99
109
turbofish_range,
100
110
|builder| {
101
- builder. replace ( underscore_range, turbofish_type . to_string ( ) ) ;
111
+ builder. replace ( underscore_range, returned_type ) ;
102
112
builder. delete ( turbofish_range) ;
103
113
} ,
104
114
) ;
@@ -115,6 +125,7 @@ mod tests {
115
125
116
126
#[ test]
117
127
fn replaces_turbofish_for_vec_string ( ) {
128
+ cov_mark:: check!( fallback_to_turbofish_type_if_type_info_not_available) ;
118
129
check_assist (
119
130
replace_turbofish_with_explicit_type,
120
131
r#"
@@ -135,6 +146,7 @@ fn main() {
135
146
#[ test]
136
147
fn replaces_method_calls ( ) {
137
148
// foo.make() is a method call which uses a different expr in the let initializer
149
+ cov_mark:: check!( fallback_to_turbofish_type_if_type_info_not_available) ;
138
150
check_assist (
139
151
replace_turbofish_with_explicit_type,
140
152
r#"
@@ -237,6 +249,82 @@ fn make<T>() -> T {}
237
249
fn main() {
238
250
let a = make$0::<Vec<String>, i32>();
239
251
}
252
+ "# ,
253
+ ) ;
254
+ }
255
+
256
+ #[ test]
257
+ fn replaces_turbofish_for_known_type ( ) {
258
+ check_assist (
259
+ replace_turbofish_with_explicit_type,
260
+ r#"
261
+ fn make<T>() -> T {}
262
+ fn main() {
263
+ let a = make$0::<i32>();
264
+ }
265
+ "# ,
266
+ r#"
267
+ fn make<T>() -> T {}
268
+ fn main() {
269
+ let a: i32 = make();
270
+ }
271
+ "# ,
272
+ ) ;
273
+ check_assist (
274
+ replace_turbofish_with_explicit_type,
275
+ r#"
276
+ //- minicore: option
277
+ fn make<T>() -> T {}
278
+ fn main() {
279
+ let a = make$0::<Option<bool>>();
280
+ }
281
+ "# ,
282
+ r#"
283
+ fn make<T>() -> T {}
284
+ fn main() {
285
+ let a: Option<bool> = make();
286
+ }
287
+ "# ,
288
+ ) ;
289
+ }
290
+
291
+ #[ test]
292
+ fn replaces_turbofish_not_same_type ( ) {
293
+ check_assist (
294
+ replace_turbofish_with_explicit_type,
295
+ r#"
296
+ //- minicore: option
297
+ fn make<T>() -> Option<T> {}
298
+ fn main() {
299
+ let a = make$0::<u128>();
300
+ }
301
+ "# ,
302
+ r#"
303
+ fn make<T>() -> Option<T> {}
304
+ fn main() {
305
+ let a: Option<u128> = make();
306
+ }
307
+ "# ,
308
+ ) ;
309
+ }
310
+
311
+ #[ test]
312
+ fn replaces_turbofish_for_type_with_defaulted_generic_param ( ) {
313
+ check_assist (
314
+ replace_turbofish_with_explicit_type,
315
+ r#"
316
+ struct HasDefault<T, U = i32>(T, U);
317
+ fn make<T>() -> HasDefault<T> {}
318
+ fn main() {
319
+ let a = make$0::<bool>();
320
+ }
321
+ "# ,
322
+ r#"
323
+ struct HasDefault<T, U = i32>(T, U);
324
+ fn make<T>() -> HasDefault<T> {}
325
+ fn main() {
326
+ let a: HasDefault<bool> = make();
327
+ }
240
328
"# ,
241
329
) ;
242
330
}
0 commit comments