Lint explicit_auto_deref in implicit return positions for closures

This commit is contained in:
Jason Newcomb 2022-08-08 10:25:05 -04:00
parent 5285928bc0
commit ecb51fe6a5
5 changed files with 42 additions and 20 deletions

View File

@ -1,7 +1,7 @@
use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_hir_and_then};
use clippy_utils::source::{snippet_with_applicability, snippet_with_context};
use clippy_utils::sugg::has_enclosing_paren;
use clippy_utils::ty::{expr_sig, peel_mid_ty_refs, variant_of_res};
use clippy_utils::ty::{expr_sig, peel_mid_ty_refs, ty_sig, variant_of_res};
use clippy_utils::{get_parent_expr, is_lint_allowed, path_to_local, walk_to_expr_usage};
use rustc_ast::util::parser::{PREC_POSTFIX, PREC_PREFIX};
use rustc_data_structures::fx::FxIndexMap;
@ -704,24 +704,13 @@ fn walk_parents<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) -> (Position, &
let owner_id = cx.tcx.hir().body_owner(cx.enclosing_body.unwrap());
Some(
if let Node::Expr(
closure @ Expr {
kind: ExprKind::Closure(&Closure { fn_decl, .. }),
closure_expr @ Expr {
kind: ExprKind::Closure(closure),
..
},
) = cx.tcx.hir().get(owner_id)
{
match fn_decl.output {
FnRetTy::Return(ty) => {
if let Some(sig) = expr_sig(cx, closure)
&& let Some(output) = sig.output()
{
binding_ty_auto_deref_stability(cx, ty, precedence, output.bound_vars())
} else {
Position::Other(precedence)
}
},
FnRetTy::DefaultReturn(_) => Position::Other(precedence),
}
closure_result_position(cx, closure, cx.typeck_results().expr_ty(closure_expr), precedence)
} else {
let output = cx
.tcx
@ -730,6 +719,12 @@ fn walk_parents<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) -> (Position, &
},
)
},
ExprKind::Closure(closure) => Some(closure_result_position(
cx,
closure,
cx.typeck_results().expr_ty(parent),
precedence,
)),
ExprKind::Call(func, _) if func.hir_id == child_id => {
(child_id == e.hir_id).then_some(Position::Callee)
},
@ -825,6 +820,26 @@ fn walk_parents<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) -> (Position, &
(position, adjustments)
}
fn closure_result_position<'tcx>(
cx: &LateContext<'tcx>,
closure: &'tcx Closure<'_>,
ty: Ty<'tcx>,
precedence: i8,
) -> Position {
match closure.fn_decl.output {
FnRetTy::Return(hir_ty) => {
if let Some(sig) = ty_sig(cx, ty)
&& let Some(output) = sig.output()
{
binding_ty_auto_deref_stability(cx, hir_ty, precedence, output.bound_vars())
} else {
Position::Other(precedence)
}
},
FnRetTy::DefaultReturn(_) => Position::Other(precedence),
}
}
// Checks the stability of auto-deref when assigned to a binding with the given explicit type.
//
// e.g.

View File

@ -572,7 +572,8 @@ pub fn expr_sig<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'_>) -> Option<ExprFnS
}
}
fn ty_sig<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Option<ExprFnSig<'tcx>> {
/// If the type is function like, get the signature for it.
pub fn ty_sig<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Option<ExprFnSig<'tcx>> {
if ty.is_box() {
return ty_sig(cx, ty.boxed_ty());
}

View File

@ -257,13 +257,13 @@ fn main() {
let x = S7([0]);
let _: &[u32] = &*x;
let c1 = |x: &Vec<&u32>| {};
let c1 = |_: &Vec<&u32>| {};
let x = &&vec![&1u32];
c1(x);
let _ = for<'a, 'b> |x: &'a &'a Vec<&'b u32>, b: bool| -> &'a Vec<&'b u32> {
if b {
return x;
}
*x
x
};
}

View File

@ -257,7 +257,7 @@ fn main() {
let x = S7([0]);
let _: &[u32] = &*x;
let c1 = |x: &Vec<&u32>| {};
let c1 = |_: &Vec<&u32>| {};
let x = &&vec![&1u32];
c1(*x);
let _ = for<'a, 'b> |x: &'a &'a Vec<&'b u32>, b: bool| -> &'a Vec<&'b u32> {

View File

@ -228,5 +228,11 @@ error: deref which would be done by auto-deref
LL | return *x;
| ^^ help: try this: `x`
error: aborting due to 38 previous errors
error: deref which would be done by auto-deref
--> $DIR/explicit_auto_deref.rs:267:9
|
LL | *x
| ^^ help: try this: `x`
error: aborting due to 39 previous errors