@@ -22,6 +22,7 @@ use syntax::ast::*;
22
22
use syntax:: attr;
23
23
use syntax:: source_map:: Spanned ;
24
24
use syntax:: symbol:: keywords;
25
+ use syntax:: ptr:: P ;
25
26
use syntax:: visit:: { self , Visitor } ;
26
27
use syntax_pos:: Span ;
27
28
use errors;
@@ -167,11 +168,61 @@ impl<'a> AstValidator<'a> {
167
168
"only lifetime parameters can be used in this context" ) ;
168
169
}
169
170
}
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
+
170
219
}
171
220
172
221
impl < ' a > Visitor < ' a > for AstValidator < ' a > {
173
222
fn visit_expr ( & mut self , expr : & ' a Expr ) {
174
223
match expr. node {
224
+ ExprKind :: IfLet ( _, ref expr, _, _) | ExprKind :: WhileLet ( _, ref expr, _, _) =>
225
+ self . while_if_let_ambiguity ( & expr) ,
175
226
ExprKind :: InlineAsm ( ..) if !self . session . target . target . options . allow_asm => {
176
227
span_err ! ( self . session, expr. span, E0472 , "asm! is unsupported on this target" ) ;
177
228
}
0 commit comments