Skip to content

Commit 0e970e0

Browse files
committed
move expr_requires_coercion to clippy_utils & some other adjustments
1 parent 635c375 commit 0e970e0

File tree

2 files changed

+90
-75
lines changed

2 files changed

+90
-75
lines changed

clippy_lints/src/matches/manual_utils.rs

Lines changed: 4 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -4,17 +4,15 @@ use clippy_utils::source::{snippet_with_applicability, snippet_with_context};
44
use clippy_utils::sugg::Sugg;
55
use clippy_utils::ty::{is_copy, is_type_diagnostic_item, peel_mid_ty_refs_is_mutable, type_is_unsafe_function};
66
use clippy_utils::{
7-
can_move_expr_to_closure, fn_def_id, is_else_clause, is_lint_allowed, is_res_lang_ctor, path_res, path_to_local_id,
8-
peel_blocks, peel_hir_expr_refs, peel_hir_expr_while, CaptureKind,
7+
can_move_expr_to_closure, expr_requires_coercion, is_else_clause, is_lint_allowed, is_res_lang_ctor, path_res,
8+
path_to_local_id, peel_blocks, peel_hir_expr_refs, peel_hir_expr_while, CaptureKind,
99
};
1010
use rustc_ast::util::parser::PREC_UNAMBIGUOUS;
1111
use rustc_errors::Applicability;
1212
use rustc_hir::def::Res;
1313
use rustc_hir::LangItem::{OptionNone, OptionSome};
14-
use rustc_hir::{self as hir, BindingMode, Expr, ExprKind, HirId, Mutability, Pat, PatKind, Path, QPath};
14+
use rustc_hir::{BindingMode, Expr, ExprKind, HirId, Mutability, Pat, PatKind, Path, QPath};
1515
use rustc_lint::LateContext;
16-
use rustc_middle::ty::adjustment::Adjust;
17-
use rustc_middle::ty::{TypeFlags, TypeVisitableExt};
1816
use rustc_span::{sym, SyntaxContext};
1917

2018
#[expect(clippy::too_many_arguments)]
@@ -75,7 +73,7 @@ where
7573
}
7674

7775
// `map` won't perform any adjustments.
78-
if expr_has_type_coercion(cx, expr) {
76+
if expr_requires_coercion(cx, expr) {
7977
return None;
8078
}
8179

@@ -274,71 +272,3 @@ pub(super) fn try_parse_pattern<'tcx>(
274272
fn is_none_expr(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
275273
is_res_lang_ctor(cx, path_res(cx, peel_blocks(expr)), OptionNone)
276274
}
277-
278-
fn expr_ty_adjusted(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
279-
cx.typeck_results()
280-
.expr_adjustments(expr)
281-
.iter()
282-
// We do not care about exprs with `NeverToAny` adjustments, such as `panic!` call.
283-
.any(|adj| !matches!(adj.kind, Adjust::NeverToAny))
284-
}
285-
286-
fn expr_has_type_coercion<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'tcx>) -> bool {
287-
if expr.span.from_expansion() {
288-
return false;
289-
}
290-
if expr_ty_adjusted(cx, expr) {
291-
return true;
292-
}
293-
294-
// Identify coercion sites and recursively check it those sites
295-
// actually has type adjustments.
296-
match expr.kind {
297-
// Function/method calls, including enum initialization.
298-
ExprKind::Call(_, args) | ExprKind::MethodCall(_, _, args, _) if let Some(def_id) = fn_def_id(cx, expr) => {
299-
let fn_sig = cx.tcx.fn_sig(def_id).instantiate_identity();
300-
if !fn_sig.output().skip_binder().has_type_flags(TypeFlags::HAS_TY_PARAM) {
301-
return false;
302-
}
303-
let mut args_with_ty_param = fn_sig
304-
.inputs()
305-
.skip_binder()
306-
.iter()
307-
.zip(args)
308-
.filter_map(|(arg_ty, arg)| if arg_ty.has_type_flags(TypeFlags::HAS_TY_PARAM) {
309-
Some(arg)
310-
} else {
311-
None
312-
});
313-
args_with_ty_param.any(|arg| expr_has_type_coercion(cx, arg))
314-
},
315-
// Struct/union initialization.
316-
ExprKind::Struct(_, fields, _) => {
317-
fields.iter().map(|expr_field| expr_field.expr).any(|ex| expr_has_type_coercion(cx, ex))
318-
},
319-
// those two `ref` keywords cannot be removed
320-
#[allow(clippy::needless_borrow)]
321-
// Function results, including the final line of a block or a `return` expression.
322-
ExprKind::Block(hir::Block { expr: Some(ref ret_expr), .. }, _) |
323-
ExprKind::Ret(Some(ref ret_expr)) => expr_has_type_coercion(cx, ret_expr),
324-
325-
// ===== Coercion-propagation expressions =====
326-
327-
// Array, where the type is `[U; n]`.
328-
ExprKind::Array(elems) |
329-
// Tuple, `(U_0, U_1, ..., U_n)`.
330-
ExprKind::Tup(elems) => {
331-
elems.iter().any(|elem| expr_has_type_coercion(cx, elem))
332-
},
333-
// Array but with repeating syntax.
334-
ExprKind::Repeat(rep_elem, _) => expr_has_type_coercion(cx, rep_elem),
335-
// Others that may contain coercion sites.
336-
ExprKind::If(_, then, maybe_else) => {
337-
expr_has_type_coercion(cx, then) || maybe_else.is_some_and(|e| expr_has_type_coercion(cx, e))
338-
}
339-
ExprKind::Match(_, arms, _) => {
340-
arms.iter().map(|arm| arm.body).any(|body| expr_has_type_coercion(cx, body))
341-
}
342-
_ => false
343-
}
344-
}

