@@ -6,7 +6,7 @@ use crate::path_names_to_string;
6
6
use crate :: { Finalize , Module , ModuleKind , ModuleOrUniformRoot } ;
7
7
use crate :: { PathResult , PathSource , Segment } ;
8
8
9
- use rustc_ast:: visit:: FnKind ;
9
+ use rustc_ast:: visit:: { FnCtxt , FnKind } ;
10
10
use rustc_ast:: {
11
11
self as ast, AssocItemKind , Expr , ExprKind , GenericParam , GenericParamKind , Item , ItemKind ,
12
12
NodeId , Path , Ty , TyKind ,
@@ -144,15 +144,22 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> {
144
144
let is_enum_variant = & |res| matches ! ( res, Res :: Def ( DefKind :: Variant , _) ) ;
145
145
146
146
// Make the base error.
147
+ struct BaseError < ' a > {
148
+ msg : String ,
149
+ fallback_label : String ,
150
+ span : Span ,
151
+ could_be_expr : bool ,
152
+ suggestion : Option < ( Span , & ' a str , String ) > ,
153
+ }
147
154
let mut expected = source. descr_expected ( ) ;
148
155
let path_str = Segment :: names_to_string ( path) ;
149
156
let item_str = path. last ( ) . unwrap ( ) . ident ;
150
- let ( base_msg , fallback_label , base_span , could_be_expr ) = if let Some ( res) = res {
151
- (
152
- format ! ( "expected {}, found {} `{}`" , expected, res. descr( ) , path_str) ,
153
- format ! ( "not a {}" , expected ) ,
157
+ let base_error = if let Some ( res) = res {
158
+ BaseError {
159
+ msg : format ! ( "expected {}, found {} `{}`" , expected, res. descr( ) , path_str) ,
160
+ fallback_label : format ! ( "not a {expected}" ) ,
154
161
span,
155
- match res {
162
+ could_be_expr : match res {
156
163
Res :: Def ( DefKind :: Fn , _) => {
157
164
// Verify whether this is a fn call or an Fn used as a type.
158
165
self . r
@@ -171,45 +178,78 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> {
171
178
| Res :: Local ( _) => true ,
172
179
_ => false ,
173
180
} ,
174
- )
181
+ suggestion : None ,
182
+ }
175
183
} else {
176
184
let item_span = path. last ( ) . unwrap ( ) . ident . span ;
177
- let ( mod_prefix, mod_str) = if path. len ( ) == 1 {
178
- ( String :: new ( ) , "this scope" . to_string ( ) )
185
+ let ( mod_prefix, mod_str, suggestion) = if path. len ( ) == 1 {
186
+ debug ! ( ?self . diagnostic_metadata. current_impl_items) ;
187
+ debug ! ( ?self . diagnostic_metadata. current_function) ;
188
+ let suggestion = if let Some ( items) = self . diagnostic_metadata . current_impl_items
189
+ && let Some ( ( fn_kind, _) ) = self . diagnostic_metadata . current_function
190
+ && self . current_trait_ref . is_none ( )
191
+ && let Some ( FnCtxt :: Assoc ( _) ) = fn_kind. ctxt ( )
192
+ && let Some ( item) = items. iter ( ) . find ( |i| {
193
+ if let AssocItemKind :: Fn ( fn_) = & i. kind
194
+ && !fn_. sig . decl . has_self ( )
195
+ && i. ident . name == item_str. name
196
+ {
197
+ debug ! ( ?item_str. name) ;
198
+ debug ! ( ?fn_. sig. decl. inputs) ;
199
+ return true
200
+ }
201
+ false
202
+ } )
203
+ {
204
+ Some ( (
205
+ item_span,
206
+ "consider using the associated function" ,
207
+ format ! ( "Self::{}" , item. ident)
208
+ ) )
209
+ } else {
210
+ None
211
+ } ;
212
+ ( String :: new ( ) , "this scope" . to_string ( ) , suggestion)
179
213
} else if path. len ( ) == 2 && path[ 0 ] . ident . name == kw:: PathRoot {
180
214
if self . r . session . edition ( ) > Edition :: Edition2015 {
181
215
// In edition 2018 onwards, the `::foo` syntax may only pull from the extern prelude
182
216
// which overrides all other expectations of item type
183
217
expected = "crate" ;
184
- ( String :: new ( ) , "the list of imported crates" . to_string ( ) )
218
+ ( String :: new ( ) , "the list of imported crates" . to_string ( ) , None )
185
219
} else {
186
- ( String :: new ( ) , "the crate root" . to_string ( ) )
220
+ ( String :: new ( ) , "the crate root" . to_string ( ) , None )
187
221
}
188
222
} else if path. len ( ) == 2 && path[ 0 ] . ident . name == kw:: Crate {
189
- ( String :: new ( ) , "the crate root" . to_string ( ) )
223
+ ( String :: new ( ) , "the crate root" . to_string ( ) , None )
190
224
} else {
191
225
let mod_path = & path[ ..path. len ( ) - 1 ] ;
192
226
let mod_prefix = match self . resolve_path ( mod_path, Some ( TypeNS ) , Finalize :: No ) {
193
227
PathResult :: Module ( ModuleOrUniformRoot :: Module ( module) ) => module. res ( ) ,
194
228
_ => None ,
195
229
}
196
230
. map_or_else ( String :: new, |res| format ! ( "{} " , res. descr( ) ) ) ;
197
- ( mod_prefix, format ! ( "`{}`" , Segment :: names_to_string( mod_path) ) )
231
+ ( mod_prefix, format ! ( "`{}`" , Segment :: names_to_string( mod_path) ) , None )
198
232
} ;
199
- (
200
- format ! ( "cannot find {} `{}` in {}{}" , expected , item_str , mod_prefix , mod_str ) ,
201
- if path_str == "async" && expected. starts_with ( "struct" ) {
233
+ BaseError {
234
+ msg : format ! ( "cannot find {expected } `{item_str }` in {mod_prefix}{mod_str}" ) ,
235
+ fallback_label : if path_str == "async" && expected. starts_with ( "struct" ) {
202
236
"`async` blocks are only allowed in Rust 2018 or later" . to_string ( )
203
237
} else {
204
- format ! ( "not found in {}" , mod_str )
238
+ format ! ( "not found in {mod_str}" )
205
239
} ,
206
- item_span,
207
- false ,
208
- )
240
+ span : item_span,
241
+ could_be_expr : false ,
242
+ suggestion,
243
+ }
209
244
} ;
210
245
211
246
let code = source. error_code ( res. is_some ( ) ) ;
212
- let mut err = self . r . session . struct_span_err_with_code ( base_span, & base_msg, code) ;
247
+ let mut err =
248
+ self . r . session . struct_span_err_with_code ( base_error. span , & base_error. msg , code) ;
249
+
250
+ if let Some ( sugg) = base_error. suggestion {
251
+ err. span_suggestion_verbose ( sugg. 0 , sugg. 1 , sugg. 2 , Applicability :: MaybeIncorrect ) ;
252
+ }
213
253
214
254
if let Some ( span) = self . diagnostic_metadata . current_block_could_be_bare_struct_literal {
215
255
err. multipart_suggestion (
@@ -269,7 +309,7 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> {
269
309
}
270
310
}
271
311
272
- self . detect_assoct_type_constraint_meant_as_path ( base_span , & mut err) ;
312
+ self . detect_assoct_type_constraint_meant_as_path ( base_error . span , & mut err) ;
273
313
274
314
// Emit special messages for unresolved `Self` and `self`.
275
315
if is_self_type ( path, ns) {
@@ -471,16 +511,17 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> {
471
511
source,
472
512
res,
473
513
& path_str,
474
- & fallback_label,
514
+ & base_error . fallback_label ,
475
515
) {
476
516
// We do this to avoid losing a secondary span when we override the main error span.
477
517
self . r . add_typo_suggestion ( & mut err, typo_sugg, ident_span) ;
478
518
return ( err, candidates) ;
479
519
}
480
520
}
481
521
482
- let is_macro = base_span. from_expansion ( ) && base_span. desugaring_kind ( ) . is_none ( ) ;
483
- if !self . type_ascription_suggestion ( & mut err, base_span) {
522
+ let is_macro =
523
+ base_error. span . from_expansion ( ) && base_error. span . desugaring_kind ( ) . is_none ( ) ;
524
+ if !self . type_ascription_suggestion ( & mut err, base_error. span ) {
484
525
let mut fallback = false ;
485
526
if let (
486
527
PathSource :: Trait ( AliasPossibility :: Maybe ) ,
@@ -493,7 +534,7 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> {
493
534
let spans: Vec < Span > = bounds
494
535
. iter ( )
495
536
. map ( |bound| bound. span ( ) )
496
- . filter ( |& sp| sp != base_span )
537
+ . filter ( |& sp| sp != base_error . span )
497
538
. collect ( ) ;
498
539
499
540
let start_span = bounds. iter ( ) . map ( |bound| bound. span ( ) ) . next ( ) . unwrap ( ) ;
@@ -515,7 +556,7 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> {
515
556
multi_span. push_span_label ( sp, msg) ;
516
557
}
517
558
multi_span. push_span_label (
518
- base_span ,
559
+ base_error . span ,
519
560
"expected this type to be a trait..." . to_string ( ) ,
520
561
) ;
521
562
err. span_help (
@@ -525,14 +566,14 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> {
525
566
) ;
526
567
if bounds. iter ( ) . all ( |bound| match bound {
527
568
ast:: GenericBound :: Outlives ( _) => true ,
528
- ast:: GenericBound :: Trait ( tr, _) => tr. span == base_span ,
569
+ ast:: GenericBound :: Trait ( tr, _) => tr. span == base_error . span ,
529
570
} ) {
530
571
let mut sugg = vec ! [ ] ;
531
- if base_span != start_span {
532
- sugg. push ( ( start_span. until ( base_span ) , String :: new ( ) ) ) ;
572
+ if base_error . span != start_span {
573
+ sugg. push ( ( start_span. until ( base_error . span ) , String :: new ( ) ) ) ;
533
574
}
534
- if base_span != end_span {
535
- sugg. push ( ( base_span . shrink_to_hi ( ) . to ( end_span) , String :: new ( ) ) ) ;
575
+ if base_error . span != end_span {
576
+ sugg. push ( ( base_error . span . shrink_to_hi ( ) . to ( end_span) , String :: new ( ) ) ) ;
536
577
}
537
578
538
579
err. multipart_suggestion (
@@ -550,7 +591,7 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> {
550
591
fallback = true ;
551
592
match self . diagnostic_metadata . current_let_binding {
552
593
Some ( ( pat_sp, Some ( ty_sp) , None ) )
553
- if ty_sp. contains ( base_span ) && could_be_expr =>
594
+ if ty_sp. contains ( base_error . span ) && base_error . could_be_expr =>
554
595
{
555
596
err. span_suggestion_short (
556
597
pat_sp. between ( ty_sp) ,
@@ -568,7 +609,7 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> {
568
609
}
569
610
if fallback {
570
611
// Fallback label.
571
- err. span_label ( base_span , fallback_label) ;
612
+ err. span_label ( base_error . span , base_error . fallback_label ) ;
572
613
}
573
614
}
574
615
if let Some ( err_code) = & err. code {
0 commit comments