@@ -282,14 +282,48 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
282
282
}
283
283
if !candidates. is_empty ( ) {
284
284
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}" ,
287
286
an = if candidates. len( ) == 1 { "an" } else { "" } ,
288
287
s = pluralize!( candidates. len( ) ) ,
289
288
were = pluralize!( "was" , candidates. len( ) ) ,
290
- one_of_them = if candidates. len( ) == 1 { "it" } else { "one_of_them" } ,
291
289
) ;
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
+ ) ;
293
327
}
294
328
if let ty:: Ref ( region, t_type, mutability) = rcvr_ty. kind ( ) {
295
329
if needs_mut {
@@ -3051,49 +3085,69 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
3051
3085
}
3052
3086
}
3053
3087
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
+ {
3055
3092
let parent_map = self . tcx . visible_parent_map ( ( ) ) ;
3056
3093
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
+ } ) ;
3073
3100
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
+ }
3076
3119
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
+ } ) ;
3080
3122
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
+ } ) ;
3084
3131
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
+ } ;
3095
3144
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) ;
3097
3151
}
3098
3152
3099
3153
fn suggest_valid_traits (
@@ -3118,20 +3172,38 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
3118
3172
err. help ( "items from traits can only be used if the trait is in scope" ) ;
3119
3173
}
3120
3174
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" ,
3123
3176
this_trait_is = if candidates. len( ) == 1 {
3124
3177
format!(
3125
3178
"trait `{}` which provides `{item_name}` is" ,
3126
3179
self . tcx. item_name( candidates[ 0 ] ) ,
3127
3180
)
3128
3181
} else {
3129
3182
format!( "the following traits which provide `{item_name}` are" )
3130
- } ,
3131
- one_of_them = if candidates. len( ) == 1 { "it" } else { "one of them" } ,
3183
+ }
3132
3184
) ;
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
+ } ) ;
3133
3206
3134
- self . suggest_use_candidates ( err, msg, candidates) ;
3135
3207
if let Some ( did) = edition_fix {
3136
3208
err. note ( format ! (
3137
3209
"'{}' is included in the prelude starting in Edition 2021" ,
0 commit comments