Skip to content

Commit e7a3cb7

Browse files
committed
Auto merge of #12021 - PartiallyTyped:11982, r=flip1995
FP: `needless_return_with_question_mark` with implicit Error Conversion Return with a question mark was triggered in situations where the `?` desuraging was performing error conversion via `Into`/`From`. The desugared `?` produces a match over an expression with type `std::ops::ControlFlow<B,C>` with `B:Result<Infallible, E:Error>` and `C:Result<_, E':Error>`, and the arms perform the conversion. The patch adds another check in the lint that checks that `E == E'`. If `E == E'`, then the `?` is indeed unnecessary. changelog: False Positive: [`needless_return_with_question_mark`] when implicit Error Conversion occurs. fixes: #11982
2 parents 8ccf6a6 + 3aa2c27 commit e7a3cb7

File tree

3 files changed

+114
-2
lines changed

3 files changed

+114
-2
lines changed

clippy_lints/src/returns.rs

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,14 @@ use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then, span_lin
22
use clippy_utils::source::{snippet_opt, snippet_with_context};
33
use clippy_utils::sugg::has_enclosing_paren;
44
use clippy_utils::visitors::{for_each_expr_with_closures, Descend};
5-
use clippy_utils::{fn_def_id, is_from_proc_macro, is_inside_let_else, path_to_local_id, span_find_starting_semi};
5+
use clippy_utils::{
6+
fn_def_id, is_from_proc_macro, is_inside_let_else, is_res_lang_ctor, path_res, path_to_local_id,
7+
span_find_starting_semi,
8+
};
69
use core::ops::ControlFlow;
710
use rustc_errors::Applicability;
811
use rustc_hir::intravisit::FnKind;
12+
use rustc_hir::LangItem::ResultErr;
913
use rustc_hir::{
1014
Block, Body, Expr, ExprKind, FnDecl, HirId, ItemKind, LangItem, MatchSource, Node, OwnerNode, PatKind, QPath, Stmt,
1115
StmtKind,
@@ -182,7 +186,15 @@ impl<'tcx> LateLintPass<'tcx> for Return {
182186
if !in_external_macro(cx.sess(), stmt.span)
183187
&& let StmtKind::Semi(expr) = stmt.kind
184188
&& let ExprKind::Ret(Some(ret)) = expr.kind
185-
&& let ExprKind::Match(.., MatchSource::TryDesugar(_)) = ret.kind
189+
// return Err(...)? desugars to a match
190+
// over a Err(...).branch()
191+
// which breaks down to a branch call, with the callee being
192+
// the constructor of the Err variant
193+
&& let ExprKind::Match(maybe_cons, _, MatchSource::TryDesugar(_)) = ret.kind
194+
&& let ExprKind::Call(_, [maybe_result_err]) = maybe_cons.kind
195+
&& let ExprKind::Call(maybe_constr, _) = maybe_result_err.kind
196+
&& is_res_lang_ctor(cx, path_res(cx, maybe_constr), ResultErr)
197+
186198
// Ensure this is not the final stmt, otherwise removing it would cause a compile error
187199
&& let OwnerNode::Item(item) = cx.tcx.hir().owner(cx.tcx.hir().get_parent_item(expr.hir_id))
188200
&& let ItemKind::Fn(_, _, body) = item.kind

tests/ui/needless_return_with_question_mark.fixed

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,3 +77,53 @@ fn issue11616() -> Result<(), ()> {
7777
};
7878
Ok(())
7979
}
80+
81+
fn issue11982() {
82+
mod bar {
83+
pub struct Error;
84+
pub fn foo(_: bool) -> Result<(), Error> {
85+
Ok(())
86+
}
87+
}
88+
89+
pub struct Error;
90+
91+
impl From<bar::Error> for Error {
92+
fn from(_: bar::Error) -> Self {
93+
Error
94+
}
95+
}
96+
97+
fn foo(ok: bool) -> Result<(), Error> {
98+
if !ok {
99+
return bar::foo(ok).map(|_| Ok::<(), Error>(()))?;
100+
};
101+
Ok(())
102+
}
103+
}
104+
105+
fn issue11982_no_conversion() {
106+
mod bar {
107+
pub struct Error;
108+
pub fn foo(_: bool) -> Result<(), Error> {
109+
Ok(())
110+
}
111+
}
112+
113+
fn foo(ok: bool) -> Result<(), bar::Error> {
114+
if !ok {
115+
return bar::foo(ok).map(|_| Ok::<(), bar::Error>(()))?;
116+
};
117+
Ok(())
118+
}
119+
}
120+
121+
fn general_return() {
122+
fn foo(ok: bool) -> Result<(), ()> {
123+
let bar = Result::Ok(Result::<(), ()>::Ok(()));
124+
if !ok {
125+
return bar?;
126+
};
127+
Ok(())
128+
}
129+
}

tests/ui/needless_return_with_question_mark.rs

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,3 +77,53 @@ fn issue11616() -> Result<(), ()> {
7777
};
7878
Ok(())
7979
}
80+
81+
fn issue11982() {
82+
mod bar {
83+
pub struct Error;
84+
pub fn foo(_: bool) -> Result<(), Error> {
85+
Ok(())
86+
}
87+
}
88+
89+
pub struct Error;
90+
91+
impl From<bar::Error> for Error {
92+
fn from(_: bar::Error) -> Self {
93+
Error
94+
}
95+
}
96+
97+
fn foo(ok: bool) -> Result<(), Error> {
98+
if !ok {
99+
return bar::foo(ok).map(|_| Ok::<(), Error>(()))?;
100+
};
101+
Ok(())
102+
}
103+
}
104+
105+
fn issue11982_no_conversion() {
106+
mod bar {
107+
pub struct Error;
108+
pub fn foo(_: bool) -> Result<(), Error> {
109+
Ok(())
110+
}
111+
}
112+
113+
fn foo(ok: bool) -> Result<(), bar::Error> {
114+
if !ok {
115+
return bar::foo(ok).map(|_| Ok::<(), bar::Error>(()))?;
116+
};
117+
Ok(())
118+
}
119+
}
120+
121+
fn general_return() {
122+
fn foo(ok: bool) -> Result<(), ()> {
123+
let bar = Result::Ok(Result::<(), ()>::Ok(()));
124+
if !ok {
125+
return bar?;
126+
};
127+
Ok(())
128+
}
129+
}

0 commit comments

Comments
 (0)