@@ -22,6 +22,7 @@ use syntax::ast::*;
2222use syntax:: attr;
2323use syntax:: source_map:: Spanned ;
2424use syntax:: symbol:: keywords;
25+ use syntax:: ptr:: P ;
2526use syntax:: visit:: { self , Visitor } ;
2627use syntax_pos:: Span ;
2728use errors;
@@ -167,11 +168,61 @@ impl<'a> AstValidator<'a> {
167168 "only lifetime parameters can be used in this context" ) ;
168169 }
169170 }
171+
172+ /// With eRFC 2497, we need to check whether an expression is ambigious and warn or error
173+ /// depending on the edition, this function handles that.
174+ fn while_if_let_ambiguity ( & self , expr : & P < Expr > ) {
175+ if let Some ( ( span, op_kind) ) = self . while_if_let_expr_ambiguity ( & expr) {
176+ let mut err = self . err_handler ( ) . struct_span_err (
177+ span, & format ! ( "ambigious use of `{}`" , op_kind. to_string( ) )
178+ ) ;
179+
180+ err. note (
181+ "this will be a error until the `let_chains` feature is stabilized"
182+ ) ;
183+ err. note (
184+ "see rust-lang/rust#53668 for more information"
185+ ) ;
186+
187+ if let Ok ( snippet) = self . session . source_map ( ) . span_to_snippet ( span) {
188+ err. span_suggestion (
189+ span, "consider adding parentheses" , format ! ( "({})" , snippet) ,
190+ ) ;
191+ }
192+
193+ err. emit ( ) ;
194+ }
195+ }
196+
197+ /// With eRFC 2497 adding if-let chains, there is a requirement that the parsing of
198+ /// `&&` and `||` in a if-let statement be unambigious. This function returns a span and
199+ /// a `BinOpKind` (either `&&` or `||` depending on what was ambigious) if it is determined
200+ /// that the current expression parsed is ambigious and will break in future.
201+ fn while_if_let_expr_ambiguity ( & self , expr : & P < Expr > ) -> Option < ( Span , BinOpKind ) > {
202+ debug ! ( "while_if_let_expr_ambiguity: expr.node: {:?}" , expr. node) ;
203+ match & expr. node {
204+ ExprKind :: Binary ( op, _, _) if op. node == BinOpKind :: And || op. node == BinOpKind :: Or => {
205+ Some ( ( expr. span , op. node ) )
206+ } ,
207+ ExprKind :: Range ( ref lhs, ref rhs, _) => {
208+ let lhs_ambigious = lhs. as_ref ( )
209+ . and_then ( |lhs| self . while_if_let_expr_ambiguity ( lhs) ) ;
210+ let rhs_ambigious = rhs. as_ref ( )
211+ . and_then ( |rhs| self . while_if_let_expr_ambiguity ( rhs) ) ;
212+
213+ lhs_ambigious. or ( rhs_ambigious)
214+ }
215+ _ => None ,
216+ }
217+ }
218+
170219}
171220
172221impl < ' a > Visitor < ' a > for AstValidator < ' a > {
173222 fn visit_expr ( & mut self , expr : & ' a Expr ) {
174223 match expr. node {
224+ ExprKind :: IfLet ( _, ref expr, _, _) | ExprKind :: WhileLet ( _, ref expr, _, _) =>
225+ self . while_if_let_ambiguity ( & expr) ,
175226 ExprKind :: InlineAsm ( ..) if !self . session . target . target . options . allow_asm => {
176227 span_err ! ( self . session, expr. span, E0472 , "asm! is unsupported on this target" ) ;
177228 }
0 commit comments