Skip to content

Commit fb945f0

Browse files
committed
Auto merge of #53854 - davidtwco:issue-53668, r=nikomatsakis
if- and while-let-chains, take 2 - edition changes Part of #53668. r? @nikomatsakis
2 parents fdcd4a4 + 0a8cf67 commit fb945f0

File tree

5 files changed

+261
-0
lines changed

5 files changed

+261
-0
lines changed

src/librustc_passes/ast_validation.rs

+51
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ use syntax::ast::*;
2222
use syntax::attr;
2323
use syntax::source_map::Spanned;
2424
use syntax::symbol::keywords;
25+
use syntax::ptr::P;
2526
use syntax::visit::{self, Visitor};
2627
use syntax_pos::Span;
2728
use 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

172221
impl<'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
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
// edition:2015
12+
13+
// Enabling `ireffutable_let_patterns` isn't necessary for what this tests, but it makes coming up
14+
// with examples easier.
15+
#![feature(irrefutable_let_patterns)]
16+
17+
#[allow(irrefutable_let_patterns)]
18+
fn main() {
19+
use std::ops::Range;
20+
21+
if let Range { start: _, end: _ } = true..true && false { }
22+
//~^ ERROR ambigious use of `&&`
23+
24+
if let Range { start: _, end: _ } = true..true || false { }
25+
//~^ ERROR ambigious use of `||`
26+
27+
while let Range { start: _, end: _ } = true..true && false { }
28+
//~^ ERROR ambigious use of `&&`
29+
30+
while let Range { start: _, end: _ } = true..true || false { }
31+
//~^ ERROR ambigious use of `||`
32+
33+
if let true = false && false { }
34+
//~^ ERROR ambigious use of `&&`
35+
36+
while let true = (1 == 2) && false { }
37+
//~^ ERROR ambigious use of `&&`
38+
39+
// The following cases are not an error as parenthesis are used to
40+
// clarify intent:
41+
42+
if let Range { start: _, end: _ } = true..(true || false) { }
43+
44+
if let Range { start: _, end: _ } = true..(true && false) { }
45+
46+
while let Range { start: _, end: _ } = true..(true || false) { }
47+
48+
while let Range { start: _, end: _ } = true..(true && false) { }
49+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
error: ambigious use of `&&`
2+
--> $DIR/syntax-ambiguity-2015.rs:21:47
3+
|
4+
LL | if let Range { start: _, end: _ } = true..true && false { }
5+
| ^^^^^^^^^^^^^ help: consider adding parentheses: `(true && false)`
6+
|
7+
= note: this will be a error until the `let_chains` feature is stabilized
8+
= note: see rust-lang/rust#53668 for more information
9+
10+
error: ambigious use of `||`
11+
--> $DIR/syntax-ambiguity-2015.rs:24:47
12+
|
13+
LL | if let Range { start: _, end: _ } = true..true || false { }
14+
| ^^^^^^^^^^^^^ help: consider adding parentheses: `(true || false)`
15+
|
16+
= note: this will be a error until the `let_chains` feature is stabilized
17+
= note: see rust-lang/rust#53668 for more information
18+
19+
error: ambigious use of `&&`
20+
--> $DIR/syntax-ambiguity-2015.rs:27:50
21+
|
22+
LL | while let Range { start: _, end: _ } = true..true && false { }
23+
| ^^^^^^^^^^^^^ help: consider adding parentheses: `(true && false)`
24+
|
25+
= note: this will be a error until the `let_chains` feature is stabilized
26+
= note: see rust-lang/rust#53668 for more information
27+
28+
error: ambigious use of `||`
29+
--> $DIR/syntax-ambiguity-2015.rs:30:50
30+
|
31+
LL | while let Range { start: _, end: _ } = true..true || false { }
32+
| ^^^^^^^^^^^^^ help: consider adding parentheses: `(true || false)`
33+
|
34+
= note: this will be a error until the `let_chains` feature is stabilized
35+
= note: see rust-lang/rust#53668 for more information
36+
37+
error: ambigious use of `&&`
38+
--> $DIR/syntax-ambiguity-2015.rs:33:19
39+
|
40+
LL | if let true = false && false { }
41+
| ^^^^^^^^^^^^^^ help: consider adding parentheses: `(false && false)`
42+
|
43+
= note: this will be a error until the `let_chains` feature is stabilized
44+
= note: see rust-lang/rust#53668 for more information
45+
46+
error: ambigious use of `&&`
47+
--> $DIR/syntax-ambiguity-2015.rs:36:22
48+
|
49+
LL | while let true = (1 == 2) && false { }
50+
| ^^^^^^^^^^^^^^^^^ help: consider adding parentheses: `((1 == 2) && false)`
51+
|
52+
= note: this will be a error until the `let_chains` feature is stabilized
53+
= note: see rust-lang/rust#53668 for more information
54+
55+
error: aborting due to 6 previous errors
56+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
// edition:2018
12+
13+
// Enabling `ireffutable_let_patterns` isn't necessary for what this tests, but it makes coming up
14+
// with examples easier.
15+
#![feature(irrefutable_let_patterns)]
16+
17+
#[allow(irrefutable_let_patterns)]
18+
fn main() {
19+
use std::ops::Range;
20+
21+
if let Range { start: _, end: _ } = true..true && false { }
22+
//~^ ERROR ambigious use of `&&`
23+
24+
if let Range { start: _, end: _ } = true..true || false { }
25+
//~^ ERROR ambigious use of `||`
26+
27+
while let Range { start: _, end: _ } = true..true && false { }
28+
//~^ ERROR ambigious use of `&&`
29+
30+
while let Range { start: _, end: _ } = true..true || false { }
31+
//~^ ERROR ambigious use of `||`
32+
33+
if let true = false && false { }
34+
//~^ ERROR ambigious use of `&&`
35+
36+
while let true = (1 == 2) && false { }
37+
//~^ ERROR ambigious use of `&&`
38+
39+
// The following cases are not an error as parenthesis are used to
40+
// clarify intent:
41+
42+
if let Range { start: _, end: _ } = true..(true || false) { }
43+
44+
if let Range { start: _, end: _ } = true..(true && false) { }
45+
46+
while let Range { start: _, end: _ } = true..(true || false) { }
47+
48+
while let Range { start: _, end: _ } = true..(true && false) { }
49+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
error: ambigious use of `&&`
2+
--> $DIR/syntax-ambiguity-2018.rs:21:47
3+
|
4+
LL | if let Range { start: _, end: _ } = true..true && false { }
5+
| ^^^^^^^^^^^^^ help: consider adding parentheses: `(true && false)`
6+
|
7+
= note: this will be a error until the `let_chains` feature is stabilized
8+
= note: see rust-lang/rust#53668 for more information
9+
10+
error: ambigious use of `||`
11+
--> $DIR/syntax-ambiguity-2018.rs:24:47
12+
|
13+
LL | if let Range { start: _, end: _ } = true..true || false { }
14+
| ^^^^^^^^^^^^^ help: consider adding parentheses: `(true || false)`
15+
|
16+
= note: this will be a error until the `let_chains` feature is stabilized
17+
= note: see rust-lang/rust#53668 for more information
18+
19+
error: ambigious use of `&&`
20+
--> $DIR/syntax-ambiguity-2018.rs:27:50
21+
|
22+
LL | while let Range { start: _, end: _ } = true..true && false { }
23+
| ^^^^^^^^^^^^^ help: consider adding parentheses: `(true && false)`
24+
|
25+
= note: this will be a error until the `let_chains` feature is stabilized
26+
= note: see rust-lang/rust#53668 for more information
27+
28+
error: ambigious use of `||`
29+
--> $DIR/syntax-ambiguity-2018.rs:30:50
30+
|
31+
LL | while let Range { start: _, end: _ } = true..true || false { }
32+
| ^^^^^^^^^^^^^ help: consider adding parentheses: `(true || false)`
33+
|
34+
= note: this will be a error until the `let_chains` feature is stabilized
35+
= note: see rust-lang/rust#53668 for more information
36+
37+
error: ambigious use of `&&`
38+
--> $DIR/syntax-ambiguity-2018.rs:33:19
39+
|
40+
LL | if let true = false && false { }
41+
| ^^^^^^^^^^^^^^ help: consider adding parentheses: `(false && false)`
42+
|
43+
= note: this will be a error until the `let_chains` feature is stabilized
44+
= note: see rust-lang/rust#53668 for more information
45+
46+
error: ambigious use of `&&`
47+
--> $DIR/syntax-ambiguity-2018.rs:36:22
48+
|
49+
LL | while let true = (1 == 2) && false { }
50+
| ^^^^^^^^^^^^^^^^^ help: consider adding parentheses: `((1 == 2) && false)`
51+
|
52+
= note: this will be a error until the `let_chains` feature is stabilized
53+
= note: see rust-lang/rust#53668 for more information
54+
55+
error: aborting due to 6 previous errors
56+

0 commit comments

Comments
 (0)