@@ -282,14 +282,52 @@ 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 < ' _ > , 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
+ ) ;
293
331
}
294
332
if let ty:: Ref ( region, t_type, mutability) = rcvr_ty. kind ( ) {
295
333
if needs_mut {
@@ -3051,49 +3089,65 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
3051
3089
}
3052
3090
}
3053
3091
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
+ {
3055
3096
let parent_map = self . tcx . visible_parent_map ( ( ) ) ;
3056
3097
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
+ } ) ;
3073
3104
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
+ }
3076
3123
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
+ } ) ;
3080
3126
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
+ } ) ;
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}{}::*; // 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 ) ;
3095
3147
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) ;
3097
3151
}
3098
3152
3099
3153
fn suggest_valid_traits (
@@ -3118,20 +3172,43 @@ 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 < ' _ > , 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
+ } ) ;
3133
3211
3134
- self . suggest_use_candidates ( err, msg, candidates) ;
3135
3212
if let Some ( did) = edition_fix {
3136
3213
err. note ( format ! (
3137
3214
"'{}' is included in the prelude starting in Edition 2021" ,
0 commit comments