diff options
| author | David Wood <david@davidtw.co> | 2018-08-31 15:59:42 +0200 |
|---|---|---|
| committer | David Wood <david@davidtw.co> | 2018-08-31 16:13:42 +0200 |
| commit | 2ce56c5ebf4b63c274da678c367a4d85a13994a8 (patch) | |
| tree | e9cb2588f31e1d4a79f5008ebabc35f3d5566f4b /src/libsyntax/parse | |
| parent | 685fb543174f8f2cadc38ec0b2c6df635eb1c087 (diff) | |
| download | rust-2ce56c5ebf4b63c274da678c367a4d85a13994a8.tar.gz rust-2ce56c5ebf4b63c274da678c367a4d85a13994a8.zip | |
Added warning/error for if-let-chain ambiguity.
With eRFC 2497, previously accepted ambigious syntax regarding use of `&&` and `||` in if-let and while-let statements should now warn or error depending on the edition. This commit takes a naive approach to detecting ambigious use of `&&` or `||` and will probably need fine tuned to handle all cases.
Diffstat (limited to 'src/libsyntax/parse')
| -rw-r--r-- | src/libsyntax/parse/parser.rs | 53 |
1 files changed, 53 insertions, 0 deletions
diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 1695d3a8f96..f0e6dfb8775 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -3327,6 +3327,8 @@ impl<'a> Parser<'a> { let pats = self.parse_pats()?; self.expect(&token::Eq)?; let expr = self.parse_expr_res(Restrictions::NO_STRUCT_LITERAL, None)?; + self.while_if_let_ambiguity(&expr); + let thn = self.parse_block()?; let (hi, els) = if self.eat_keyword(keywords::Else) { let expr = self.parse_else_expr()?; @@ -3337,6 +3339,56 @@ impl<'a> Parser<'a> { Ok(self.mk_expr(lo.to(hi), ExprKind::IfLet(pats, expr, thn, els), attrs)) } + /// With eRFC 2497, we need to check whether an expression is ambigious and warn or error + /// depending on the edition, this function handles that. + fn while_if_let_ambiguity(&self, expr: &P<Expr>) { + if let Some((span, op_kind)) = self.while_if_let_expr_ambiguity(&expr) { + let message = format!("ambigious use of `{}`", op_kind.to_string()); + let mut err = if self.span.edition() >= Edition::Edition2018 { + self.diagnostic().struct_span_err(span, &message) + } else { + self.diagnostic().struct_span_warn(span, &message) + }; + + let note = if self.span.edition() >= Edition::Edition2018 { + "This will be a error until the `let_chains` feature is stabilized." + } else { + "This will be a error in Rust 2018 until the `let_chains` feature is stabilized." + }; + err.note(note); + + if let Ok(snippet) = self.sess.source_map().span_to_snippet(span) { + err.span_suggestion( + span, "consider adding parenthesis", format!("({})", snippet), + ); + } + + err.emit(); + } + } + + /// With eRFC 2497 adding if-let chains, there is a requirement that the parsing of + /// `&&` and `||` in a if-let statement be unambigious. This function returns a span and + /// a `BinOpKind` (either `&&` or `||` depending on what was ambigious) if it is determined + /// that the current expression parsed is ambigious and will break in future. + fn while_if_let_expr_ambiguity(&self, expr: &P<Expr>) -> Option<(Span, BinOpKind)> { + debug!("while_if_let_expr_ambiguity: expr.node: {:?}", expr.node); + match &expr.node { + ExprKind::Binary(op, _, _) if op.node == BinOpKind::And || op.node == BinOpKind::Or => { + Some((expr.span, op.node)) + }, + ExprKind::Range(ref lhs, ref rhs, _) => { + let lhs_ambigious = lhs.as_ref() + .and_then(|lhs| self.while_if_let_expr_ambiguity(lhs)); + let rhs_ambigious = rhs.as_ref() + .and_then(|rhs| self.while_if_let_expr_ambiguity(rhs)); + + lhs_ambigious.or(rhs_ambigious) + } + _ => None, + } + } + // `move |args| expr` fn parse_lambda_expr(&mut self, attrs: ThinVec<Attribute>) @@ -3437,6 +3489,7 @@ impl<'a> Parser<'a> { let pats = self.parse_pats()?; self.expect(&token::Eq)?; let expr = self.parse_expr_res(Restrictions::NO_STRUCT_LITERAL, None)?; + self.while_if_let_ambiguity(&expr); let (iattrs, body) = self.parse_inner_attrs_and_block()?; attrs.extend(iattrs); let span = span_lo.to(body.span); |
