@@ -130,6 +130,16 @@ pub(super) enum LifetimeElisionCandidate {
130
130
Missing ( MissingLifetime ) ,
131
131
}
132
132
133
+ /// Only used for diagnostics.
134
+ struct BaseError {
135
+ msg : String ,
136
+ fallback_label : String ,
137
+ span : Span ,
138
+ span_label : Option < ( Span , & ' static str ) > ,
139
+ could_be_expr : bool ,
140
+ suggestion : Option < ( Span , & ' static str , String ) > ,
141
+ }
142
+
133
143
impl < ' a : ' ast , ' ast > LateResolutionVisitor < ' a , ' _ , ' ast > {
134
144
fn def_span ( & self , def_id : DefId ) -> Option < Span > {
135
145
match def_id. krate {
@@ -138,35 +148,18 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> {
138
148
}
139
149
}
140
150
141
- /// Handles error reporting for `smart_resolve_path_fragment` function.
142
- /// Creates base error and amends it with one short label and possibly some longer helps/notes.
143
- pub ( crate ) fn smart_resolve_report_errors (
151
+ fn make_base_error (
144
152
& mut self ,
145
153
path : & [ Segment ] ,
146
154
span : Span ,
147
155
source : PathSource < ' _ > ,
148
156
res : Option < Res > ,
149
- ) -> ( DiagnosticBuilder < ' a , ErrorGuaranteed > , Vec < ImportSuggestion > ) {
150
- let ident_span = path. last ( ) . map_or ( span, |ident| ident. ident . span ) ;
151
- let ns = source. namespace ( ) ;
152
- let is_expected = & |res| source. is_expected ( res) ;
153
- let is_enum_variant = & |res| matches ! ( res, Res :: Def ( DefKind :: Variant , _) ) ;
154
-
155
- debug ! ( ?res, ?source) ;
156
-
157
+ ) -> BaseError {
157
158
// Make the base error.
158
- struct BaseError < ' a > {
159
- msg : String ,
160
- fallback_label : String ,
161
- span : Span ,
162
- span_label : Option < ( Span , & ' a str ) > ,
163
- could_be_expr : bool ,
164
- suggestion : Option < ( Span , & ' a str , String ) > ,
165
- }
166
159
let mut expected = source. descr_expected ( ) ;
167
160
let path_str = Segment :: names_to_string ( path) ;
168
161
let item_str = path. last ( ) . unwrap ( ) . ident ;
169
- let base_error = if let Some ( res) = res {
162
+ if let Some ( res) = res {
170
163
BaseError {
171
164
msg : format ! ( "expected {}, found {} `{}`" , expected, res. descr( ) , path_str) ,
172
165
fallback_label : format ! ( "not a {expected}" ) ,
@@ -277,8 +270,20 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> {
277
270
could_be_expr : false ,
278
271
suggestion,
279
272
}
280
- } ;
273
+ }
274
+ }
281
275
276
+ /// Handles error reporting for `smart_resolve_path_fragment` function.
277
+ /// Creates base error and amends it with one short label and possibly some longer helps/notes.
278
+ pub ( crate ) fn smart_resolve_report_errors (
279
+ & mut self ,
280
+ path : & [ Segment ] ,
281
+ span : Span ,
282
+ source : PathSource < ' _ > ,
283
+ res : Option < Res > ,
284
+ ) -> ( DiagnosticBuilder < ' a , ErrorGuaranteed > , Vec < ImportSuggestion > ) {
285
+ debug ! ( ?res, ?source) ;
286
+ let base_error = self . make_base_error ( path, span, source, res) ;
282
287
let code = source. error_code ( res. is_some ( ) ) ;
283
288
let mut err =
284
289
self . r . session . struct_span_err_with_code ( base_error. span , & base_error. msg , code) ;
@@ -289,41 +294,79 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> {
289
294
err. span_label ( span, label) ;
290
295
}
291
296
292
- if let Some ( sugg) = base_error. suggestion {
293
- err. span_suggestion_verbose ( sugg. 0 , sugg. 1 , sugg. 2 , Applicability :: MaybeIncorrect ) ;
297
+ if let Some ( ref sugg) = base_error. suggestion {
298
+ err. span_suggestion_verbose ( sugg. 0 , sugg. 1 , & sugg. 2 , Applicability :: MaybeIncorrect ) ;
294
299
}
295
300
296
- if let Some ( span ) = self . diagnostic_metadata . current_block_could_be_bare_struct_literal {
297
- err . multipart_suggestion (
298
- "you might have meant to write a `struct` literal" ,
299
- vec ! [
300
- ( span . shrink_to_lo ( ) , "{ SomeStruct " . to_string ( ) ) ,
301
- ( span. shrink_to_hi ( ) , "}" . to_string ( ) ) ,
302
- ] ,
303
- Applicability :: HasPlaceholders ,
304
- ) ;
301
+ self . suggest_bare_struct_literal ( & mut err ) ;
302
+ self . suggest_pattern_match_with_let ( & mut err , source , span ) ;
303
+
304
+ self . suggest_self_or_self_ref ( & mut err , path , span ) ;
305
+ self . detect_assoct_type_constraint_meant_as_path ( & mut err , & base_error ) ;
306
+ if self . suggest_self_ty ( & mut err , source , path , span)
307
+ || self . suggest_self_value ( & mut err , source , path , span )
308
+ {
309
+ return ( err , Vec :: new ( ) ) ;
305
310
}
306
- match ( source, self . diagnostic_metadata . in_if_condition ) {
307
- (
308
- PathSource :: Expr ( _) ,
309
- Some ( Expr { span : expr_span, kind : ExprKind :: Assign ( lhs, _, _) , .. } ) ,
310
- ) => {
311
- // Icky heuristic so we don't suggest:
312
- // `if (i + 2) = 2` => `if let (i + 2) = 2` (approximately pattern)
313
- // `if 2 = i` => `if let 2 = i` (lhs needs to contain error span)
314
- if lhs. is_approximately_pattern ( ) && lhs. span . contains ( span) {
315
- err. span_suggestion_verbose (
316
- expr_span. shrink_to_lo ( ) ,
317
- "you might have meant to use pattern matching" ,
318
- "let " ,
319
- Applicability :: MaybeIncorrect ,
320
- ) ;
311
+
312
+ let ( found, candidates) =
313
+ self . try_lookup_name_relaxed ( & mut err, source, path, span, res, & base_error) ;
314
+ if found {
315
+ return ( err, candidates) ;
316
+ }
317
+
318
+ if !self . type_ascription_suggestion ( & mut err, base_error. span ) {
319
+ let mut fallback =
320
+ self . suggest_trait_and_bounds ( & mut err, source, res, span, & base_error) ;
321
+ fallback |= self . suggest_typo ( & mut err, source, path, span, & base_error) ;
322
+ if fallback {
323
+ // Fallback label.
324
+ err. span_label ( base_error. span , & base_error. fallback_label ) ;
325
+ }
326
+ }
327
+ self . err_code_special_cases ( & mut err, source, path, span) ;
328
+
329
+ ( err, candidates)
330
+ }
331
+
332
+ fn detect_assoct_type_constraint_meant_as_path (
333
+ & self ,
334
+ err : & mut Diagnostic ,
335
+ base_error : & BaseError ,
336
+ ) {
337
+ let Some ( ty) = self . diagnostic_metadata . current_type_path else { return ; } ;
338
+ let TyKind :: Path ( _, path) = & ty. kind else { return ; } ;
339
+ for segment in & path. segments {
340
+ let Some ( params) = & segment. args else { continue ; } ;
341
+ let ast:: GenericArgs :: AngleBracketed ( ref params) = params. deref ( ) else { continue ; } ;
342
+ for param in & params. args {
343
+ let ast:: AngleBracketedArg :: Constraint ( constraint) = param else { continue ; } ;
344
+ let ast:: AssocConstraintKind :: Bound { bounds } = & constraint. kind else {
345
+ continue ;
346
+ } ;
347
+ for bound in bounds {
348
+ let ast:: GenericBound :: Trait ( trait_ref, ast:: TraitBoundModifier :: None )
349
+ = bound else
350
+ {
351
+ continue ;
352
+ } ;
353
+ if base_error. span == trait_ref. span {
354
+ err. span_suggestion_verbose (
355
+ constraint. ident . span . between ( trait_ref. span ) ,
356
+ "you might have meant to write a path instead of an associated type bound" ,
357
+ "::" ,
358
+ Applicability :: MachineApplicable ,
359
+ ) ;
360
+ }
321
361
}
322
362
}
323
- _ => { }
324
363
}
364
+ }
325
365
366
+ fn suggest_self_or_self_ref ( & mut self , err : & mut Diagnostic , path : & [ Segment ] , span : Span ) {
326
367
let is_assoc_fn = self . self_type_is_available ( ) ;
368
+ let Some ( path_last_segment) = path. last ( ) else { return } ;
369
+ let item_str = path_last_segment. ident ;
327
370
// Emit help message for fake-self from other languages (e.g., `this` in Javascript).
328
371
if [ "this" , "my" ] . contains ( & item_str. as_str ( ) ) && is_assoc_fn {
329
372
err. span_suggestion_short (
@@ -358,96 +401,25 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> {
358
401
}
359
402
}
360
403
}
404
+ }
361
405
362
- self . detect_assoct_type_constraint_meant_as_path ( base_error. span , & mut err) ;
363
-
364
- // Emit special messages for unresolved `Self` and `self`.
365
- if is_self_type ( path, ns) {
366
- err. code ( rustc_errors:: error_code!( E0411 ) ) ;
367
- err. span_label (
368
- span,
369
- "`Self` is only available in impls, traits, and type definitions" . to_string ( ) ,
370
- ) ;
371
- if let Some ( item_kind) = self . diagnostic_metadata . current_item {
372
- err. span_label (
373
- item_kind. ident . span ,
374
- format ! (
375
- "`Self` not allowed in {} {}" ,
376
- item_kind. kind. article( ) ,
377
- item_kind. kind. descr( )
378
- ) ,
379
- ) ;
380
- }
381
- return ( err, Vec :: new ( ) ) ;
382
- }
383
- if is_self_value ( path, ns) {
384
- debug ! ( "smart_resolve_path_fragment: E0424, source={:?}" , source) ;
385
-
386
- err. code ( rustc_errors:: error_code!( E0424 ) ) ;
387
- err. span_label ( span, match source {
388
- PathSource :: Pat => "`self` value is a keyword and may not be bound to variables or shadowed" ,
389
- _ => "`self` value is a keyword only available in methods with a `self` parameter" ,
390
- } ) ;
391
- if let Some ( ( fn_kind, span) ) = & self . diagnostic_metadata . current_function {
392
- // The current function has a `self' parameter, but we were unable to resolve
393
- // a reference to `self`. This can only happen if the `self` identifier we
394
- // are resolving came from a different hygiene context.
395
- if fn_kind. decl ( ) . inputs . get ( 0 ) . map_or ( false , |p| p. is_self ( ) ) {
396
- err. span_label ( * span, "this function has a `self` parameter, but a macro invocation can only access identifiers it receives from parameters" ) ;
397
- } else {
398
- let doesnt = if is_assoc_fn {
399
- let ( span, sugg) = fn_kind
400
- . decl ( )
401
- . inputs
402
- . get ( 0 )
403
- . map ( |p| ( p. span . shrink_to_lo ( ) , "&self, " ) )
404
- . unwrap_or_else ( || {
405
- // Try to look for the "(" after the function name, if possible.
406
- // This avoids placing the suggestion into the visibility specifier.
407
- let span = fn_kind
408
- . ident ( )
409
- . map_or ( * span, |ident| span. with_lo ( ident. span . hi ( ) ) ) ;
410
- (
411
- self . r
412
- . session
413
- . source_map ( )
414
- . span_through_char ( span, '(' )
415
- . shrink_to_hi ( ) ,
416
- "&self" ,
417
- )
418
- } ) ;
419
- err. span_suggestion_verbose (
420
- span,
421
- "add a `self` receiver parameter to make the associated `fn` a method" ,
422
- sugg,
423
- Applicability :: MaybeIncorrect ,
424
- ) ;
425
- "doesn't"
426
- } else {
427
- "can't"
428
- } ;
429
- if let Some ( ident) = fn_kind. ident ( ) {
430
- err. span_label (
431
- ident. span ,
432
- & format ! ( "this function {} have a `self` parameter" , doesnt) ,
433
- ) ;
434
- }
435
- }
436
- } else if let Some ( item_kind) = self . diagnostic_metadata . current_item {
437
- err. span_label (
438
- item_kind. ident . span ,
439
- format ! (
440
- "`self` not allowed in {} {}" ,
441
- item_kind. kind. article( ) ,
442
- item_kind. kind. descr( )
443
- ) ,
444
- ) ;
445
- }
446
- return ( err, Vec :: new ( ) ) ;
447
- }
448
-
406
+ fn try_lookup_name_relaxed (
407
+ & mut self ,
408
+ err : & mut DiagnosticBuilder < ' _ , ErrorGuaranteed > ,
409
+ source : PathSource < ' _ > ,
410
+ path : & [ Segment ] ,
411
+ span : Span ,
412
+ res : Option < Res > ,
413
+ base_error : & BaseError ,
414
+ ) -> ( bool , Vec < ImportSuggestion > ) {
449
415
// Try to lookup name in more relaxed fashion for better error reporting.
450
416
let ident = path. last ( ) . unwrap ( ) . ident ;
417
+ let is_expected = & |res| source. is_expected ( res) ;
418
+ let ns = source. namespace ( ) ;
419
+ let is_enum_variant = & |res| matches ! ( res, Res :: Def ( DefKind :: Variant , _) ) ;
420
+ let path_str = Segment :: names_to_string ( path) ;
421
+ let ident_span = path. last ( ) . map_or ( span, |ident| ident. ident . span ) ;
422
+
451
423
let mut candidates = self
452
424
. r
453
425
. lookup_import_candidates ( ident, ns, & self . parent_scope , is_expected)
@@ -494,7 +466,7 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> {
494
466
{
495
467
// Already reported this issue on the lhs of the type ascription.
496
468
err. delay_as_bug ( ) ;
497
- return ( err , candidates) ;
469
+ return ( true , candidates) ;
498
470
}
499
471
}
500
472
@@ -522,8 +494,9 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> {
522
494
) ;
523
495
}
524
496
}
497
+
525
498
// Try Levenshtein algorithm.
526
- let typo_sugg = self . lookup_typo_candidate ( path, ns , is_expected) ;
499
+ let typo_sugg = self . lookup_typo_candidate ( path, source . namespace ( ) , is_expected) ;
527
500
if path. len ( ) == 1 && self . self_type_is_available ( ) {
528
501
if let Some ( candidate) = self . lookup_assoc_candidate ( ident, ns, is_expected) {
529
502
let self_is_available = self . self_value_is_available ( path[ 0 ] . ident . span ) ;
@@ -560,8 +533,8 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> {
560
533
) ;
561
534
}
562
535
}
563
- self . r . add_typo_suggestion ( & mut err, typo_sugg, ident_span) ;
564
- return ( err , candidates) ;
536
+ self . r . add_typo_suggestion ( err, typo_sugg, ident_span) ;
537
+ return ( true , candidates) ;
565
538
}
566
539
567
540
// If the first argument in call is `self` suggest calling a method.
@@ -579,121 +552,150 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> {
579
552
format ! ( "self.{path_str}({args_snippet})" ) ,
580
553
Applicability :: MachineApplicable ,
581
554
) ;
582
- return ( err , candidates) ;
555
+ return ( true , candidates) ;
583
556
}
584
557
}
585
558
586
559
// Try context-dependent help if relaxed lookup didn't work.
587
560
if let Some ( res) = res {
588
561
if self . smart_resolve_context_dependent_help (
589
- & mut err,
562
+ err,
590
563
span,
591
564
source,
592
565
res,
593
566
& path_str,
594
567
& base_error. fallback_label ,
595
568
) {
596
569
// We do this to avoid losing a secondary span when we override the main error span.
597
- self . r . add_typo_suggestion ( & mut err, typo_sugg, ident_span) ;
598
- return ( err , candidates) ;
570
+ self . r . add_typo_suggestion ( err, typo_sugg, ident_span) ;
571
+ return ( true , candidates) ;
599
572
}
600
573
}
574
+ return ( false , candidates) ;
575
+ }
601
576
577
+ fn suggest_trait_and_bounds (
578
+ & mut self ,
579
+ err : & mut DiagnosticBuilder < ' _ , ErrorGuaranteed > ,
580
+ source : PathSource < ' _ > ,
581
+ res : Option < Res > ,
582
+ span : Span ,
583
+ base_error : & BaseError ,
584
+ ) -> bool {
602
585
let is_macro =
603
586
base_error. span . from_expansion ( ) && base_error. span . desugaring_kind ( ) . is_none ( ) ;
604
- if !self . type_ascription_suggestion ( & mut err, base_error. span ) {
605
- let mut fallback = false ;
606
- if let (
607
- PathSource :: Trait ( AliasPossibility :: Maybe ) ,
608
- Some ( Res :: Def ( DefKind :: Struct | DefKind :: Enum | DefKind :: Union , _) ) ,
609
- false ,
610
- ) = ( source, res, is_macro)
611
- {
612
- if let Some ( bounds @ [ _, .., _] ) = self . diagnostic_metadata . current_trait_object {
613
- fallback = true ;
614
- let spans: Vec < Span > = bounds
615
- . iter ( )
616
- . map ( |bound| bound. span ( ) )
617
- . filter ( |& sp| sp != base_error. span )
618
- . collect ( ) ;
587
+ let mut fallback = false ;
619
588
620
- let start_span = bounds[ 0 ] . span ( ) ;
621
- // `end_span` is the end of the poly trait ref (Foo + 'baz + Bar><)
622
- let end_span = bounds. last ( ) . unwrap ( ) . span ( ) ;
623
- // `last_bound_span` is the last bound of the poly trait ref (Foo + >'baz< + Bar)
624
- let last_bound_span = spans. last ( ) . cloned ( ) . unwrap ( ) ;
625
- let mut multi_span: MultiSpan = spans. clone ( ) . into ( ) ;
626
- for sp in spans {
627
- let msg = if sp == last_bound_span {
628
- format ! (
629
- "...because of {these} bound{s}" ,
630
- these = pluralize!( "this" , bounds. len( ) - 1 ) ,
631
- s = pluralize!( bounds. len( ) - 1 ) ,
632
- )
633
- } else {
634
- String :: new ( )
635
- } ;
636
- multi_span. push_span_label ( sp, msg) ;
637
- }
638
- multi_span
639
- . push_span_label ( base_error. span , "expected this type to be a trait..." ) ;
640
- err. span_help (
641
- multi_span,
642
- "`+` is used to constrain a \" trait object\" type with lifetimes or \
643
- auto-traits; structs and enums can't be bound in that way",
644
- ) ;
645
- if bounds. iter ( ) . all ( |bound| match bound {
646
- ast:: GenericBound :: Outlives ( _) => true ,
647
- ast:: GenericBound :: Trait ( tr, _) => tr. span == base_error. span ,
648
- } ) {
649
- let mut sugg = vec ! [ ] ;
650
- if base_error. span != start_span {
651
- sugg. push ( ( start_span. until ( base_error. span ) , String :: new ( ) ) ) ;
652
- }
653
- if base_error. span != end_span {
654
- sugg. push ( ( base_error. span . shrink_to_hi ( ) . to ( end_span) , String :: new ( ) ) ) ;
655
- }
589
+ if let (
590
+ PathSource :: Trait ( AliasPossibility :: Maybe ) ,
591
+ Some ( Res :: Def ( DefKind :: Struct | DefKind :: Enum | DefKind :: Union , _) ) ,
592
+ false ,
593
+ ) = ( source, res, is_macro)
594
+ {
595
+ if let Some ( bounds @ [ _, .., _] ) = self . diagnostic_metadata . current_trait_object {
596
+ fallback = true ;
597
+ let spans: Vec < Span > = bounds
598
+ . iter ( )
599
+ . map ( |bound| bound. span ( ) )
600
+ . filter ( |& sp| sp != base_error. span )
601
+ . collect ( ) ;
656
602
657
- err. multipart_suggestion (
658
- "if you meant to use a type and not a trait here, remove the bounds" ,
659
- sugg,
660
- Applicability :: MaybeIncorrect ,
661
- ) ;
603
+ let start_span = bounds[ 0 ] . span ( ) ;
604
+ // `end_span` is the end of the poly trait ref (Foo + 'baz + Bar><)
605
+ let end_span = bounds. last ( ) . unwrap ( ) . span ( ) ;
606
+ // `last_bound_span` is the last bound of the poly trait ref (Foo + >'baz< + Bar)
607
+ let last_bound_span = spans. last ( ) . cloned ( ) . unwrap ( ) ;
608
+ let mut multi_span: MultiSpan = spans. clone ( ) . into ( ) ;
609
+ for sp in spans {
610
+ let msg = if sp == last_bound_span {
611
+ format ! (
612
+ "...because of {these} bound{s}" ,
613
+ these = pluralize!( "this" , bounds. len( ) - 1 ) ,
614
+ s = pluralize!( bounds. len( ) - 1 ) ,
615
+ )
616
+ } else {
617
+ String :: new ( )
618
+ } ;
619
+ multi_span. push_span_label ( sp, msg) ;
620
+ }
621
+ multi_span. push_span_label ( base_error. span , "expected this type to be a trait..." ) ;
622
+ err. span_help (
623
+ multi_span,
624
+ "`+` is used to constrain a \" trait object\" type with lifetimes or \
625
+ auto-traits; structs and enums can't be bound in that way",
626
+ ) ;
627
+ if bounds. iter ( ) . all ( |bound| match bound {
628
+ ast:: GenericBound :: Outlives ( _) => true ,
629
+ ast:: GenericBound :: Trait ( tr, _) => tr. span == base_error. span ,
630
+ } ) {
631
+ let mut sugg = vec ! [ ] ;
632
+ if base_error. span != start_span {
633
+ sugg. push ( ( start_span. until ( base_error. span ) , String :: new ( ) ) ) ;
662
634
}
635
+ if base_error. span != end_span {
636
+ sugg. push ( ( base_error. span . shrink_to_hi ( ) . to ( end_span) , String :: new ( ) ) ) ;
637
+ }
638
+
639
+ err. multipart_suggestion (
640
+ "if you meant to use a type and not a trait here, remove the bounds" ,
641
+ sugg,
642
+ Applicability :: MaybeIncorrect ,
643
+ ) ;
663
644
}
664
645
}
646
+ }
665
647
666
- fallback |= self . restrict_assoc_type_in_where_clause ( span, & mut err) ;
648
+ fallback |= self . restrict_assoc_type_in_where_clause ( span, err) ;
649
+ fallback
650
+ }
667
651
668
- if !self . r . add_typo_suggestion ( & mut err, typo_sugg, ident_span) {
669
- fallback = true ;
670
- match self . diagnostic_metadata . current_let_binding {
671
- Some ( ( pat_sp, Some ( ty_sp) , None ) )
672
- if ty_sp. contains ( base_error. span ) && base_error. could_be_expr =>
673
- {
674
- err. span_suggestion_short (
675
- pat_sp. between ( ty_sp) ,
676
- "use `=` if you meant to assign" ,
677
- " = " ,
678
- Applicability :: MaybeIncorrect ,
679
- ) ;
680
- }
681
- _ => { }
652
+ fn suggest_typo (
653
+ & mut self ,
654
+ err : & mut DiagnosticBuilder < ' _ , ErrorGuaranteed > ,
655
+ source : PathSource < ' _ > ,
656
+ path : & [ Segment ] ,
657
+ span : Span ,
658
+ base_error : & BaseError ,
659
+ ) -> bool {
660
+ let is_expected = & |res| source. is_expected ( res) ;
661
+ let ident_span = path. last ( ) . map_or ( span, |ident| ident. ident . span ) ;
662
+ let typo_sugg = self . lookup_typo_candidate ( path, source. namespace ( ) , is_expected) ;
663
+ let mut fallback = false ;
664
+ if !self . r . add_typo_suggestion ( err, typo_sugg, ident_span) {
665
+ fallback = true ;
666
+ match self . diagnostic_metadata . current_let_binding {
667
+ Some ( ( pat_sp, Some ( ty_sp) , None ) )
668
+ if ty_sp. contains ( base_error. span ) && base_error. could_be_expr =>
669
+ {
670
+ err. span_suggestion_short (
671
+ pat_sp. between ( ty_sp) ,
672
+ "use `=` if you meant to assign" ,
673
+ " = " ,
674
+ Applicability :: MaybeIncorrect ,
675
+ ) ;
682
676
}
683
-
684
- // If the trait has a single item (which wasn't matched by Levenshtein), suggest it
685
- let suggestion = self . get_single_associated_item ( & path, & source, is_expected) ;
686
- self . r . add_typo_suggestion ( & mut err, suggestion, ident_span) ;
687
- }
688
- if fallback {
689
- // Fallback label.
690
- err. span_label ( base_error. span , base_error. fallback_label ) ;
677
+ _ => { }
691
678
}
679
+
680
+ // If the trait has a single item (which wasn't matched by Levenshtein), suggest it
681
+ let suggestion = self . get_single_associated_item ( & path, & source, is_expected) ;
682
+ self . r . add_typo_suggestion ( err, suggestion, ident_span) ;
692
683
}
684
+ fallback
685
+ }
686
+
687
+ fn err_code_special_cases (
688
+ & mut self ,
689
+ err : & mut DiagnosticBuilder < ' _ , ErrorGuaranteed > ,
690
+ source : PathSource < ' _ > ,
691
+ path : & [ Segment ] ,
692
+ span : Span ,
693
+ ) {
693
694
if let Some ( err_code) = & err. code {
694
695
if err_code == & rustc_errors:: error_code!( E0425 ) {
695
696
for label_rib in & self . label_ribs {
696
697
for ( label_ident, node_id) in & label_rib. bindings {
698
+ let ident = path. last ( ) . unwrap ( ) . ident ;
697
699
if format ! ( "'{}" , ident) == label_ident. to_string ( ) {
698
700
err. span_label ( label_ident. span , "a label with a similar name exists" ) ;
699
701
if let PathSource :: Expr ( Some ( Expr {
@@ -724,38 +726,116 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> {
724
726
}
725
727
}
726
728
}
729
+ }
727
730
728
- ( err, candidates)
731
+ /// Emit special messages for unresolved `Self` and `self`.
732
+ fn suggest_self_ty (
733
+ & mut self ,
734
+ err : & mut Diagnostic ,
735
+ source : PathSource < ' _ > ,
736
+ path : & [ Segment ] ,
737
+ span : Span ,
738
+ ) -> bool {
739
+ if !is_self_type ( path, source. namespace ( ) ) {
740
+ return false ;
741
+ }
742
+ err. code ( rustc_errors:: error_code!( E0411 ) ) ;
743
+ err. span_label (
744
+ span,
745
+ "`Self` is only available in impls, traits, and type definitions" . to_string ( ) ,
746
+ ) ;
747
+ if let Some ( item_kind) = self . diagnostic_metadata . current_item {
748
+ err. span_label (
749
+ item_kind. ident . span ,
750
+ format ! (
751
+ "`Self` not allowed in {} {}" ,
752
+ item_kind. kind. article( ) ,
753
+ item_kind. kind. descr( )
754
+ ) ,
755
+ ) ;
756
+ }
757
+ true
729
758
}
730
759
731
- fn detect_assoct_type_constraint_meant_as_path ( & self , base_span : Span , err : & mut Diagnostic ) {
732
- let Some ( ty) = self . diagnostic_metadata . current_type_path else { return ; } ;
733
- let TyKind :: Path ( _, path) = & ty. kind else { return ; } ;
734
- for segment in & path. segments {
735
- let Some ( params) = & segment. args else { continue ; } ;
736
- let ast:: GenericArgs :: AngleBracketed ( ref params) = params. deref ( ) else { continue ; } ;
737
- for param in & params. args {
738
- let ast:: AngleBracketedArg :: Constraint ( constraint) = param else { continue ; } ;
739
- let ast:: AssocConstraintKind :: Bound { bounds } = & constraint. kind else {
740
- continue ;
760
+ fn suggest_self_value (
761
+ & mut self ,
762
+ err : & mut Diagnostic ,
763
+ source : PathSource < ' _ > ,
764
+ path : & [ Segment ] ,
765
+ span : Span ,
766
+ ) -> bool {
767
+ if !is_self_value ( path, source. namespace ( ) ) {
768
+ return false ;
769
+ }
770
+
771
+ debug ! ( "smart_resolve_path_fragment: E0424, source={:?}" , source) ;
772
+ err. code ( rustc_errors:: error_code!( E0424 ) ) ;
773
+ err. span_label (
774
+ span,
775
+ match source {
776
+ PathSource :: Pat => {
777
+ "`self` value is a keyword and may not be bound to variables or shadowed"
778
+ }
779
+ _ => "`self` value is a keyword only available in methods with a `self` parameter" ,
780
+ } ,
781
+ ) ;
782
+ let is_assoc_fn = self . self_type_is_available ( ) ;
783
+ if let Some ( ( fn_kind, span) ) = & self . diagnostic_metadata . current_function {
784
+ // The current function has a `self' parameter, but we were unable to resolve
785
+ // a reference to `self`. This can only happen if the `self` identifier we
786
+ // are resolving came from a different hygiene context.
787
+ if fn_kind. decl ( ) . inputs . get ( 0 ) . map_or ( false , |p| p. is_self ( ) ) {
788
+ err. span_label ( * span, "this function has a `self` parameter, but a macro invocation can only access identifiers it receives from parameters" ) ;
789
+ } else {
790
+ let doesnt = if is_assoc_fn {
791
+ let ( span, sugg) = fn_kind
792
+ . decl ( )
793
+ . inputs
794
+ . get ( 0 )
795
+ . map ( |p| ( p. span . shrink_to_lo ( ) , "&self, " ) )
796
+ . unwrap_or_else ( || {
797
+ // Try to look for the "(" after the function name, if possible.
798
+ // This avoids placing the suggestion into the visibility specifier.
799
+ let span = fn_kind
800
+ . ident ( )
801
+ . map_or ( * span, |ident| span. with_lo ( ident. span . hi ( ) ) ) ;
802
+ (
803
+ self . r
804
+ . session
805
+ . source_map ( )
806
+ . span_through_char ( span, '(' )
807
+ . shrink_to_hi ( ) ,
808
+ "&self" ,
809
+ )
810
+ } ) ;
811
+ err. span_suggestion_verbose (
812
+ span,
813
+ "add a `self` receiver parameter to make the associated `fn` a method" ,
814
+ sugg,
815
+ Applicability :: MaybeIncorrect ,
816
+ ) ;
817
+ "doesn't"
818
+ } else {
819
+ "can't"
741
820
} ;
742
- for bound in bounds {
743
- let ast:: GenericBound :: Trait ( trait_ref, ast:: TraitBoundModifier :: None )
744
- = bound else
745
- {
746
- continue ;
747
- } ;
748
- if base_span == trait_ref. span {
749
- err. span_suggestion_verbose (
750
- constraint. ident . span . between ( trait_ref. span ) ,
751
- "you might have meant to write a path instead of an associated type bound" ,
752
- "::" ,
753
- Applicability :: MachineApplicable ,
754
- ) ;
755
- }
821
+ if let Some ( ident) = fn_kind. ident ( ) {
822
+ err. span_label (
823
+ ident. span ,
824
+ & format ! ( "this function {} have a `self` parameter" , doesnt) ,
825
+ ) ;
756
826
}
757
827
}
828
+ } else if let Some ( item_kind) = self . diagnostic_metadata . current_item {
829
+ err. span_label (
830
+ item_kind. ident . span ,
831
+ format ! (
832
+ "`self` not allowed in {} {}" ,
833
+ item_kind. kind. article( ) ,
834
+ item_kind. kind. descr( )
835
+ ) ,
836
+ ) ;
758
837
}
838
+ true
759
839
}
760
840
761
841
fn suggest_swapping_misplaced_self_ty_and_trait (
@@ -787,6 +867,45 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> {
787
867
}
788
868
}
789
869
870
+ fn suggest_bare_struct_literal ( & mut self , err : & mut Diagnostic ) {
871
+ if let Some ( span) = self . diagnostic_metadata . current_block_could_be_bare_struct_literal {
872
+ err. multipart_suggestion (
873
+ "you might have meant to write a `struct` literal" ,
874
+ vec ! [
875
+ ( span. shrink_to_lo( ) , "{ SomeStruct " . to_string( ) ) ,
876
+ ( span. shrink_to_hi( ) , "}" . to_string( ) ) ,
877
+ ] ,
878
+ Applicability :: HasPlaceholders ,
879
+ ) ;
880
+ }
881
+ }
882
+
883
+ fn suggest_pattern_match_with_let (
884
+ & mut self ,
885
+ err : & mut Diagnostic ,
886
+ source : PathSource < ' _ > ,
887
+ span : Span ,
888
+ ) {
889
+ if let PathSource :: Expr ( _) = source &&
890
+ let Some ( Expr {
891
+ span : expr_span,
892
+ kind : ExprKind :: Assign ( lhs, _, _) ,
893
+ ..
894
+ } ) = self . diagnostic_metadata . in_if_condition {
895
+ // Icky heuristic so we don't suggest:
896
+ // `if (i + 2) = 2` => `if let (i + 2) = 2` (approximately pattern)
897
+ // `if 2 = i` => `if let 2 = i` (lhs needs to contain error span)
898
+ if lhs. is_approximately_pattern ( ) && lhs. span . contains ( span) {
899
+ err. span_suggestion_verbose (
900
+ expr_span. shrink_to_lo ( ) ,
901
+ "you might have meant to use pattern matching" ,
902
+ "let " ,
903
+ Applicability :: MaybeIncorrect ,
904
+ ) ;
905
+ }
906
+ }
907
+ }
908
+
790
909
fn get_single_associated_item (
791
910
& mut self ,
792
911
path : & [ Segment ] ,
0 commit comments