@@ -294,17 +294,22 @@ impl<'a> Parser<'a> {
294294 let ( pat, colon) =
295295 self . parse_pat_before_ty ( None , RecoverComma :: Yes , PatternLocation :: LetBinding ) ?;
296296
297- let ( err, ty) = if colon {
297+ let ( err, ty, colon_sp ) = if colon {
298298 // Save the state of the parser before parsing type normally, in case there is a `:`
299299 // instead of an `=` typo.
300300 let parser_snapshot_before_type = self . clone ( ) ;
301301 let colon_sp = self . prev_token . span ;
302302 match self . parse_ty ( ) {
303- Ok ( ty) => ( None , Some ( ty) ) ,
303+ Ok ( ty) => ( None , Some ( ty) , Some ( colon_sp ) ) ,
304304 Err ( mut err) => {
305- if let Ok ( snip) = self . span_to_snippet ( pat. span ) {
306- err. span_label ( pat. span , format ! ( "while parsing the type for `{snip}`" ) ) ;
307- }
305+ err. span_label (
306+ colon_sp,
307+ format ! (
308+ "while parsing the type for {}" ,
309+ pat. descr( )
310+ . map_or_else( || "the binding" . to_string( ) , |n| format!( "`{n}`" ) )
311+ ) ,
312+ ) ;
308313 // we use noexpect here because we don't actually expect Eq to be here
309314 // but we are still checking for it in order to be able to handle it if
310315 // it is there
@@ -317,11 +322,11 @@ impl<'a> Parser<'a> {
317322 mem:: replace ( self , parser_snapshot_before_type) ;
318323 Some ( ( parser_snapshot_after_type, colon_sp, err) )
319324 } ;
320- ( err, None )
325+ ( err, None , Some ( colon_sp ) )
321326 }
322327 }
323328 } else {
324- ( None , None )
329+ ( None , None , None )
325330 } ;
326331 let init = match ( self . parse_initializer ( err. is_some ( ) ) , err) {
327332 ( Ok ( init) , None ) => {
@@ -380,7 +385,16 @@ impl<'a> Parser<'a> {
380385 }
381386 } ;
382387 let hi = if self . token == token:: Semi { self . token . span } else { self . prev_token . span } ;
383- Ok ( P ( ast:: Local { ty, pat, kind, id : DUMMY_NODE_ID , span : lo. to ( hi) , attrs, tokens : None } ) )
388+ Ok ( P ( ast:: Local {
389+ ty,
390+ pat,
391+ kind,
392+ id : DUMMY_NODE_ID ,
393+ span : lo. to ( hi) ,
394+ colon_sp,
395+ attrs,
396+ tokens : None ,
397+ } ) )
384398 }
385399
386400 fn check_let_else_init_bool_expr ( & self , init : & ast:: Expr ) {
@@ -750,15 +764,55 @@ impl<'a> Parser<'a> {
750764 }
751765 }
752766 StmtKind :: Expr ( _) | StmtKind :: MacCall ( _) => { }
753- StmtKind :: Local ( local) if let Err ( e) = self . expect_semi ( ) => {
767+ StmtKind :: Local ( local) if let Err ( mut e) = self . expect_semi ( ) => {
754768 // We might be at the `,` in `let x = foo<bar, baz>;`. Try to recover.
755769 match & mut local. kind {
756770 LocalKind :: Init ( expr) | LocalKind :: InitElse ( expr, _) => {
757771 self . check_mistyped_turbofish_with_multiple_type_params ( e, expr) ?;
758772 // We found `foo<bar, baz>`, have we fully recovered?
759773 self . expect_semi ( ) ?;
760774 }
761- LocalKind :: Decl => return Err ( e) ,
775+ LocalKind :: Decl => {
776+ if let Some ( colon_sp) = local. colon_sp {
777+ e. span_label (
778+ colon_sp,
779+ format ! (
780+ "while parsing the type for {}" ,
781+ local. pat. descr( ) . map_or_else(
782+ || "the binding" . to_string( ) ,
783+ |n| format!( "`{n}`" )
784+ )
785+ ) ,
786+ ) ;
787+ let suggest_eq = if self . token . kind == token:: Dot
788+ && let _ = self . bump ( )
789+ && let mut snapshot = self . create_snapshot_for_diagnostic ( )
790+ && let Ok ( _) = snapshot. parse_dot_suffix_expr (
791+ colon_sp,
792+ self . mk_expr_err (
793+ colon_sp,
794+ self . dcx ( ) . delayed_bug ( "error during `:` -> `=` recovery" ) ,
795+ ) ,
796+ ) {
797+ true
798+ } else if let Some ( op) = self . check_assoc_op ( )
799+ && op. node . can_continue_expr_unambiguously ( )
800+ {
801+ true
802+ } else {
803+ false
804+ } ;
805+ if suggest_eq {
806+ e. span_suggestion_short (
807+ colon_sp,
808+ "use `=` if you meant to assign" ,
809+ "=" ,
810+ Applicability :: MaybeIncorrect ,
811+ ) ;
812+ }
813+ }
814+ return Err ( e) ;
815+ }
762816 }
763817 eat_semi = false ;
764818 }
0 commit comments