Skip to content

Commit 83693ca

Browse files
committed
fix: return_and_then FP when return type is not Option or Result
1 parent 57cbadd commit 83693ca

File tree

3 files changed

+73
-4
lines changed

3 files changed

+73
-4
lines changed

clippy_lints/src/methods/return_and_then.rs

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ use clippy_utils::diagnostics::span_lint_and_sugg;
99
use clippy_utils::source::{indent_of, reindent_multiline, snippet_with_applicability};
1010
use clippy_utils::ty::get_type_diagnostic_name;
1111
use clippy_utils::visitors::for_each_unconsumed_temporary;
12-
use clippy_utils::{get_parent_expr, peel_blocks};
12+
use clippy_utils::{get_parent_expr, peel_blocks, return_ty};
1313

1414
use super::RETURN_AND_THEN;
1515

@@ -21,12 +21,29 @@ pub(super) fn check<'tcx>(
2121
recv: &'tcx hir::Expr<'tcx>,
2222
arg: &'tcx hir::Expr<'_>,
2323
) {
24-
if cx.tcx.hir_get_fn_id_for_return_block(expr.hir_id).is_none() {
24+
let Some(fn_def_id) = cx.tcx.hir_get_fn_id_for_return_block(expr.hir_id) else {
2525
return;
26-
}
26+
};
2727

28+
let fn_return_type = if let hir::Node::Expr(expr) = cx.tcx.hir_node(fn_def_id)
29+
&& let hir::ExprKind::Closure(..) = expr.kind
30+
&& let expr_ty = cx.typeck_results().expr_ty(expr)
31+
&& let ty::Closure(_, args) = expr_ty.kind()
32+
{
33+
let fn_sig = args.as_closure().sig();
34+
cx.tcx.instantiate_bound_regions_with_erased(fn_sig.output())
35+
} else if let Some(fn_owner_id) = fn_def_id.as_owner() {
36+
return_ty(cx, fn_owner_id)
37+
} else {
38+
return;
39+
};
2840
let recv_type = cx.typeck_results().expr_ty(recv);
29-
if !matches!(get_type_diagnostic_name(cx, recv_type), Some(sym::Option | sym::Result)) {
41+
42+
let fn_return_symbol = get_type_diagnostic_name(cx, fn_return_type);
43+
let recv_symbol = get_type_diagnostic_name(cx, recv_type);
44+
if fn_return_symbol != recv_symbol
45+
|| !matches!(get_type_diagnostic_name(cx, recv_type), Some(sym::Option | sym::Result))
46+
{
3047
return;
3148
}
3249

tests/ui/return_and_then.fixed

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,3 +124,29 @@ mod issue14781 {
124124
Ok(())
125125
}
126126
}
127+
128+
mod issue14927 {
129+
use std::path::Path;
130+
131+
struct A {
132+
pub func: fn(check: bool, a: &Path, b: Option<&Path>),
133+
}
134+
135+
const MY_A: A = A {
136+
func: |check, a, b| {
137+
if check {
138+
let _ = ();
139+
} else if let Some(parent) = b.and_then(|p| p.parent()) {
140+
let _ = ();
141+
}
142+
},
143+
};
144+
145+
fn foo(check: bool, a: &Path, b: Option<&Path>) {
146+
if check {
147+
let _ = ();
148+
} else if let Some(parent) = b.and_then(|p| p.parent()) {
149+
let _ = ();
150+
}
151+
}
152+
}

tests/ui/return_and_then.rs

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,3 +115,29 @@ mod issue14781 {
115115
Ok(())
116116
}
117117
}
118+
119+
mod issue14927 {
120+
use std::path::Path;
121+
122+
struct A {
123+
pub func: fn(check: bool, a: &Path, b: Option<&Path>),
124+
}
125+
126+
const MY_A: A = A {
127+
func: |check, a, b| {
128+
if check {
129+
let _ = ();
130+
} else if let Some(parent) = b.and_then(|p| p.parent()) {
131+
let _ = ();
132+
}
133+
},
134+
};
135+
136+
fn foo(check: bool, a: &Path, b: Option<&Path>) {
137+
if check {
138+
let _ = ();
139+
} else if let Some(parent) = b.and_then(|p| p.parent()) {
140+
let _ = ();
141+
}
142+
}
143+
}

0 commit comments

Comments
 (0)