@@ -100,6 +100,7 @@ pub enum PathStyle {
100
100
enum SemiColonMode {
101
101
Break ,
102
102
Ignore ,
103
+ Comma ,
103
104
}
104
105
105
106
#[ derive( Clone , Copy , PartialEq , Debug ) ]
@@ -1988,6 +1989,44 @@ impl<'a> Parser<'a> {
1988
1989
1989
1990
result. unwrap ( )
1990
1991
}
1992
+ token:: Dot if self . look_ahead ( 1 , |t| match t {
1993
+ token:: Literal ( parse:: token:: Lit :: Integer ( _) , _) => true ,
1994
+ _ => false ,
1995
+ } ) => { // recover from `let x = .4;`
1996
+ let lo = self . span ;
1997
+ self . bump ( ) ;
1998
+ if let token:: Literal (
1999
+ parse:: token:: Lit :: Integer ( val) ,
2000
+ suffix,
2001
+ ) = self . token {
2002
+ let suffix = suffix. and_then ( |s| {
2003
+ let s = s. as_str ( ) . get ( ) ;
2004
+ if [ "f32" , "f64" ] . contains ( & s) {
2005
+ Some ( s)
2006
+ } else {
2007
+ None
2008
+ }
2009
+ } ) . unwrap_or ( "" ) ;
2010
+ self . bump ( ) ;
2011
+ let sp = lo. to ( self . prev_span ) ;
2012
+ let mut err = self . diagnostic ( )
2013
+ . struct_span_err ( sp, "float literals must have an integer part" ) ;
2014
+ err. span_suggestion_with_applicability (
2015
+ sp,
2016
+ "must have an integer part" ,
2017
+ format ! ( "0.{}{}" , val, suffix) ,
2018
+ Applicability :: MachineApplicable ,
2019
+ ) ;
2020
+ err. emit ( ) ;
2021
+ return Ok ( match suffix {
2022
+ "f32" => ast:: LitKind :: Float ( val, ast:: FloatTy :: F32 ) ,
2023
+ "f64" => ast:: LitKind :: Float ( val, ast:: FloatTy :: F64 ) ,
2024
+ _ => ast:: LitKind :: FloatUnsuffixed ( val) ,
2025
+ } ) ;
2026
+ } else {
2027
+ unreachable ! ( ) ;
2028
+ } ;
2029
+ }
1991
2030
_ => { return self . unexpected_last ( & self . token ) ; }
1992
2031
} ;
1993
2032
@@ -2656,8 +2695,24 @@ impl<'a> Parser<'a> {
2656
2695
break ;
2657
2696
}
2658
2697
2698
+ let mut recovery_field = None ;
2699
+ if let token:: Ident ( ident, _) = self . token {
2700
+ if !self . token . is_reserved_ident ( ) && self . look_ahead ( 1 , |t| * t == token:: Colon ) {
2701
+ // Use in case of error after field-looking code: `S { foo: () with a }`
2702
+ let mut ident = ident. clone ( ) ;
2703
+ ident. span = self . span ;
2704
+ recovery_field = Some ( ast:: Field {
2705
+ ident,
2706
+ span : self . span ,
2707
+ expr : self . mk_expr ( self . span , ExprKind :: Err , ThinVec :: new ( ) ) ,
2708
+ is_shorthand : false ,
2709
+ attrs : ThinVec :: new ( ) ,
2710
+ } ) ;
2711
+ }
2712
+ }
2713
+ let mut parsed_field = None ;
2659
2714
match self . parse_field ( ) {
2660
- Ok ( f) => fields . push ( f) ,
2715
+ Ok ( f) => parsed_field = Some ( f) ,
2661
2716
Err ( mut e) => {
2662
2717
e. span_label ( struct_sp, "while parsing this struct" ) ;
2663
2718
e. emit ( ) ;
@@ -2666,19 +2721,28 @@ impl<'a> Parser<'a> {
2666
2721
// what comes next as additional fields, rather than
2667
2722
// bailing out until next `}`.
2668
2723
if self . token != token:: Comma {
2669
- self . recover_stmt ( ) ;
2670
- break ;
2724
+ self . recover_stmt_ ( SemiColonMode :: Comma , BlockMode :: Ignore ) ;
2725
+ if self . token != token:: Comma {
2726
+ break ;
2727
+ }
2671
2728
}
2672
2729
}
2673
2730
}
2674
2731
2675
2732
match self . expect_one_of ( & [ token:: Comma ] ,
2676
2733
& [ token:: CloseDelim ( token:: Brace ) ] ) {
2677
- Ok ( ( ) ) => { }
2734
+ Ok ( ( ) ) => if let Some ( f) = parsed_field. or ( recovery_field) {
2735
+ // only include the field if there's no parse error for the field name
2736
+ fields. push ( f) ;
2737
+ }
2678
2738
Err ( mut e) => {
2739
+ if let Some ( f) = recovery_field {
2740
+ fields. push ( f) ;
2741
+ }
2742
+ e. span_label ( struct_sp, "while parsing this struct" ) ;
2679
2743
e. emit ( ) ;
2680
- self . recover_stmt ( ) ;
2681
- break ;
2744
+ self . recover_stmt_ ( SemiColonMode :: Comma , BlockMode :: Ignore ) ;
2745
+ self . eat ( & token :: Comma ) ;
2682
2746
}
2683
2747
}
2684
2748
}
@@ -4542,13 +4606,13 @@ impl<'a> Parser<'a> {
4542
4606
token:: CloseDelim ( token:: DelimToken :: Brace ) => {
4543
4607
if brace_depth == 0 {
4544
4608
debug ! ( "recover_stmt_ return - close delim {:?}" , self . token) ;
4545
- return ;
4609
+ break ;
4546
4610
}
4547
4611
brace_depth -= 1 ;
4548
4612
self . bump ( ) ;
4549
4613
if in_block && bracket_depth == 0 && brace_depth == 0 {
4550
4614
debug ! ( "recover_stmt_ return - block end {:?}" , self . token) ;
4551
- return ;
4615
+ break ;
4552
4616
}
4553
4617
}
4554
4618
token:: CloseDelim ( token:: DelimToken :: Bracket ) => {
@@ -4560,15 +4624,25 @@ impl<'a> Parser<'a> {
4560
4624
}
4561
4625
token:: Eof => {
4562
4626
debug ! ( "recover_stmt_ return - Eof" ) ;
4563
- return ;
4627
+ break ;
4564
4628
}
4565
4629
token:: Semi => {
4566
4630
self . bump ( ) ;
4567
4631
if break_on_semi == SemiColonMode :: Break &&
4568
4632
brace_depth == 0 &&
4569
4633
bracket_depth == 0 {
4570
4634
debug ! ( "recover_stmt_ return - Semi" ) ;
4571
- return ;
4635
+ break ;
4636
+ }
4637
+ }
4638
+ token:: Comma => {
4639
+ if break_on_semi == SemiColonMode :: Comma &&
4640
+ brace_depth == 0 &&
4641
+ bracket_depth == 0 {
4642
+ debug ! ( "recover_stmt_ return - Semi" ) ;
4643
+ break ;
4644
+ } else {
4645
+ self . bump ( ) ;
4572
4646
}
4573
4647
}
4574
4648
_ => {
0 commit comments