@@ -41,7 +41,7 @@ type Res = def::Res<ast::NodeId>;
41
41
42
42
/// A field or associated item from self type suggested in case of resolution failure.
43
43
enum AssocSuggestion {
44
- Field ,
44
+ Field ( Span ) ,
45
45
MethodWithSelf { called : bool } ,
46
46
AssocFn { called : bool } ,
47
47
AssocType ,
@@ -51,7 +51,7 @@ enum AssocSuggestion {
51
51
impl AssocSuggestion {
52
52
fn action ( & self ) -> & ' static str {
53
53
match self {
54
- AssocSuggestion :: Field => "use the available field" ,
54
+ AssocSuggestion :: Field ( _ ) => "use the available field" ,
55
55
AssocSuggestion :: MethodWithSelf { called : true } => {
56
56
"call the method with the fully-qualified path"
57
57
}
@@ -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,17 +656,30 @@ 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
- AssocSuggestion :: Field => {
673
+ AssocSuggestion :: Field ( field_span ) => {
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 {
634
- err. span_label ( span , "a field by this name exists in `Self`" ) ;
682
+ err. span_label ( field_span , "a field by that name exists in `Self`" ) ;
635
683
}
636
684
}
637
685
AssocSuggestion :: MethodWithSelf { called } if self_is_available => {
@@ -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
}
@@ -1667,11 +1715,11 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
1667
1715
resolution. full_res ( )
1668
1716
{
1669
1717
if let Some ( field_ids) = self . r . field_def_ids ( did) {
1670
- if field_ids
1718
+ if let Some ( field_id ) = field_ids
1671
1719
. iter ( )
1672
- . any ( | & field_id| ident. name == self . r . tcx . item_name ( field_id) )
1720
+ . find ( | & & field_id| ident. name == self . r . tcx . item_name ( field_id) )
1673
1721
{
1674
- return Some ( AssocSuggestion :: Field ) ;
1722
+ return Some ( AssocSuggestion :: Field ( self . r . def_span ( * field_id ) ) ) ;
1675
1723
}
1676
1724
}
1677
1725
}
0 commit comments