@@ -303,14 +303,57 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
303303                } 
304304                if  !candidates. is_empty ( )  { 
305305                    let  help = format ! ( 
306-                         "{an}other candidate{s} {were} found in the following trait{s}, perhaps \  
307- , 
306+                         "{an}other candidate{s} {were} found in the following trait{s}" , 
308307                        an = if  candidates. len( )  == 1  {  "an"  }  else {  ""  } , 
309308                        s = pluralize!( candidates. len( ) ) , 
310309                        were = pluralize!( "was" ,  candidates. len( ) ) , 
311-                         one_of_them = if  candidates. len( )  == 1  {  "it"  }  else {  "one_of_them"  } , 
312310                    ) ; 
313-                     self . suggest_use_candidates ( & mut  err,  help,  candidates) ; 
311+                     self . suggest_use_candidates ( 
312+                         candidates, 
313+                         |accessible_sugg,  inaccessible_sugg,  span| { 
314+                             let  suggest_for_access =
315+                                 |err :  & mut  Diag < ' _ > ,  mut  msg :  String ,  sugg :  Vec < _ > | { 
316+                                     msg += & format ! ( 
317+                                         ", perhaps add a `use` for {one_of_them}:" , 
318+                                         one_of_them =
319+                                             if  sugg. len( )  == 1  {  "it"  }  else {  "one_of_them"  } , 
320+                                     ) ; 
321+                                     err. span_suggestions ( 
322+                                         span, 
323+                                         msg, 
324+                                         sugg, 
325+                                         Applicability :: MaybeIncorrect , 
326+                                     ) ; 
327+                                 } ; 
328+                             let  suggest_for_privacy =
329+                                 |err :  & mut  Diag < ' _ > ,  mut  msg :  String ,  sugg :  Vec < String > | { 
330+                                     if  sugg. len ( )  == 1  { 
331+                                         let  msg = format ! ( "\  
332+ , 
333+                                             sugg[ 0 ] . trim( ) 
334+                                         ) ; 
335+                                         err. help ( msg) ; 
336+                                     }  else  { 
337+                                         msg += & format ! ( " but {} not reachable" ,  pluralize!( "is" ,  sugg. len( ) ) ) ; 
338+                                         err. span_suggestions ( 
339+                                             span, 
340+                                             msg, 
341+                                             sugg, 
342+                                             Applicability :: MaybeIncorrect , 
343+                                         ) ; 
344+                                     } 
345+                                 } ; 
346+                             if  accessible_sugg. is_empty ( )  { 
347+                                 // `inaccessible_sugg` must not be empty 
348+                                 suggest_for_privacy ( & mut  err,  help,  inaccessible_sugg) ; 
349+                             }  else  if  inaccessible_sugg. is_empty ( )  { 
350+                                 suggest_for_access ( & mut  err,  help,  accessible_sugg) ; 
351+                             }  else  { 
352+                                 suggest_for_access ( & mut  err,  help. clone ( ) ,  accessible_sugg) ; 
353+                                 suggest_for_privacy ( & mut  err,  help,  inaccessible_sugg) ; 
354+                             } 
355+                         } , 
356+                     ) ; 
314357                } 
315358                if  let  ty:: Ref ( region,  t_type,  mutability)  = rcvr_ty. kind ( )  { 
316359                    if  needs_mut { 
@@ -3089,49 +3132,69 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
30893132        } 
30903133    } 
30913134
3092-     fn  suggest_use_candidates ( & self ,  err :  & mut  Diag < ' _ > ,  msg :  String ,  candidates :  Vec < DefId > )  { 
3135+     fn  suggest_use_candidates < F > ( & self ,  candidates :  Vec < DefId > ,  handle_candidates :  F ) 
3136+     where 
3137+         F :  FnOnce ( Vec < String > ,  Vec < String > ,  Span ) , 
3138+     { 
30933139        let  parent_map = self . tcx . visible_parent_map ( ( ) ) ; 
30943140
3095-         // Separate out candidates that must be imported with a glob, because they are named `_` 
3096-         // and cannot be referred with their identifier. 
3097-         let  ( candidates,  globs) :  ( Vec < _ > ,  Vec < _ > )  = candidates. into_iter ( ) . partition ( |trait_did| { 
3098-             if  let  Some ( parent_did)  = parent_map. get ( trait_did)  { 
3099-                 // If the item is re-exported as `_`, we should suggest a glob-import instead. 
3100-                 if  * parent_did != self . tcx . parent ( * trait_did) 
3101-                     && self 
3102-                         . tcx 
3103-                         . module_children ( * parent_did) 
3104-                         . iter ( ) 
3105-                         . filter ( |child| child. res . opt_def_id ( )  == Some ( * trait_did) ) 
3106-                         . all ( |child| child. ident . name  == kw:: Underscore ) 
3107-                 { 
3108-                     return  false ; 
3109-                 } 
3110-             } 
3141+         let  scope = self . tcx . parent_module_from_def_id ( self . body_id ) ; 
3142+         let  ( accessible_candidates,  inaccessible_candidates) :  ( Vec < _ > ,  Vec < _ > )  =
3143+             candidates. into_iter ( ) . partition ( |id| { 
3144+                 let  vis = self . tcx . visibility ( * id) ; 
3145+                 vis. is_accessible_from ( scope,  self . tcx ) 
3146+             } ) ; 
31113147
3112-             true 
3113-         } ) ; 
3148+         let  sugg = |candidates :  Vec < _ > ,  visible| { 
3149+             // Separate out candidates that must be imported with a glob, because they are named `_` 
3150+             // and cannot be referred with their identifier. 
3151+             let  ( candidates,  globs) :  ( Vec < _ > ,  Vec < _ > )  =
3152+                 candidates. into_iter ( ) . partition ( |trait_did| { 
3153+                     if  let  Some ( parent_did)  = parent_map. get ( trait_did)  { 
3154+                         // If the item is re-exported as `_`, we should suggest a glob-import instead. 
3155+                         if  * parent_did != self . tcx . parent ( * trait_did) 
3156+                             && self 
3157+                                 . tcx 
3158+                                 . module_children ( * parent_did) 
3159+                                 . iter ( ) 
3160+                                 . filter ( |child| child. res . opt_def_id ( )  == Some ( * trait_did) ) 
3161+                                 . all ( |child| child. ident . name  == kw:: Underscore ) 
3162+                         { 
3163+                             return  false ; 
3164+                         } 
3165+                     } 
31143166
3115-         let  module_did = self . tcx . parent_module_from_def_id ( self . body_id ) ; 
3116-         let  ( module,  _,  _)  = self . tcx . hir ( ) . get_module ( module_did) ; 
3117-         let  span = module. spans . inject_use_span ; 
3167+                     true 
3168+                 } ) ; 
31183169
3119-         let  path_strings = candidates. iter ( ) . map ( |trait_did| { 
3120-             format ! ( "use {};\n " ,  with_crate_prefix!( self . tcx. def_path_str( * trait_did) ) , ) 
3121-         } ) ; 
3170+             let  prefix = if  visible {  "use "  }  else  {  ""  } ; 
3171+             let  postfix = if  visible {  ";"  }  else  {  ""  } ; 
3172+             let  path_strings = candidates. iter ( ) . map ( |trait_did| { 
3173+                 format ! ( 
3174+                     "{prefix}{}{postfix}\n " , 
3175+                     with_crate_prefix!( self . tcx. def_path_str( * trait_did) ) , 
3176+                 ) 
3177+             } ) ; 
31223178
3123-         let  glob_path_strings = globs. iter ( ) . map ( |trait_did| { 
3124-             let  parent_did = parent_map. get ( trait_did) . unwrap ( ) ; 
3125-             format ! ( 
3126-                 "use {}::*; // trait {}\n " , 
3127-                 with_crate_prefix!( self . tcx. def_path_str( * parent_did) ) , 
3128-                 self . tcx. item_name( * trait_did) , 
3129-             ) 
3130-         } ) ; 
3131-         let  mut  sugg:  Vec < _ >  = path_strings. chain ( glob_path_strings) . collect ( ) ; 
3132-         sugg. sort ( ) ; 
3179+             let  glob_path_strings = globs. iter ( ) . map ( |trait_did| { 
3180+                 let  parent_did = parent_map. get ( trait_did) . unwrap ( ) ; 
3181+                 format ! ( 
3182+                     "{prefix}{}::*{postfix} // trait {}\n " , 
3183+                     with_crate_prefix!( self . tcx. def_path_str( * parent_did) ) , 
3184+                     self . tcx. item_name( * trait_did) , 
3185+                 ) 
3186+             } ) ; 
3187+             let  mut  sugg:  Vec < _ >  = path_strings. chain ( glob_path_strings) . collect ( ) ; 
3188+             sugg. sort ( ) ; 
3189+             sugg
3190+         } ; 
31333191
3134-         err. span_suggestions ( span,  msg,  sugg,  Applicability :: MaybeIncorrect ) ; 
3192+         let  accessible_sugg = sugg ( accessible_candidates,  true ) ; 
3193+         let  inaccessible_sugg = sugg ( inaccessible_candidates,  false ) ; 
3194+ 
3195+         let  ( module,  _,  _)  = self . tcx . hir ( ) . get_module ( scope) ; 
3196+         let  span = module. spans . inject_use_span ; 
3197+         handle_candidates ( accessible_sugg,  inaccessible_sugg,  span) ; 
31353198    } 
31363199
31373200    fn  suggest_valid_traits ( 
@@ -3155,21 +3218,53 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
31553218            if  explain { 
31563219                err. help ( "items from traits can only be used if the trait is in scope" ) ; 
31573220            } 
3221+ 
31583222            let  msg = format ! ( 
3159-                 "{this_trait_is} implemented but not in scope; perhaps you want to import \  
3160- , 
3223+                 "{this_trait_is} implemented but not in scope" , 
31613224                this_trait_is = if  candidates. len( )  == 1  { 
31623225                    format!( 
31633226                        "trait `{}` which provides `{item_name}` is" , 
31643227                        self . tcx. item_name( candidates[ 0 ] ) , 
31653228                    ) 
31663229                }  else { 
31673230                    format!( "the following traits which provide `{item_name}` are" ) 
3168-                 } , 
3169-                 one_of_them = if  candidates. len( )  == 1  {  "it"  }  else {  "one of them"  } , 
3231+                 } 
31703232            ) ; 
31713233
3172-             self . suggest_use_candidates ( err,  msg,  candidates) ; 
3234+             self . suggest_use_candidates ( candidates,  |accessible_sugg,  inaccessible_sugg,  span| { 
3235+                 let  suggest_for_access = |err :  & mut  Diag < ' _ > ,  mut  msg :  String ,  sugg :  Vec < _ > | { 
3236+                     msg += & format ! ( 
3237+                         "; perhaps you want to import {one_of}" , 
3238+                         one_of = if  sugg. len( )  == 1  {  "it"  }  else {  "one of them"  } , 
3239+                     ) ; 
3240+                     err. span_suggestions ( span,  msg,  sugg,  Applicability :: MaybeIncorrect ) ; 
3241+                 } ; 
3242+                 let  suggest_for_privacy = |err :  & mut  Diag < ' _ > ,  sugg :  Vec < String > | { 
3243+                     let  msg = format ! ( 
3244+                         "{this_trait_is} implemented but not reachable" , 
3245+                         this_trait_is = if  sugg. len( )  == 1  { 
3246+                             format!( "trait `{}` which provides `{item_name}` is" ,  sugg[ 0 ] . trim( ) ) 
3247+                         }  else { 
3248+                             format!( "the following traits which provide `{item_name}` are" ) 
3249+                         } 
3250+                     ) ; 
3251+                     if  sugg. len ( )  == 1  { 
3252+                         err. help ( msg) ; 
3253+                     }  else  { 
3254+                         err. span_suggestions ( span,  msg,  sugg,  Applicability :: MaybeIncorrect ) ; 
3255+                     } 
3256+                 } ; 
3257+                 if  accessible_sugg. is_empty ( )  { 
3258+                     // `inaccessible_sugg` must not be empty 
3259+                     suggest_for_privacy ( err,  inaccessible_sugg) ; 
3260+                 }  else  if  inaccessible_sugg. is_empty ( )  { 
3261+                     suggest_for_access ( err,  msg,  accessible_sugg) ; 
3262+                 }  else  { 
3263+                     suggest_for_access ( err,  msg,  accessible_sugg) ; 
3264+                     suggest_for_privacy ( err,  inaccessible_sugg) ; 
3265+                 } 
3266+             } ) ; 
3267+ 
31733268            if  let  Some ( did)  = edition_fix { 
31743269                err. note ( format ! ( 
31753270                    "'{}' is included in the prelude starting in Edition 2021" , 
0 commit comments