-
Notifications
You must be signed in to change notification settings - Fork 12.7k
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
suggest !
instead of erroneous not
on if/while block parse failure
#48858
Conversation
Impressing confused Python users with magical diagnostics is probably worth this very slight (only 25ish lines) extra complexity in the parser? FIXME comments have been left to note that the formatting after autofixing the suggestion (with `rustfix` or an RLS-powered IDE) won't be optimal. (It doesn't look like any of the existing `CodeMap` methods make it easy to adjust the span.) Resolves rust-lang#46836.
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.
LGTM, minor suggestions.
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 comment
The reason will be displayed to describe this comment to others. Learn more.
Can you also modify parse_block
so that this suggestion is not given if the next token is an open brace, like in these cases? The suggestion as is is more likely to be wrong than right.
.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 comment
The reason will be displayed to describe this comment to others. Learn more.
You could merge the cond.span
with the next span, get the snippet and synthesize a span that does include the whitespace (in a similar way as suggested in #47574 (comment)).
@@ -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 |
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
Could you please place the |
This is a quite limited ad hoc way to check for
This would cover tests from this PR and more. |
@@ -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 comment
The 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 not
with !
", but as a minimum the word "identifier" can be removed here.
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.
The motivation was to emphasize that not
has no special meaning in Rust-the-language (it's just another ordinary variable/identifier), even if rustc
-the-compiler is (after this PR) nice enough to try to figure out notice what you meant, but I agree that ceteris paribus, longer messages are worse.
So, the set (already inverted) is |
Yeah, that's a good point.
Thanks for the pointer! I can probably look into doing it this way later today or tomorrow. |
I've made some exciting progress on the parse-prefix approach, but in addition to producing awesome diagnostics, my code also misparses some legitimate uses of I'm pretty busy with a new dayjob lately, so I likely won't be able to look at this again for a week. |
For example? |
I think it's more likely to be an off-by-one-token error in my recovery logic, an error which we can pray will be revealed in the cold light of (This commit is only using ident/literal/pound as the can't-continue-expression-after-ident set, because of the conjunction of my not feeling confident that I understand how the |
Ah, of course, the next token lookup is done with |
continued: #49258 |
suggest `!` for erroneous identifier `not` ![not_recovery](https://user-images.githubusercontent.com/1076988/37753255-3b669c42-2d59-11e8-9071-efad8eaf3086.png) This supersedes #48858. r? @petrochenkov
Impressing confused Python users with magical diagnostics is probably
worth this very slight (only 25ish lines) extra complexity in the
parser?
FIXME comments have been left to note that the formatting after
autofixing the suggestion (with
rustfix
or an RLS-powered IDE) won'tbe optimal. (It doesn't look like any of the existing
CodeMap
methodsmake it easy to adjust the span.)
Unfortunately, the parser doesn't seem smart enough to know which of the "try placing this code inside a block" and
!
suggestions is correct. (Also, the function that sets the "inside a block" suggestion doesn't and shouldn't know about the condition, so canceling that suggestion if the!
suggestion is issued would require a new clear-suggestions method onDiagnostic
/DiagnosticBuilder
, which I didn't want to write until we're convinced it's necessary.) The last function in the new UI test demonstrates a case in which the "block" suggestion is right and the!
suggestion is wrong.Resolves #46836.
r? @estebank