@@ -282,14 +282,52 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
282282 }
283283 if !candidates. is_empty ( ) {
284284 let help = format ! (
285- "{an}other candidate{s} {were} found in the following trait{s}, perhaps \
286- add a `use` for {one_of_them}:",
285+ "{an}other candidate{s} {were} found in the following trait{s}," ,
287286 an = if candidates. len( ) == 1 { "an" } else { "" } ,
288287 s = pluralize!( candidates. len( ) ) ,
289288 were = pluralize!( "was" , candidates. len( ) ) ,
290- one_of_them = if candidates. len( ) == 1 { "it" } else { "one_of_them" } ,
291289 ) ;
292- self . suggest_use_candidates ( & mut err, help, candidates) ;
290+ self . suggest_use_candidates (
291+ candidates,
292+ |accessible_sugg, inaccessible_sugg, span| {
293+ let suggest_for_access =
294+ |err : & mut Diag < ' _ > , mut msg : String , sugg : Vec < _ > | {
295+ msg += & format ! (
296+ " perhaps add a `use` for {one_of_them}:" ,
297+ one_of_them =
298+ if sugg. len( ) == 1 { "it" } else { "one_of_them" } ,
299+ ) ;
300+ err. span_suggestions (
301+ span,
302+ msg,
303+ sugg,
304+ Applicability :: MaybeIncorrect ,
305+ ) ;
306+ } ;
307+ let suggest_for_privacy =
308+ |err : & mut Diag < ' _ > , mut msg : String , sugg : Vec < _ > | {
309+ msg += & format ! (
310+ " perhaps you want to modify {one_of}the visibility and use it" ,
311+ one_of = if sugg. len( ) == 1 { "" } else { "one of " } ,
312+ ) ;
313+ err. span_suggestions (
314+ span,
315+ msg,
316+ sugg,
317+ Applicability :: MaybeIncorrect ,
318+ ) ;
319+ } ;
320+ if accessible_sugg. is_empty ( ) {
321+ // `inaccessible_sugg` must not be empty
322+ suggest_for_privacy ( & mut err, help, inaccessible_sugg) ;
323+ } else if inaccessible_sugg. is_empty ( ) {
324+ suggest_for_access ( & mut err, help, accessible_sugg) ;
325+ } else {
326+ suggest_for_access ( & mut err, help. clone ( ) , accessible_sugg) ;
327+ suggest_for_privacy ( & mut err, help, inaccessible_sugg) ;
328+ }
329+ } ,
330+ ) ;
293331 }
294332 if let ty:: Ref ( region, t_type, mutability) = rcvr_ty. kind ( ) {
295333 if needs_mut {
@@ -3051,49 +3089,65 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
30513089 }
30523090 }
30533091
3054- fn suggest_use_candidates ( & self , err : & mut Diag < ' _ > , msg : String , candidates : Vec < DefId > ) {
3092+ fn suggest_use_candidates < F > ( & self , candidates : Vec < DefId > , f : F )
3093+ where
3094+ F : FnOnce ( Vec < String > , Vec < String > , Span ) ,
3095+ {
30553096 let parent_map = self . tcx . visible_parent_map ( ( ) ) ;
30563097
3057- // Separate out candidates that must be imported with a glob, because they are named `_`
3058- // and cannot be referred with their identifier.
3059- let ( candidates, globs) : ( Vec < _ > , Vec < _ > ) = candidates. into_iter ( ) . partition ( |trait_did| {
3060- if let Some ( parent_did) = parent_map. get ( trait_did) {
3061- // If the item is re-exported as `_`, we should suggest a glob-import instead.
3062- if * parent_did != self . tcx . parent ( * trait_did)
3063- && self
3064- . tcx
3065- . module_children ( * parent_did)
3066- . iter ( )
3067- . filter ( |child| child. res . opt_def_id ( ) == Some ( * trait_did) )
3068- . all ( |child| child. ident . name == kw:: Underscore )
3069- {
3070- return false ;
3071- }
3072- }
3098+ let scope = self . tcx . parent_module_from_def_id ( self . body_id ) ;
3099+ let ( accessible_candidates, inaccessible_candidates) : ( Vec < _ > , Vec < _ > ) =
3100+ candidates. into_iter ( ) . partition ( |id| {
3101+ let vis = self . tcx . visibility ( * id) ;
3102+ vis. is_accessible_from ( scope, self . tcx )
3103+ } ) ;
30733104
3074- true
3075- } ) ;
3105+ let sugg = |candidates : Vec < _ > , visible| {
3106+ // Separate out candidates that must be imported with a glob, because they are named `_`
3107+ // and cannot be referred with their identifier.
3108+ let ( candidates, globs) : ( Vec < _ > , Vec < _ > ) =
3109+ candidates. into_iter ( ) . partition ( |trait_did| {
3110+ if let Some ( parent_did) = parent_map. get ( trait_did) {
3111+ // If the item is re-exported as `_`, we should suggest a glob-import instead.
3112+ if * parent_did != self . tcx . parent ( * trait_did)
3113+ && self
3114+ . tcx
3115+ . module_children ( * parent_did)
3116+ . iter ( )
3117+ . filter ( |child| child. res . opt_def_id ( ) == Some ( * trait_did) )
3118+ . all ( |child| child. ident . name == kw:: Underscore )
3119+ {
3120+ return false ;
3121+ }
3122+ }
30763123
3077- let module_did = self . tcx . parent_module_from_def_id ( self . body_id ) ;
3078- let ( module, _, _) = self . tcx . hir ( ) . get_module ( module_did) ;
3079- let span = module. spans . inject_use_span ;
3124+ true
3125+ } ) ;
30803126
3081- let path_strings = candidates. iter ( ) . map ( |trait_did| {
3082- format ! ( "use {};\n " , with_crate_prefix!( self . tcx. def_path_str( * trait_did) ) , )
3083- } ) ;
3127+ let prefix = if visible { "use " } else { "" } ;
3128+ let path_strings = candidates. iter ( ) . map ( |trait_did| {
3129+ format ! ( "{prefix}{};\n " , with_crate_prefix!( self . tcx. def_path_str( * trait_did) ) , )
3130+ } ) ;
30843131
3085- let glob_path_strings = globs. iter ( ) . map ( |trait_did| {
3086- let parent_did = parent_map. get ( trait_did) . unwrap ( ) ;
3087- format ! (
3088- "use {}::*; // trait {}\n " ,
3089- with_crate_prefix!( self . tcx. def_path_str( * parent_did) ) ,
3090- self . tcx. item_name( * trait_did) ,
3091- )
3092- } ) ;
3093- let mut sugg: Vec < _ > = path_strings. chain ( glob_path_strings) . collect ( ) ;
3094- sugg. sort ( ) ;
3132+ let glob_path_strings = globs. iter ( ) . map ( |trait_did| {
3133+ let parent_did = parent_map. get ( trait_did) . unwrap ( ) ;
3134+ format ! (
3135+ "{prefix}{}::*; // trait {}\n " ,
3136+ with_crate_prefix!( self . tcx. def_path_str( * parent_did) ) ,
3137+ self . tcx. item_name( * trait_did) ,
3138+ )
3139+ } ) ;
3140+ let mut sugg: Vec < _ > = path_strings. chain ( glob_path_strings) . collect ( ) ;
3141+ sugg. sort ( ) ;
3142+ sugg
3143+ } ;
3144+
3145+ let accessible_sugg = sugg ( accessible_candidates, true ) ;
3146+ let inaccessible_sugg = sugg ( inaccessible_candidates, false ) ;
30953147
3096- err. span_suggestions ( span, msg, sugg, Applicability :: MaybeIncorrect ) ;
3148+ let ( module, _, _) = self . tcx . hir ( ) . get_module ( scope) ;
3149+ let span = module. spans . inject_use_span ;
3150+ f ( accessible_sugg, inaccessible_sugg, span) ;
30973151 }
30983152
30993153 fn suggest_valid_traits (
@@ -3118,20 +3172,43 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
31183172 err. help ( "items from traits can only be used if the trait is in scope" ) ;
31193173 }
31203174 let msg = format ! (
3121- "{this_trait_is} implemented but not in scope; perhaps you want to import \
3122- {one_of_them}",
3175+ "{this_trait_is} implemented but not in scope;" ,
31233176 this_trait_is = if candidates. len( ) == 1 {
31243177 format!(
31253178 "trait `{}` which provides `{item_name}` is" ,
31263179 self . tcx. item_name( candidates[ 0 ] ) ,
31273180 )
31283181 } else {
31293182 format!( "the following traits which provide `{item_name}` are" )
3130- } ,
3131- one_of_them = if candidates. len( ) == 1 { "it" } else { "one of them" } ,
3183+ }
31323184 ) ;
3185+ self . suggest_use_candidates ( candidates, |accessible_sugg, inaccessible_sugg, span| {
3186+ let suggest_for_access = |err : & mut Diag < ' _ > , mut msg : String , sugg : Vec < _ > | {
3187+ msg += & format ! (
3188+ " perhaps you want to import {one_of}" ,
3189+ one_of = if sugg. len( ) == 1 { "it" } else { "one of them" } ,
3190+ ) ;
3191+ err. span_suggestions ( span, msg, sugg, Applicability :: MaybeIncorrect ) ;
3192+ } ;
3193+ let suggest_for_privacy = |err : & mut Diag < ' _ > , mut msg : String , sugg : Vec < _ > | {
3194+ msg += & format ! (
3195+ " perhaps you want to use {one_of}the inaccessible trait{s}" ,
3196+ one_of = if sugg. len( ) == 1 { "" } else { "one of " } ,
3197+ s = pluralize!( sugg. len( ) )
3198+ ) ;
3199+ err. span_suggestions ( span, msg, sugg, Applicability :: MaybeIncorrect ) ;
3200+ } ;
3201+ if accessible_sugg. is_empty ( ) {
3202+ // `inaccessible_sugg` must not be empty
3203+ suggest_for_privacy ( err, msg, inaccessible_sugg) ;
3204+ } else if inaccessible_sugg. is_empty ( ) {
3205+ suggest_for_access ( err, msg, accessible_sugg) ;
3206+ } else {
3207+ suggest_for_access ( err, msg. clone ( ) , accessible_sugg) ;
3208+ suggest_for_privacy ( err, msg, inaccessible_sugg) ;
3209+ }
3210+ } ) ;
31333211
3134- self . suggest_use_candidates ( err, msg, candidates) ;
31353212 if let Some ( did) = edition_fix {
31363213 err. note ( format ! (
31373214 "'{}' is included in the prelude starting in Edition 2021" ,
0 commit comments