2
2
3
3
use std:: ops:: ControlFlow ;
4
4
5
- use hir:: { sym , HasContainer , ItemContainer , MethodCandidateCallback , Name } ;
5
+ use hir:: { HasContainer , ItemContainer , MethodCandidateCallback , Name } ;
6
6
use ide_db:: FxHashSet ;
7
7
use syntax:: SmolStr ;
8
8
@@ -25,8 +25,13 @@ pub(crate) fn complete_dot(
25
25
_ => return ,
26
26
} ;
27
27
28
+ let is_field_access = matches ! ( dot_access. kind, DotAccessKind :: Field { .. } ) ;
29
+ let is_method_access_with_parens =
30
+ matches ! ( dot_access. kind, DotAccessKind :: Method { has_parens: true } ) ;
31
+ let traits_in_scope = ctx. traits_in_scope ( ) ;
32
+
28
33
// Suggest .await syntax for types that implement Future trait
29
- if receiver_ty. impls_into_future ( ctx. db ) {
34
+ if let Some ( future_output ) = receiver_ty. into_future_output ( ctx. db ) {
30
35
let mut item = CompletionItem :: new (
31
36
CompletionItemKind :: Keyword ,
32
37
ctx. source_range ( ) ,
@@ -35,11 +40,37 @@ pub(crate) fn complete_dot(
35
40
) ;
36
41
item. detail ( "expr.await" ) ;
37
42
item. add_to ( acc, ctx. db ) ;
38
- }
39
43
40
- let is_field_access = matches ! ( dot_access. kind, DotAccessKind :: Field { .. } ) ;
41
- let is_method_access_with_parens =
42
- matches ! ( dot_access. kind, DotAccessKind :: Method { has_parens: true } ) ;
44
+ // Completions that skip `.await`, e.g. `.await.foo()`.
45
+ let dot_access_kind = match & dot_access. kind {
46
+ DotAccessKind :: Field { receiver_is_ambiguous_float_literal : _ } => {
47
+ DotAccessKind :: Field { receiver_is_ambiguous_float_literal : false }
48
+ }
49
+ it @ DotAccessKind :: Method { .. } => * it,
50
+ } ;
51
+ let dot_access = DotAccess {
52
+ receiver : dot_access. receiver . clone ( ) ,
53
+ receiver_ty : Some ( hir:: TypeInfo { original : future_output. clone ( ) , adjusted : None } ) ,
54
+ kind : dot_access_kind,
55
+ ctx : dot_access. ctx ,
56
+ } ;
57
+ complete_fields (
58
+ acc,
59
+ ctx,
60
+ & future_output,
61
+ |acc, field, ty| {
62
+ acc. add_field ( ctx, & dot_access, Some ( SmolStr :: new_static ( "await" ) ) , field, & ty)
63
+ } ,
64
+ |acc, field, ty| {
65
+ acc. add_tuple_field ( ctx, Some ( SmolStr :: new_static ( "await" ) ) , field, & ty)
66
+ } ,
67
+ is_field_access,
68
+ is_method_access_with_parens,
69
+ ) ;
70
+ complete_methods ( ctx, & future_output, & traits_in_scope, |func| {
71
+ acc. add_method ( ctx, & dot_access, func, Some ( SmolStr :: new_static ( "await" ) ) , None )
72
+ } ) ;
73
+ }
43
74
44
75
complete_fields (
45
76
acc,
@@ -50,8 +81,41 @@ pub(crate) fn complete_dot(
50
81
is_field_access,
51
82
is_method_access_with_parens,
52
83
) ;
84
+ complete_methods ( ctx, receiver_ty, & traits_in_scope, |func| {
85
+ acc. add_method ( ctx, dot_access, func, None , None )
86
+ } ) ;
53
87
54
- complete_methods ( ctx, receiver_ty, |func| acc. add_method ( ctx, dot_access, func, None , None ) ) ;
88
+ // Checking for the existence of `iter()` is complicated in our setup, because we need to substitute
89
+ // its return type, so we instead check for `<&Self as IntoIterator>::IntoIter`.
90
+ let iter = receiver_ty
91
+ . strip_references ( )
92
+ . add_reference ( hir:: Mutability :: Shared )
93
+ . into_iterator_iter ( ctx. db )
94
+ . map ( |ty| ( ty, SmolStr :: new_static ( "iter()" ) ) )
95
+ . or_else ( || {
96
+ receiver_ty
97
+ . clone ( )
98
+ . into_iterator_iter ( ctx. db )
99
+ . map ( |ty| ( ty, SmolStr :: new_static ( "into_iter()" ) ) )
100
+ } ) ;
101
+ if let Some ( ( iter, iter_sym) ) = iter {
102
+ // Skip iterators, e.g. complete `.iter().filter_map()`.
103
+ let dot_access_kind = match & dot_access. kind {
104
+ DotAccessKind :: Field { receiver_is_ambiguous_float_literal : _ } => {
105
+ DotAccessKind :: Field { receiver_is_ambiguous_float_literal : false }
106
+ }
107
+ it @ DotAccessKind :: Method { .. } => * it,
108
+ } ;
109
+ let dot_access = DotAccess {
110
+ receiver : dot_access. receiver . clone ( ) ,
111
+ receiver_ty : Some ( hir:: TypeInfo { original : iter. clone ( ) , adjusted : None } ) ,
112
+ kind : dot_access_kind,
113
+ ctx : dot_access. ctx ,
114
+ } ;
115
+ complete_methods ( ctx, & iter, & traits_in_scope, |func| {
116
+ acc. add_method ( ctx, & dot_access, func, Some ( iter_sym. clone ( ) ) , None )
117
+ } ) ;
118
+ }
55
119
}
56
120
57
121
pub ( crate ) fn complete_undotted_self (
@@ -94,18 +158,16 @@ pub(crate) fn complete_undotted_self(
94
158
in_breakable : expr_ctx. in_breakable ,
95
159
} ,
96
160
} ,
97
- Some ( Name :: new_symbol_root ( sym :: self_ . clone ( ) ) ) ,
161
+ Some ( SmolStr :: new_static ( "self" ) ) ,
98
162
field,
99
163
& ty,
100
164
)
101
165
} ,
102
- |acc, field, ty| {
103
- acc. add_tuple_field ( ctx, Some ( Name :: new_symbol_root ( sym:: self_. clone ( ) ) ) , field, & ty)
104
- } ,
166
+ |acc, field, ty| acc. add_tuple_field ( ctx, Some ( SmolStr :: new_static ( "self" ) ) , field, & ty) ,
105
167
true ,
106
168
false ,
107
169
) ;
108
- complete_methods ( ctx, & ty, |func| {
170
+ complete_methods ( ctx, & ty, & ctx . traits_in_scope ( ) , |func| {
109
171
acc. add_method (
110
172
ctx,
111
173
& DotAccess {
@@ -118,7 +180,7 @@ pub(crate) fn complete_undotted_self(
118
180
} ,
119
181
} ,
120
182
func,
121
- Some ( Name :: new_symbol_root ( sym :: self_ . clone ( ) ) ) ,
183
+ Some ( SmolStr :: new_static ( "self" ) ) ,
122
184
None ,
123
185
)
124
186
} ) ;
@@ -160,6 +222,7 @@ fn complete_fields(
160
222
fn complete_methods (
161
223
ctx : & CompletionContext < ' _ > ,
162
224
receiver : & hir:: Type ,
225
+ traits_in_scope : & FxHashSet < hir:: TraitId > ,
163
226
f : impl FnMut ( hir:: Function ) ,
164
227
) {
165
228
struct Callback < ' a , F > {
@@ -205,7 +268,7 @@ fn complete_methods(
205
268
receiver. iterate_method_candidates_split_inherent (
206
269
ctx. db ,
207
270
& ctx. scope ,
208
- & ctx . traits_in_scope ( ) ,
271
+ traits_in_scope,
209
272
Some ( ctx. module ) ,
210
273
None ,
211
274
Callback { ctx, f, seen_methods : FxHashSet :: default ( ) } ,
@@ -1306,4 +1369,73 @@ fn baz() {
1306
1369
"# ] ] ,
1307
1370
) ;
1308
1371
}
1372
+
1373
+ #[ test]
1374
+ fn skip_iter ( ) {
1375
+ check_no_kw (
1376
+ r#"
1377
+ //- minicore: iterator
1378
+ fn foo() {
1379
+ [].$0
1380
+ }
1381
+ "# ,
1382
+ expect ! [ [ r#"
1383
+ me clone() (as Clone) fn(&self) -> Self
1384
+ me into_iter() (as IntoIterator) fn(self) -> <Self as IntoIterator>::IntoIter
1385
+ "# ] ] ,
1386
+ ) ;
1387
+ check_no_kw (
1388
+ r#"
1389
+ //- minicore: iterator
1390
+ struct MyIntoIter;
1391
+ impl IntoIterator for MyIntoIter {
1392
+ type Item = ();
1393
+ type IntoIter = MyIterator;
1394
+ fn into_iter(self) -> Self::IntoIter {
1395
+ MyIterator
1396
+ }
1397
+ }
1398
+
1399
+ struct MyIterator;
1400
+ impl Iterator for MyIterator {
1401
+ type Item = ();
1402
+ fn next(&mut self) -> Self::Item {}
1403
+ }
1404
+
1405
+ fn foo() {
1406
+ MyIntoIter.$0
1407
+ }
1408
+ "# ,
1409
+ expect ! [ [ r#"
1410
+ me into_iter() (as IntoIterator) fn(self) -> <Self as IntoIterator>::IntoIter
1411
+ me into_iter().by_ref() (as Iterator) fn(&mut self) -> &mut Self
1412
+ me into_iter().into_iter() (as IntoIterator) fn(self) -> <Self as IntoIterator>::IntoIter
1413
+ me into_iter().next() (as Iterator) fn(&mut self) -> Option<<Self as Iterator>::Item>
1414
+ me into_iter().nth(…) (as Iterator) fn(&mut self, usize) -> Option<<Self as Iterator>::Item>
1415
+ "# ] ] ,
1416
+ ) ;
1417
+ }
1418
+
1419
+ #[ test]
1420
+ fn skip_await ( ) {
1421
+ check_no_kw (
1422
+ r#"
1423
+ //- minicore: future
1424
+ struct Foo;
1425
+ impl Foo {
1426
+ fn foo(self) {}
1427
+ }
1428
+
1429
+ async fn foo() -> Foo { Foo }
1430
+
1431
+ async fn bar() {
1432
+ foo().$0
1433
+ }
1434
+ "# ,
1435
+ expect ! [ [ r#"
1436
+ me await.foo() fn(self)
1437
+ me into_future() (use core::future::IntoFuture) fn(self) -> <Self as IntoFuture>::IntoFuture
1438
+ "# ] ] ,
1439
+ ) ;
1440
+ }
1309
1441
}
0 commit comments