@@ -103,6 +103,7 @@ pub(crate) struct ImportSuggestion {
103
103
pub descr : & ' static str ,
104
104
pub path : Path ,
105
105
pub accessible : bool ,
106
+ pub via_import : bool ,
106
107
/// An extra note that should be issued if this item is suggested
107
108
pub note : Option < String > ,
108
109
}
@@ -140,9 +141,9 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
140
141
}
141
142
142
143
let mut reported_spans = FxHashSet :: default ( ) ;
143
- for error in & self . privacy_errors {
144
+ for error in std :: mem :: take ( & mut self . privacy_errors ) {
144
145
if reported_spans. insert ( error. dedup_span ) {
145
- self . report_privacy_error ( error) ;
146
+ self . report_privacy_error ( & error) ;
146
147
}
147
148
}
148
149
}
@@ -1256,6 +1257,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
1256
1257
path,
1257
1258
accessible : child_accessible,
1258
1259
note,
1260
+ via_import,
1259
1261
} ) ;
1260
1262
}
1261
1263
}
@@ -1609,8 +1611,9 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
1609
1611
None
1610
1612
}
1611
1613
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;
1614
1617
1615
1618
let res = binding. res ( ) ;
1616
1619
let ctor_fields_span = self . ctor_fields_span ( binding) ;
@@ -1627,6 +1630,33 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
1627
1630
struct_span_err ! ( self . tcx. sess, ident. span, E0603 , "{} `{}` is private" , descr, ident) ;
1628
1631
err. span_label ( ident. span , format ! ( "private {}" , descr) ) ;
1629
1632
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
+
1630
1660
let mut non_exhaustive = None ;
1631
1661
// If an ADT is foreign and marked as `non_exhaustive`, then that's
1632
1662
// probably why we have the privacy error.
@@ -2455,7 +2485,8 @@ pub(crate) fn import_candidates(
2455
2485
2456
2486
/// When an entity with a given name is not available in scope, we search for
2457
2487
/// 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`.
2459
2490
fn show_candidates (
2460
2491
tcx : TyCtxt < ' _ > ,
2461
2492
err : & mut Diagnostic ,
@@ -2467,19 +2498,19 @@ fn show_candidates(
2467
2498
mode : DiagnosticMode ,
2468
2499
path : Vec < Segment > ,
2469
2500
append : & str ,
2470
- ) {
2501
+ ) -> bool {
2471
2502
if candidates. is_empty ( ) {
2472
- return ;
2503
+ return false ;
2473
2504
}
2474
2505
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 ) > =
2476
2507
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 ) > =
2478
2509
Vec :: new ( ) ;
2479
2510
2480
2511
candidates. iter ( ) . for_each ( |c| {
2481
2512
( 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 ) )
2483
2514
} ) ;
2484
2515
2485
2516
// we want consistent results across executions, but candidates are produced
@@ -2493,20 +2524,25 @@ fn show_candidates(
2493
2524
}
2494
2525
2495
2526
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
+ } ;
2501
2538
2502
2539
let instead = if let Instead :: Yes = instead { " instead" } else { "" } ;
2503
2540
let mut msg = if let DiagnosticMode :: Pattern = mode {
2504
2541
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" ,
2507
2543
)
2508
2544
} else {
2509
- format ! ( "consider importing {} {}{}" , determiner , kind , instead)
2545
+ format ! ( "consider importing {determiner } {kind}{through}{ instead}" )
2510
2546
} ;
2511
2547
2512
2548
for note in accessible_path_strings. iter ( ) . flat_map ( |cand| cand. 3 . as_ref ( ) ) {
@@ -2522,7 +2558,7 @@ fn show_candidates(
2522
2558
accessible_path_strings. into_iter ( ) . map ( |a| a. 0 ) ,
2523
2559
Applicability :: MaybeIncorrect ,
2524
2560
) ;
2525
- return ;
2561
+ return true ;
2526
2562
}
2527
2563
DiagnosticMode :: Import => ( "" , "" ) ,
2528
2564
DiagnosticMode :: Normal => ( "use " , ";\n " ) ,
@@ -2563,6 +2599,7 @@ fn show_candidates(
2563
2599
2564
2600
err. help ( msg) ;
2565
2601
}
2602
+ true
2566
2603
} else if !matches ! ( mode, DiagnosticMode :: Import ) {
2567
2604
assert ! ( !inaccessible_path_strings. is_empty( ) ) ;
2568
2605
@@ -2571,13 +2608,9 @@ fn show_candidates(
2571
2608
} else {
2572
2609
""
2573
2610
} ;
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[ ..] {
2576
2612
let msg = format ! (
2577
- "{}{} `{}`{} exists but is inaccessible" ,
2578
- prefix,
2579
- descr,
2580
- name,
2613
+ "{prefix}{descr} `{name}`{} exists but is inaccessible" ,
2581
2614
if let DiagnosticMode :: Pattern = mode { ", which" } else { "" }
2582
2615
) ;
2583
2616
@@ -2594,11 +2627,11 @@ fn show_candidates(
2594
2627
err. note ( note. to_string ( ) ) ;
2595
2628
}
2596
2629
} else {
2597
- let ( _, descr_first, _, _) = & inaccessible_path_strings[ 0 ] ;
2630
+ let ( _, descr_first, _, _, _ ) = & inaccessible_path_strings[ 0 ] ;
2598
2631
let descr = if inaccessible_path_strings
2599
2632
. iter ( )
2600
2633
. skip ( 1 )
2601
- . all ( |( _, descr, _, _) | descr == descr_first)
2634
+ . all ( |( _, descr, _, _, _ ) | descr == descr_first)
2602
2635
{
2603
2636
descr_first
2604
2637
} else {
@@ -2611,7 +2644,7 @@ fn show_candidates(
2611
2644
let mut has_colon = false ;
2612
2645
2613
2646
let mut spans = Vec :: new ( ) ;
2614
- for ( name, _, def_id, _) in & inaccessible_path_strings {
2647
+ for ( name, _, def_id, _, _ ) in & inaccessible_path_strings {
2615
2648
if let Some ( local_def_id) = def_id. and_then ( |did| did. as_local ( ) ) {
2616
2649
let span = tcx. source_span ( local_def_id) ;
2617
2650
let span = tcx. sess . source_map ( ) . guess_head_span ( span) ;
@@ -2637,6 +2670,9 @@ fn show_candidates(
2637
2670
2638
2671
err. span_note ( multi_span, msg) ;
2639
2672
}
2673
+ true
2674
+ } else {
2675
+ false
2640
2676
}
2641
2677
}
2642
2678
0 commit comments