Skip to content

Parse lets as if they were items for diagnostics. - #159044

Draft
kpreid wants to merge 3 commits into
rust-lang:mainfrom
kpreid:pub-let
Draft

Parse lets as if they were items for diagnostics. #159044
kpreid wants to merge 3 commits into
rust-lang:mainfrom
kpreid:pub-let

Conversation

@kpreid

@kpreid kpreid commented Jul 9, 2026

Copy link
Copy Markdown
Contributor

View all comments

Partially addresses #92615.
Fixes #101622.

This change provides a precise diagnostic in all cases of let appearing in a context where items but not statements are permitted, and let appearing after an item modifier keyword (pub or final).

It provides a suggestion for replacing let with const (which should be usable interactively in rust-analyzer). It provides advice when the user might have thought final meant what it means in Java (immutable variable declaration).

It also consolidates two existing, less powerful let diagnostics into the new code: one for module bodies, and one for trait/impl bodies.

In order to be able to determine whether a let would parse if written properly, it adds a new parameter to the parsing functions, StmtWouldBeAllowed. This is a bit intrusive and not ideal, but I couldn’t think of a better solution, other than extending FnContext to mean more than it currently does, which seems not necessarily wise.

@rustbot

rustbot commented Jul 9, 2026

Copy link
Copy Markdown
Collaborator

rustfmt is developed in its own repository. If possible, consider making this change to rust-lang/rustfmt instead.

cc @rust-lang/rustfmt

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

cc @fmease

@rustbot rustbot added the S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. label Jul 9, 2026
@rustbot rustbot added T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. T-rustdoc Relevant to the rustdoc team, which will review and decide on the PR/issue. T-rustfmt Relevant to the rustfmt team, which will review and decide on the PR/issue. labels Jul 9, 2026
@rustbot

rustbot commented Jul 9, 2026

Copy link
Copy Markdown
Collaborator

r? @fee1-dead

rustbot has assigned @fee1-dead.
They will have a look at your PR within the next two weeks and either review your PR or reassign to another reviewer.

Use r? to explicitly pick a reviewer

Why was this reviewer chosen?

The reviewer was selected based on:

  • Owners of files modified in this PR: compiler, parser
  • compiler, parser expanded to 75 candidates
  • Random selection from 20 candidates

@rust-log-analyzer

This comment has been minimized.

