Description
Code
trait T {
fn f(self);
}
impl T for () {
fn f(self) {
let self = ();
}
}
Current output
error[E0424]: expected unit struct, unit variant or constant, found local variable `self`
--> src/lib.rs:6:11
|
5 | / fn f(self) {
6 | | let self = ();
| | ^^^^ `self` value is a keyword and may not be bound to variables or shadowed
7 | | }
| |___- this function has a `self` parameter, but a macro invocation can only access identifiers it receives from parameters
Desired output
error[E0424]: expected unit struct, unit variant or constant, found local variable `self`
--> src/lib.rs:6:11
|
5 | fn f(self) {
6 | let self = ();
| ^^^^ `self` value is a keyword and may not be bound to variables or shadowed
7 | }
|
|
help: remove this `let` keyword if you meant to assign to `self`
7 | let self = ();
| ^^^
Rationale and extra context
This code uses absolutely no macros, yet the diagnostic complains about macro hygiene! This seems to have been introduced while fixing #39057
I'm not really sure what's the best diagnostic here. Suggesting to remove the let
keyword like i did here is probably not the best choice? But at least in the very simple case of let self =
, it is probably what the user intended. (nevermind that self
is not mut
, because if the suggestion is applied, another diagnostic will suggest to add mut
to the receiver)
Maybe a better diagnostic would briefly explain what is expected on the left-hand-side of an assignment expression where the self
value is allowed, why it's not quite the same as a pattern, and that this is in fact a pattern where the self
value is never allowed, or link to a documentation page explaining the difference.
If the method has no receiver ("Other cases", T::f()
), then let self = ();
will instead suggest adding a receiver. This is also wrong, because adding a receiver is not a valid fix to the issue (i.e. self
value is never valid in a pattern).
Maybe the diagnostic in both cases should be identical, and only explain that self
is not valid in this position, and that it has nothing to do with whether or not the method has a receiver or not?
The diagnostic for let self = ();
in a toplevel function ("Other cases", g()
) is already good, and simply states that the function cannot have a self
receiver.
Other cases
trait T {
fn f();
}
impl T for () {
fn f() {
let self = ();
}
}
fn g() {
let self = ();
}
Output from other cases
error[E0424]: expected unit struct, unit variant or constant, found module `self`
--> src/main.rs:6:13
|
5 | fn f() {
| - this function doesn't have a `self` parameter
6 | let self = ();
| ^^^^ `self` value is a keyword and may not be bound to variables or shadowed
|
help: add a `self` receiver parameter to make the associated `fn` a method
|
5 | fn f(&self) {
| +++++
error[E0424]: expected unit struct, unit variant or constant, found module `self`
--> src/main.rs:11:9
|
10 | fn g() {
| - this function can't have a `self` parameter
11 | let self = ();
| ^^^^ `self` value is a keyword and may not be bound to variables or shadowed
Rust Version
rustc 1.90.0-nightly (bdaba05a9 2025-06-27)
binary: rustc
commit-hash: bdaba05a953eb5abeba0011cdda2560d157aed2e
commit-date: 2025-06-27
host: x86_64-unknown-linux-gnu
release: 1.90.0-nightly
LLVM version: 20.1.7