@@ -1081,6 +1081,16 @@ impl<'a> Parser<'a> {
1081
1081
None => token:: CloseDelim ( self . token_cursor . frame . delim ) ,
1082
1082
} )
1083
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
+ }
1084
1094
pub fn fatal ( & self , m : & str ) -> DiagnosticBuilder < ' a > {
1085
1095
self . sess . span_diagnostic . struct_span_fatal ( self . span , m)
1086
1096
}
@@ -2805,13 +2815,10 @@ impl<'a> Parser<'a> {
2805
2815
}
2806
2816
// Special cases:
2807
2817
if op == AssocOp :: As {
2808
- // Save the state of the parser before parsing type normally, in case there is a
2809
- // LessThan comparison after this cast.
2810
- lhs = self . parse_assoc_op_as ( lhs, lhs_span) ?;
2818
+ lhs = self . parse_assoc_op_cast ( lhs, lhs_span, ExprKind :: Cast ) ?;
2811
2819
continue
2812
2820
} else if op == AssocOp :: Colon {
2813
- let rhs = self . parse_ty_no_plus ( ) ?;
2814
- 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 ) ?;
2815
2822
continue
2816
2823
} else if op == AssocOp :: DotDot || op == AssocOp :: DotDotDot {
2817
2824
// If we didn’t have to handle `x..`/`x...`, it would be pretty easy to
@@ -2905,61 +2912,61 @@ impl<'a> Parser<'a> {
2905
2912
Ok ( lhs)
2906
2913
}
2907
2914
2908
- fn parse_assoc_op_as ( & mut self , lhs : P < Expr > , lhs_span : Span ) -> PResult < ' a , P < Expr > > {
2909
- 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 ( ) ;
2910
2925
match self . parse_ty_no_plus ( ) {
2911
2926
Ok ( rhs) => {
2912
- Ok ( self . mk_expr ( lhs_span. to ( rhs. span ) ,
2913
- ExprKind :: Cast ( lhs, rhs) ,
2914
- ThinVec :: new ( ) ) )
2927
+ Ok ( mk_expr ( self , rhs) )
2915
2928
}
2916
- Err ( mut err) => {
2917
- let rp_err = self . clone ( ) ;
2918
- 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) ;
2919
2935
2920
- // Rewind to before attempting to parse the type with generics, to get
2921
- // arround #22644.
2922
- mem:: replace ( self , rp) ;
2923
- let lo = self . span ;
2924
2936
match self . parse_path_without_generics ( PathStyle :: Type ) {
2925
2937
Ok ( path) => {
2926
- // Successfully parsed the type leaving a `<` yet to parse
2927
- err. cancel ( ) ;
2928
- let codemap = self . sess . codemap ( ) ;
2929
- let suggestion_span = lhs_span. to ( self . prev_span ) ;
2930
- let warn_message = match codemap. span_to_snippet ( self . prev_span ) {
2931
- Ok ( lstring) => format ! ( "`{}`" , lstring) ,
2932
- _ => "a type" . to_string ( ) ,
2933
- } ;
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.
2934
2943
let msg = format ! ( "`<` is interpreted as a start of generic \
2935
- arguments for {} , not a comparison",
2936
- warn_message ) ;
2937
- let mut err = self . sess . span_diagnostic . struct_span_err ( sp , & msg ) ;
2938
- 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 " ) ;
2939
2948
err. span_label ( self . span , "not interpreted as comparison" ) ;
2940
- let suggestion = match codemap. span_to_snippet ( suggestion_span) {
2941
- Ok ( lstring) => format ! ( "({})" , lstring) ,
2942
- _ => format ! ( "(<expression> as <type>)" )
2943
- } ;
2944
- 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 ,
2945
2959
"if you want to compare the casted value then write:" ,
2946
- suggestion ) ;
2960
+ format ! ( "({})" , expr_str ) ) ;
2947
2961
err. emit ( ) ;
2948
2962
2949
- let path = TyKind :: Path ( None , path) ;
2950
- let span = lo. to ( self . prev_span ) ;
2951
- let rhs = P ( Ty { node : path, span : span, id : ast:: DUMMY_NODE_ID } ) ;
2952
- // Letting the parser accept the recovered type to avoid further errors,
2953
- // but the code will still not compile due to the error emitted above.
2954
- Ok ( self . mk_expr ( lhs_span. to ( rhs. span ) ,
2955
- ExprKind :: Cast ( lhs, rhs) ,
2956
- ThinVec :: new ( ) ) )
2963
+ Ok ( expr)
2957
2964
}
2958
2965
Err ( mut path_err) => {
2959
- // Still couldn 't parse, return original error and parser state
2966
+ // Couldn 't parse as a path , return original error and parser state.
2960
2967
path_err. cancel ( ) ;
2961
- mem:: replace ( self , rp_err ) ;
2962
- Err ( err )
2968
+ mem:: replace ( self , parser_snapshot_after_type ) ;
2969
+ Err ( type_err )
2963
2970
}
2964
2971
}
2965
2972
}
0 commit comments