suggest ! instead of erroneous not on if/while block parse failure#48858
suggest ! instead of erroneous not on if/while block parse failure#48858zackmdavis wants to merge 1 commit intorust-lang:masterfrom
! instead of erroneous not on if/while block parse failure#48858Conversation
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.
estebank
left a comment
There was a problem hiding this comment.
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.
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.
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)).
| 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 |
|
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. |
| 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.
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.
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`  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
rustfixor an RLS-powered IDE) won'tbe optimal. (It doesn't look like any of the existing
CodeMapmethodsmake 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