@@ -282,14 +282,48 @@ 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 < ' _ > , msg : String , sugg : Vec < _ > | {
309+ err. span_suggestions (
310+ span,
311+ msg,
312+ sugg,
313+ Applicability :: MaybeIncorrect ,
314+ ) ;
315+ } ;
316+ if accessible_sugg. is_empty ( ) {
317+ // `inaccessible_sugg` must not be empty
318+ suggest_for_privacy ( & mut err, help, inaccessible_sugg) ;
319+ } else if inaccessible_sugg. is_empty ( ) {
320+ suggest_for_access ( & mut err, help, accessible_sugg) ;
321+ } else {
322+ suggest_for_access ( & mut err, help. clone ( ) , accessible_sugg) ;
323+ suggest_for_privacy ( & mut err, help, inaccessible_sugg) ;
324+ }
325+ } ,
326+ ) ;
293327 }
294328 if let ty:: Ref ( region, t_type, mutability) = rcvr_ty. kind ( ) {
295329 if needs_mut {
@@ -3051,49 +3085,69 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
30513085 }
30523086 }
30533087
3054- fn suggest_use_candidates ( & self , err : & mut Diag < ' _ > , msg : String , candidates : Vec < DefId > ) {
3088+ fn suggest_use_candidates < F > ( & self , candidates : Vec < DefId > , handle_candidates : F )
3089+ where
3090+ F : FnOnce ( Vec < String > , Vec < String > , Span ) ,
3091+ {
30553092 let parent_map = self . tcx . visible_parent_map ( ( ) ) ;
30563093
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- }
3094+ let scope = self . tcx . parent_module_from_def_id ( self . body_id ) ;
3095+ let ( accessible_candidates, inaccessible_candidates) : ( Vec < _ > , Vec < _ > ) =
3096+ candidates. into_iter ( ) . partition ( |id| {
3097+ let vis = self . tcx . visibility ( * id) ;
3098+ vis. is_accessible_from ( scope, self . tcx )
3099+ } ) ;
30733100
3074- true
3075- } ) ;
3101+ let sugg = |candidates : Vec < _ > , visible| {
3102+ // Separate out candidates that must be imported with a glob, because they are named `_`
3103+ // and cannot be referred with their identifier.
3104+ let ( candidates, globs) : ( Vec < _ > , Vec < _ > ) =
3105+ candidates. into_iter ( ) . partition ( |trait_did| {
3106+ if let Some ( parent_did) = parent_map. get ( trait_did) {
3107+ // If the item is re-exported as `_`, we should suggest a glob-import instead.
3108+ if * parent_did != self . tcx . parent ( * trait_did)
3109+ && self
3110+ . tcx
3111+ . module_children ( * parent_did)
3112+ . iter ( )
3113+ . filter ( |child| child. res . opt_def_id ( ) == Some ( * trait_did) )
3114+ . all ( |child| child. ident . name == kw:: Underscore )
3115+ {
3116+ return false ;
3117+ }
3118+ }
30763119
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 ;
3120+ true
3121+ } ) ;
30803122
3081- let path_strings = candidates. iter ( ) . map ( |trait_did| {
3082- format ! ( "use {};\n " , with_crate_prefix!( self . tcx. def_path_str( * trait_did) ) , )
3083- } ) ;
3123+ let prefix = if visible { "use " } else { "" } ;
3124+ let postfix = if visible { ";" } else { "" } ;
3125+ let path_strings = candidates. iter ( ) . map ( |trait_did| {
3126+ format ! (
3127+ "{prefix}{}{postfix}\n " ,
3128+ with_crate_prefix!( self . tcx. def_path_str( * trait_did) ) ,
3129+ )
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}{}::*{postfix} // 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+ } ;
30953144
3096- err. span_suggestions ( span, msg, sugg, Applicability :: MaybeIncorrect ) ;
3145+ let accessible_sugg = sugg ( accessible_candidates, true ) ;
3146+ let inaccessible_sugg = sugg ( inaccessible_candidates, false ) ;
3147+
3148+ let ( module, _, _) = self . tcx . hir ( ) . get_module ( scope) ;
3149+ let span = module. spans . inject_use_span ;
3150+ handle_candidates ( accessible_sugg, inaccessible_sugg, span) ;
30973151 }
30983152
30993153 fn suggest_valid_traits (
@@ -3118,20 +3172,38 @@ 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 < ' _ > , msg : String , sugg : Vec < _ > | {
3194+ err. span_suggestions ( span, msg, sugg, Applicability :: MaybeIncorrect ) ;
3195+ } ;
3196+ if accessible_sugg. is_empty ( ) {
3197+ // `inaccessible_sugg` must not be empty
3198+ suggest_for_privacy ( err, msg, inaccessible_sugg) ;
3199+ } else if inaccessible_sugg. is_empty ( ) {
3200+ suggest_for_access ( err, msg, accessible_sugg) ;
3201+ } else {
3202+ suggest_for_access ( err, msg. clone ( ) , accessible_sugg) ;
3203+ suggest_for_privacy ( err, msg, inaccessible_sugg) ;
3204+ }
3205+ } ) ;
31333206
3134- self . suggest_use_candidates ( err, msg, candidates) ;
31353207 if let Some ( did) = edition_fix {
31363208 err. note ( format ! (
31373209 "'{}' is included in the prelude starting in Edition 2021" ,
0 commit comments