@@ -973,7 +973,15 @@ impl<'a> Resolver<'a> {
973973
974974 let import_suggestions =
975975 self . lookup_import_candidates ( ident, Namespace :: MacroNS , parent_scope, is_expected) ;
976- show_candidates ( err, None , & import_suggestions, false , true ) ;
976+ show_candidates (
977+ & self . definitions ,
978+ self . session ,
979+ err,
980+ None ,
981+ & import_suggestions,
982+ false ,
983+ true ,
984+ ) ;
977985
978986 if macro_kind == MacroKind :: Derive && ( ident. name == sym:: Send || ident. name == sym:: Sync ) {
979987 let msg = format ! ( "unsafe traits like `{}` should be implemented explicitly" , ident) ;
@@ -1713,6 +1721,8 @@ fn find_span_immediately_after_crate_name(
17131721/// entities with that name in all crates. This method allows outputting the
17141722/// results of this search in a programmer-friendly way
17151723crate fn show_candidates (
1724+ definitions : & rustc_hir:: definitions:: Definitions ,
1725+ session : & Session ,
17161726 err : & mut DiagnosticBuilder < ' _ > ,
17171727 // This is `None` if all placement locations are inside expansions
17181728 use_placement_span : Option < Span > ,
@@ -1724,43 +1734,111 @@ crate fn show_candidates(
17241734 return ;
17251735 }
17261736
1737+ let mut accessible_path_strings: Vec < ( String , & str , Option < DefId > ) > = Vec :: new ( ) ;
1738+ let mut inaccessible_path_strings: Vec < ( String , & str , Option < DefId > ) > = Vec :: new ( ) ;
1739+
1740+ candidates. iter ( ) . for_each ( |c| {
1741+ ( if c. accessible { & mut accessible_path_strings } else { & mut inaccessible_path_strings } )
1742+ . push ( ( path_names_to_string ( & c. path ) , c. descr , c. did ) )
1743+ } ) ;
1744+
17271745 // we want consistent results across executions, but candidates are produced
17281746 // by iterating through a hash map, so make sure they are ordered:
1729- let mut path_strings: Vec < _ > =
1730- candidates. iter ( ) . map ( |c| path_names_to_string ( & c. path ) ) . collect ( ) ;
1747+ for path_strings in [ & mut accessible_path_strings, & mut inaccessible_path_strings] {
1748+ path_strings. sort_by ( |a, b| a. 0 . cmp ( & b. 0 ) ) ;
1749+ let core_path_strings =
1750+ path_strings. drain_filter ( |p| p. 0 . starts_with ( "core::" ) ) . collect :: < Vec < _ > > ( ) ;
1751+ path_strings. extend ( core_path_strings) ;
1752+ path_strings. dedup_by ( |a, b| a. 0 == b. 0 ) ;
1753+ }
1754+
1755+ if !accessible_path_strings. is_empty ( ) {
1756+ let ( determiner, kind) = if accessible_path_strings. len ( ) == 1 {
1757+ ( "this" , accessible_path_strings[ 0 ] . 1 )
1758+ } else {
1759+ ( "one of these" , "items" )
1760+ } ;
17311761
1732- path_strings. sort ( ) ;
1733- let core_path_strings =
1734- path_strings. drain_filter ( |p| p. starts_with ( "core::" ) ) . collect :: < Vec < String > > ( ) ;
1735- path_strings. extend ( core_path_strings) ;
1736- path_strings. dedup ( ) ;
1762+ let instead = if instead { " instead" } else { "" } ;
1763+ let mut msg = format ! ( "consider importing {} {}{}" , determiner, kind, instead) ;
17371764
1738- let ( determiner, kind) = if candidates. len ( ) == 1 {
1739- ( "this" , candidates[ 0 ] . descr )
1740- } else {
1741- ( "one of these" , "items" )
1742- } ;
1743-
1744- let instead = if instead { " instead" } else { "" } ;
1745- let mut msg = format ! ( "consider importing {} {}{}" , determiner, kind, instead) ;
1746-
1747- if let Some ( span) = use_placement_span {
1748- for candidate in & mut path_strings {
1749- // produce an additional newline to separate the new use statement
1750- // from the directly following item.
1751- let additional_newline = if found_use { "" } else { "\n " } ;
1752- * candidate = format ! ( "use {};\n {}" , candidate, additional_newline) ;
1753- }
1765+ if let Some ( span) = use_placement_span {
1766+ for candidate in & mut accessible_path_strings {
1767+ // produce an additional newline to separate the new use statement
1768+ // from the directly following item.
1769+ let additional_newline = if found_use { "" } else { "\n " } ;
1770+ candidate. 0 = format ! ( "use {};\n {}" , & candidate. 0 , additional_newline) ;
1771+ }
17541772
1755- err. span_suggestions ( span, & msg, path_strings. into_iter ( ) , Applicability :: Unspecified ) ;
1756- } else {
1757- msg. push ( ':' ) ;
1773+ err. span_suggestions (
1774+ span,
1775+ & msg,
1776+ accessible_path_strings. into_iter ( ) . map ( |a| a. 0 ) ,
1777+ Applicability :: Unspecified ,
1778+ ) ;
1779+ } else {
1780+ msg. push ( ':' ) ;
17581781
1759- for candidate in path_strings {
1760- msg. push ( '\n' ) ;
1761- msg. push_str ( & candidate) ;
1782+ for candidate in accessible_path_strings {
1783+ msg. push ( '\n' ) ;
1784+ msg. push_str ( & candidate. 0 ) ;
1785+ }
1786+
1787+ err. note ( & msg) ;
17621788 }
1789+ } else {
1790+ assert ! ( !inaccessible_path_strings. is_empty( ) ) ;
1791+
1792+ if inaccessible_path_strings. len ( ) == 1 {
1793+ let ( name, descr, def_id) = & inaccessible_path_strings[ 0 ] ;
1794+ let msg = format ! ( "{} `{}` exists but is inaccessible" , descr, name) ;
1795+
1796+ if let Some ( local_def_id) = def_id. and_then ( |did| did. as_local ( ) ) {
1797+ let span = definitions. def_span ( local_def_id) ;
1798+ let span = session. source_map ( ) . guess_head_span ( span) ;
1799+ let mut multi_span = MultiSpan :: from_span ( span) ;
1800+ multi_span. push_span_label ( span, "not accessible" . to_string ( ) ) ;
1801+ err. span_note ( multi_span, & msg) ;
1802+ } else {
1803+ err. note ( & msg) ;
1804+ }
1805+ } else {
1806+ let ( _, descr_first, _) = & inaccessible_path_strings[ 0 ] ;
1807+ let descr = if inaccessible_path_strings
1808+ . iter ( )
1809+ . skip ( 1 )
1810+ . all ( |( _, descr, _) | descr == descr_first)
1811+ {
1812+ format ! ( "{}" , descr_first)
1813+ } else {
1814+ "item" . to_string ( )
1815+ } ;
1816+
1817+ let mut msg = format ! ( "these {}s exist but are inaccessible" , descr) ;
1818+ let mut has_colon = false ;
17631819
1764- err. note ( & msg) ;
1820+ let mut spans = Vec :: new ( ) ;
1821+ for ( name, _, def_id) in & inaccessible_path_strings {
1822+ if let Some ( local_def_id) = def_id. and_then ( |did| did. as_local ( ) ) {
1823+ let span = definitions. def_span ( local_def_id) ;
1824+ let span = session. source_map ( ) . guess_head_span ( span) ;
1825+ spans. push ( ( name, span) ) ;
1826+ } else {
1827+ if !has_colon {
1828+ msg. push ( ':' ) ;
1829+ has_colon = true ;
1830+ }
1831+ msg. push ( '\n' ) ;
1832+ msg. push_str ( name) ;
1833+ }
1834+ }
1835+
1836+ let mut multi_span = MultiSpan :: from_spans ( spans. iter ( ) . map ( |( _, sp) | * sp) . collect ( ) ) ;
1837+ for ( name, span) in spans {
1838+ multi_span. push_span_label ( span, format ! ( "`{}`: not accessible" , name) ) ;
1839+ }
1840+
1841+ err. span_note ( multi_span, & msg) ;
1842+ }
17651843 }
17661844}
0 commit comments