-
Notifications
You must be signed in to change notification settings - Fork 12.8k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Warn on useless bindings like let v2 = v1.sort();
#71432
Comments
It seems like we at least want the |
It could possibly occur legitimately due to a macro, though. For example, this silly macro doesn't care whether the expression returns macro_rules! say_hello_after_evaluating_expr {
($expr:expr) => { {
let ret = $expr;
println!("hello!");
ret
} }
}
fn main() {
let forty_two = say_hello_after_evaluating_expr!(42);
say_hello_after_evaluating_expr!(println!("this returns ()!"));
} |
Well, in that situation the macro writer could just do a local |
How about nested fn foo() -> io::Result<()> { ... }
fn main() {
if let Ok(x) = foo() { ... }
} IOW, is this just about the RHS being |
I think this is about binding a name to Maybe the lint would then be less about the "this function returns unit" (though that could be a special case to provide better messaging on), but more so that any binding with a type of I'm trying to think of what exactly makes |
I think it would be reasonable to warn on any binding to Though any solution that captures simple cases like my original example is probably sufficient to provide most of the benefit here.
|
I definitely agree that catching just unit is probably enough. I was mostly trying to come up with some cases where I also want this for non-unit types -- but I was unable to do so. I'm going to nominate this issue for lang to hopefully gauge whether we want an FCP here or if adding a lint like this (naming to be bikeshedded) needs a full RFC. I personally lean towards maybe an FCP, maybe even just "no one in the room has objections" approval (we'd have some time to roll it back if necessary, of course). |
Of course clippy has this covered. There's probably even an xkcd for that. It was only recently downgraded to pedantic (allowed): rust-lang/rust-clippy#5409 |
I agree with @dtolnay that the bug there (with inference) seems like a hard blocker. But it seems plausible that we'd perhaps want it in rustc regardless as allow by default to start. Maybe if we throw compiler team at it someone will come up with an idea how to do it (seems related to @nikomatsakis work on the ! type inference). |
let _: () = f();
|
To bikeshed this further, i would argue that |
I think that this belongs in rustc (I have argued as much in the past) and the rules should be:
|
Agreed. The lint should cover the case where the user doesn't explicitly write the type |
We discussed this further in today's language team meeting, and came to the following consensus:
|
…ffleLapkin Add allow-by-default lint for unit bindings ### Example ```rust #![warn(unit_bindings)] macro_rules! owo { () => { let whats_this = (); } } fn main() { // No warning if user explicitly wrote `()` on either side. let expr = (); let () = expr; let _ = (); let _ = expr; //~ WARN binding has unit type let pat = expr; //~ WARN binding has unit type let _pat = expr; //~ WARN binding has unit type // No warning for let bindings with unit type in macro expansions. owo!(); // No warning if user explicitly annotates the unit type on the binding. let pat: () = expr; } ``` outputs ``` warning: binding has unit type `()` --> $DIR/unit-bindings.rs:17:5 | LL | let _ = expr; | ^^^^-^^^^^^^^ | | | this pattern is inferred to be the unit type `()` | note: the lint level is defined here --> $DIR/unit-bindings.rs:3:9 | LL | #![warn(unit_bindings)] | ^^^^^^^^^^^^^ warning: binding has unit type `()` --> $DIR/unit-bindings.rs:18:5 | LL | let pat = expr; | ^^^^---^^^^^^^^ | | | this pattern is inferred to be the unit type `()` warning: binding has unit type `()` --> $DIR/unit-bindings.rs:19:5 | LL | let _pat = expr; | ^^^^----^^^^^^^^ | | | this pattern is inferred to be the unit type `()` warning: 3 warnings emitted ``` This lint is not triggered if any of the following conditions are met: - The user explicitly annotates the binding with the `()` type. - The binding is from a macro expansion. - The user explicitly wrote `let () = init;` - The user explicitly wrote `let pat = ();`. This is allowed for local lifetimes. ### Known Issue It is known that this lint can trigger on some proc-macro generated code whose span returns false for `Span::from_expansion` because e.g. the proc-macro simply forwards user code spans, and otherwise don't have distinguishing syntax context compared to non-macro-generated code. For those kind of proc-macros, I believe the correct way to fix them is to instead emit identifers with span like `Span::mixed_site().located_at(user_span)`. Closes rust-lang#71432.
I've seen a lot of beginning Rust programmers make a mistake similar to the program below, which compiles and runs without warning:
The bug in this program is hard for new Rust programmers to spot. The compiler should help them, by warning that
x.sort()
does not return a value.This could be done with a new attribute
#[must_not_use]
, applied to functions likesort
. This would be the inverse ofmust_use
: It would warn only if the result of the function is used. Likemust_use
, it would take an optional argument that provides an additional diagnostic message.(Bikeshed:
must_not_use
may be a confusing name. Other suggestions welcome.)Or perhaps any assignment
let foo = expr;
whereexpr
has type()
should cause a warning by default. This would be a more general solution, catching more possible errors but also potentially causing more disruption. The warnings in this case might be less helpful, because they wouldn't include suggestions tailored to specific functions.The text was updated successfully, but these errors were encountered: