Do not suggest `;` if expression is side effect free
When a tail expression isn't unit, we previously always suggested adding a trailing `;` to turn it into a statement. This suggestion isn't appropriate for any expression that doesn't have side-effects, as the user will have likely wanted to call something else or do something with the resulting value, instead of just discarding it.
This commit is contained in:
parent
020edd91a9
commit
d669882f38
|
@ -1,5 +1,6 @@
|
|||
// ignore-tidy-filelength
|
||||
use crate::def::{DefKind, Namespace, Res};
|
||||
use crate::def::{CtorKind, DefKind, Namespace, Res};
|
||||
use crate::def_id::DefId;
|
||||
crate use crate::hir_id::HirId;
|
||||
use crate::{itemlikevisit, LangItem};
|
||||
|
@ -1554,6 +1555,63 @@ impl Expr<'_> {
|
|||
}
|
||||
expr
|
||||
}
|
||||
|
||||
pub fn can_have_side_effects(&self) -> bool {
|
||||
match self.peel_drop_temps().kind {
|
||||
ExprKind::Path(_) | ExprKind::Lit(_) => false,
|
||||
ExprKind::Type(base, _)
|
||||
| ExprKind::Unary(_, base)
|
||||
| ExprKind::Field(base, _)
|
||||
| ExprKind::Index(base, _)
|
||||
| ExprKind::AddrOf(.., base)
|
||||
| ExprKind::Cast(base, _) => {
|
||||
// This isn't exactly true for `Index` and all `Unnary`, but we are using this
|
||||
// method exclusively for diagnostics and there's a *cultural* pressure against
|
||||
// them being used only for its side-effects.
|
||||
base.can_have_side_effects()
|
||||
}
|
||||
ExprKind::Struct(_, fields, init) => fields
|
||||
.iter()
|
||||
.map(|field| field.expr)
|
||||
.chain(init.into_iter())
|
||||
.all(|e| e.can_have_side_effects()),
|
||||
|
||||
ExprKind::Array(args)
|
||||
| ExprKind::Tup(args)
|
||||
| ExprKind::Call(
|
||||
Expr {
|
||||
kind:
|
||||
ExprKind::Path(QPath::Resolved(
|
||||
None,
|
||||
Path { res: Res::Def(DefKind::Ctor(_, CtorKind::Fn), _), .. },
|
||||
)),
|
||||
..
|
||||
},
|
||||
args,
|
||||
) => args.iter().all(|arg| arg.can_have_side_effects()),
|
||||
ExprKind::If(..)
|
||||
| ExprKind::Match(..)
|
||||
| ExprKind::MethodCall(..)
|
||||
| ExprKind::Call(..)
|
||||
| ExprKind::Closure(..)
|
||||
| ExprKind::Block(..)
|
||||
| ExprKind::Repeat(..)
|
||||
| ExprKind::Break(..)
|
||||
| ExprKind::Continue(..)
|
||||
| ExprKind::Ret(..)
|
||||
| ExprKind::Loop(..)
|
||||
| ExprKind::Assign(..)
|
||||
| ExprKind::InlineAsm(..)
|
||||
| ExprKind::LlvmInlineAsm(..)
|
||||
| ExprKind::AssignOp(..)
|
||||
| ExprKind::ConstBlock(..)
|
||||
| ExprKind::Box(..)
|
||||
| ExprKind::Binary(..)
|
||||
| ExprKind::Yield(..)
|
||||
| ExprKind::DropTemps(..)
|
||||
| ExprKind::Err => true,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Checks if the specified expression is a built-in range literal.
|
||||
|
|
|
@ -1450,7 +1450,9 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> {
|
|||
) {
|
||||
if cond_expr.span.desugaring_kind().is_none() {
|
||||
err.span_label(cond_expr.span, "expected this to be `()`");
|
||||
fcx.suggest_semicolon_at_end(cond_expr.span, &mut err);
|
||||
if expr.can_have_side_effects() {
|
||||
fcx.suggest_semicolon_at_end(cond_expr.span, &mut err);
|
||||
}
|
||||
}
|
||||
}
|
||||
fcx.get_node_fn_decl(parent).map(|(fn_decl, _, is_main)| (fn_decl, is_main))
|
||||
|
|
|
@ -561,7 +561,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
hir::StmtKind::Expr(ref expr) => {
|
||||
// Check with expected type of `()`.
|
||||
self.check_expr_has_type_or_error(&expr, self.tcx.mk_unit(), |err| {
|
||||
self.suggest_semicolon_at_end(expr.span, err);
|
||||
if expr.can_have_side_effects() {
|
||||
self.suggest_semicolon_at_end(expr.span, err);
|
||||
}
|
||||
});
|
||||
}
|
||||
hir::StmtKind::Semi(ref expr) => {
|
||||
|
|
|
@ -44,11 +44,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
blk_id: hir::HirId,
|
||||
) -> bool {
|
||||
let expr = expr.peel_drop_temps();
|
||||
self.suggest_missing_semicolon(err, expr, expected, cause_span);
|
||||
if expr.can_have_side_effects() {
|
||||
self.suggest_missing_semicolon(err, expr, expected, cause_span);
|
||||
}
|
||||
let mut pointing_at_return_type = false;
|
||||
if let Some((fn_decl, can_suggest)) = self.get_fn_decl(blk_id) {
|
||||
pointing_at_return_type =
|
||||
self.suggest_missing_return_type(err, &fn_decl, expected, found, can_suggest);
|
||||
self.suggest_missing_return_expr(err, expr, &fn_decl, expected, found);
|
||||
}
|
||||
pointing_at_return_type
|
||||
}
|
||||
|
@ -392,7 +395,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
| ExprKind::Loop(..)
|
||||
| ExprKind::If(..)
|
||||
| ExprKind::Match(..)
|
||||
| ExprKind::Block(..) => {
|
||||
| ExprKind::Block(..)
|
||||
if expression.can_have_side_effects() =>
|
||||
{
|
||||
err.span_suggestion(
|
||||
cause_span.shrink_to_hi(),
|
||||
"consider using a semicolon here",
|
||||
|
|
|
@ -14,9 +14,7 @@ LL | | true
|
|||
| | ^^^^ expected `()`, found `bool`
|
||||
LL | |
|
||||
LL | | }
|
||||
| | -- help: consider using a semicolon here
|
||||
| |_____|
|
||||
| expected this to be `()`
|
||||
| |_____- expected this to be `()`
|
||||
|
||||
error: aborting due to previous error; 1 warning emitted
|
||||
|
||||
|
|
|
@ -7,10 +7,6 @@ LL | if let Some(x) = a { true } else { false }
|
|||
| | expected `()`, found `bool`
|
||||
| expected this to be `()`
|
||||
|
|
||||
help: consider using a semicolon here
|
||||
|
|
||||
LL | if let Some(x) = a { true } else { false };
|
||||
| ^
|
||||
help: you might have meant to return this value
|
||||
|
|
||||
LL | if let Some(x) = a { return true; } else { false }
|
||||
|
@ -25,10 +21,6 @@ LL | if let Some(x) = a { true } else { false }
|
|||
| | expected `()`, found `bool`
|
||||
| expected this to be `()`
|
||||
|
|
||||
help: consider using a semicolon here
|
||||
|
|
||||
LL | if let Some(x) = a { true } else { false };
|
||||
| ^
|
||||
help: you might have meant to return this value
|
||||
|
|
||||
LL | if let Some(x) = a { true } else { return false; }
|
||||
|
|
|
@ -57,7 +57,7 @@ error[E0308]: mismatched types
|
|||
--> $DIR/struct-literal-variant-in-if.rs:10:20
|
||||
|
|
||||
LL | if x == E::V { field } {}
|
||||
| ---------------^^^^^--- help: consider using a semicolon here
|
||||
| ---------------^^^^^--
|
||||
| | |
|
||||
| | expected `()`, found `bool`
|
||||
| expected this to be `()`
|
||||
|
|
|
@ -9,14 +9,6 @@ LL | | }
|
|||
|
|
||||
= note: expected unit type `()`
|
||||
found enum `std::result::Result<_, {integer}>`
|
||||
help: consider using a semicolon here
|
||||
|
|
||||
LL | Err(42);
|
||||
| ^
|
||||
help: consider using a semicolon here
|
||||
|
|
||||
LL | };
|
||||
| ^
|
||||
help: you might have meant to return this value
|
||||
|
|
||||
LL | return Err(42);
|
||||
|
|
|
@ -1,18 +0,0 @@
|
|||
// check-only
|
||||
// run-rustfix
|
||||
|
||||
fn main() {
|
||||
match 3 {
|
||||
4 => 1,
|
||||
3 => {
|
||||
2 //~ ERROR mismatched types
|
||||
}
|
||||
_ => 2
|
||||
};
|
||||
match 3 { //~ ERROR mismatched types
|
||||
4 => 1,
|
||||
3 => 2,
|
||||
_ => 2
|
||||
};
|
||||
let _ = ();
|
||||
}
|
|
@ -1,11 +1,10 @@
|
|||
// check-only
|
||||
// run-rustfix
|
||||
|
||||
fn main() {
|
||||
match 3 {
|
||||
4 => 1,
|
||||
3 => {
|
||||
2 //~ ERROR mismatched types
|
||||
foo() //~ ERROR mismatched types
|
||||
}
|
||||
_ => 2
|
||||
}
|
||||
|
@ -16,3 +15,7 @@ fn main() {
|
|||
}
|
||||
let _ = ();
|
||||
}
|
||||
|
||||
fn foo() -> i32 {
|
||||
42
|
||||
}
|
||||
|
|
|
@ -1,20 +1,27 @@
|
|||
error[E0308]: mismatched types
|
||||
--> $DIR/match-needing-semi.rs:8:13
|
||||
--> $DIR/match-needing-semi.rs:7:13
|
||||
|
|
||||
LL | / match 3 {
|
||||
LL | | 4 => 1,
|
||||
LL | | 3 => {
|
||||
LL | | 2
|
||||
| | ^ expected `()`, found integer
|
||||
LL | | foo()
|
||||
| | ^^^^^ expected `()`, found `i32`
|
||||
LL | | }
|
||||
LL | | _ => 2
|
||||
LL | | }
|
||||
| | -- help: consider using a semicolon here
|
||||
| |_____|
|
||||
| expected this to be `()`
|
||||
| |_____- expected this to be `()`
|
||||
|
|
||||
help: consider using a semicolon here
|
||||
|
|
||||
LL | foo();
|
||||
| ^
|
||||
help: consider using a semicolon here
|
||||
|
|
||||
LL | };
|
||||
| ^
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/match-needing-semi.rs:12:5
|
||||
--> $DIR/match-needing-semi.rs:11:5
|
||||
|
|
||||
LL | / match 3 {
|
||||
LL | | 4 => 1,
|
||||
|
|
Loading…
Reference in New Issue