@@ -949,7 +949,15 @@ impl<'a> Resolver<'a> {
949
949
950
950
let import_suggestions =
951
951
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
+ ) ;
953
961
954
962
if macro_kind == MacroKind :: Derive && ( ident. name == sym:: Send || ident. name == sym:: Sync ) {
955
963
let msg = format ! ( "unsafe traits like `{}` should be implemented explicitly" , ident) ;
@@ -1689,6 +1697,8 @@ fn find_span_immediately_after_crate_name(
1689
1697
/// entities with that name in all crates. This method allows outputting the
1690
1698
/// results of this search in a programmer-friendly way
1691
1699
crate fn show_candidates (
1700
+ definitions : & rustc_hir:: definitions:: Definitions ,
1701
+ session : & Session ,
1692
1702
err : & mut DiagnosticBuilder < ' _ > ,
1693
1703
// This is `None` if all placement locations are inside expansions
1694
1704
use_placement_span : Option < Span > ,
@@ -1700,22 +1710,22 @@ crate fn show_candidates(
1700
1710
return ;
1701
1711
}
1702
1712
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 ( ) ;
1705
1715
1706
1716
candidates. iter ( ) . for_each ( |c| {
1707
1717
( 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 ) )
1709
1719
} ) ;
1710
1720
1711
1721
// we want consistent results across executions, but candidates are produced
1712
1722
// by iterating through a hash map, so make sure they are ordered:
1713
1723
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 ) ) ;
1715
1725
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 < _ > > ( ) ;
1717
1727
path_strings. extend ( core_path_strings) ;
1718
- path_strings. dedup ( ) ;
1728
+ path_strings. dedup_by ( |a , b| a . 0 == b . 0 ) ;
1719
1729
}
1720
1730
1721
1731
if !accessible_path_strings. is_empty ( ) {
@@ -1755,19 +1765,56 @@ crate fn show_candidates(
1755
1765
} else {
1756
1766
assert ! ( !inaccessible_path_strings. is_empty( ) ) ;
1757
1767
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
+ }
1760
1781
} 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
+ } ;
1763
1792
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 ;
1765
1795
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
+ }
1770
1816
1771
- err. note ( & msg) ;
1817
+ err. span_note ( multi_span, & msg) ;
1818
+ }
1772
1819
}
1773
1820
}
0 commit comments