@@ -708,7 +708,9 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> {
708708
709709 // If the trait has a single item (which wasn't matched by Levenshtein), suggest it
710710 let suggestion = self . get_single_associated_item ( & path, & source, is_expected) ;
711- self . r . add_typo_suggestion ( err, suggestion, ident_span) ;
711+ if !self . r . add_typo_suggestion ( err, suggestion, ident_span) {
712+ fallback = !self . let_binding_suggestion ( err, ident_span) ;
713+ }
712714 }
713715 fallback
714716 }
@@ -1105,41 +1107,14 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> {
11051107 // where a brace being opened means a block is being started. Look
11061108 // ahead for the next text to see if `span` is followed by a `{`.
11071109 let sm = self . r . session . source_map ( ) ;
1108- let mut sp = span;
1109- loop {
1110- sp = sm. next_point ( sp) ;
1111- match sm. span_to_snippet ( sp) {
1112- Ok ( ref snippet) => {
1113- if snippet. chars ( ) . any ( |c| !c. is_whitespace ( ) ) {
1114- break ;
1115- }
1116- }
1117- _ => break ,
1118- }
1119- }
1110+ let sp = sm. span_look_ahead ( span, None , Some ( 50 ) ) ;
11201111 let followed_by_brace = matches ! ( sm. span_to_snippet( sp) , Ok ( ref snippet) if snippet == "{" ) ;
11211112 // In case this could be a struct literal that needs to be surrounded
11221113 // by parentheses, find the appropriate span.
1123- let mut i = 0 ;
1124- let mut closing_brace = None ;
1125- loop {
1126- sp = sm. next_point ( sp) ;
1127- match sm. span_to_snippet ( sp) {
1128- Ok ( ref snippet) => {
1129- if snippet == "}" {
1130- closing_brace = Some ( span. to ( sp) ) ;
1131- break ;
1132- }
1133- }
1134- _ => break ,
1135- }
1136- i += 1 ;
1137- // The bigger the span, the more likely we're incorrect --
1138- // bound it to 100 chars long.
1139- if i > 100 {
1140- break ;
1141- }
1142- }
1114+ let closing_span = sm. span_look_ahead ( span, Some ( "}" ) , Some ( 50 ) ) ;
1115+ let closing_brace: Option < Span > = sm
1116+ . span_to_snippet ( closing_span)
1117+ . map_or ( None , |s| if s == "}" { Some ( span. to ( closing_span) ) } else { None } ) ;
11431118 ( followed_by_brace, closing_brace)
11441119 }
11451120
@@ -1779,26 +1754,16 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> {
17791754 }
17801755 }
17811756 if let Ok ( base_snippet) = base_snippet {
1782- let mut sp = after_colon_sp;
1783- for _ in 0 ..100 {
1784- // Try to find an assignment
1785- sp = sm. next_point ( sp) ;
1786- let snippet = sm. span_to_snippet ( sp) ;
1787- match snippet {
1788- Ok ( ref x) if x. as_str ( ) == "=" => {
1789- err. span_suggestion (
1790- base_span,
1791- "maybe you meant to write an assignment here" ,
1792- format ! ( "let {}" , base_snippet) ,
1793- Applicability :: MaybeIncorrect ,
1794- ) ;
1795- show_label = false ;
1796- break ;
1797- }
1798- Ok ( ref x) if x. as_str ( ) == "\n " => break ,
1799- Err ( _) => break ,
1800- Ok ( _) => { }
1801- }
1757+ // Try to find an assignment
1758+ let eq_span = sm. span_look_ahead ( after_colon_sp, Some ( "=" ) , Some ( 50 ) ) ;
1759+ if let Ok ( ref snippet) = sm. span_to_snippet ( eq_span) && snippet == "=" {
1760+ err. span_suggestion (
1761+ base_span,
1762+ "maybe you meant to write an assignment here" ,
1763+ format ! ( "let {}" , base_snippet) ,
1764+ Applicability :: MaybeIncorrect ,
1765+ ) ;
1766+ show_label = false ;
18021767 }
18031768 }
18041769 }
@@ -1815,6 +1780,31 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> {
18151780 false
18161781 }
18171782
1783+ fn let_binding_suggestion ( & self , err : & mut Diagnostic , ident_span : Span ) -> bool {
1784+ // try to give a suggestion for this pattern: `name = 1`, which is common in other languages
1785+ let mut added_suggestion = false ;
1786+ if let Some ( Expr { kind : ExprKind :: Assign ( lhs, _rhs, _) , .. } ) = self . diagnostic_metadata . in_assignment &&
1787+ let ast:: ExprKind :: Path ( None , _) = lhs. kind {
1788+ let sm = self . r . session . source_map ( ) ;
1789+ let line_span = sm. span_extend_to_line ( ident_span) ;
1790+ let ident_name = sm. span_to_snippet ( ident_span) . unwrap ( ) ;
1791+ // HACK(chenyukang): make sure ident_name is at the starting of the line to protect against macros
1792+ if sm
1793+ . span_to_snippet ( line_span)
1794+ . map_or ( false , |s| s. trim ( ) . starts_with ( & ident_name) )
1795+ {
1796+ err. span_suggestion_verbose (
1797+ ident_span. shrink_to_lo ( ) ,
1798+ "you might have meant to introduce a new binding" ,
1799+ "let " . to_string ( ) ,
1800+ Applicability :: MaybeIncorrect ,
1801+ ) ;
1802+ added_suggestion = true ;
1803+ }
1804+ }
1805+ added_suggestion
1806+ }
1807+
18181808 fn find_module ( & mut self , def_id : DefId ) -> Option < ( Module < ' a > , ImportSuggestion ) > {
18191809 let mut result = None ;
18201810 let mut seen_modules = FxHashSet :: default ( ) ;
0 commit comments