Skip to content

Commit e22019d

Browse files
committed
Auto merge of #10593 - feniljain:fix-needless-return, r=xFrednet
fix(needless_return): do not trigger on ambiguous match arms return If we see a case where match returns something other than `()`, we just skip `needless_return` lint in that case Should fix #10546 Relevant Zulip Discussion: https://rust-lang.zulipchat.com/#narrow/stream/257328-clippy/topic/Issue.20.2310546 --- changelog: FP: [`needless_return`]: No longer lints match statements with incompatible branches [#10593](#10593) <!-- changelog_checked -->
2 parents 4904d75 + 9cf57d0 commit e22019d

File tree

3 files changed

+43
-7
lines changed

3 files changed

+43
-7
lines changed

clippy_lints/src/returns.rs

+25-7
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ use rustc_hir::intravisit::FnKind;
99
use rustc_hir::{Block, Body, Expr, ExprKind, FnDecl, LangItem, MatchSource, PatKind, QPath, StmtKind};
1010
use rustc_lint::{LateContext, LateLintPass, LintContext};
1111
use rustc_middle::lint::in_external_macro;
12-
use rustc_middle::ty::subst::GenericArgKind;
12+
use rustc_middle::ty::{self, subst::GenericArgKind, Ty};
1313
use rustc_session::{declare_lint_pass, declare_tool_lint};
1414
use rustc_span::def_id::LocalDefId;
1515
use rustc_span::source_map::Span;
@@ -175,7 +175,7 @@ impl<'tcx> LateLintPass<'tcx> for Return {
175175
} else {
176176
RetReplacement::Empty
177177
};
178-
check_final_expr(cx, body.value, vec![], replacement);
178+
check_final_expr(cx, body.value, vec![], replacement, None);
179179
},
180180
FnKind::ItemFn(..) | FnKind::Method(..) => {
181181
check_block_return(cx, &body.value.kind, sp, vec![]);
@@ -188,11 +188,11 @@ impl<'tcx> LateLintPass<'tcx> for Return {
188188
fn check_block_return<'tcx>(cx: &LateContext<'tcx>, expr_kind: &ExprKind<'tcx>, sp: Span, mut semi_spans: Vec<Span>) {
189189
if let ExprKind::Block(block, _) = expr_kind {
190190
if let Some(block_expr) = block.expr {
191-
check_final_expr(cx, block_expr, semi_spans, RetReplacement::Empty);
191+
check_final_expr(cx, block_expr, semi_spans, RetReplacement::Empty, None);
192192
} else if let Some(stmt) = block.stmts.iter().last() {
193193
match stmt.kind {
194194
StmtKind::Expr(expr) => {
195-
check_final_expr(cx, expr, semi_spans, RetReplacement::Empty);
195+
check_final_expr(cx, expr, semi_spans, RetReplacement::Empty, None);
196196
},
197197
StmtKind::Semi(semi_expr) => {
198198
// Remove ending semicolons and any whitespace ' ' in between.
@@ -202,7 +202,7 @@ fn check_block_return<'tcx>(cx: &LateContext<'tcx>, expr_kind: &ExprKind<'tcx>,
202202
span_find_starting_semi(cx.sess().source_map(), semi_span.with_hi(sp.hi()));
203203
semi_spans.push(semi_span_to_remove);
204204
}
205-
check_final_expr(cx, semi_expr, semi_spans, RetReplacement::Empty);
205+
check_final_expr(cx, semi_expr, semi_spans, RetReplacement::Empty, None);
206206
},
207207
_ => (),
208208
}
@@ -216,6 +216,7 @@ fn check_final_expr<'tcx>(
216216
semi_spans: Vec<Span>, /* containing all the places where we would need to remove semicolons if finding an
217217
* needless return */
218218
replacement: RetReplacement<'tcx>,
219+
match_ty_opt: Option<Ty<'_>>,
219220
) {
220221
let peeled_drop_expr = expr.peel_drop_temps();
221222
match &peeled_drop_expr.kind {
@@ -244,7 +245,22 @@ fn check_final_expr<'tcx>(
244245
RetReplacement::Expr(snippet, applicability)
245246
}
246247
} else {
247-
replacement
248+
match match_ty_opt {
249+
Some(match_ty) => {
250+
match match_ty.kind() {
251+
// If the code got till here with
252+
// tuple not getting detected before it,
253+
// then we are sure it's going to be Unit
254+
// type
255+
ty::Tuple(_) => RetReplacement::Unit,
256+
// We don't want to anything in this case
257+
// cause we can't predict what the user would
258+
// want here
259+
_ => return,
260+
}
261+
},
262+
None => replacement,
263+
}
248264
};
249265

250266
if !cx.tcx.hir().attrs(expr.hir_id).is_empty() {
@@ -268,8 +284,9 @@ fn check_final_expr<'tcx>(
268284
// note, if without else is going to be a type checking error anyways
269285
// (except for unit type functions) so we don't match it
270286
ExprKind::Match(_, arms, MatchSource::Normal) => {
287+
let match_ty = cx.typeck_results().expr_ty(peeled_drop_expr);
271288
for arm in arms.iter() {
272-
check_final_expr(cx, arm.body, semi_spans.clone(), RetReplacement::Unit);
289+
check_final_expr(cx, arm.body, semi_spans.clone(), RetReplacement::Unit, Some(match_ty));
273290
}
274291
},
275292
// if it's a whole block, check it
@@ -293,6 +310,7 @@ fn emit_return_lint(cx: &LateContext<'_>, ret_span: Span, semi_spans: Vec<Span>,
293310
if ret_span.from_expansion() {
294311
return;
295312
}
313+
296314
let applicability = replacement.applicability().unwrap_or(Applicability::MachineApplicable);
297315
let return_replacement = replacement.to_string();
298316
let sugg_help = replacement.sugg_help();

tests/ui/needless_return.fixed

+9
Original file line numberDiff line numberDiff line change
@@ -307,4 +307,13 @@ mod issue10049 {
307307
}
308308
}
309309

310+
fn test_match_as_stmt() {
311+
let x = 9;
312+
match x {
313+
1 => 2,
314+
2 => return,
315+
_ => 0,
316+
};
317+
}
318+
310319
fn main() {}

tests/ui/needless_return.rs

+9
Original file line numberDiff line numberDiff line change
@@ -317,4 +317,13 @@ mod issue10049 {
317317
}
318318
}
319319

320+
fn test_match_as_stmt() {
321+
let x = 9;
322+
match x {
323+
1 => 2,
324+
2 => return,
325+
_ => 0,
326+
};
327+
}
328+
320329
fn main() {}

0 commit comments

Comments
 (0)