Skip to content

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

Open
kpreid wants to merge 2 commits into
rust-lang:mainfrom
kpreid:pub-let
Open

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

Conversation

@kpreid

@kpreid kpreid commented Jul 9, 2026

Copy link
Copy Markdown
Contributor

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.

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.
.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

@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

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

Copy link
Copy Markdown
Collaborator

The job tidy failed! Check out the build log: (web) (plain enhanced) (plain)

Click to see the possible cause of the failure (guessed by this bot)
fmt: checked 6998 files
tidy check
tidy [rustdoc_json (src)]: `rustdoc-json-types` modified, checking format version
tidy: Skipping binary file check, read-only filesystem
tidy [style (compiler)]: /checkout/compiler/rustc_parse/src/parser/item.rs: too many lines (3054) (add `// ignore-tidy-filelength` to the file to suppress this error)
tidy [style (compiler)]: FAIL
removing old virtual environment
creating virtual environment at '/checkout/obj/build/venv' using 'python3.10' and 'venv'
creating virtual environment at '/checkout/obj/build/venv' using 'python3.10' and 'virtualenv'
Requirement already satisfied: pip in ./build/venv/lib/python3.10/site-packages (26.1.2)
linting python files
---
info: ✓ ES-Check passed! All files are ES10 compatible.
typechecking javascript files
tidy: The following check failed: style (compiler)
Bootstrap failed while executing `test src/tools/tidy tidyselftest --extra-checks=py,cpp,js,spellcheck`
Command `/checkout/obj/build/x86_64-unknown-linux-gnu/stage1-tools-bin/rust-tidy --root-path=/checkout --cargo-path=/checkout/obj/build/x86_64-unknown-linux-gnu/stage0/bin/cargo --output-dir=/checkout/obj/build --concurrency=4 --npm-path=/node/bin/yarn --ci=true --extra-checks=py,cpp,js,spellcheck` failed with exit code 1
Created at: src/bootstrap/src/core/build_steps/tool.rs:1625:23
Executed at: src/bootstrap/src/core/build_steps/test.rs:1646:29

--- BACKTRACE vvv
   0: <bootstrap::utils::exec::DeferredCommand>::finish_process
             at /checkout/src/bootstrap/src/utils/exec.rs:939:17
   1: <bootstrap::utils::exec::DeferredCommand>::wait_for_output::<&bootstrap::utils::exec::ExecutionContext>
             at /checkout/src/bootstrap/src/utils/exec.rs:831:21
   2: <bootstrap::utils::exec::ExecutionContext>::run
             at /checkout/src/bootstrap/src/utils/exec.rs:741:45
   3: <bootstrap::utils::exec::BootstrapCommand>::run::<&bootstrap::core::builder::Builder>
             at /checkout/src/bootstrap/src/utils/exec.rs:339:27
   4: <bootstrap::core::build_steps::test::Tidy as bootstrap::core::builder::Step>::run
             at /checkout/src/bootstrap/src/core/build_steps/test.rs:1646:29
   5: <bootstrap::core::builder::Builder>::ensure::<bootstrap::core::build_steps::test::Tidy>
             at /checkout/src/bootstrap/src/core/builder/mod.rs:1607:36
   6: <bootstrap::core::build_steps::test::Tidy as bootstrap::core::builder::Step>::make_run
             at /checkout/src/bootstrap/src/core/build_steps/test.rs:1568:21
   7: <bootstrap::core::builder::StepDescription>::maybe_run
             at /checkout/src/bootstrap/src/core/builder/mod.rs:476:13
   8: bootstrap::core::builder::cli_paths::match_paths_to_steps_and_run
             at /checkout/src/bootstrap/src/core/builder/cli_paths.rs:232:18
   9: <bootstrap::core::builder::Builder>::run_step_descriptions
             at /checkout/src/bootstrap/src/core/builder/mod.rs:1140:9
  10: <bootstrap::core::builder::Builder>::execute_cli
             at /checkout/src/bootstrap/src/core/builder/mod.rs:1119:14
  11: <bootstrap::Build>::build
             at /checkout/src/bootstrap/src/lib.rs:803:25
  12: bootstrap::main
             at /checkout/src/bootstrap/src/bin/main.rs:130:11
  13: <fn() as core::ops::function::FnOnce<()>>::call_once
             at /rustc/0417c25868d6dfbd1c291dfeae950504faa6f790/library/core/src/ops/function.rs:250:5
  14: std::sys::backtrace::__rust_begin_short_backtrace::<fn(), ()>
             at /rustc/0417c25868d6dfbd1c291dfeae950504faa6f790/library/std/src/sys/backtrace.rs:166:18
  15: std::rt::lang_start::<()>::{closure#0}
             at /rustc/0417c25868d6dfbd1c291dfeae950504faa6f790/library/std/src/rt.rs:206:18
  16: <&dyn core::ops::function::Fn<(), Output = i32> + core::marker::Sync + core::panic::unwind_safe::RefUnwindSafe as core::ops::function::FnOnce<()>>::call_once
             at /rustc/0417c25868d6dfbd1c291dfeae950504faa6f790/library/core/src/ops/function.rs:287:21
  17: std::panicking::catch_unwind::do_call::<&dyn core::ops::function::Fn<(), Output = i32> + core::marker::Sync + core::panic::unwind_safe::RefUnwindSafe, i32>
             at /rustc/0417c25868d6dfbd1c291dfeae950504faa6f790/library/std/src/panicking.rs:581:40
  18: std::panicking::catch_unwind::<i32, &dyn core::ops::function::Fn<(), Output = i32> + core::marker::Sync + core::panic::unwind_safe::RefUnwindSafe>
             at /rustc/0417c25868d6dfbd1c291dfeae950504faa6f790/library/std/src/panicking.rs:544:19
  19: std::panic::catch_unwind::<&dyn core::ops::function::Fn<(), Output = i32> + core::marker::Sync + core::panic::unwind_safe::RefUnwindSafe, i32>
             at /rustc/0417c25868d6dfbd1c291dfeae950504faa6f790/library/std/src/panic.rs:359:14
  20: std::rt::lang_start_internal::{closure#0}
             at /rustc/0417c25868d6dfbd1c291dfeae950504faa6f790/library/std/src/rt.rs:175:24
  21: std::panicking::catch_unwind::do_call::<std::rt::lang_start_internal::{closure#0}, isize>
             at /rustc/0417c25868d6dfbd1c291dfeae950504faa6f790/library/std/src/panicking.rs:581:40
---
  28: __libc_start_main
  29: _start


Command has failed. Rerun with -v to see more details.
Build completed unsuccessfully in 0:02:32
  local time: Fri Jul 10 00:01:58 UTC 2026
  network time: Fri, 10 Jul 2026 00:01:58 GMT
##[error]Process completed with exit code 1.
##[group]Run echo "disk usage:"

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. 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 = ...

4 participants