@@ -6,7 +6,7 @@ use crate::path_names_to_string;
66use crate :: { Module , ModuleKind , ModuleOrUniformRoot } ;
77use crate :: { PathResult , PathSource , Segment } ;
88
9- use rustc_ast:: visit:: FnKind ;
9+ use rustc_ast:: visit:: { FnCtxt , FnKind } ;
1010use rustc_ast:: {
1111 self as ast, AssocItemKind , Expr , ExprKind , GenericParam , GenericParamKind , Item , ItemKind ,
1212 NodeId , Path , Ty , TyKind ,
@@ -144,15 +144,22 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> {
144144 let is_enum_variant = & |res| matches ! ( res, Res :: Def ( DefKind :: Variant , _) ) ;
145145
146146 // 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+ }
147154 let mut expected = source. descr_expected ( ) ;
148155 let path_str = Segment :: names_to_string ( path) ;
149156 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}" ) ,
154161 span,
155- match res {
162+ could_be_expr : match res {
156163 Res :: Def ( DefKind :: Fn , _) => {
157164 // Verify whether this is a fn call or an Fn used as a type.
158165 self . r
@@ -171,45 +178,78 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> {
171178 | Res :: Local ( _) => true ,
172179 _ => false ,
173180 } ,
174- )
181+ suggestion : None ,
182+ }
175183 } else {
176184 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)
179213 } else if path. len ( ) == 2 && path[ 0 ] . ident . name == kw:: PathRoot {
180214 if self . r . session . edition ( ) > Edition :: Edition2015 {
181215 // In edition 2018 onwards, the `::foo` syntax may only pull from the extern prelude
182216 // which overrides all other expectations of item type
183217 expected = "crate" ;
184- ( String :: new ( ) , "the list of imported crates" . to_string ( ) )
218+ ( String :: new ( ) , "the list of imported crates" . to_string ( ) , None )
185219 } else {
186- ( String :: new ( ) , "the crate root" . to_string ( ) )
220+ ( String :: new ( ) , "the crate root" . to_string ( ) , None )
187221 }
188222 } 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 )
190224 } else {
191225 let mod_path = & path[ ..path. len ( ) - 1 ] ;
192226 let mod_prefix = match self . resolve_path ( mod_path, Some ( TypeNS ) , None ) {
193227 PathResult :: Module ( ModuleOrUniformRoot :: Module ( module) ) => module. res ( ) ,
194228 _ => None ,
195229 }
196230 . 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 )
198232 } ;
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" ) {
202236 "`async` blocks are only allowed in Rust 2018 or later" . to_string ( )
203237 } else {
204- format ! ( "not found in {}" , mod_str )
238+ format ! ( "not found in {mod_str}" )
205239 } ,
206- item_span,
207- false ,
208- )
240+ span : item_span,
241+ could_be_expr : false ,
242+ suggestion,
243+ }
209244 } ;
210245
211246 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+ }
213253
214254 if let Some ( span) = self . diagnostic_metadata . current_block_could_be_bare_struct_literal {
215255 err. multipart_suggestion (
@@ -269,7 +309,7 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> {
269309 }
270310 }
271311
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) ;
273313
274314 // Emit special messages for unresolved `Self` and `self`.
275315 if is_self_type ( path, ns) {
@@ -471,16 +511,17 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> {
471511 source,
472512 res,
473513 & path_str,
474- & fallback_label,
514+ & base_error . fallback_label ,
475515 ) {
476516 // We do this to avoid losing a secondary span when we override the main error span.
477517 self . r . add_typo_suggestion ( & mut err, typo_sugg, ident_span) ;
478518 return ( err, candidates) ;
479519 }
480520 }
481521
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 ) {
484525 let mut fallback = false ;
485526 if let (
486527 PathSource :: Trait ( AliasPossibility :: Maybe ) ,
@@ -493,7 +534,7 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> {
493534 let spans: Vec < Span > = bounds
494535 . iter ( )
495536 . map ( |bound| bound. span ( ) )
496- . filter ( |& sp| sp != base_span )
537+ . filter ( |& sp| sp != base_error . span )
497538 . collect ( ) ;
498539
499540 let start_span = bounds. iter ( ) . map ( |bound| bound. span ( ) ) . next ( ) . unwrap ( ) ;
@@ -515,7 +556,7 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> {
515556 multi_span. push_span_label ( sp, msg) ;
516557 }
517558 multi_span. push_span_label (
518- base_span ,
559+ base_error . span ,
519560 "expected this type to be a trait..." . to_string ( ) ,
520561 ) ;
521562 err. span_help (
@@ -525,14 +566,14 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> {
525566 ) ;
526567 if bounds. iter ( ) . all ( |bound| match bound {
527568 ast:: GenericBound :: Outlives ( _) => true ,
528- ast:: GenericBound :: Trait ( tr, _) => tr. span == base_span ,
569+ ast:: GenericBound :: Trait ( tr, _) => tr. span == base_error . span ,
529570 } ) {
530571 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 ( ) ) ) ;
533574 }
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 ( ) ) ) ;
536577 }
537578
538579 err. multipart_suggestion (
@@ -550,7 +591,7 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> {
550591 fallback = true ;
551592 match self . diagnostic_metadata . current_let_binding {
552593 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 =>
554595 {
555596 err. span_suggestion_short (
556597 pat_sp. between ( ty_sp) ,
@@ -568,7 +609,7 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> {
568609 }
569610 if fallback {
570611 // Fallback label.
571- err. span_label ( base_span , fallback_label) ;
612+ err. span_label ( base_error . span , base_error . fallback_label ) ;
572613 }
573614 }
574615 if let Some ( err_code) = & err. code {
0 commit comments