Auto merge of #10844 - Centri3:let_unit_value, r=Alexendoo

Don't lint `let_unit_value` when `()` is explicit

since these are explicitly written (and not the result of a function call or anything else), they should be allowed, as they are both useful in some cases described in #9048

Fixes #9048

changelog: [`let_unit_value`]: Don't lint when `()` is explicit
This commit is contained in:
bors 2024-01-05 16:13:38 +00:00
commit 394f63fe94
7 changed files with 71 additions and 127 deletions

View file

@ -13,12 +13,31 @@ use rustc_middle::ty;
use super::LET_UNIT_VALUE; use super::LET_UNIT_VALUE;
pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, local: &'tcx Local<'_>) { pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, local: &'tcx Local<'_>) {
// skip `let () = { ... }`
if let PatKind::Tuple(fields, ..) = local.pat.kind
&& fields.is_empty()
{
return;
}
if let Some(init) = local.init if let Some(init) = local.init
&& !local.pat.span.from_expansion() && !local.pat.span.from_expansion()
&& !in_external_macro(cx.sess(), local.span) && !in_external_macro(cx.sess(), local.span)
&& !is_from_async_await(local.span) && !is_from_async_await(local.span)
&& cx.typeck_results().pat_ty(local.pat).is_unit() && cx.typeck_results().pat_ty(local.pat).is_unit()
{ {
// skip `let awa = ()`
if let ExprKind::Tup([]) = init.kind {
return;
}
// skip `let _: () = { ... }`
if let Some(ty) = local.ty
&& let TyKind::Tup([]) = ty.kind
{
return;
}
if (local.ty.map_or(false, |ty| !matches!(ty.kind, TyKind::Infer)) if (local.ty.map_or(false, |ty| !matches!(ty.kind, TyKind::Infer))
|| matches!(local.pat.kind, PatKind::Tuple([], ddpos) if ddpos.as_opt_usize().is_none())) || matches!(local.pat.kind, PatKind::Tuple([], ddpos) if ddpos.as_opt_usize().is_none()))
&& expr_needs_inferred_result(cx, init) && expr_needs_inferred_result(cx, init)
@ -34,7 +53,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, local: &'tcx Local<'_>) {
|diag| { |diag| {
diag.span_suggestion( diag.span_suggestion(
local.pat.span, local.pat.span,
"use a wild (`_`) binding", "use a wildcard binding",
"_", "_",
Applicability::MaybeIncorrect, // snippet Applicability::MaybeIncorrect, // snippet
); );

View file

@ -1,10 +0,0 @@
#![warn(clippy::let_unit_value)]
fn f() {}
static FN: fn() = f;
fn main() {
FN();
//~^ ERROR: this let-binding has unit value
//~| NOTE: `-D clippy::let-unit-value` implied by `-D warnings`
}

View file

@ -5,6 +5,4 @@ static FN: fn() = f;
fn main() { fn main() {
let _: () = FN(); let _: () = FN();
//~^ ERROR: this let-binding has unit value
//~| NOTE: `-D clippy::let-unit-value` implied by `-D warnings`
} }

View file

@ -1,11 +0,0 @@
error: this let-binding has unit value
--> $DIR/ice-8821.rs:7:5
|
LL | let _: () = FN();
| ^^^^^^^^^^^^^^^^^ help: omit the `let` binding: `FN();`
|
= note: `-D clippy::let-unit-value` implied by `-D warnings`
= help: to override `-D warnings` add `#[allow(clippy::let_unit_value)]`
error: aborting due to 1 previous error

View file

@ -13,7 +13,14 @@ fn main() {
let _y = 1; // this is fine let _y = 1; // this is fine
let _z = ((), 1); // this as well let _z = ((), 1); // this as well
if true { if true {
(); // do not lint this, since () is explicit
let _a = ();
let () = dummy();
let () = ();
() = dummy();
() = ();
let _a: () = ();
let _a: () = dummy();
} }
consume_units_with_for_loop(); // should be fine as well consume_units_with_for_loop(); // should be fine as well
@ -23,6 +30,8 @@ fn main() {
let_and_return!(()) // should be fine let_and_return!(()) // should be fine
} }
fn dummy() {}
// Related to issue #1964 // Related to issue #1964
fn consume_units_with_for_loop() { fn consume_units_with_for_loop() {
// `for_let_unit` lint should not be triggered by consuming them using for loop. // `for_let_unit` lint should not be triggered by consuming them using for loop.
@ -74,40 +83,29 @@ fn _returns_generic() {
x.then(|| T::default()) x.then(|| T::default())
} }
let _: () = f(); // Ok let _: () = f();
let _: () = f(); // Lint. let x: () = f();
let _: () = f2(0i32); // Ok let _: () = f2(0i32);
let _: () = f2(0i32); // Lint. let x: () = f2(0i32);
f3(()); // Lint let _: () = f3(());
f3(()); // Lint let x: () = f3(());
// Should lint: fn f4<T>(mut x: Vec<T>) -> T {
// fn f4<T>(mut x: Vec<T>) -> T { x.pop().unwrap()
// x.pop().unwrap() }
// } let _: () = f4(vec![()]);
// let _: () = f4(vec![()]); let x: () = f4(vec![()]);
// let x: () = f4(vec![()]);
// Ok
let _: () = { let _: () = {
let x = 5; let x = 5;
f2(x) f2(x)
}; };
let _: () = if true { f() } else { f2(0) }; // Ok let _: () = if true { f() } else { f2(0) };
let _: () = if true { f() } else { f2(0) }; // Lint let x: () = if true { f() } else { f2(0) };
// Ok
let _: () = match Some(0) {
None => f2(1),
Some(0) => f(),
Some(1) => f2(3),
Some(_) => f2('x'),
};
// Lint
match Some(0) { match Some(0) {
None => f2(1), None => f2(1),
Some(0) => f(), Some(0) => f(),
@ -155,7 +153,7 @@ fn _returns_generic() {
{ {
let _: () = x; let _: () = x;
let _: () = y; let _: () = y;
z; let _: () = z;
let _: () = x1; let _: () = x1;
let _: () = x2; let _: () = x2;
let _: () = opt; let _: () = opt;

View file

@ -13,7 +13,14 @@ fn main() {
let _y = 1; // this is fine let _y = 1; // this is fine
let _z = ((), 1); // this as well let _z = ((), 1); // this as well
if true { if true {
// do not lint this, since () is explicit
let _a = (); let _a = ();
let () = dummy();
let () = ();
() = dummy();
() = ();
let _a: () = ();
let _a: () = dummy();
} }
consume_units_with_for_loop(); // should be fine as well consume_units_with_for_loop(); // should be fine as well
@ -23,6 +30,8 @@ fn main() {
let_and_return!(()) // should be fine let_and_return!(()) // should be fine
} }
fn dummy() {}
// Related to issue #1964 // Related to issue #1964
fn consume_units_with_for_loop() { fn consume_units_with_for_loop() {
// `for_let_unit` lint should not be triggered by consuming them using for loop. // `for_let_unit` lint should not be triggered by consuming them using for loop.
@ -74,41 +83,30 @@ fn _returns_generic() {
x.then(|| T::default()) x.then(|| T::default())
} }
let _: () = f(); // Ok let _: () = f();
let x: () = f(); // Lint. let x: () = f();
let _: () = f2(0i32); // Ok let _: () = f2(0i32);
let x: () = f2(0i32); // Lint. let x: () = f2(0i32);
let _: () = f3(()); // Lint let _: () = f3(());
let x: () = f3(()); // Lint let x: () = f3(());
// Should lint: fn f4<T>(mut x: Vec<T>) -> T {
// fn f4<T>(mut x: Vec<T>) -> T { x.pop().unwrap()
// x.pop().unwrap() }
// } let _: () = f4(vec![()]);
// let _: () = f4(vec![()]); let x: () = f4(vec![()]);
// let x: () = f4(vec![()]);
// Ok
let _: () = { let _: () = {
let x = 5; let x = 5;
f2(x) f2(x)
}; };
let _: () = if true { f() } else { f2(0) }; // Ok let _: () = if true { f() } else { f2(0) };
let x: () = if true { f() } else { f2(0) }; // Lint let x: () = if true { f() } else { f2(0) };
// Ok let x = match Some(0) {
let _: () = match Some(0) {
None => f2(1),
Some(0) => f(),
Some(1) => f2(3),
Some(_) => f2('x'),
};
// Lint
let _: () = match Some(0) {
None => f2(1), None => f2(1),
Some(0) => f(), Some(0) => f(),
Some(1) => f2(3), Some(1) => f2(3),

View file

@ -8,13 +8,7 @@ LL | let _x = println!("x");
= help: to override `-D warnings` add `#[allow(clippy::let_unit_value)]` = help: to override `-D warnings` add `#[allow(clippy::let_unit_value)]`
error: this let-binding has unit value error: this let-binding has unit value
--> $DIR/let_unit.rs:16:9 --> $DIR/let_unit.rs:60:5
|
LL | let _a = ();
| ^^^^^^^^^^^^ help: omit the `let` binding: `();`
error: this let-binding has unit value
--> $DIR/let_unit.rs:51:5
| |
LL | / let _ = v LL | / let _ = v
LL | | .into_iter() LL | | .into_iter()
@ -37,45 +31,9 @@ LL + .unwrap();
| |
error: this let-binding has unit value error: this let-binding has unit value
--> $DIR/let_unit.rs:78:5 --> $DIR/let_unit.rs:109:5
| |
LL | let x: () = f(); // Lint. LL | / let x = match Some(0) {
| ^^^^-^^^^^^^^^^^
| |
| help: use a wild (`_`) binding: `_`
error: this let-binding has unit value
--> $DIR/let_unit.rs:81:5
|
LL | let x: () = f2(0i32); // Lint.
| ^^^^-^^^^^^^^^^^^^^^^
| |
| help: use a wild (`_`) binding: `_`
error: this let-binding has unit value
--> $DIR/let_unit.rs:83:5
|
LL | let _: () = f3(()); // Lint
| ^^^^^^^^^^^^^^^^^^^ help: omit the `let` binding: `f3(());`
error: this let-binding has unit value
--> $DIR/let_unit.rs:84:5
|
LL | let x: () = f3(()); // Lint
| ^^^^^^^^^^^^^^^^^^^ help: omit the `let` binding: `f3(());`
error: this let-binding has unit value
--> $DIR/let_unit.rs:100:5
|
LL | let x: () = if true { f() } else { f2(0) }; // Lint
| ^^^^-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| |
| help: use a wild (`_`) binding: `_`
error: this let-binding has unit value
--> $DIR/let_unit.rs:111:5
|
LL | / let _: () = match Some(0) {
LL | | None => f2(1), LL | | None => f2(1),
LL | | Some(0) => f(), LL | | Some(0) => f(),
LL | | Some(1) => f2(3), LL | | Some(1) => f2(3),
@ -93,11 +51,5 @@ LL + Some(_) => (),
LL + }; LL + };
| |
error: this let-binding has unit value error: aborting due to 3 previous errors
--> $DIR/let_unit.rs:158:13
|
LL | let _: () = z;
| ^^^^^^^^^^^^^^ help: omit the `let` binding: `z;`
error: aborting due to 10 previous errors