.parse_item(
ForceCollect::Yes,
AllowConstBlockItems::Yes,
StmtWouldBeAllowed::NoOrUnknown,

@kpreid kpreid Jul 9, 2026

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 don’t like that I had to add a new parameter to parse_item everywhere, but I don’t know what would be better. Probably a new distinct entry point function.

View changes since the review

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

yeah, I don't like we need to change parse_item everywhere, seems not worth for this diganostic.

@kpreid kpreid Jul 9, 2026

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.

Tidy doesn’t like how long this file is now. Should I split it in this PR? Put up a separate PR? Ignore?

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.

In the absence of outside advice, I have split a new file parser/function.rs out of parser/item.rs to satisfy tidy. I will be happy to make that change in a separate PR if that is preferred.

let error = match allow_suggest_stmt {
StmtWouldBeAllowed::Yes => {
// We are in a function, `const` block, or other context in which a `let`
// *would* be allowed, except that we must have parsed some item-modifier

@kpreid kpreid Jul 9, 2026

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.

Is there an established term for these keywords like pub and final that appear before the item-kind keyword? I picked “modifier” arbitrarily.

View changes since the review

}
};

// FIXME: Ideally, we would have a `ItemKind::Err` that optionally defines a name but

@kpreid kpreid Jul 9, 2026

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 could try to add this new item kind to this PR if desired.

View changes since the review

@rust-log-analyzer

This comment has been minimized.

@rust-bors

This comment has been minimized.

@rustbot

This comment has been minimized.

@rust-log-analyzer

This comment has been minimized.

kpreid added 3 commits July 16, 2026 17:18
This is needed to keep `item.rs` under the length limit.
This change provides a precise diagnostic in all cases of `let` appearing
in a context where items but not statements are permitted, and `let`
appearing after an item modifier keyword (`pub` or `final`).

It provides a suggestion for replacing `let` with `const` (which should
be usable interactively in rust-analyzer). It provides advice when the
user might have thought `final` meant what it means in Java (immutable
variable declaration).

It also consolidates two existing, less powerful `let` diagnostics into
the new code: one for module bodies, and one for `trait`/`impl` bodies.

In order to be able to determine whether a `let` *would* parse if
written properly, it adds a new parameter, `StmtWouldBeAllowed`. This
is a bit intrusive and not ideal, but I couldn’t think of a better
solution, other than extending `FnContext` to mean more than it
currently does, which seems not necessarily wise.
@rustbot

rustbot commented Jul 17, 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.

@fee1-dead

Copy link
Copy Markdown
Member

Sorry to be doing this but I am too swamped IRL to review a diff with this size.

@rustbot reroll

@rustbot rustbot assigned tiif and unassigned fee1-dead Jul 22, 2026
@kpreid

kpreid commented Jul 23, 2026

Copy link
Copy Markdown
Contributor Author

Note that this PR would be much smaller if:

  • the move of function parsing was in a different PR, or
  • StmtWouldBeAllowed was not added to many callers, and the needed information was obtained some other way.

I would welcome any guidance as to whether and how to do those things.

@rust-bors

rust-bors Bot commented Jul 24, 2026

Copy link
Copy Markdown
Contributor

☔ The latest upstream changes (presumably #159814) made this pull request unmergeable. Please resolve the merge conflicts by rebasing.

@tiif tiif left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Sorry for the delay, I tried to take a look at this but this change is too big for an area that I am not very familiar with. I just have a small comment.

@rustbot reroll

View changes since this review

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

This seems weird because there is no let statement here 🤔

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.

This is a .fixed file: it is an edited version of the corresponding .rs file which shows the result of applying a suggestion. This particular suggestion replaced let with const. So, it is correct that the //~^ ERROR shows an error that is not in the file.

| ^^^
|
= note: `let` cannot be used to define global variables
= help: consider using `static` and a `Mutex` instead of `let mut`

@chenyukang chenyukang Jul 28, 2026

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

why we remove the url link in old stderr, something like

error: expected item, found keyword `let`
 --> tests/ui/parser/let/suggest-const-for-global-var.rs:1:1
  |
1 | let X: i32 = 12;
  | ^^^
  | |
  | `let` cannot be used for global variables
  | help: consider using `static` or `const` instead of `let`
  |
  = note: for a full list of items that can appear in modules, see <https://doc.rust-lang.org/reference/items.html>

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.

The link is part of an error path primarily meant for the parser telling the user “You gave me something I don’t recognize at all. Here are the things I do recognize.” But in this case, we know exactly what the syntax means, and it’s just not valid in this context. So, telling the user to browse the full list, looking for something that resembles what they want, is not useful.

That said, it would be easy to put this link back. I just don’t think we should.

macro_rules! m {
() => {
let //~ ERROR macro expansion ignores keyword `let` and any tokens following
loop //~ ERROR macro expansion ignores keyword `loop` and any tokens following

@chenyukang chenyukang Jul 28, 2026

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

not sure why you change this test.

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.

Because using let here would no longer exercise the code path that this test is meant to exercise.

@chenyukang

Copy link
Copy Markdown
Member

Note that this PR would be much smaller if:

  • the move of function parsing was in a different PR, or
  • StmtWouldBeAllowed was not added to many callers, and the needed information was obtained some other way.

I would welcome any guidance as to whether and how to do those things.

it's better to split the moving of function parsing to another seperate PR, it's better to review.

@kpreid

kpreid commented Jul 28, 2026

Copy link
Copy Markdown
Contributor Author

it's better to split the moving of function parsing to another seperate PR, it's better to review.

I have just done that: #160040

@kpreid
kpreid marked this pull request as draft July 28, 2026 15:51
@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 28, 2026
jhpratt added a commit to jhpratt/rust that referenced this pull request Jul 30, 2026
Split function parsing out of `item.rs` to a new module.

`item.rs` is approaching the tidy-enforced length limit, and this will make room for new additions.

I have split this change out of PR rust-lang#159044 to reduce its complexity (and because this large code move quickly becomes stale).
JonathanBrouwer added a commit to JonathanBrouwer/rust that referenced this pull request Jul 30, 2026
Split function parsing out of `item.rs` to a new module.

`item.rs` is approaching the tidy-enforced length limit, and this will make room for new additions.

I have split this change out of PR rust-lang#159044 to reduce its complexity (and because this large code move quickly becomes stale).
jhpratt added a commit to jhpratt/rust that referenced this pull request Jul 30, 2026
Split function parsing out of `item.rs` to a new module.

`item.rs` is approaching the tidy-enforced length limit, and this will make room for new additions.

I have split this change out of PR rust-lang#159044 to reduce its complexity (and because this large code move quickly becomes stale).
JonathanBrouwer added a commit to JonathanBrouwer/rust that referenced this pull request Jul 30, 2026
Split function parsing out of `item.rs` to a new module.

`item.rs` is approaching the tidy-enforced length limit, and this will make room for new additions.

I have split this change out of PR rust-lang#159044 to reduce its complexity (and because this large code move quickly becomes stale).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. T-rustdoc Relevant to the rustdoc team, which will review and decide on the PR/issue. T-rustfmt Relevant to the rustfmt team, which will review and decide on the PR/issue.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Poor recovery from pub let x = ...

6 participants