@@ -949,7 +949,15 @@ impl<'a> Resolver<'a> {
949949
950950 let import_suggestions =
951951 self . lookup_import_candidates ( ident, Namespace :: MacroNS , parent_scope, is_expected) ;
952- show_candidates ( err, None , & import_suggestions, false , true ) ;
952+ show_candidates (
953+ & self . definitions ,
954+ self . session ,
955+ err,
956+ None ,
957+ & import_suggestions,
958+ false ,
959+ true ,
960+ ) ;
953961
954962 if macro_kind == MacroKind :: Derive && ( ident. name == sym:: Send || ident. name == sym:: Sync ) {
955963 let msg = format ! ( "unsafe traits like `{}` should be implemented explicitly" , ident) ;
@@ -1689,6 +1697,8 @@ fn find_span_immediately_after_crate_name(
16891697/// entities with that name in all crates. This method allows outputting the
16901698/// results of this search in a programmer-friendly way
16911699crate fn show_candidates (
1700+ definitions : & rustc_hir:: definitions:: Definitions ,
1701+ session : & Session ,
16921702 err : & mut DiagnosticBuilder < ' _ > ,
16931703 // This is `None` if all placement locations are inside expansions
16941704 use_placement_span : Option < Span > ,
@@ -1700,22 +1710,22 @@ crate fn show_candidates(
17001710 return ;
17011711 }
17021712
1703- let mut accessible_path_strings: Vec < ( String , & str ) > = Vec :: new ( ) ;
1704- let mut inaccessible_path_strings: Vec < ( String , & str ) > = Vec :: new ( ) ;
1713+ let mut accessible_path_strings: Vec < ( String , & str , Option < DefId > ) > = Vec :: new ( ) ;
1714+ let mut inaccessible_path_strings: Vec < ( String , & str , Option < DefId > ) > = Vec :: new ( ) ;
17051715
17061716 candidates. iter ( ) . for_each ( |c| {
17071717 ( if c. accessible { & mut accessible_path_strings } else { & mut inaccessible_path_strings } )
1708- . push ( ( path_names_to_string ( & c. path ) , c. descr ) )
1718+ . push ( ( path_names_to_string ( & c. path ) , c. descr , c . did ) )
17091719 } ) ;
17101720
17111721 // we want consistent results across executions, but candidates are produced
17121722 // by iterating through a hash map, so make sure they are ordered:
17131723 for path_strings in [ & mut accessible_path_strings, & mut inaccessible_path_strings] {
1714- path_strings. sort ( ) ;
1724+ path_strings. sort_by ( |a , b| a . 0 . cmp ( & b . 0 ) ) ;
17151725 let core_path_strings =
1716- path_strings. drain_filter ( |p| p. starts_with ( "core::" ) ) . collect :: < Vec < String > > ( ) ;
1726+ path_strings. drain_filter ( |p| p. 0 . starts_with ( "core::" ) ) . collect :: < Vec < _ > > ( ) ;
17171727 path_strings. extend ( core_path_strings) ;
1718- path_strings. dedup ( ) ;
1728+ path_strings. dedup_by ( |a , b| a . 0 == b . 0 ) ;
17191729 }
17201730
17211731 if !accessible_path_strings. is_empty ( ) {
@@ -1755,19 +1765,56 @@ crate fn show_candidates(
17551765 } else {
17561766 assert ! ( !inaccessible_path_strings. is_empty( ) ) ;
17571767
1758- let ( determiner, kind, verb1, verb2) = if inaccessible_path_strings. len ( ) == 1 {
1759- ( "this" , inaccessible_path_strings[ 0 ] . 1 , "exists" , "is" )
1768+ if inaccessible_path_strings. len ( ) == 1 {
1769+ let ( name, descr, def_id) = & inaccessible_path_strings[ 0 ] ;
1770+ let msg = format ! ( "{} `{}` exists but is inaccessible" , descr, name) ;
1771+
1772+ if let Some ( local_def_id) = def_id. and_then ( |did| did. as_local ( ) ) {
1773+ let span = definitions. def_span ( local_def_id) ;
1774+ let span = session. source_map ( ) . guess_head_span ( span) ;
1775+ let mut multi_span = MultiSpan :: from_span ( span) ;
1776+ multi_span. push_span_label ( span, "not accessible" . to_string ( ) ) ;
1777+ err. span_note ( multi_span, & msg) ;
1778+ } else {
1779+ err. note ( & msg) ;
1780+ }
17601781 } else {
1761- ( "these" , "items" , "exist" , "are" )
1762- } ;
1782+ let ( _, descr_first, _) = & inaccessible_path_strings[ 0 ] ;
1783+ let descr = if inaccessible_path_strings
1784+ . iter ( )
1785+ . skip ( 1 )
1786+ . all ( |( _, descr, _) | descr == descr_first)
1787+ {
1788+ format ! ( "{}" , descr_first)
1789+ } else {
1790+ "item" . to_string ( )
1791+ } ;
17631792
1764- let mut msg = format ! ( "{} {} {} but {} inaccessible:" , determiner, kind, verb1, verb2) ;
1793+ let mut msg = format ! ( "these {}s exist but are inaccessible" , descr) ;
1794+ let mut has_colon = false ;
17651795
1766- for candidate in inaccessible_path_strings {
1767- msg. push ( '\n' ) ;
1768- msg. push_str ( & candidate. 0 ) ;
1769- }
1796+ let mut spans = Vec :: new ( ) ;
1797+ for ( name, _, def_id) in & inaccessible_path_strings {
1798+ if let Some ( local_def_id) = def_id. and_then ( |did| did. as_local ( ) ) {
1799+ let span = definitions. def_span ( local_def_id) ;
1800+ let span = session. source_map ( ) . guess_head_span ( span) ;
1801+ spans. push ( ( name, span) ) ;
1802+ } else {
1803+ if !has_colon {
1804+ msg. push ( ':' ) ;
1805+ has_colon = true ;
1806+ }
1807+ msg. push ( '\n' ) ;
1808+ msg. push_str ( name) ;
1809+ }
1810+ }
1811+
1812+ let mut multi_span = MultiSpan :: from_spans ( spans. iter ( ) . map ( |( _, sp) | * sp) . collect ( ) ) ;
1813+ for ( name, span) in spans {
1814+ multi_span. push_span_label ( span, format ! ( "`{}`: not accessible" , name) ) ;
1815+ }
17701816
1771- err. note ( & msg) ;
1817+ err. span_note ( multi_span, & msg) ;
1818+ }
17721819 }
17731820}
0 commit comments