@@ -1081,6 +1081,16 @@ impl<'a> Parser<'a> {
10811081 None => token:: CloseDelim ( self . token_cursor . frame . delim ) ,
10821082 } )
10831083 }
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+ }
10841094 pub fn fatal ( & self , m : & str ) -> DiagnosticBuilder < ' a > {
10851095 self . sess . span_diagnostic . struct_span_fatal ( self . span , m)
10861096 }
@@ -2805,13 +2815,10 @@ impl<'a> Parser<'a> {
28052815 }
28062816 // Special cases:
28072817 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 ) ?;
28112819 continue
28122820 } 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 ) ?;
28152822 continue
28162823 } else if op == AssocOp :: DotDot || op == AssocOp :: DotDotDot {
28172824 // If we didn’t have to handle `x..`/`x...`, it would be pretty easy to
@@ -2905,61 +2912,61 @@ impl<'a> Parser<'a> {
29052912 Ok ( lhs)
29062913 }
29072914
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 ( ) ;
29102925 match self . parse_ty_no_plus ( ) {
29112926 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) )
29152928 }
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) ;
29192935
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 ;
29242936 match self . parse_path_without_generics ( PathStyle :: Type ) {
29252937 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.
29342943 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 " ) ;
29392948 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 ,
29452959 "if you want to compare the casted value then write:" ,
2946- suggestion ) ;
2960+ format ! ( "({})" , expr_str ) ) ;
29472961 err. emit ( ) ;
29482962
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)
29572964 }
29582965 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.
29602967 path_err. cancel ( ) ;
2961- mem:: replace ( self , rp_err ) ;
2962- Err ( err )
2968+ mem:: replace ( self , parser_snapshot_after_type ) ;
2969+ Err ( type_err )
29632970 }
29642971 }
29652972 }
0 commit comments