@@ -679,7 +679,9 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> {
679679
680680 // If the trait has a single item (which wasn't matched by Levenshtein), suggest it
681681 let suggestion = self . get_single_associated_item ( & path, & source, is_expected) ;
682- self . r . add_typo_suggestion ( err, suggestion, ident_span) ;
682+ if !self . r . add_typo_suggestion ( err, suggestion, ident_span) {
683+ fallback = !self . let_binding_suggestion ( err, ident_span) ;
684+ }
683685 }
684686 fallback
685687 }
@@ -1076,41 +1078,14 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> {
10761078 // where a brace being opened means a block is being started. Look
10771079 // ahead for the next text to see if `span` is followed by a `{`.
10781080 let sm = self . r . session . source_map ( ) ;
1079- let mut sp = span;
1080- loop {
1081- sp = sm. next_point ( sp) ;
1082- match sm. span_to_snippet ( sp) {
1083- Ok ( ref snippet) => {
1084- if snippet. chars ( ) . any ( |c| !c. is_whitespace ( ) ) {
1085- break ;
1086- }
1087- }
1088- _ => break ,
1089- }
1090- }
1081+ let sp = sm. span_look_ahead ( span, None , Some ( 50 ) ) ;
10911082 let followed_by_brace = matches ! ( sm. span_to_snippet( sp) , Ok ( ref snippet) if snippet == "{" ) ;
10921083 // In case this could be a struct literal that needs to be surrounded
10931084 // by parentheses, find the appropriate span.
1094- let mut i = 0 ;
1095- let mut closing_brace = None ;
1096- loop {
1097- sp = sm. next_point ( sp) ;
1098- match sm. span_to_snippet ( sp) {
1099- Ok ( ref snippet) => {
1100- if snippet == "}" {
1101- closing_brace = Some ( span. to ( sp) ) ;
1102- break ;
1103- }
1104- }
1105- _ => break ,
1106- }
1107- i += 1 ;
1108- // The bigger the span, the more likely we're incorrect --
1109- // bound it to 100 chars long.
1110- if i > 100 {
1111- break ;
1112- }
1113- }
1085+ let closing_span = sm. span_look_ahead ( span, Some ( "}" ) , Some ( 50 ) ) ;
1086+ let closing_brace: Option < Span > = sm
1087+ . span_to_snippet ( closing_span)
1088+ . map_or ( None , |s| if s == "}" { Some ( span. to ( closing_span) ) } else { None } ) ;
11141089 ( followed_by_brace, closing_brace)
11151090 }
11161091
@@ -1727,26 +1702,16 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> {
17271702 }
17281703 }
17291704 if let Ok ( base_snippet) = base_snippet {
1730- let mut sp = after_colon_sp;
1731- for _ in 0 ..100 {
1732- // Try to find an assignment
1733- sp = sm. next_point ( sp) ;
1734- let snippet = sm. span_to_snippet ( sp) ;
1735- match snippet {
1736- Ok ( ref x) if x. as_str ( ) == "=" => {
1737- err. span_suggestion (
1738- base_span,
1739- "maybe you meant to write an assignment here" ,
1740- format ! ( "let {}" , base_snippet) ,
1741- Applicability :: MaybeIncorrect ,
1742- ) ;
1743- show_label = false ;
1744- break ;
1745- }
1746- Ok ( ref x) if x. as_str ( ) == "\n " => break ,
1747- Err ( _) => break ,
1748- Ok ( _) => { }
1749- }
1705+ // Try to find an assignment
1706+ let eq_span = sm. span_look_ahead ( after_colon_sp, Some ( "=" ) , Some ( 50 ) ) ;
1707+ if let Ok ( ref snippet) = sm. span_to_snippet ( eq_span) && snippet == "=" {
1708+ err. span_suggestion (
1709+ base_span,
1710+ "maybe you meant to write an assignment here" ,
1711+ format ! ( "let {}" , base_snippet) ,
1712+ Applicability :: MaybeIncorrect ,
1713+ ) ;
1714+ show_label = false ;
17501715 }
17511716 }
17521717 }
@@ -1763,6 +1728,31 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> {
17631728 false
17641729 }
17651730
1731+ fn let_binding_suggestion ( & self , err : & mut Diagnostic , ident_span : Span ) -> bool {
1732+ // try to give a suggestion for this pattern: `name = 1`, which is common in other languages
1733+ let mut added_suggestion = false ;
1734+ if let Some ( Expr { kind : ExprKind :: Assign ( lhs, _rhs, _) , .. } ) = self . diagnostic_metadata . in_assignment &&
1735+ let ast:: ExprKind :: Path ( None , _) = lhs. kind {
1736+ let sm = self . r . session . source_map ( ) ;
1737+ let line_span = sm. span_extend_to_line ( ident_span) ;
1738+ let ident_name = sm. span_to_snippet ( ident_span) . unwrap ( ) ;
1739+ // HACK(chenyukang): make sure ident_name is at the starting of the line to protect against macros
1740+ if sm
1741+ . span_to_snippet ( line_span)
1742+ . map_or ( false , |s| s. trim ( ) . starts_with ( & ident_name) )
1743+ {
1744+ err. span_suggestion_verbose (
1745+ ident_span. shrink_to_lo ( ) ,
1746+ "you might have meant to introduce a new binding" ,
1747+ "let " . to_string ( ) ,
1748+ Applicability :: MaybeIncorrect ,
1749+ ) ;
1750+ added_suggestion = true ;
1751+ }
1752+ }
1753+ added_suggestion
1754+ }
1755+
17661756 fn find_module ( & mut self , def_id : DefId ) -> Option < ( Module < ' a > , ImportSuggestion ) > {
17671757 let mut result = None ;
17681758 let mut seen_modules = FxHashSet :: default ( ) ;
0 commit comments