22
33use std:: ops:: ControlFlow ;
44
5- use hir:: { sym , HasContainer , ItemContainer , MethodCandidateCallback , Name } ;
5+ use hir:: { HasContainer , ItemContainer , MethodCandidateCallback , Name } ;
66use ide_db:: FxHashSet ;
77use syntax:: SmolStr ;
88
@@ -25,8 +25,13 @@ pub(crate) fn complete_dot(
2525 _ => return ,
2626 } ;
2727
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+
2833 // 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 ) {
3035 let mut item = CompletionItem :: new (
3136 CompletionItemKind :: Keyword ,
3237 ctx. source_range ( ) ,
@@ -35,11 +40,37 @@ pub(crate) fn complete_dot(
3540 ) ;
3641 item. detail ( "expr.await" ) ;
3742 item. add_to ( acc, ctx. db ) ;
38- }
3943
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+ }
4374
4475 complete_fields (
4576 acc,
@@ -50,8 +81,41 @@ pub(crate) fn complete_dot(
5081 is_field_access,
5182 is_method_access_with_parens,
5283 ) ;
84+ complete_methods ( ctx, receiver_ty, & traits_in_scope, |func| {
85+ acc. add_method ( ctx, dot_access, func, None , None )
86+ } ) ;
5387
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+ }
55119}
56120
57121pub ( crate ) fn complete_undotted_self (
@@ -94,18 +158,16 @@ pub(crate) fn complete_undotted_self(
94158 in_breakable : expr_ctx. in_breakable ,
95159 } ,
96160 } ,
97- Some ( Name :: new_symbol_root ( sym :: self_ . clone ( ) ) ) ,
161+ Some ( SmolStr :: new_static ( "self" ) ) ,
98162 field,
99163 & ty,
100164 )
101165 } ,
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) ,
105167 true ,
106168 false ,
107169 ) ;
108- complete_methods ( ctx, & ty, |func| {
170+ complete_methods ( ctx, & ty, & ctx . traits_in_scope ( ) , |func| {
109171 acc. add_method (
110172 ctx,
111173 & DotAccess {
@@ -118,7 +180,7 @@ pub(crate) fn complete_undotted_self(
118180 } ,
119181 } ,
120182 func,
121- Some ( Name :: new_symbol_root ( sym :: self_ . clone ( ) ) ) ,
183+ Some ( SmolStr :: new_static ( "self" ) ) ,
122184 None ,
123185 )
124186 } ) ;
@@ -160,6 +222,7 @@ fn complete_fields(
160222fn complete_methods (
161223 ctx : & CompletionContext < ' _ > ,
162224 receiver : & hir:: Type ,
225+ traits_in_scope : & FxHashSet < hir:: TraitId > ,
163226 f : impl FnMut ( hir:: Function ) ,
164227) {
165228 struct Callback < ' a , F > {
@@ -205,7 +268,7 @@ fn complete_methods(
205268 receiver. iterate_method_candidates_split_inherent (
206269 ctx. db ,
207270 & ctx. scope ,
208- & ctx . traits_in_scope ( ) ,
271+ traits_in_scope,
209272 Some ( ctx. module ) ,
210273 None ,
211274 Callback { ctx, f, seen_methods : FxHashSet :: default ( ) } ,
@@ -1306,4 +1369,73 @@ fn baz() {
13061369 "# ] ] ,
13071370 ) ;
13081371 }
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+ }
13091441}
0 commit comments