@@ -215,7 +215,8 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
215215 }
216216 } else {
217217 let mut span_label = None ;
218- let item_span = path. last ( ) . unwrap ( ) . ident . span ;
218+ let item_ident = path. last ( ) . unwrap ( ) . ident ;
219+ let item_span = item_ident. span ;
219220 let ( mod_prefix, mod_str, module, suggestion) = if path. len ( ) == 1 {
220221 debug ! ( ?self . diagnostic_metadata. current_impl_items) ;
221222 debug ! ( ?self . diagnostic_metadata. current_function) ;
@@ -231,9 +232,35 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
231232 } )
232233 {
233234 let sp = item_span. shrink_to_lo ( ) ;
235+
236+ // Account for `Foo { field }` when suggesting `self.field` so we result on
237+ // `Foo { field: self.field }`.
238+ let field = match source {
239+ PathSource :: Expr ( Some ( Expr { kind : ExprKind :: Struct ( expr) , .. } ) ) => {
240+ expr. fields . iter ( ) . find ( |f| f. ident == item_ident)
241+ }
242+ _ => None ,
243+ } ;
244+ let pre = if let Some ( field) = field && field. is_shorthand {
245+ format ! ( "{item_ident}: " )
246+ } else {
247+ String :: new ( )
248+ } ;
249+ // Ensure we provide a structured suggestion for an assoc fn only for
250+ // expressions that are actually a fn call.
251+ let is_call = match field {
252+ Some ( ast:: ExprField { expr, .. } ) => {
253+ matches ! ( expr. kind, ExprKind :: Call ( ..) )
254+ }
255+ _ => matches ! (
256+ source,
257+ PathSource :: Expr ( Some ( Expr { kind: ExprKind :: Call ( ..) , ..} ) ) ,
258+ ) ,
259+ } ;
260+
234261 match & item. kind {
235262 AssocItemKind :: Fn ( fn_)
236- if !sig. decl . has_self ( ) && fn_. sig . decl . has_self ( ) => {
263+ if ( !sig. decl . has_self ( ) || !is_call ) && fn_. sig . decl . has_self ( ) => {
237264 // Ensure that we only suggest `self.` if `self` is available,
238265 // you can't call `fn foo(&self)` from `fn bar()` (#115992).
239266 // We also want to mention that the method exists.
@@ -243,20 +270,28 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
243270 ) ) ;
244271 None
245272 }
273+ AssocItemKind :: Fn ( fn_)
274+ if !fn_. sig . decl . has_self ( ) && !is_call => {
275+ span_label = Some ( (
276+ item. ident . span ,
277+ "an associated function by that name is available on `Self` here" ,
278+ ) ) ;
279+ None
280+ }
246281 AssocItemKind :: Fn ( fn_) if fn_. sig . decl . has_self ( ) => Some ( (
247282 sp,
248283 "consider using the method on `Self`" ,
249- " self.". to_string ( ) ,
284+ format ! ( "{pre} self.") ,
250285 ) ) ,
251286 AssocItemKind :: Fn ( _) => Some ( (
252287 sp,
253288 "consider using the associated function on `Self`" ,
254- " Self::". to_string ( ) ,
289+ format ! ( "{pre} Self::") ,
255290 ) ) ,
256291 AssocItemKind :: Const ( ..) => Some ( (
257292 sp,
258293 "consider using the associated constant on `Self`" ,
259- " Self::". to_string ( ) ,
294+ format ! ( "{pre} Self::") ,
260295 ) ) ,
261296 _ => None
262297 }
@@ -621,13 +656,26 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
621656 self . lookup_assoc_candidate ( ident, ns, is_expected, source. is_call ( ) )
622657 {
623658 let self_is_available = self . self_value_is_available ( path[ 0 ] . ident . span ) ;
659+ // Account for `Foo { field }` when suggesting `self.field` so we result on
660+ // `Foo { field: self.field }`.
661+ let pre = match source {
662+ PathSource :: Expr ( Some ( Expr { kind : ExprKind :: Struct ( expr) , .. } ) )
663+ if expr
664+ . fields
665+ . iter ( )
666+ . any ( |f| f. ident == path[ 0 ] . ident && f. is_shorthand ) =>
667+ {
668+ format ! ( "{path_str}: " )
669+ }
670+ _ => String :: new ( ) ,
671+ } ;
624672 match candidate {
625673 AssocSuggestion :: Field => {
626674 if self_is_available {
627- err. span_suggestion (
628- span,
675+ err. span_suggestion_verbose (
676+ span. shrink_to_lo ( ) ,
629677 "you might have meant to use the available field" ,
630- format ! ( "self.{path_str} " ) ,
678+ format ! ( "{pre}self. " ) ,
631679 Applicability :: MachineApplicable ,
632680 ) ;
633681 } else {
@@ -640,21 +688,21 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
640688 } else {
641689 "you might have meant to refer to the method"
642690 } ;
643- err. span_suggestion (
644- span,
691+ err. span_suggestion_verbose (
692+ span. shrink_to_lo ( ) ,
645693 msg,
646- format ! ( "self.{path_str}" ) ,
694+ "self." . to_string ( ) ,
647695 Applicability :: MachineApplicable ,
648696 ) ;
649697 }
650698 AssocSuggestion :: MethodWithSelf { .. }
651699 | AssocSuggestion :: AssocFn { .. }
652700 | AssocSuggestion :: AssocConst
653701 | AssocSuggestion :: AssocType => {
654- err. span_suggestion (
655- span,
702+ err. span_suggestion_verbose (
703+ span. shrink_to_lo ( ) ,
656704 format ! ( "you might have meant to {}" , candidate. action( ) ) ,
657- format ! ( "Self::{path_str}" ) ,
705+ "Self::" . to_string ( ) ,
658706 Applicability :: MachineApplicable ,
659707 ) ;
660708 }
0 commit comments