about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2023-04-10 21:52:47 +0000
committerbors <bors@rust-lang.org>2023-04-10 21:52:47 +0000
commite22019d0b78778a8a3ae1067082d2481690d4210 (patch)
treee54ee7bdc39a24e85aa8da2212470e21436d50d9
parent4904d754e07fd802bcd377c7e19d877a2f2895c8 (diff)
parent9cf57d0a8f95c51b0faeda4ce5c5b4cd629f1cae (diff)
downloadrust-e22019d0b78778a8a3ae1067082d2481690d4210.tar.gz
rust-e22019d0b78778a8a3ae1067082d2481690d4210.zip
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](https://github.com/rust-lang/rust-clippy/pull/10593)
<!-- changelog_checked -->
-rw-r--r--clippy_lints/src/returns.rs32
-rw-r--r--tests/ui/needless_return.fixed9
-rw-r--r--tests/ui/needless_return.rs9
3 files changed, 43 insertions, 7 deletions
diff --git a/clippy_lints/src/returns.rs b/clippy_lints/src/returns.rs
index f0d7dd23a67..df126d7617e 100644
--- a/clippy_lints/src/returns.rs
+++ b/clippy_lints/src/returns.rs
@@ -9,7 +9,7 @@ use rustc_hir::intravisit::FnKind;
 use rustc_hir::{Block, Body, Expr, ExprKind, FnDecl, LangItem, MatchSource, PatKind, QPath, StmtKind};
 use rustc_lint::{LateContext, LateLintPass, LintContext};
 use rustc_middle::lint::in_external_macro;
-use rustc_middle::ty::subst::GenericArgKind;
+use rustc_middle::ty::{self, subst::GenericArgKind, Ty};
 use rustc_session::{declare_lint_pass, declare_tool_lint};
 use rustc_span::def_id::LocalDefId;
 use rustc_span::source_map::Span;
@@ -175,7 +175,7 @@ impl<'tcx> LateLintPass<'tcx> for Return {
                 } else {
                     RetReplacement::Empty
                 };
-                check_final_expr(cx, body.value, vec![], replacement);
+                check_final_expr(cx, body.value, vec![], replacement, None);
             },
             FnKind::ItemFn(..) | FnKind::Method(..) => {
                 check_block_return(cx, &body.value.kind, sp, vec![]);
@@ -188,11 +188,11 @@ impl<'tcx> LateLintPass<'tcx> for Return {
 fn check_block_return<'tcx>(cx: &LateContext<'tcx>, expr_kind: &ExprKind<'tcx>, sp: Span, mut semi_spans: Vec<Span>) {
     if let ExprKind::Block(block, _) = expr_kind {
         if let Some(block_expr) = block.expr {
-            check_final_expr(cx, block_expr, semi_spans, RetReplacement::Empty);
+            check_final_expr(cx, block_expr, semi_spans, RetReplacement::Empty, None);
         } else if let Some(stmt) = block.stmts.iter().last() {
             match stmt.kind {
                 StmtKind::Expr(expr) => {
-                    check_final_expr(cx, expr, semi_spans, RetReplacement::Empty);
+                    check_final_expr(cx, expr, semi_spans, RetReplacement::Empty, None);
                 },
                 StmtKind::Semi(semi_expr) => {
                     // Remove ending semicolons and any whitespace ' ' in between.
@@ -202,7 +202,7 @@ fn check_block_return<'tcx>(cx: &LateContext<'tcx>, expr_kind: &ExprKind<'tcx>,
                             span_find_starting_semi(cx.sess().source_map(), semi_span.with_hi(sp.hi()));
                         semi_spans.push(semi_span_to_remove);
                     }
-                    check_final_expr(cx, semi_expr, semi_spans, RetReplacement::Empty);
+                    check_final_expr(cx, semi_expr, semi_spans, RetReplacement::Empty, None);
                 },
                 _ => (),
             }
@@ -216,6 +216,7 @@ fn check_final_expr<'tcx>(
     semi_spans: Vec<Span>, /* containing all the places where we would need to remove semicolons if finding an
                             * needless return */
     replacement: RetReplacement<'tcx>,
+    match_ty_opt: Option<Ty<'_>>,
 ) {
     let peeled_drop_expr = expr.peel_drop_temps();
     match &peeled_drop_expr.kind {
@@ -244,7 +245,22 @@ fn check_final_expr<'tcx>(
                     RetReplacement::Expr(snippet, applicability)
                 }
             } else {
-                replacement
+                match match_ty_opt {
+                    Some(match_ty) => {
+                        match match_ty.kind() {
+                            // If the code got till here with
+                            // tuple not getting detected before it,
+                            // then we are sure it's going to be Unit
+                            // type
+                            ty::Tuple(_) => RetReplacement::Unit,
+                            // We don't want to anything in this case
+                            // cause we can't predict what the user would
+                            // want here
+                            _ => return,
+                        }
+                    },
+                    None => replacement,
+                }
             };
 
             if !cx.tcx.hir().attrs(expr.hir_id).is_empty() {
@@ -268,8 +284,9 @@ fn check_final_expr<'tcx>(
         // note, if without else is going to be a type checking error anyways
         // (except for unit type functions) so we don't match it
         ExprKind::Match(_, arms, MatchSource::Normal) => {
+            let match_ty = cx.typeck_results().expr_ty(peeled_drop_expr);
             for arm in arms.iter() {
-                check_final_expr(cx, arm.body, semi_spans.clone(), RetReplacement::Unit);
+                check_final_expr(cx, arm.body, semi_spans.clone(), RetReplacement::Unit, Some(match_ty));
             }
         },
         // 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>,
     if ret_span.from_expansion() {
         return;
     }
+
     let applicability = replacement.applicability().unwrap_or(Applicability::MachineApplicable);
     let return_replacement = replacement.to_string();
     let sugg_help = replacement.sugg_help();
diff --git a/tests/ui/needless_return.fixed b/tests/ui/needless_return.fixed
index 0f525dd294c..57c08996ce2 100644
--- a/tests/ui/needless_return.fixed
+++ b/tests/ui/needless_return.fixed
@@ -307,4 +307,13 @@ mod issue10049 {
     }
 }
 
+fn test_match_as_stmt() {
+    let x = 9;
+    match x {
+        1 => 2,
+        2 => return,
+        _ => 0,
+    };
+}
+
 fn main() {}
diff --git a/tests/ui/needless_return.rs b/tests/ui/needless_return.rs
index a1db8375d95..7c1feefbe32 100644
--- a/tests/ui/needless_return.rs
+++ b/tests/ui/needless_return.rs
@@ -317,4 +317,13 @@ mod issue10049 {
     }
 }
 
+fn test_match_as_stmt() {
+    let x = 9;
+    match x {
+        1 => 2,
+        2 => return,
+        _ => 0,
+    };
+}
+
 fn main() {}