// 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};
}
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.
) {
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))
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) => {
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
}
| 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",
| | ^^^^ 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
| | 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 }
| | 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; }
--> $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 `()`
|
= 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);
+++ /dev/null
-// 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 _ = ();
-}
// check-only
-// run-rustfix
fn main() {
match 3 {
4 => 1,
3 => {
- 2 //~ ERROR mismatched types
+ foo() //~ ERROR mismatched types
}
_ => 2
}
}
let _ = ();
}
+
+fn foo() -> i32 {
+ 42
+}
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,