@@ -4,7 +4,7 @@ use rustc_ast::ptr::P;
44use rustc_ast:: visit:: { self , Visitor } ;
55use rustc_ast:: { self as ast, Crate , ItemKind , ModKind , NodeId , Path , CRATE_NODE_ID } ;
66use rustc_ast_pretty:: pprust;
7- use rustc_data_structures:: fx:: FxHashSet ;
7+ use rustc_data_structures:: fx:: { FxHashMap , FxHashSet } ;
88use rustc_errors:: struct_span_err;
99use rustc_errors:: { Applicability , Diagnostic , DiagnosticBuilder , ErrorGuaranteed , MultiSpan } ;
1010use rustc_feature:: BUILTIN_ATTRIBUTES ;
@@ -48,13 +48,15 @@ pub(crate) type Suggestion = (Vec<(Span, String)>, String, Applicability);
4848/// similarly named label and whether or not it is reachable.
4949pub ( crate ) type LabelSuggestion = ( Ident , bool ) ;
5050
51+ #[ derive( Clone , PartialEq , Eq ) ]
5152pub ( crate ) enum SuggestionTarget {
5253 /// The target has a similar name as the name used by the programmer (probably a typo)
5354 SimilarlyNamed ,
5455 /// The target is the only valid item that can be used in the corresponding context
5556 SingleItem ,
5657}
5758
59+ #[ derive( Clone , PartialEq , Eq ) ]
5860pub ( crate ) struct TypoSuggestion {
5961 pub candidate : Symbol ,
6062 pub res : Res ,
@@ -1829,7 +1831,7 @@ impl<'a> Resolver<'a> {
18291831 & mut self ,
18301832 ident : Symbol ,
18311833 ribs : Option < & PerNS < Vec < Rib < ' a > > > > ,
1832- ) -> Option < Symbol > {
1834+ ) -> Option < TypoSuggestion > {
18331835 fn is_type_candidate ( res : Res ) -> bool {
18341836 matches ! (
18351837 res,
@@ -1884,14 +1886,20 @@ impl<'a> Resolver<'a> {
18841886 } ) )
18851887 }
18861888
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 ) ) ;
18891893 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 ( ) ;
18901897
1891- match find_best_match_for_name ( & names , ident, None ) {
1898+ match find_best_match_for_name ( & symbols , ident, None ) {
18921899 Some ( sugg) if sugg == ident => None ,
18931900 sugg => sugg,
18941901 }
1902+ . map ( |sugg| typo_suggestions. get ( & sugg) . unwrap ( ) . clone ( ) )
18951903 }
18961904
18971905 pub ( crate ) fn report_path_resolution_error (
@@ -2061,8 +2069,12 @@ impl<'a> Resolver<'a> {
20612069 } else {
20622070 self . find_similarly_named_type ( ident. name , ribs) . map ( |sugg| {
20632071 (
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+ ) ,
20662078 Applicability :: MaybeIncorrect ,
20672079 )
20682080 } )
@@ -2087,8 +2099,12 @@ impl<'a> Resolver<'a> {
20872099 } else {
20882100 self . find_similarly_named_type ( ident. name , ribs) . map ( |sugg| {
20892101 (
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+ ) ,
20922108 Applicability :: MaybeIncorrect ,
20932109 )
20942110 } )
0 commit comments