提交 fb945f0e 编写于 作者: B bors

Auto merge of #53854 - davidtwco:issue-53668, r=nikomatsakis

if- and while-let-chains, take 2 - edition changes

Part of #53668.

r? @nikomatsakis
......@@ -22,6 +22,7 @@
use syntax::attr;
use syntax::source_map::Spanned;
use syntax::symbol::keywords;
use syntax::ptr::P;
use syntax::visit::{self, Visitor};
use syntax_pos::Span;
use errors;
......@@ -167,11 +168,61 @@ fn check_late_bound_lifetime_defs(&self, params: &[GenericParam]) {
"only lifetime parameters can be used in this context");
}
}
/// 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 mut err = self.err_handler().struct_span_err(
span, &format!("ambigious use of `{}`", op_kind.to_string())
);
err.note(
"this will be a error until the `let_chains` feature is stabilized"
);
err.note(
"see rust-lang/rust#53668 for more information"
);
if let Ok(snippet) = self.session.source_map().span_to_snippet(span) {
err.span_suggestion(
span, "consider adding parentheses", 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,
}
}
}
impl<'a> Visitor<'a> for AstValidator<'a> {
fn visit_expr(&mut self, expr: &'a Expr) {
match expr.node {
ExprKind::IfLet(_, ref expr, _, _) | ExprKind::WhileLet(_, ref expr, _, _) =>
self.while_if_let_ambiguity(&expr),
ExprKind::InlineAsm(..) if !self.session.target.target.options.allow_asm => {
span_err!(self.session, expr.span, E0472, "asm! is unsupported on this target");
}
......
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// edition:2015
// Enabling `ireffutable_let_patterns` isn't necessary for what this tests, but it makes coming up
// with examples easier.
#![feature(irrefutable_let_patterns)]
#[allow(irrefutable_let_patterns)]
fn main() {
use std::ops::Range;
if let Range { start: _, end: _ } = true..true && false { }
//~^ ERROR ambigious use of `&&`
if let Range { start: _, end: _ } = true..true || false { }
//~^ ERROR ambigious use of `||`
while let Range { start: _, end: _ } = true..true && false { }
//~^ ERROR ambigious use of `&&`
while let Range { start: _, end: _ } = true..true || false { }
//~^ ERROR ambigious use of `||`
if let true = false && false { }
//~^ ERROR ambigious use of `&&`
while let true = (1 == 2) && false { }
//~^ ERROR ambigious use of `&&`
// The following cases are not an error as parenthesis are used to
// clarify intent:
if let Range { start: _, end: _ } = true..(true || false) { }
if let Range { start: _, end: _ } = true..(true && false) { }
while let Range { start: _, end: _ } = true..(true || false) { }
while let Range { start: _, end: _ } = true..(true && false) { }
}
error: ambigious use of `&&`
--> $DIR/syntax-ambiguity-2015.rs:21:47
|
LL | if let Range { start: _, end: _ } = true..true && false { }
| ^^^^^^^^^^^^^ help: consider adding parentheses: `(true && false)`
|
= note: this will be a error until the `let_chains` feature is stabilized
= note: see rust-lang/rust#53668 for more information
error: ambigious use of `||`
--> $DIR/syntax-ambiguity-2015.rs:24:47
|
LL | if let Range { start: _, end: _ } = true..true || false { }
| ^^^^^^^^^^^^^ help: consider adding parentheses: `(true || false)`
|
= note: this will be a error until the `let_chains` feature is stabilized
= note: see rust-lang/rust#53668 for more information
error: ambigious use of `&&`
--> $DIR/syntax-ambiguity-2015.rs:27:50
|
LL | while let Range { start: _, end: _ } = true..true && false { }
| ^^^^^^^^^^^^^ help: consider adding parentheses: `(true && false)`
|
= note: this will be a error until the `let_chains` feature is stabilized
= note: see rust-lang/rust#53668 for more information
error: ambigious use of `||`
--> $DIR/syntax-ambiguity-2015.rs:30:50
|
LL | while let Range { start: _, end: _ } = true..true || false { }
| ^^^^^^^^^^^^^ help: consider adding parentheses: `(true || false)`
|
= note: this will be a error until the `let_chains` feature is stabilized
= note: see rust-lang/rust#53668 for more information
error: ambigious use of `&&`
--> $DIR/syntax-ambiguity-2015.rs:33:19
|
LL | if let true = false && false { }
| ^^^^^^^^^^^^^^ help: consider adding parentheses: `(false && false)`
|
= note: this will be a error until the `let_chains` feature is stabilized
= note: see rust-lang/rust#53668 for more information
error: ambigious use of `&&`
--> $DIR/syntax-ambiguity-2015.rs:36:22
|
LL | while let true = (1 == 2) && false { }
| ^^^^^^^^^^^^^^^^^ help: consider adding parentheses: `((1 == 2) && false)`
|
= note: this will be a error until the `let_chains` feature is stabilized
= note: see rust-lang/rust#53668 for more information
error: aborting due to 6 previous errors
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// edition:2018
// Enabling `ireffutable_let_patterns` isn't necessary for what this tests, but it makes coming up
// with examples easier.
#![feature(irrefutable_let_patterns)]
#[allow(irrefutable_let_patterns)]
fn main() {
use std::ops::Range;
if let Range { start: _, end: _ } = true..true && false { }
//~^ ERROR ambigious use of `&&`
if let Range { start: _, end: _ } = true..true || false { }
//~^ ERROR ambigious use of `||`
while let Range { start: _, end: _ } = true..true && false { }
//~^ ERROR ambigious use of `&&`
while let Range { start: _, end: _ } = true..true || false { }
//~^ ERROR ambigious use of `||`
if let true = false && false { }
//~^ ERROR ambigious use of `&&`
while let true = (1 == 2) && false { }
//~^ ERROR ambigious use of `&&`
// The following cases are not an error as parenthesis are used to
// clarify intent:
if let Range { start: _, end: _ } = true..(true || false) { }
if let Range { start: _, end: _ } = true..(true && false) { }
while let Range { start: _, end: _ } = true..(true || false) { }
while let Range { start: _, end: _ } = true..(true && false) { }
}
error: ambigious use of `&&`
--> $DIR/syntax-ambiguity-2018.rs:21:47
|
LL | if let Range { start: _, end: _ } = true..true && false { }
| ^^^^^^^^^^^^^ help: consider adding parentheses: `(true && false)`
|
= note: this will be a error until the `let_chains` feature is stabilized
= note: see rust-lang/rust#53668 for more information
error: ambigious use of `||`
--> $DIR/syntax-ambiguity-2018.rs:24:47
|
LL | if let Range { start: _, end: _ } = true..true || false { }
| ^^^^^^^^^^^^^ help: consider adding parentheses: `(true || false)`
|
= note: this will be a error until the `let_chains` feature is stabilized
= note: see rust-lang/rust#53668 for more information
error: ambigious use of `&&`
--> $DIR/syntax-ambiguity-2018.rs:27:50
|
LL | while let Range { start: _, end: _ } = true..true && false { }
| ^^^^^^^^^^^^^ help: consider adding parentheses: `(true && false)`
|
= note: this will be a error until the `let_chains` feature is stabilized
= note: see rust-lang/rust#53668 for more information
error: ambigious use of `||`
--> $DIR/syntax-ambiguity-2018.rs:30:50
|
LL | while let Range { start: _, end: _ } = true..true || false { }
| ^^^^^^^^^^^^^ help: consider adding parentheses: `(true || false)`
|
= note: this will be a error until the `let_chains` feature is stabilized
= note: see rust-lang/rust#53668 for more information
error: ambigious use of `&&`
--> $DIR/syntax-ambiguity-2018.rs:33:19
|
LL | if let true = false && false { }
| ^^^^^^^^^^^^^^ help: consider adding parentheses: `(false && false)`
|
= note: this will be a error until the `let_chains` feature is stabilized
= note: see rust-lang/rust#53668 for more information
error: ambigious use of `&&`
--> $DIR/syntax-ambiguity-2018.rs:36:22
|
LL | while let true = (1 == 2) && false { }
| ^^^^^^^^^^^^^^^^^ help: consider adding parentheses: `((1 == 2) && false)`
|
= note: this will be a error until the `let_chains` feature is stabilized
= note: see rust-lang/rust#53668 for more information
error: aborting due to 6 previous errors
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册