@@ -103,6 +103,7 @@ pub(crate) struct ImportSuggestion {
103103 pub descr : & ' static str ,
104104 pub path : Path ,
105105 pub accessible : bool ,
106+ pub via_import : bool ,
106107 /// An extra note that should be issued if this item is suggested
107108 pub note : Option < String > ,
108109}
@@ -140,9 +141,9 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
140141 }
141142
142143 let mut reported_spans = FxHashSet :: default ( ) ;
143- for error in & self . privacy_errors {
144+ for error in std :: mem :: take ( & mut self . privacy_errors ) {
144145 if reported_spans. insert ( error. dedup_span ) {
145- self . report_privacy_error ( error) ;
146+ self . report_privacy_error ( & error) ;
146147 }
147148 }
148149 }
@@ -1256,6 +1257,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
12561257 path,
12571258 accessible : child_accessible,
12581259 note,
1260+ via_import,
12591261 } ) ;
12601262 }
12611263 }
@@ -1609,8 +1611,9 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
16091611 None
16101612 }
16111613
1612- fn report_privacy_error ( & self , privacy_error : & PrivacyError < ' _ > ) {
1613- let PrivacyError { ident, binding, .. } = * privacy_error;
1614+ fn report_privacy_error ( & mut self , privacy_error : & PrivacyError < ' a > ) {
1615+ let PrivacyError { ident, binding, outermost_res, parent_scope, dedup_span } =
1616+ * privacy_error;
16141617
16151618 let res = binding. res ( ) ;
16161619 let ctor_fields_span = self . ctor_fields_span ( binding) ;
@@ -1627,6 +1630,33 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
16271630 struct_span_err ! ( self . tcx. sess, ident. span, E0603 , "{} `{}` is private" , descr, ident) ;
16281631 err. span_label ( ident. span , format ! ( "private {}" , descr) ) ;
16291632
1633+ if let Some ( ( this_res, outer_ident) ) = outermost_res {
1634+ let import_suggestions = self . lookup_import_candidates (
1635+ outer_ident,
1636+ this_res. ns ( ) . unwrap_or ( Namespace :: TypeNS ) ,
1637+ & parent_scope,
1638+ & |res : Res | res == this_res,
1639+ ) ;
1640+ let point_to_def = !show_candidates (
1641+ self . tcx ,
1642+ & mut err,
1643+ Some ( dedup_span. until ( outer_ident. span . shrink_to_hi ( ) ) ) ,
1644+ & import_suggestions,
1645+ Instead :: Yes ,
1646+ FoundUse :: Yes ,
1647+ DiagnosticMode :: Import ,
1648+ vec ! [ ] ,
1649+ "" ,
1650+ ) ;
1651+ // If we suggest importing a public re-export, don't point at the definition.
1652+ if point_to_def && ident. span != outer_ident. span {
1653+ err. span_label (
1654+ outer_ident. span ,
1655+ format ! ( "{} `{outer_ident}` is not publicly re-exported" , this_res. descr( ) ) ,
1656+ ) ;
1657+ }
1658+ }
1659+
16301660 let mut non_exhaustive = None ;
16311661 // If an ADT is foreign and marked as `non_exhaustive`, then that's
16321662 // probably why we have the privacy error.
@@ -2455,7 +2485,8 @@ pub(crate) fn import_candidates(
24552485
24562486/// When an entity with a given name is not available in scope, we search for
24572487/// entities with that name in all crates. This method allows outputting the
2458- /// results of this search in a programmer-friendly way
2488+ /// results of this search in a programmer-friendly way. If any entities are
2489+ /// found and suggested, returns `true`, otherwise returns `false`.
24592490fn show_candidates (
24602491 tcx : TyCtxt < ' _ > ,
24612492 err : & mut Diagnostic ,
@@ -2467,19 +2498,19 @@ fn show_candidates(
24672498 mode : DiagnosticMode ,
24682499 path : Vec < Segment > ,
24692500 append : & str ,
2470- ) {
2501+ ) -> bool {
24712502 if candidates. is_empty ( ) {
2472- return ;
2503+ return false ;
24732504 }
24742505
2475- let mut accessible_path_strings: Vec < ( String , & str , Option < DefId > , & Option < String > ) > =
2506+ let mut accessible_path_strings: Vec < ( String , & str , Option < DefId > , & Option < String > , bool ) > =
24762507 Vec :: new ( ) ;
2477- let mut inaccessible_path_strings: Vec < ( String , & str , Option < DefId > , & Option < String > ) > =
2508+ let mut inaccessible_path_strings: Vec < ( String , & str , Option < DefId > , & Option < String > , bool ) > =
24782509 Vec :: new ( ) ;
24792510
24802511 candidates. iter ( ) . for_each ( |c| {
24812512 ( if c. accessible { & mut accessible_path_strings } else { & mut inaccessible_path_strings } )
2482- . push ( ( path_names_to_string ( & c. path ) , c. descr , c. did , & c. note ) )
2513+ . push ( ( path_names_to_string ( & c. path ) , c. descr , c. did , & c. note , c . via_import ) )
24832514 } ) ;
24842515
24852516 // we want consistent results across executions, but candidates are produced
@@ -2493,20 +2524,25 @@ fn show_candidates(
24932524 }
24942525
24952526 if !accessible_path_strings. is_empty ( ) {
2496- let ( determiner, kind, name) = if accessible_path_strings. len ( ) == 1 {
2497- ( "this" , accessible_path_strings[ 0 ] . 1 , format ! ( " `{}`" , accessible_path_strings[ 0 ] . 0 ) )
2498- } else {
2499- ( "one of these" , "items" , String :: new ( ) )
2500- } ;
2527+ let ( determiner, kind, name, through) =
2528+ if let [ ( name, descr, _, _, via_import) ] = & accessible_path_strings[ ..] {
2529+ (
2530+ "this" ,
2531+ * descr,
2532+ format ! ( " `{name}`" ) ,
2533+ if * via_import { " through its public re-export" } else { "" } ,
2534+ )
2535+ } else {
2536+ ( "one of these" , "items" , String :: new ( ) , "" )
2537+ } ;
25012538
25022539 let instead = if let Instead :: Yes = instead { " instead" } else { "" } ;
25032540 let mut msg = if let DiagnosticMode :: Pattern = mode {
25042541 format ! (
2505- "if you meant to match on {}{}{}, use the full path in the pattern" ,
2506- kind, instead, name
2542+ "if you meant to match on {kind}{instead}{name}, use the full path in the pattern" ,
25072543 )
25082544 } else {
2509- format ! ( "consider importing {} {}{}" , determiner , kind , instead)
2545+ format ! ( "consider importing {determiner } {kind}{through}{ instead}" )
25102546 } ;
25112547
25122548 for note in accessible_path_strings. iter ( ) . flat_map ( |cand| cand. 3 . as_ref ( ) ) {
@@ -2522,7 +2558,7 @@ fn show_candidates(
25222558 accessible_path_strings. into_iter ( ) . map ( |a| a. 0 ) ,
25232559 Applicability :: MaybeIncorrect ,
25242560 ) ;
2525- return ;
2561+ return true ;
25262562 }
25272563 DiagnosticMode :: Import => ( "" , "" ) ,
25282564 DiagnosticMode :: Normal => ( "use " , ";\n " ) ,
@@ -2563,6 +2599,7 @@ fn show_candidates(
25632599
25642600 err. help ( msg) ;
25652601 }
2602+ true
25662603 } else if !matches ! ( mode, DiagnosticMode :: Import ) {
25672604 assert ! ( !inaccessible_path_strings. is_empty( ) ) ;
25682605
@@ -2571,13 +2608,9 @@ fn show_candidates(
25712608 } else {
25722609 ""
25732610 } ;
2574- if inaccessible_path_strings. len ( ) == 1 {
2575- let ( name, descr, def_id, note) = & inaccessible_path_strings[ 0 ] ;
2611+ if let [ ( name, descr, def_id, note, _) ] = & inaccessible_path_strings[ ..] {
25762612 let msg = format ! (
2577- "{}{} `{}`{} exists but is inaccessible" ,
2578- prefix,
2579- descr,
2580- name,
2613+ "{prefix}{descr} `{name}`{} exists but is inaccessible" ,
25812614 if let DiagnosticMode :: Pattern = mode { ", which" } else { "" }
25822615 ) ;
25832616
@@ -2594,11 +2627,11 @@ fn show_candidates(
25942627 err. note ( note. to_string ( ) ) ;
25952628 }
25962629 } else {
2597- let ( _, descr_first, _, _) = & inaccessible_path_strings[ 0 ] ;
2630+ let ( _, descr_first, _, _, _ ) = & inaccessible_path_strings[ 0 ] ;
25982631 let descr = if inaccessible_path_strings
25992632 . iter ( )
26002633 . skip ( 1 )
2601- . all ( |( _, descr, _, _) | descr == descr_first)
2634+ . all ( |( _, descr, _, _, _ ) | descr == descr_first)
26022635 {
26032636 descr_first
26042637 } else {
@@ -2611,7 +2644,7 @@ fn show_candidates(
26112644 let mut has_colon = false ;
26122645
26132646 let mut spans = Vec :: new ( ) ;
2614- for ( name, _, def_id, _) in & inaccessible_path_strings {
2647+ for ( name, _, def_id, _, _ ) in & inaccessible_path_strings {
26152648 if let Some ( local_def_id) = def_id. and_then ( |did| did. as_local ( ) ) {
26162649 let span = tcx. source_span ( local_def_id) ;
26172650 let span = tcx. sess . source_map ( ) . guess_head_span ( span) ;
@@ -2637,6 +2670,9 @@ fn show_candidates(
26372670
26382671 err. span_note ( multi_span, msg) ;
26392672 }
2673+ true
2674+ } else {
2675+ false
26402676 }
26412677}
26422678
0 commit comments