-
Notifications
You must be signed in to change notification settings - Fork 13.3k
suggest !
instead of erroneous not
on if/while block parse failure
#48858
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -3211,6 +3211,21 @@ impl<'a> Parser<'a> { | |
} | ||
} | ||
|
||
/// If the condition of a `while` or `if` expression was an identifier | ||
/// named `not`, that's a clue that the confused user likely meant `!`. | ||
fn is_identifier_not(&self, cond: &Expr) -> bool { | ||
if let ExprKind::Path(_, ref path) = cond.node { | ||
if path.segments.len() == 1 { // just `not`, not `not::etc` | ||
if let Some(segment) = path.segments.iter().next() { | ||
if segment.identifier.name.as_str() == "not" { | ||
return true; | ||
} | ||
} | ||
} | ||
} | ||
false | ||
} | ||
|
||
/// Parse an 'if' or 'if let' expression ('if' token already eaten) | ||
pub fn parse_if_expr(&mut self, attrs: ThinVec<Attribute>) -> PResult<'a, P<Expr>> { | ||
if self.check_keyword(keywords::Let) { | ||
|
@@ -3232,6 +3247,11 @@ impl<'a> Parser<'a> { | |
} | ||
let not_block = self.token != token::OpenDelim(token::Brace); | ||
let thn = self.parse_block().map_err(|mut err| { | ||
if self.is_identifier_not(&cond) { | ||
err.span_suggestion(cond.span, // FIXME: replaced span doesn't incl. whitespace | ||
"try replacing identifier `not` with the negation operator", | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Looks a bit too wordy for a label, I'd personally use something "try replacing There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The motivation was to emphasize that |
||
"!".to_owned()); | ||
} | ||
if not_block { | ||
err.span_label(lo, "this `if` statement has a condition, but no block"); | ||
} | ||
|
@@ -3342,7 +3362,15 @@ impl<'a> Parser<'a> { | |
return self.parse_while_let_expr(opt_label, span_lo, attrs); | ||
} | ||
let cond = self.parse_expr_res(Restrictions::NO_STRUCT_LITERAL, None)?; | ||
let (iattrs, body) = self.parse_inner_attrs_and_block()?; | ||
let (iattrs, body) = self.parse_inner_attrs_and_block() | ||
.map_err(|mut err| { | ||
if self.is_identifier_not(&cond) { | ||
let msg = "try replacing identifier `not` with the negation operator"; | ||
// FIXME: replaced span doesn't include trailing whitespace | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You could merge the |
||
err.span_suggestion(cond.span, msg, "!".to_owned()); | ||
} | ||
err | ||
})?; | ||
attrs.extend(iattrs); | ||
let span = span_lo.to(body.span); | ||
return Ok(self.mk_expr(span, ExprKind::While(cond, body, opt_label), attrs)); | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
// Copyright 2018 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. | ||
|
||
fn gratitude() { | ||
let for_you = false; | ||
if not for_you { | ||
//~^ ERROR expected `{` | ||
println!("I couldn't"); | ||
//~^ ERROR expected one of | ||
} | ||
} | ||
|
||
fn qualification() { | ||
let the_worst = true; | ||
while not the_worst { | ||
//~^ ERROR expected one of | ||
println!("still pretty bad"); | ||
} | ||
} | ||
|
||
fn defer() { | ||
let department = false; | ||
// `not` as one segment of a longer path doesn't trigger the smart help | ||
if not::my department { | ||
//~^ ERROR expected `{` | ||
println!("pass"); | ||
//~^ ERROR expected one of | ||
} | ||
} | ||
|
||
fn should_we() { | ||
let not = true; | ||
if not // lack of braces is [sic] | ||
println!("Then when?"); | ||
//~^ ERROR expected `{` | ||
} | ||
|
||
fn main() {} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,68 @@ | ||
error: expected one of `,` or `}`, found `!` | ||
--> $DIR/issue-46836-identifier-not-instead-of-negation.rs:15:16 | ||
| | ||
LL | println!("I couldn't"); | ||
| ^ expected one of `,` or `}` here | ||
|
||
error: expected `{`, found `for_you` | ||
--> $DIR/issue-46836-identifier-not-instead-of-negation.rs:13:12 | ||
| | ||
LL | if not for_you { | ||
| -- ^^^^^^^ | ||
| | | ||
| this `if` statement has a condition, but no block | ||
help: try placing this code inside a block | ||
| | ||
LL | if not { for_you{println,}; } | ||
| ^^^^^^^^^^^^^^^^^^^^^^ | ||
help: try replacing identifier `not` with the negation operator | ||
| | ||
LL | if ! for_you { | ||
| ^ | ||
|
||
error: expected one of `!`, `.`, `::`, `?`, `{`, or an operator, found `the_worst` | ||
--> $DIR/issue-46836-identifier-not-instead-of-negation.rs:22:15 | ||
| | ||
LL | while not the_worst { | ||
| --- ^^^^^^^^^ expected one of `!`, `.`, `::`, `?`, `{`, or an operator here | ||
| | | ||
| help: try replacing identifier `not` with the negation operator: `!` | ||
|
||
error: expected one of `,` or `}`, found `!` | ||
--> $DIR/issue-46836-identifier-not-instead-of-negation.rs:33:16 | ||
| | ||
LL | println!("pass"); | ||
| ^ expected one of `,` or `}` here | ||
|
||
error: expected `{`, found `department` | ||
--> $DIR/issue-46836-identifier-not-instead-of-negation.rs:31:16 | ||
| | ||
LL | if not::my department { | ||
| -- -^^^^^^^^^ | ||
| _____|__________| | ||
| | | | ||
| | this `if` statement has a condition, but no block | ||
LL | | //~^ ERROR expected `{` | ||
LL | | println!("pass"); | ||
LL | | //~^ ERROR expected one of | ||
LL | | } | ||
| |_____- help: try placing this code inside a block: `{ department{println,}; }` | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can you also modify |
||
|
||
error: expected `{`, found `println` | ||
--> $DIR/issue-46836-identifier-not-instead-of-negation.rs:41:9 | ||
| | ||
LL | if not // lack of braces is [sic] | ||
| -- this `if` statement has a condition, but no block | ||
LL | println!("Then when?"); | ||
| ^^^^^^^ | ||
help: try placing this code inside a block | ||
| | ||
LL | { println!("Then when?") } | ||
| | ||
help: try replacing identifier `not` with the negation operator | ||
| | ||
LL | if ! // lack of braces is [sic] | ||
| ^ | ||
|
||
error: aborting due to 6 previous errors | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
re: span, same as below