@@ -28,6 +28,13 @@ pub(crate) fn complete_dot(
28
28
29
29
if let DotAccessKind :: Method { .. } = dot_access. kind {
30
30
cov_mark:: hit!( test_no_struct_field_completion_for_method_call) ;
31
+ complete_fn_fields (
32
+ acc,
33
+ ctx,
34
+ receiver_ty,
35
+ |acc, field, ty| acc. add_field ( ctx, dot_access, None , field, & ty) ,
36
+ |acc, field, ty| acc. add_tuple_field ( ctx, None , field, & ty) ,
37
+ ) ;
31
38
} else {
32
39
complete_fields (
33
40
acc,
@@ -144,6 +151,33 @@ fn complete_methods(
144
151
) ;
145
152
}
146
153
154
+ fn complete_fn_fields (
155
+ acc : & mut Completions ,
156
+ ctx : & CompletionContext < ' _ > ,
157
+ receiver : & hir:: Type ,
158
+ mut named_field : impl FnMut ( & mut Completions , hir:: Field , hir:: Type ) ,
159
+ mut tuple_index : impl FnMut ( & mut Completions , usize , hir:: Type ) ,
160
+ ) {
161
+ let mut seen_names = FxHashSet :: default ( ) ;
162
+ for receiver in receiver. autoderef ( ctx. db ) {
163
+ for ( field, ty) in receiver. fields ( ctx. db ) {
164
+ if seen_names. insert ( field. name ( ctx. db ) ) && ( ty. is_fn ( ) || ty. is_closure ( ) ) {
165
+ named_field ( acc, field, ty) ;
166
+ }
167
+ }
168
+ for ( i, ty) in receiver. tuple_fields ( ctx. db ) . into_iter ( ) . enumerate ( ) {
169
+ // Tuples are always the last type in a deref chain, so just check if the name is
170
+ // already seen without inserting into the hashset.
171
+ if !seen_names. contains ( & hir:: Name :: new_tuple_field ( i) )
172
+ && ( ty. is_fn ( ) || ty. is_closure ( ) )
173
+ {
174
+ // Tuple fields are always public (tuple struct fields are handled above).
175
+ tuple_index ( acc, i, ty) ;
176
+ }
177
+ }
178
+ }
179
+ }
180
+
147
181
#[ cfg( test) ]
148
182
mod tests {
149
183
use expect_test:: { expect, Expect } ;
0 commit comments