Skip to content

Detect missing else in let statement#156949

Open
bb1yd wants to merge 3 commits into
rust-lang:mainfrom
bb1yd:detect-missing-else
Open

Detect missing else in let statement#156949
bb1yd wants to merge 3 commits into
rust-lang:mainfrom
bb1yd:detect-missing-else

Conversation

@bb1yd

@bb1yd bb1yd commented May 26, 2026

Copy link
Copy Markdown
Contributor

View all comments

Fixes #135857

I add the help message in rustc_resolve. It now will display something like this:

error: expected identifier, found keyword `return`
 --> ./test.rs:8:24
  |
8 |      let Some(a) = bar{return;};
  |                    --- ^^^^^^ expected identifier, found keyword
  |                    |
  |                    while parsing this struct
  |
help: escape `return` to use it as an identifier
  |
8 |      let Some(a) = bar{r#return;};
  |                        ++

error[E0574]: expected struct, variant or union type, found local variable `bar`
 --> ./test.rs:8:20
  |
8 |      let Some(a) = bar{return;};
  |                    ^^^ not a struct, variant or union type
  |
help: try adding `else` here:
  |
8 |      let Some(a) = bar else {return;};
  |                        ++++

error: aborting due to 2 previous errors

For more information about this error, try `rustc --explain E0574`.

r? estebank

@rustbot rustbot added S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. labels May 26, 2026
@rust-log-analyzer

This comment has been minimized.

@rust-log-analyzer

This comment has been minimized.

@bb1yd

bb1yd commented May 26, 2026

Copy link
Copy Markdown
Contributor Author

@bors squash msg="fix issue-156949"

@rust-bors

This comment has been minimized.

@rust-bors

rust-bors Bot commented May 26, 2026

Copy link
Copy Markdown
Contributor

🔨 4 commits were squashed into 6bbafec.

@rust-bors
rust-bors Bot force-pushed the detect-missing-else branch from 7b541ec to 6bbafec Compare May 26, 2026 14:21
@bb1yd
bb1yd force-pushed the detect-missing-else branch from 6bbafec to 4946c86 Compare May 26, 2026 14:46

@estebank estebank left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for taking this on! I have some nitpicks for things that we should touch-up, but I think you're in the right direction.

View changes since this review

Comment thread tests/ui/resolve/detect-missing-else-in-let-1.rs
Comment thread compiler/rustc_resolve/src/late.rs Outdated
Comment thread compiler/rustc_resolve/src/late.rs Outdated
Comment thread compiler/rustc_resolve/src/late.rs Outdated
Comment thread tests/ui/resolve/detect-missing-else-in-let-1.stderr Outdated
@bb1yd

bb1yd commented Jun 1, 2026

Copy link
Copy Markdown
Contributor Author

@estebank Fixed

@bb1yd

bb1yd commented Jul 6, 2026

Copy link
Copy Markdown
Contributor Author

@rustbot author

@rustbot rustbot added S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels Jul 6, 2026
@rustbot

rustbot commented Jul 6, 2026

Copy link
Copy Markdown
Collaborator

Reminder, once the PR becomes ready for a review, use @rustbot ready.

@bb1yd
bb1yd force-pushed the detect-missing-else branch from d7ba54d to c68037d Compare July 8, 2026 12:46
@rustbot

This comment has been minimized.

@rustbot

rustbot commented Jul 8, 2026

Copy link
Copy Markdown
Collaborator

The parser was modified, potentially altering the grammar of (stable) Rust
which would be a breaking change.

cc @fmease

@bb1yd
bb1yd force-pushed the detect-missing-else branch from 7d6bb50 to 47e8efe Compare July 8, 2026 12:52
@rustbot

This comment has been minimized.

@bb1yd
bb1yd force-pushed the detect-missing-else branch from 47e8efe to fcb6c44 Compare July 8, 2026 13:00
@rustbot

This comment has been minimized.

@bb1yd
bb1yd force-pushed the detect-missing-else branch 2 times, most recently from 1243bc5 to 7f175f8 Compare July 8, 2026 13:43
@bb1yd

bb1yd commented Jul 10, 2026

Copy link
Copy Markdown
Contributor Author

I change the code to rustc_parse and it now only emit one error:

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

@rustbot rustbot added S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. and removed S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. labels Jul 10, 2026
@rust-bors

This comment has been minimized.

@bb1yd
bb1yd force-pushed the detect-missing-else branch from 7f175f8 to 0ea7df6 Compare July 12, 2026 13:54
@rustbot

rustbot commented Jul 12, 2026

Copy link
Copy Markdown
Collaborator

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.

Comment thread compiler/rustc_parse/src/parser/stmt.rs Outdated
Comment thread compiler/rustc_parse/src/parser/expr.rs Outdated
Comment thread compiler/rustc_parse/src/parser/expr.rs Outdated
Comment on lines +3960 to +3962
snapshot.recover_stmt();
snapshot.bump();
if might_be_stmt && snapshot.eat(exp!(Semi)) {

@estebank estebank Jul 14, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

View changes since the review

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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?

@bb1yd
bb1yd force-pushed the detect-missing-else branch from 0ea7df6 to 3ee2fb1 Compare July 15, 2026 08:30
@bb1yd

bb1yd commented Jul 15, 2026

Copy link
Copy Markdown
Contributor Author

@estebank Fixed

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Detect missing else in block with return

4 participants