clippy_utils/src/lib.rs

Lines changed: 86 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,7 @@ use rustc_middle::ty::fast_reject::SimplifiedType;
116116
use rustc_middle::ty::layout::IntegerExt;
117117
use rustc_middle::ty::{
118118
self as rustc_ty, Binder, BorrowKind, ClosureKind, EarlyBinder, FloatTy, GenericArgsRef, IntTy, ParamEnv,
119-
ParamEnvAnd, Ty, TyCtxt, TypeVisitableExt, UintTy, UpvarCapture,
119+
ParamEnvAnd, Ty, TyCtxt, TypeFlags, TypeVisitableExt, UintTy, UpvarCapture,
120120
};
121121
use rustc_span::hygiene::{ExpnKind, MacroKind};
122122
use rustc_span::source_map::SourceMap;
@@ -3492,3 +3492,88 @@ pub fn is_receiver_of_method_call(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool
34923492
}
34933493
false
34943494
}
3495+
3496+
pub fn expr_requires_coercion<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'tcx>) -> bool {
3497+
if expr.span.from_expansion() {
3498+
return false;
3499+
}
3500+
3501+
let expr_ty_is_adjusted = cx
3502+
.typeck_results()
3503+
.expr_adjustments(expr)
3504+
.iter()
3505+
// We do not care about exprs with `NeverToAny` adjustments, such as `panic!` call.
3506+
.any(|adj| !matches!(adj.kind, Adjust::NeverToAny));
3507+
if expr_ty_is_adjusted {
3508+
return true;
3509+
}
3510+
3511+
// Identify coercion sites and recursively check it those sites
3512+
// actually has type adjustments.
3513+
match expr.kind {
3514+
ExprKind::Call(_, args)
3515+
| ExprKind::MethodCall(_, _, args, _) if let Some(def_id) = fn_def_id(cx, expr) => {
3516+
let fn_sig = cx.tcx.fn_sig(def_id).instantiate_identity();
3517+
3518+
if !fn_sig.output().skip_binder().has_type_flags(TypeFlags::HAS_TY_PARAM) {
3519+
return false;
3520+
}
3521+
3522+
let self_arg_count = usize::from(matches!(expr.kind, ExprKind::MethodCall(..)));
3523+
let mut args_with_ty_param = {
3524+
fn_sig
3525+
.inputs()
3526+
.skip_binder()
3527+
.iter()
3528+
.skip(self_arg_count)
3529+
.zip(args)
3530+
.filter_map(|(arg_ty, arg)| {
3531+
if arg_ty.has_type_flags(TypeFlags::HAS_TY_PARAM) {
3532+
Some(arg)
3533+
} else {
3534+
None
3535+
}
3536+
})
3537+
};
3538+
args_with_ty_param.any(|arg| expr_requires_coercion(cx, arg))
3539+
}
3540+
// Struct/union initialization.
3541+
ExprKind::Struct(qpath, _, _) => {
3542+
let res = cx.typeck_results().qpath_res(qpath, expr.hir_id);
3543+
if let Some((_, v_def)) = adt_and_variant_of_res(cx, res) {
3544+
let generic_args = cx.typeck_results().node_args(expr.hir_id);
3545+
v_def.fields
3546+
.iter()
3547+
.any(|field| field.ty(cx.tcx, generic_args).has_type_flags(TypeFlags::HAS_TY_PARAM))
3548+
} else {
3549+
false
3550+
}
3551+
}
3552+
// Function results, including the final line of a block or a `return` expression.
3553+
ExprKind::Block(
3554+
&Block {
3555+
expr: Some(ret_expr), ..
3556+
},
3557+
_,
3558+
)
3559+
| ExprKind::Ret(Some(ret_expr)) => expr_requires_coercion(cx, ret_expr),
3560+
3561+
// ===== Coercion-propagation expressions =====
3562+
3563+
// Array, where the type is `[U; n]`.
3564+
ExprKind::Array(elems)
3565+
// Tuple, `(U_0, U_1, ..., U_n)`.
3566+
| ExprKind::Tup(elems) => elems.iter().any(|elem| expr_requires_coercion(cx, elem)),
3567+
// Array but with repeating syntax.
3568+
ExprKind::Repeat(rep_elem, _) => expr_requires_coercion(cx, rep_elem),
3569+
// Others that may contain coercion sites.
3570+
ExprKind::If(_, then, maybe_else) => {
3571+
expr_requires_coercion(cx, then) || maybe_else.is_some_and(|e| expr_requires_coercion(cx, e))
3572+
},
3573+
ExprKind::Match(_, arms, _) => arms
3574+
.iter()
3575+
.map(|arm| arm.body)
3576+
.any(|body| expr_requires_coercion(cx, body)),
3577+
_ => false,
3578+
}
3579+
}

0 commit comments

Comments
 (0)