@@ -123,7 +123,7 @@ impl<'a> Resolver<'a> {
123123 let ( span, found_use) = if let Some ( def_id) = def_id. as_local ( ) {
124124 UsePlacementFinder :: check ( krate, self . def_id_to_node_id [ def_id] )
125125 } else {
126- ( None , false )
126+ ( None , FoundUse :: No )
127127 } ;
128128 if !candidates. is_empty ( ) {
129129 show_candidates (
@@ -132,8 +132,9 @@ impl<'a> Resolver<'a> {
132132 & mut err,
133133 span,
134134 & candidates,
135- instead,
135+ if instead { Instead :: Yes } else { Instead :: No } ,
136136 found_use,
137+ IsPattern :: No ,
137138 ) ;
138139 } else if let Some ( ( span, msg, sugg, appl) ) = suggestion {
139140 err. span_suggestion ( span, msg, sugg, appl) ;
@@ -493,14 +494,14 @@ impl<'a> Resolver<'a> {
493494 ///
494495 /// This takes the error provided, combines it with the span and any additional spans inside the
495496 /// 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 > ) {
497498 self . into_struct_error ( span, resolution_error) . emit ( ) ;
498499 }
499500
500501 crate fn into_struct_error (
501- & self ,
502+ & mut self ,
502503 span : Span ,
503- resolution_error : ResolutionError < ' _ > ,
504+ resolution_error : ResolutionError < ' a > ,
504505 ) -> DiagnosticBuilder < ' _ , ErrorGuaranteed > {
505506 match resolution_error {
506507 ResolutionError :: GenericParamsFromOuterFunction ( outer_res, has_generic_params) => {
@@ -650,7 +651,7 @@ impl<'a> Resolver<'a> {
650651 }
651652 err
652653 }
653- ResolutionError :: VariableNotBoundInPattern ( binding_error) => {
654+ ResolutionError :: VariableNotBoundInPattern ( binding_error, parent_scope ) => {
654655 let BindingError { name, target, origin, could_be_path } = binding_error;
655656
656657 let target_sp = target. iter ( ) . copied ( ) . collect :: < Vec < _ > > ( ) ;
@@ -670,13 +671,41 @@ impl<'a> Resolver<'a> {
670671 for sp in origin_sp {
671672 err. span_label ( sp, "variable not in all patterns" ) ;
672673 }
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 ,
678708 ) ;
679- err. span_help ( span, & help_msg) ;
680709 }
681710 err
682711 }
@@ -1022,7 +1051,7 @@ impl<'a> Resolver<'a> {
10221051 }
10231052
10241053 crate fn report_vis_error (
1025- & self ,
1054+ & mut self ,
10261055 vis_resolution_error : VisResolutionError < ' _ > ,
10271056 ) -> ErrorGuaranteed {
10281057 match vis_resolution_error {
@@ -1453,8 +1482,9 @@ impl<'a> Resolver<'a> {
14531482 err,
14541483 None ,
14551484 & import_suggestions,
1456- false ,
1457- true ,
1485+ Instead :: No ,
1486+ FoundUse :: Yes ,
1487+ IsPattern :: No ,
14581488 ) ;
14591489
14601490 if macro_kind == MacroKind :: Derive && ( ident. name == sym:: Send || ident. name == sym:: Sync ) {
@@ -2390,6 +2420,27 @@ fn find_span_immediately_after_crate_name(
23902420 ( next_left_bracket == after_second_colon, from_second_colon)
23912421}
23922422
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+
23932444/// When an entity with a given name is not available in scope, we search for
23942445/// entities with that name in all crates. This method allows outputting the
23952446/// results of this search in a programmer-friendly way
@@ -2400,8 +2451,9 @@ fn show_candidates(
24002451 // This is `None` if all placement locations are inside expansions
24012452 use_placement_span : Option < Span > ,
24022453 candidates : & [ ImportSuggestion ] ,
2403- instead : bool ,
2404- found_use : bool ,
2454+ instead : Instead ,
2455+ found_use : FoundUse ,
2456+ is_pattern : IsPattern ,
24052457) {
24062458 if candidates. is_empty ( ) {
24072459 return ;
@@ -2428,32 +2480,46 @@ fn show_candidates(
24282480 }
24292481
24302482 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 ) )
24332485 } else {
2434- ( "one of these" , "items" )
2486+ ( "one of these" , "items" , String :: new ( ) )
24352487 } ;
24362488
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+ } ;
24392498
24402499 for note in accessible_path_strings. iter ( ) . flat_map ( |cand| cand. 3 . as_ref ( ) ) {
24412500 err. note ( note) ;
24422501 }
24432502
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 {
24452511 for candidate in & mut accessible_path_strings {
24462512 // produce an additional newline to separate the new use statement
24472513 // 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 " } ;
24492515 candidate. 0 = format ! ( "use {};\n {}" , & candidate. 0 , additional_newline) ;
24502516 }
24512517
24522518 err. span_suggestions (
24532519 span,
24542520 & msg,
24552521 accessible_path_strings. into_iter ( ) . map ( |a| a. 0 ) ,
2456- Applicability :: Unspecified ,
2522+ Applicability :: MaybeIncorrect ,
24572523 ) ;
24582524 } else {
24592525 msg. push ( ':' ) ;
@@ -2468,9 +2534,17 @@ fn show_candidates(
24682534 } else {
24692535 assert ! ( !inaccessible_path_strings. is_empty( ) ) ;
24702536
2537+ let prefix =
2538+ if let IsPattern :: Yes = is_pattern { "you might have meant to match on " } else { "" } ;
24712539 if inaccessible_path_strings. len ( ) == 1 {
24722540 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+ ) ;
24742548
24752549 if let Some ( local_def_id) = def_id. and_then ( |did| did. as_local ( ) ) {
24762550 let span = definitions. def_span ( local_def_id) ;
@@ -2496,7 +2570,7 @@ fn show_candidates(
24962570 "item" . to_string ( )
24972571 } ;
24982572
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) ;
25002574 let mut has_colon = false ;
25012575
25022576 let mut spans = Vec :: new ( ) ;
@@ -2537,14 +2611,14 @@ struct UsePlacementFinder {
25372611}
25382612
25392613impl UsePlacementFinder {
2540- fn check ( krate : & Crate , target_module : NodeId ) -> ( Option < Span > , bool ) {
2614+ fn check ( krate : & Crate , target_module : NodeId ) -> ( Option < Span > , FoundUse ) {
25412615 let mut finder =
25422616 UsePlacementFinder { target_module, first_legal_span : None , first_use_span : None } ;
25432617 finder. visit_crate ( krate) ;
25442618 if let Some ( use_span) = finder. first_use_span {
2545- ( Some ( use_span) , true )
2619+ ( Some ( use_span) , FoundUse :: Yes )
25462620 } else {
2547- ( finder. first_legal_span , false )
2621+ ( finder. first_legal_span , FoundUse :: No )
25482622 }
25492623 }
25502624}
0 commit comments