@@ -150,13 +150,14 @@ fn maybe_append(mut lhs: Vec<Attribute>, rhs: Option<Vec<Attribute>>)
150
150
lhs
151
151
}
152
152
153
- #[ derive( Clone , PartialEq ) ]
153
+ #[ derive( Clone , Copy , PartialEq ) ]
154
154
enum PrevTokenKind {
155
155
DocComment ,
156
156
Comma ,
157
157
Plus ,
158
158
Interpolated ,
159
159
Eof ,
160
+ Ident ,
160
161
Other ,
161
162
}
162
163
@@ -1040,6 +1041,7 @@ impl<'a> Parser<'a> {
1040
1041
token:: BinOp ( token:: Plus ) => PrevTokenKind :: Plus ,
1041
1042
token:: Interpolated ( ..) => PrevTokenKind :: Interpolated ,
1042
1043
token:: Eof => PrevTokenKind :: Eof ,
1044
+ token:: Ident ( ..) => PrevTokenKind :: Ident ,
1043
1045
_ => PrevTokenKind :: Other ,
1044
1046
} ;
1045
1047
@@ -1079,6 +1081,16 @@ impl<'a> Parser<'a> {
1079
1081
None => token:: CloseDelim ( self . token_cursor . frame . delim ) ,
1080
1082
} )
1081
1083
}
1084
+ fn look_ahead_span ( & self , dist : usize ) -> Span {
1085
+ if dist == 0 {
1086
+ return self . span
1087
+ }
1088
+
1089
+ match self . token_cursor . frame . tree_cursor . look_ahead ( dist - 1 ) {
1090
+ Some ( TokenTree :: Token ( span, _) ) | Some ( TokenTree :: Delimited ( span, _) ) => span,
1091
+ None => self . look_ahead_span ( dist - 1 ) ,
1092
+ }
1093
+ }
1082
1094
pub fn fatal ( & self , m : & str ) -> DiagnosticBuilder < ' a > {
1083
1095
self . sess . span_diagnostic . struct_span_fatal ( self . span , m)
1084
1096
}
@@ -2777,10 +2789,15 @@ impl<'a> Parser<'a> {
2777
2789
self . expected_tokens . push ( TokenType :: Operator ) ;
2778
2790
while let Some ( op) = AssocOp :: from_token ( & self . token ) {
2779
2791
2780
- let lhs_span = if self . prev_token_kind == PrevTokenKind :: Interpolated {
2781
- self . prev_span
2782
- } else {
2783
- lhs. span
2792
+ // Adjust the span for interpolated LHS to point to the `$lhs` token and not to what
2793
+ // it refers to. Interpolated identifiers are unwrapped early and never show up here
2794
+ // as `PrevTokenKind::Interpolated` so if LHS is a single identifier we always process
2795
+ // it as "interpolated", it doesn't change the answer for non-interpolated idents.
2796
+ let lhs_span = match ( self . prev_token_kind , & lhs. node ) {
2797
+ ( PrevTokenKind :: Interpolated , _) => self . prev_span ,
2798
+ ( PrevTokenKind :: Ident , & ExprKind :: Path ( None , ref path) )
2799
+ if path. segments . len ( ) == 1 => self . prev_span ,
2800
+ _ => lhs. span ,
2784
2801
} ;
2785
2802
2786
2803
let cur_op_span = self . span ;
@@ -2798,13 +2815,10 @@ impl<'a> Parser<'a> {
2798
2815
}
2799
2816
// Special cases:
2800
2817
if op == AssocOp :: As {
2801
- // Save the state of the parser before parsing type normally, in case there is a
2802
- // LessThan comparison after this cast.
2803
- lhs = self . parse_assoc_op_as ( lhs, lhs_span) ?;
2818
+ lhs = self . parse_assoc_op_cast ( lhs, lhs_span, ExprKind :: Cast ) ?;
2804
2819
continue
2805
2820
} else if op == AssocOp :: Colon {
2806
- let rhs = self . parse_ty_no_plus ( ) ?;
2807
- lhs = self . mk_expr ( lhs_span. to ( rhs. span ) , ExprKind :: Type ( lhs, rhs) , ThinVec :: new ( ) ) ;
2821
+ lhs = self . parse_assoc_op_cast ( lhs, lhs_span, ExprKind :: Type ) ?;
2808
2822
continue
2809
2823
} else if op == AssocOp :: DotDot || op == AssocOp :: DotDotDot {
2810
2824
// If we didn’t have to handle `x..`/`x...`, it would be pretty easy to
@@ -2898,61 +2912,61 @@ impl<'a> Parser<'a> {
2898
2912
Ok ( lhs)
2899
2913
}
2900
2914
2901
- fn parse_assoc_op_as ( & mut self , lhs : P < Expr > , lhs_span : Span ) -> PResult < ' a , P < Expr > > {
2902
- let rp = self . clone ( ) ;
2915
+ fn parse_assoc_op_cast ( & mut self , lhs : P < Expr > , lhs_span : Span ,
2916
+ expr_kind : fn ( P < Expr > , P < Ty > ) -> ExprKind )
2917
+ -> PResult < ' a , P < Expr > > {
2918
+ let mk_expr = |this : & mut Self , rhs : P < Ty > | {
2919
+ this. mk_expr ( lhs_span. to ( rhs. span ) , expr_kind ( lhs, rhs) , ThinVec :: new ( ) )
2920
+ } ;
2921
+
2922
+ // Save the state of the parser before parsing type normally, in case there is a
2923
+ // LessThan comparison after this cast.
2924
+ let parser_snapshot_before_type = self . clone ( ) ;
2903
2925
match self . parse_ty_no_plus ( ) {
2904
2926
Ok ( rhs) => {
2905
- Ok ( self . mk_expr ( lhs_span. to ( rhs. span ) ,
2906
- ExprKind :: Cast ( lhs, rhs) ,
2907
- ThinVec :: new ( ) ) )
2927
+ Ok ( mk_expr ( self , rhs) )
2908
2928
}
2909
- Err ( mut err) => {
2910
- let rp_err = self . clone ( ) ;
2911
- let sp = rp_err. span . clone ( ) ;
2929
+ Err ( mut type_err) => {
2930
+ // Rewind to before attempting to parse the type with generics, to recover
2931
+ // from situations like `x as usize < y` in which we first tried to parse
2932
+ // `usize < y` as a type with generic arguments.
2933
+ let parser_snapshot_after_type = self . clone ( ) ;
2934
+ mem:: replace ( self , parser_snapshot_before_type) ;
2912
2935
2913
- // Rewind to before attempting to parse the type with generics, to get
2914
- // arround #22644.
2915
- mem:: replace ( self , rp) ;
2916
- let lo = self . span ;
2917
2936
match self . parse_path_without_generics ( PathStyle :: Type ) {
2918
2937
Ok ( path) => {
2919
- // Successfully parsed the type leaving a `<` yet to parse
2920
- err. cancel ( ) ;
2921
- let codemap = self . sess . codemap ( ) ;
2922
- let suggestion_span = lhs_span. to ( self . prev_span ) ;
2923
- let warn_message = match codemap. span_to_snippet ( self . prev_span ) {
2924
- Ok ( lstring) => format ! ( "`{}`" , lstring) ,
2925
- _ => "a type" . to_string ( ) ,
2926
- } ;
2938
+ // Successfully parsed the type path leaving a `<` yet to parse.
2939
+ type_err. cancel ( ) ;
2940
+
2941
+ // Report non-fatal diagnostics, keep `x as usize` as an expression
2942
+ // in AST and continue parsing.
2927
2943
let msg = format ! ( "`<` is interpreted as a start of generic \
2928
- arguments for {} , not a comparison",
2929
- warn_message ) ;
2930
- let mut err = self . sess . span_diagnostic . struct_span_err ( sp , & msg ) ;
2931
- err . span_label ( sp , "interpreted as generic argument " ) ;
2944
+ arguments for `{}` , not a comparison", path ) ;
2945
+ let mut err = self . sess . span_diagnostic . struct_span_err ( self . span , & msg ) ;
2946
+ err. span_label ( self . look_ahead_span ( 1 ) . to ( parser_snapshot_after_type . span ) ,
2947
+ "interpreted as generic arguments " ) ;
2932
2948
err. span_label ( self . span , "not interpreted as comparison" ) ;
2933
- let suggestion = match codemap. span_to_snippet ( suggestion_span) {
2934
- Ok ( lstring) => format ! ( "({})" , lstring) ,
2935
- _ => format ! ( "(<expression> as <type>)" )
2936
- } ;
2937
- err. span_suggestion ( suggestion_span,
2949
+
2950
+ let expr = mk_expr ( self , P ( Ty {
2951
+ span : path. span ,
2952
+ node : TyKind :: Path ( None , path) ,
2953
+ id : ast:: DUMMY_NODE_ID
2954
+ } ) ) ;
2955
+
2956
+ let expr_str = self . sess . codemap ( ) . span_to_snippet ( expr. span )
2957
+ . unwrap_or ( pprust:: expr_to_string ( & expr) ) ;
2958
+ err. span_suggestion ( expr. span ,
2938
2959
"if you want to compare the casted value then write:" ,
2939
- suggestion ) ;
2960
+ format ! ( "({})" , expr_str ) ) ;
2940
2961
err. emit ( ) ;
2941
2962
2942
- let path = TyKind :: Path ( None , path) ;
2943
- let span = lo. to ( self . prev_span ) ;
2944
- let rhs = P ( Ty { node : path, span : span, id : ast:: DUMMY_NODE_ID } ) ;
2945
- // Letting the parser accept the recovered type to avoid further errors,
2946
- // but the code will still not compile due to the error emitted above.
2947
- Ok ( self . mk_expr ( lhs_span. to ( rhs. span ) ,
2948
- ExprKind :: Cast ( lhs, rhs) ,
2949
- ThinVec :: new ( ) ) )
2963
+ Ok ( expr)
2950
2964
}
2951
2965
Err ( mut path_err) => {
2952
- // Still couldn 't parse, return original error and parser state
2966
+ // Couldn 't parse as a path , return original error and parser state.
2953
2967
path_err. cancel ( ) ;
2954
- mem:: replace ( self , rp_err ) ;
2955
- Err ( err )
2968
+ mem:: replace ( self , parser_snapshot_after_type ) ;
2969
+ Err ( type_err )
2956
2970
}
2957
2971
}
2958
2972
}
0 commit comments