@@ -4,7 +4,7 @@ use rustc_ast::ptr::P;
4
4
use rustc_ast:: visit:: { self , Visitor } ;
5
5
use rustc_ast:: { self as ast, Crate , ItemKind , ModKind , NodeId , Path , CRATE_NODE_ID } ;
6
6
use rustc_ast_pretty:: pprust;
7
- use rustc_data_structures:: fx:: FxHashSet ;
7
+ use rustc_data_structures:: fx:: { FxHashMap , FxHashSet } ;
8
8
use rustc_errors:: struct_span_err;
9
9
use rustc_errors:: { Applicability , Diagnostic , DiagnosticBuilder , ErrorGuaranteed , MultiSpan } ;
10
10
use rustc_feature:: BUILTIN_ATTRIBUTES ;
@@ -48,13 +48,15 @@ pub(crate) type Suggestion = (Vec<(Span, String)>, String, Applicability);
48
48
/// similarly named label and whether or not it is reachable.
49
49
pub ( crate ) type LabelSuggestion = ( Ident , bool ) ;
50
50
51
+ #[ derive( Clone , PartialEq , Eq ) ]
51
52
pub ( crate ) enum SuggestionTarget {
52
53
/// The target has a similar name as the name used by the programmer (probably a typo)
53
54
SimilarlyNamed ,
54
55
/// The target is the only valid item that can be used in the corresponding context
55
56
SingleItem ,
56
57
}
57
58
59
+ #[ derive( Clone , PartialEq , Eq ) ]
58
60
pub ( crate ) struct TypoSuggestion {
59
61
pub candidate : Symbol ,
60
62
pub res : Res ,
@@ -1829,7 +1831,7 @@ impl<'a> Resolver<'a> {
1829
1831
& mut self ,
1830
1832
ident : Symbol ,
1831
1833
ribs : Option < & PerNS < Vec < Rib < ' a > > > > ,
1832
- ) -> Option < Symbol > {
1834
+ ) -> Option < TypoSuggestion > {
1833
1835
fn is_type_candidate ( res : Res ) -> bool {
1834
1836
matches ! (
1835
1837
res,
@@ -1884,14 +1886,20 @@ impl<'a> Resolver<'a> {
1884
1886
} ) )
1885
1887
}
1886
1888
1887
- let mut names = names. iter ( ) . map ( |sugg| sugg. candidate ) . collect :: < Vec < Symbol > > ( ) ;
1888
- names. sort ( ) ;
1889
+ // We sort names here to ensure that the suggestion is deterministic.
1890
+ // (Notice that there may be a pair of TypoSuggestions whose Symbols
1891
+ // are same but Res are different.)
1892
+ names. sort_by_key ( |name| ( name. candidate , name. res ) ) ;
1889
1893
names. dedup ( ) ;
1894
+ let symbols = names. iter ( ) . map ( |sugg| sugg. candidate ) . collect :: < Vec < Symbol > > ( ) ;
1895
+ let typo_suggestions: FxHashMap < Symbol , TypoSuggestion > =
1896
+ names. into_iter ( ) . map ( |typo_sugg| ( typo_sugg. candidate , typo_sugg) ) . collect ( ) ;
1890
1897
1891
- match find_best_match_for_name ( & names , ident, None ) {
1898
+ match find_best_match_for_name ( & symbols , ident, None ) {
1892
1899
Some ( sugg) if sugg == ident => None ,
1893
1900
sugg => sugg,
1894
1901
}
1902
+ . map ( |sugg| typo_suggestions. get ( & sugg) . unwrap ( ) . clone ( ) )
1895
1903
}
1896
1904
1897
1905
pub ( crate ) fn report_path_resolution_error (
@@ -2061,8 +2069,12 @@ impl<'a> Resolver<'a> {
2061
2069
} else {
2062
2070
self . find_similarly_named_type ( ident. name , ribs) . map ( |sugg| {
2063
2071
(
2064
- vec ! [ ( ident. span, sugg. to_string( ) ) ] ,
2065
- String :: from ( "there is a type with a similar name" ) ,
2072
+ vec ! [ ( ident. span, sugg. candidate. to_string( ) ) ] ,
2073
+ format ! (
2074
+ "there is {} {} with a similar name" ,
2075
+ sugg. res. article( ) ,
2076
+ sugg. res. descr( ) ,
2077
+ ) ,
2066
2078
Applicability :: MaybeIncorrect ,
2067
2079
)
2068
2080
} )
@@ -2087,8 +2099,12 @@ impl<'a> Resolver<'a> {
2087
2099
} else {
2088
2100
self . find_similarly_named_type ( ident. name , ribs) . map ( |sugg| {
2089
2101
(
2090
- vec ! [ ( ident. span, sugg. to_string( ) ) ] ,
2091
- String :: from ( "there is a type with a similar name" ) ,
2102
+ vec ! [ ( ident. span, sugg. candidate. to_string( ) ) ] ,
2103
+ format ! (
2104
+ "there is {} {} with a similar name" ,
2105
+ sugg. res. article( ) ,
2106
+ sugg. res. descr( )
2107
+ ) ,
2092
2108
Applicability :: MaybeIncorrect ,
2093
2109
)
2094
2110
} )
0 commit comments