Detect missing else in let statement#156949
Conversation
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
|
@bors squash msg="fix issue-156949" |
This comment has been minimized.
This comment has been minimized.
|
🔨 4 commits were squashed into 6bbafec. |
7b541ec to
6bbafec
Compare
6bbafec to
4946c86
Compare
|
@estebank Fixed |
|
@rustbot author |
|
Reminder, once the PR becomes ready for a review, use |
d7ba54d to
c68037d
Compare
This comment has been minimized.
This comment has been minimized.
|
The parser was modified, potentially altering the grammar of (stable) Rust cc @fmease |
7d6bb50 to
47e8efe
Compare
This comment has been minimized.
This comment has been minimized.
47e8efe to
fcb6c44
Compare
This comment has been minimized.
This comment has been minimized.
1243bc5 to
7f175f8
Compare
|
I change the code to error: expected identifier, found keyword `return`
--> $DIR/detect-missing-else-in-let-1.rs:4:23
|
LL | let Some(a) = foo{return;};
| --- ^^^^^^ expected identifier, found keyword
| |
| while parsing this struct
|
help: escape `return` to use it as an identifier
|
LL | let Some(a) = foo{r#return;};
| ++
help: you might have meant to write a diverging block on a refutable `let` statement by using `let-else`
for more information, visit <https://doc.rust-lang.org/beta/rust-by-example/flow_control/let_else.html>
|
LL | let Some(a) = foo else {return;};
| ++++
error: aborting due to 1 previous error@rustbot ready |
This comment has been minimized.
This comment has been minimized.
7f175f8 to
0ea7df6
Compare
|
This PR was rebased onto a different main commit. Here's a range-diff highlighting what actually changed. Rebasing is a normal part of keeping PRs up to date, so no action is needed—this note is just to help reviewers. |
| snapshot.recover_stmt(); | ||
| snapshot.bump(); | ||
| if might_be_stmt && snapshot.eat(exp!(Semi)) { |
There was a problem hiding this comment.
This doesn't feel quite right. You're recovering the current statement, so if we had foo { return 42; }, it would recover, but I feel like (given that we have a snapshot), we should instead look how we parse the block in let pat = expr else { block };, and call whatever method we call for it.
I'm not entirely sure what we've advanced in each step above. I would write this like this:
// Given `foo { return 42; };`
let mut snapshot = self.create_snapshot_for_diagnostic(); // We've consumed `foo {` already
let might_be_stmt = snapshot.token.is_keyword(kw::Return); // `return`
snapshot.recover_stmt(); // consume `return 42;`
snapshot.bump(); // `}`
if might_be_stmt && snapshot.eat(exp!(Semi)) {Maybe instead of snapshot.recover_stmt() we should do consume_block(), which will eat everything within the foo { .. }, regardless of what it is.
There was a problem hiding this comment.
recover_stmt actually behaves the same as consume_block which consumes everything until reaching } (except we can let consume_block to consume the closing delim), but yes, I think consume_block is better since it makes the intent clearer.
There was a problem hiding this comment.
I actually tried to use parse_block in my first attempt to detect whether the struct field is actually a block, so the compiler will emit the diagnostic for any valid block (currently we only accept single return). If parse_block fails we cancel the error produced by it and skip this diagnostics, but parse_block will try to internally recover instead of returning an error for us to cancel even when I set Recovery to No .
That's why I choose to use is_keyword.🙁
Is this considered a bug that (maybe) a lot of places does not respect Recovery field, or it's just not how Recovery field is used for?
0ea7df6 to
3ee2fb1
Compare
|
@estebank Fixed |
View all comments
Fixes #135857
I add the help message in rustc_resolve. It now will display something like this:
r? estebank