@@ -215,7 +215,8 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
215
215
}
216
216
} else {
217
217
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;
219
220
let (mod_prefix, mod_str, module, suggestion) = if path.len() == 1 {
220
221
debug!(?self.diagnostic_metadata.current_impl_items);
221
222
debug!(?self.diagnostic_metadata.current_function);
@@ -231,9 +232,35 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
231
232
})
232
233
{
233
234
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
+
234
261
match &item.kind {
235
262
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() => {
237
264
// Ensure that we only suggest `self.` if `self` is available,
238
265
// you can't call `fn foo(&self)` from `fn bar()` (#115992).
239
266
// We also want to mention that the method exists.
@@ -243,20 +270,28 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
243
270
));
244
271
None
245
272
}
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
+ }
246
281
AssocItemKind::Fn(fn_) if fn_.sig.decl.has_self() => Some((
247
282
sp,
248
283
"consider using the method on `Self`",
249
- " self.".to_string( ),
284
+ format!("{pre} self."),
250
285
)),
251
286
AssocItemKind::Fn(_) => Some((
252
287
sp,
253
288
"consider using the associated function on `Self`",
254
- " Self::".to_string( ),
289
+ format!("{pre} Self::"),
255
290
)),
256
291
AssocItemKind::Const(..) => Some((
257
292
sp,
258
293
"consider using the associated constant on `Self`",
259
- " Self::".to_string( ),
294
+ format!("{pre} Self::"),
260
295
)),
261
296
_ => None
262
297
}
@@ -621,13 +656,26 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
621
656
self.lookup_assoc_candidate(ident, ns, is_expected, source.is_call())
622
657
{
623
658
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
+ };
624
672
match candidate {
625
673
AssocSuggestion::Field => {
626
674
if self_is_available {
627
- err.span_suggestion (
628
- span,
675
+ err.span_suggestion_verbose (
676
+ span.shrink_to_lo() ,
629
677
"you might have meant to use the available field",
630
- format!("self.{path_str} "),
678
+ format!("{pre}self. "),
631
679
Applicability::MachineApplicable,
632
680
);
633
681
} else {
@@ -640,21 +688,21 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
640
688
} else {
641
689
"you might have meant to refer to the method"
642
690
};
643
- err.span_suggestion (
644
- span,
691
+ err.span_suggestion_verbose (
692
+ span.shrink_to_lo() ,
645
693
msg,
646
- format!( "self.{path_str}" ),
694
+ "self.".to_string( ),
647
695
Applicability::MachineApplicable,
648
696
);
649
697
}
650
698
AssocSuggestion::MethodWithSelf { .. }
651
699
| AssocSuggestion::AssocFn { .. }
652
700
| AssocSuggestion::AssocConst
653
701
| AssocSuggestion::AssocType => {
654
- err.span_suggestion (
655
- span,
702
+ err.span_suggestion_verbose (
703
+ span.shrink_to_lo() ,
656
704
format!("you might have meant to {}", candidate.action()),
657
- format!( "Self::{path_str}" ),
705
+ "Self::".to_string( ),
658
706
Applicability::MachineApplicable,
659
707
);
660
708
}
0 commit comments