@@ -123,7 +123,7 @@ impl<'a> Resolver<'a> {
123
123
let ( span, found_use) = if let Some ( def_id) = def_id. as_local ( ) {
124
124
UsePlacementFinder :: check ( krate, self . def_id_to_node_id [ def_id] )
125
125
} else {
126
- ( None , false )
126
+ ( None , FoundUse :: No )
127
127
} ;
128
128
if !candidates. is_empty ( ) {
129
129
show_candidates (
@@ -132,8 +132,9 @@ impl<'a> Resolver<'a> {
132
132
& mut err,
133
133
span,
134
134
& candidates,
135
- instead,
135
+ if instead { Instead :: Yes } else { Instead :: No } ,
136
136
found_use,
137
+ IsPattern :: No ,
137
138
) ;
138
139
} else if let Some ( ( span, msg, sugg, appl) ) = suggestion {
139
140
err. span_suggestion ( span, msg, sugg, appl) ;
@@ -493,14 +494,14 @@ impl<'a> Resolver<'a> {
493
494
///
494
495
/// This takes the error provided, combines it with the span and any additional spans inside the
495
496
/// error and emits it.
496
- crate fn report_error ( & self , span : Span , resolution_error : ResolutionError < ' _ > ) {
497
+ crate fn report_error ( & mut self , span : Span , resolution_error : ResolutionError < ' a > ) {
497
498
self . into_struct_error ( span, resolution_error) . emit ( ) ;
498
499
}
499
500
500
501
crate fn into_struct_error (
501
- & self ,
502
+ & mut self ,
502
503
span : Span ,
503
- resolution_error : ResolutionError < ' _ > ,
504
+ resolution_error : ResolutionError < ' a > ,
504
505
) -> DiagnosticBuilder < ' _ , ErrorGuaranteed > {
505
506
match resolution_error {
506
507
ResolutionError :: GenericParamsFromOuterFunction ( outer_res, has_generic_params) => {
@@ -650,7 +651,7 @@ impl<'a> Resolver<'a> {
650
651
}
651
652
err
652
653
}
653
- ResolutionError :: VariableNotBoundInPattern ( binding_error) => {
654
+ ResolutionError :: VariableNotBoundInPattern ( binding_error, parent_scope ) => {
654
655
let BindingError { name, target, origin, could_be_path } = binding_error;
655
656
656
657
let target_sp = target. iter ( ) . copied ( ) . collect :: < Vec < _ > > ( ) ;
@@ -670,13 +671,41 @@ impl<'a> Resolver<'a> {
670
671
for sp in origin_sp {
671
672
err. span_label ( sp, "variable not in all patterns" ) ;
672
673
}
673
- if * could_be_path {
674
- let help_msg = format ! (
675
- "if you meant to match on a variant or a `const` item, consider \
676
- making the path in the pattern qualified: `?::{}`",
677
- name,
674
+ if could_be_path {
675
+ let import_suggestions = self . lookup_import_candidates (
676
+ Ident :: with_dummy_span ( name) ,
677
+ Namespace :: ValueNS ,
678
+ & parent_scope,
679
+ & |res : Res | match res {
680
+ Res :: Def (
681
+ DefKind :: Ctor ( CtorOf :: Variant , CtorKind :: Const )
682
+ | DefKind :: Ctor ( CtorOf :: Struct , CtorKind :: Const )
683
+ | DefKind :: Const
684
+ | DefKind :: AssocConst ,
685
+ _,
686
+ ) => true ,
687
+ _ => false ,
688
+ } ,
689
+ ) ;
690
+
691
+ if import_suggestions. is_empty ( ) {
692
+ let help_msg = format ! (
693
+ "if you meant to match on a variant or a `const` item, consider \
694
+ making the path in the pattern qualified: `path::to::ModOrType::{}`",
695
+ name,
696
+ ) ;
697
+ err. span_help ( span, & help_msg) ;
698
+ }
699
+ show_candidates (
700
+ & self . definitions ,
701
+ self . session ,
702
+ & mut err,
703
+ Some ( span) ,
704
+ & import_suggestions,
705
+ Instead :: No ,
706
+ FoundUse :: Yes ,
707
+ IsPattern :: Yes ,
678
708
) ;
679
- err. span_help ( span, & help_msg) ;
680
709
}
681
710
err
682
711
}
@@ -1022,7 +1051,7 @@ impl<'a> Resolver<'a> {
1022
1051
}
1023
1052
1024
1053
crate fn report_vis_error (
1025
- & self ,
1054
+ & mut self ,
1026
1055
vis_resolution_error : VisResolutionError < ' _ > ,
1027
1056
) -> ErrorGuaranteed {
1028
1057
match vis_resolution_error {
@@ -1453,8 +1482,9 @@ impl<'a> Resolver<'a> {
1453
1482
err,
1454
1483
None ,
1455
1484
& import_suggestions,
1456
- false ,
1457
- true ,
1485
+ Instead :: No ,
1486
+ FoundUse :: Yes ,
1487
+ IsPattern :: No ,
1458
1488
) ;
1459
1489
1460
1490
if macro_kind == MacroKind :: Derive && ( ident. name == sym:: Send || ident. name == sym:: Sync ) {
@@ -2390,6 +2420,27 @@ fn find_span_immediately_after_crate_name(
2390
2420
( next_left_bracket == after_second_colon, from_second_colon)
2391
2421
}
2392
2422
2423
+ /// A suggestion has already been emitted, change the wording slightly to clarify that both are
2424
+ /// independent options.
2425
+ enum Instead {
2426
+ Yes ,
2427
+ No ,
2428
+ }
2429
+
2430
+ /// Whether an existing place with an `use` item was found.
2431
+ enum FoundUse {
2432
+ Yes ,
2433
+ No ,
2434
+ }
2435
+
2436
+ /// Whether a binding is part of a pattern or an expression. Used for diagnostics.
2437
+ enum IsPattern {
2438
+ /// The binding is part of a pattern
2439
+ Yes ,
2440
+ /// The binding is part of an expression
2441
+ No ,
2442
+ }
2443
+
2393
2444
/// When an entity with a given name is not available in scope, we search for
2394
2445
/// entities with that name in all crates. This method allows outputting the
2395
2446
/// results of this search in a programmer-friendly way
@@ -2400,8 +2451,9 @@ fn show_candidates(
2400
2451
// This is `None` if all placement locations are inside expansions
2401
2452
use_placement_span : Option < Span > ,
2402
2453
candidates : & [ ImportSuggestion ] ,
2403
- instead : bool ,
2404
- found_use : bool ,
2454
+ instead : Instead ,
2455
+ found_use : FoundUse ,
2456
+ is_pattern : IsPattern ,
2405
2457
) {
2406
2458
if candidates. is_empty ( ) {
2407
2459
return ;
@@ -2428,32 +2480,46 @@ fn show_candidates(
2428
2480
}
2429
2481
2430
2482
if !accessible_path_strings. is_empty ( ) {
2431
- let ( determiner, kind) = if accessible_path_strings. len ( ) == 1 {
2432
- ( "this" , accessible_path_strings[ 0 ] . 1 )
2483
+ let ( determiner, kind, name ) = if accessible_path_strings. len ( ) == 1 {
2484
+ ( "this" , accessible_path_strings[ 0 ] . 1 , format ! ( " `{}`" , accessible_path_strings [ 0 ] . 0 ) )
2433
2485
} else {
2434
- ( "one of these" , "items" )
2486
+ ( "one of these" , "items" , String :: new ( ) )
2435
2487
} ;
2436
2488
2437
- let instead = if instead { " instead" } else { "" } ;
2438
- let mut msg = format ! ( "consider importing {} {}{}" , determiner, kind, instead) ;
2489
+ let instead = if let Instead :: Yes = instead { " instead" } else { "" } ;
2490
+ let mut msg = if let IsPattern :: Yes = is_pattern {
2491
+ format ! (
2492
+ "if you meant to match on {}{}{}, use the full path in the pattern" ,
2493
+ kind, instead, name
2494
+ )
2495
+ } else {
2496
+ format ! ( "consider importing {} {}{}" , determiner, kind, instead)
2497
+ } ;
2439
2498
2440
2499
for note in accessible_path_strings. iter ( ) . flat_map ( |cand| cand. 3 . as_ref ( ) ) {
2441
2500
err. note ( note) ;
2442
2501
}
2443
2502
2444
- if let Some ( span) = use_placement_span {
2503
+ if let ( IsPattern :: Yes , Some ( span) ) = ( is_pattern, use_placement_span) {
2504
+ err. span_suggestions (
2505
+ span,
2506
+ & msg,
2507
+ accessible_path_strings. into_iter ( ) . map ( |a| a. 0 ) ,
2508
+ Applicability :: MaybeIncorrect ,
2509
+ ) ;
2510
+ } else if let Some ( span) = use_placement_span {
2445
2511
for candidate in & mut accessible_path_strings {
2446
2512
// produce an additional newline to separate the new use statement
2447
2513
// from the directly following item.
2448
- let additional_newline = if found_use { "" } else { "\n " } ;
2514
+ let additional_newline = if let FoundUse :: Yes = found_use { "" } else { "\n " } ;
2449
2515
candidate. 0 = format ! ( "use {};\n {}" , & candidate. 0 , additional_newline) ;
2450
2516
}
2451
2517
2452
2518
err. span_suggestions (
2453
2519
span,
2454
2520
& msg,
2455
2521
accessible_path_strings. into_iter ( ) . map ( |a| a. 0 ) ,
2456
- Applicability :: Unspecified ,
2522
+ Applicability :: MaybeIncorrect ,
2457
2523
) ;
2458
2524
} else {
2459
2525
msg. push ( ':' ) ;
@@ -2468,9 +2534,17 @@ fn show_candidates(
2468
2534
} else {
2469
2535
assert ! ( !inaccessible_path_strings. is_empty( ) ) ;
2470
2536
2537
+ let prefix =
2538
+ if let IsPattern :: Yes = is_pattern { "you might have meant to match on " } else { "" } ;
2471
2539
if inaccessible_path_strings. len ( ) == 1 {
2472
2540
let ( name, descr, def_id, note) = & inaccessible_path_strings[ 0 ] ;
2473
- let msg = format ! ( "{} `{}` exists but is inaccessible" , descr, name) ;
2541
+ let msg = format ! (
2542
+ "{}{} `{}`{} exists but is inaccessible" ,
2543
+ prefix,
2544
+ descr,
2545
+ name,
2546
+ if let IsPattern :: Yes = is_pattern { ", which" } else { "" }
2547
+ ) ;
2474
2548
2475
2549
if let Some ( local_def_id) = def_id. and_then ( |did| did. as_local ( ) ) {
2476
2550
let span = definitions. def_span ( local_def_id) ;
@@ -2496,7 +2570,7 @@ fn show_candidates(
2496
2570
"item" . to_string ( )
2497
2571
} ;
2498
2572
2499
- let mut msg = format ! ( "these {}s exist but are inaccessible" , descr) ;
2573
+ let mut msg = format ! ( "{} these {}s exist but are inaccessible" , prefix , descr) ;
2500
2574
let mut has_colon = false ;
2501
2575
2502
2576
let mut spans = Vec :: new ( ) ;
@@ -2537,14 +2611,14 @@ struct UsePlacementFinder {
2537
2611
}
2538
2612
2539
2613
impl UsePlacementFinder {
2540
- fn check ( krate : & Crate , target_module : NodeId ) -> ( Option < Span > , bool ) {
2614
+ fn check ( krate : & Crate , target_module : NodeId ) -> ( Option < Span > , FoundUse ) {
2541
2615
let mut finder =
2542
2616
UsePlacementFinder { target_module, first_legal_span : None , first_use_span : None } ;
2543
2617
finder. visit_crate ( krate) ;
2544
2618
if let Some ( use_span) = finder. first_use_span {
2545
- ( Some ( use_span) , true )
2619
+ ( Some ( use_span) , FoundUse :: Yes )
2546
2620
} else {
2547
- ( finder. first_legal_span , false )
2621
+ ( finder. first_legal_span , FoundUse :: No )
2548
2622
}
2549
2623
}
2550
2624
}
0 commit comments