@@ -28,6 +28,13 @@ pub(crate) fn complete_dot(
2828
2929 if let DotAccessKind :: Method { .. } = dot_access. kind {
3030 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+ ) ;
3138 } else {
3239 complete_fields (
3340 acc,
@@ -144,6 +151,33 @@ fn complete_methods(
144151 ) ;
145152}
146153
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+
147181#[ cfg( test) ]
148182mod tests {
149183 use expect_test:: { expect, Expect } ;
0 commit comments