@@ -973,7 +973,15 @@ impl<'a> Resolver<'a> {
973
973
974
974
let import_suggestions =
975
975
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
+ ) ;
977
985
978
986
if macro_kind == MacroKind :: Derive && ( ident. name == sym:: Send || ident. name == sym:: Sync ) {
979
987
let msg = format ! ( "unsafe traits like `{}` should be implemented explicitly" , ident) ;
@@ -1713,6 +1721,8 @@ fn find_span_immediately_after_crate_name(
1713
1721
/// entities with that name in all crates. This method allows outputting the
1714
1722
/// results of this search in a programmer-friendly way
1715
1723
crate fn show_candidates (
1724
+ definitions : & rustc_hir:: definitions:: Definitions ,
1725
+ session : & Session ,
1716
1726
err : & mut DiagnosticBuilder < ' _ > ,
1717
1727
// This is `None` if all placement locations are inside expansions
1718
1728
use_placement_span : Option < Span > ,
@@ -1724,43 +1734,111 @@ crate fn show_candidates(
1724
1734
return ;
1725
1735
}
1726
1736
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
+
1727
1745
// we want consistent results across executions, but candidates are produced
1728
1746
// 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
+ } ;
1731
1761
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) ;
1737
1764
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
+ }
1754
1772
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 ( ':' ) ;
1758
1781
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) ;
1762
1788
}
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 ;
1763
1819
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
+ }
1765
1843
}
1766
1844
}
0 commit comments