mirror of
https://github.com/rust-lang/rust-clippy
synced 2024-11-27 15:11:30 +00:00
Auto merge of #10386 - Jarcho:issue_10384, r=Manishearth
Normalize projections types when checking `explicit_auto_deref` fixes #10384 changelog: [`explicit_auto_deref`]: Better consider projection types when checking if auto deref is applicable
This commit is contained in:
commit
51668820f4
4 changed files with 102 additions and 29 deletions
|
@ -3,7 +3,7 @@ use clippy_utils::mir::{enclosing_mir, expr_local, local_assignments, used_exact
|
|||
use clippy_utils::msrvs::{self, Msrv};
|
||||
use clippy_utils::source::{snippet_with_applicability, snippet_with_context};
|
||||
use clippy_utils::sugg::has_enclosing_paren;
|
||||
use clippy_utils::ty::{expr_sig, is_copy, peel_mid_ty_refs, ty_sig, variant_of_res};
|
||||
use clippy_utils::ty::{adt_and_variant_of_res, expr_sig, is_copy, peel_mid_ty_refs, ty_sig};
|
||||
use clippy_utils::{
|
||||
fn_def_id, get_parent_expr, get_parent_expr_for_hir, is_lint_allowed, path_to_local, walk_to_expr_usage,
|
||||
};
|
||||
|
@ -26,8 +26,8 @@ use rustc_lint::{LateContext, LateLintPass};
|
|||
use rustc_middle::mir::{Rvalue, StatementKind};
|
||||
use rustc_middle::ty::adjustment::{Adjust, Adjustment, AutoBorrow, AutoBorrowMutability};
|
||||
use rustc_middle::ty::{
|
||||
self, Binder, BoundVariableKind, Clause, EarlyBinder, FnSig, GenericArgKind, List, ParamTy, PredicateKind,
|
||||
ProjectionPredicate, Ty, TyCtxt, TypeVisitable, TypeckResults,
|
||||
self, Binder, BoundVariableKind, Clause, EarlyBinder, FnSig, GenericArgKind, List, ParamEnv, ParamTy,
|
||||
PredicateKind, ProjectionPredicate, Ty, TyCtxt, TypeVisitable, TypeckResults,
|
||||
};
|
||||
use rustc_session::{declare_tool_lint, impl_lint_pass};
|
||||
use rustc_span::{symbol::sym, Span, Symbol};
|
||||
|
@ -736,7 +736,7 @@ fn walk_parents<'tcx>(
|
|||
..
|
||||
}) if span.ctxt() == ctxt => {
|
||||
let ty = cx.tcx.type_of(owner_id.def_id);
|
||||
Some(ty_auto_deref_stability(cx, ty, precedence).position_for_result(cx))
|
||||
Some(ty_auto_deref_stability(cx.tcx, cx.param_env, ty, precedence).position_for_result(cx))
|
||||
},
|
||||
|
||||
Node::Item(&Item {
|
||||
|
@ -760,7 +760,7 @@ fn walk_parents<'tcx>(
|
|||
let output = cx
|
||||
.tcx
|
||||
.erase_late_bound_regions(cx.tcx.fn_sig(owner_id).subst_identity().output());
|
||||
Some(ty_auto_deref_stability(cx, output, precedence).position_for_result(cx))
|
||||
Some(ty_auto_deref_stability(cx.tcx, cx.param_env, output, precedence).position_for_result(cx))
|
||||
},
|
||||
|
||||
Node::ExprField(field) if field.span.ctxt() == ctxt => match get_parent_expr_for_hir(cx, field.hir_id) {
|
||||
|
@ -768,10 +768,23 @@ fn walk_parents<'tcx>(
|
|||
hir_id,
|
||||
kind: ExprKind::Struct(path, ..),
|
||||
..
|
||||
}) => variant_of_res(cx, cx.qpath_res(path, *hir_id))
|
||||
.and_then(|variant| variant.fields.iter().find(|f| f.name == field.ident.name))
|
||||
.map(|field_def| {
|
||||
ty_auto_deref_stability(cx, cx.tcx.type_of(field_def.did), precedence).position_for_arg()
|
||||
}) => adt_and_variant_of_res(cx, cx.qpath_res(path, *hir_id))
|
||||
.and_then(|(adt, variant)| {
|
||||
variant
|
||||
.fields
|
||||
.iter()
|
||||
.find(|f| f.name == field.ident.name)
|
||||
.map(|f| (adt, f))
|
||||
})
|
||||
.map(|(adt, field_def)| {
|
||||
ty_auto_deref_stability(
|
||||
cx.tcx,
|
||||
// Use the param_env of the target type.
|
||||
cx.tcx.param_env(adt.did()),
|
||||
cx.tcx.type_of(field_def.did),
|
||||
precedence,
|
||||
)
|
||||
.position_for_arg()
|
||||
}),
|
||||
_ => None,
|
||||
},
|
||||
|
@ -792,7 +805,7 @@ fn walk_parents<'tcx>(
|
|||
let output = cx
|
||||
.tcx
|
||||
.erase_late_bound_regions(cx.tcx.fn_sig(owner_id).subst_identity().output());
|
||||
ty_auto_deref_stability(cx, output, precedence).position_for_result(cx)
|
||||
ty_auto_deref_stability(cx.tcx, cx.param_env, output, precedence).position_for_result(cx)
|
||||
},
|
||||
)
|
||||
},
|
||||
|
@ -835,15 +848,20 @@ fn walk_parents<'tcx>(
|
|||
msrv,
|
||||
)
|
||||
} else {
|
||||
ty_auto_deref_stability(cx, cx.tcx.erase_late_bound_regions(ty), precedence)
|
||||
.position_for_arg()
|
||||
ty_auto_deref_stability(
|
||||
cx.tcx,
|
||||
// Use the param_env of the target function.
|
||||
sig.predicates_id().map_or(ParamEnv::empty(), |id| cx.tcx.param_env(id)),
|
||||
cx.tcx.erase_late_bound_regions(ty),
|
||||
precedence
|
||||
).position_for_arg()
|
||||
}
|
||||
},
|
||||
}
|
||||
})
|
||||
}),
|
||||
ExprKind::MethodCall(method, receiver, args, _) => {
|
||||
let id = cx.typeck_results().type_dependent_def_id(parent.hir_id).unwrap();
|
||||
let fn_id = cx.typeck_results().type_dependent_def_id(parent.hir_id).unwrap();
|
||||
if receiver.hir_id == child_id {
|
||||
// Check for calls to trait methods where the trait is implemented on a reference.
|
||||
// Two cases need to be handled:
|
||||
|
@ -852,13 +870,17 @@ fn walk_parents<'tcx>(
|
|||
// priority.
|
||||
if e.hir_id != child_id {
|
||||
return Some(Position::ReborrowStable(precedence))
|
||||
} else if let Some(trait_id) = cx.tcx.trait_of_item(id)
|
||||
} else if let Some(trait_id) = cx.tcx.trait_of_item(fn_id)
|
||||
&& let arg_ty = cx.tcx.erase_regions(cx.typeck_results().expr_ty_adjusted(e))
|
||||
&& let ty::Ref(_, sub_ty, _) = *arg_ty.kind()
|
||||
&& let subs = cx
|
||||
.typeck_results()
|
||||
.node_substs_opt(parent.hir_id).map(|subs| &subs[1..]).unwrap_or_default()
|
||||
&& let impl_ty = if cx.tcx.fn_sig(id).subst_identity().skip_binder().inputs()[0].is_ref() {
|
||||
&& let impl_ty = if cx.tcx.fn_sig(fn_id)
|
||||
.subst_identity()
|
||||
.skip_binder()
|
||||
.inputs()[0].is_ref()
|
||||
{
|
||||
// Trait methods taking `&self`
|
||||
sub_ty
|
||||
} else {
|
||||
|
@ -879,10 +901,13 @@ fn walk_parents<'tcx>(
|
|||
return Some(Position::MethodReceiver);
|
||||
}
|
||||
args.iter().position(|arg| arg.hir_id == child_id).map(|i| {
|
||||
let ty = cx.tcx.fn_sig(id).subst_identity().skip_binder().inputs()[i + 1];
|
||||
let ty = cx.tcx.fn_sig(fn_id).subst_identity().input(i + 1);
|
||||
// `e.hir_id == child_id` for https://github.com/rust-lang/rust-clippy/issues/9739
|
||||
// `method.args.is_none()` for https://github.com/rust-lang/rust-clippy/issues/9782
|
||||
if e.hir_id == child_id && method.args.is_none() && let ty::Param(param_ty) = ty.kind() {
|
||||
if e.hir_id == child_id
|
||||
&& method.args.is_none()
|
||||
&& let ty::Param(param_ty) = ty.skip_binder().kind()
|
||||
{
|
||||
needless_borrow_impl_arg_position(
|
||||
cx,
|
||||
possible_borrowers,
|
||||
|
@ -895,8 +920,10 @@ fn walk_parents<'tcx>(
|
|||
)
|
||||
} else {
|
||||
ty_auto_deref_stability(
|
||||
cx,
|
||||
cx.tcx.erase_late_bound_regions(cx.tcx.fn_sig(id).subst_identity().input(i + 1)),
|
||||
cx.tcx,
|
||||
// Use the param_env of the target function.
|
||||
cx.tcx.param_env(fn_id),
|
||||
cx.tcx.erase_late_bound_regions(ty),
|
||||
precedence,
|
||||
)
|
||||
.position_for_arg()
|
||||
|
@ -1378,11 +1405,18 @@ impl<'tcx> TyPosition<'tcx> {
|
|||
}
|
||||
|
||||
// Checks whether a type is stable when switching to auto dereferencing,
|
||||
fn ty_auto_deref_stability<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>, precedence: i8) -> TyPosition<'tcx> {
|
||||
fn ty_auto_deref_stability<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
param_env: ParamEnv<'tcx>,
|
||||
ty: Ty<'tcx>,
|
||||
precedence: i8,
|
||||
) -> TyPosition<'tcx> {
|
||||
let ty::Ref(_, mut ty, _) = *ty.kind() else {
|
||||
return Position::Other(precedence).into();
|
||||
};
|
||||
|
||||
ty = tcx.try_normalize_erasing_regions(param_env, ty).unwrap_or(ty);
|
||||
|
||||
loop {
|
||||
break match *ty.kind() {
|
||||
ty::Ref(_, ref_ty, _) => {
|
||||
|
@ -1423,9 +1457,7 @@ fn ty_auto_deref_stability<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>, precedenc
|
|||
| ty::Closure(..)
|
||||
| ty::Never
|
||||
| ty::Tuple(_)
|
||||
| ty::Alias(ty::Projection, _) => {
|
||||
Position::DerefStable(precedence, ty.is_sized(cx.tcx, cx.param_env.without_caller_bounds())).into()
|
||||
},
|
||||
| ty::Alias(ty::Projection, _) => Position::DerefStable(precedence, ty.is_sized(tcx, param_env)).into(),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
@ -894,16 +894,29 @@ impl AdtVariantInfo {
|
|||
}
|
||||
|
||||
/// Gets the struct or enum variant from the given `Res`
|
||||
pub fn variant_of_res<'tcx>(cx: &LateContext<'tcx>, res: Res) -> Option<&'tcx VariantDef> {
|
||||
pub fn adt_and_variant_of_res<'tcx>(cx: &LateContext<'tcx>, res: Res) -> Option<(AdtDef<'tcx>, &'tcx VariantDef)> {
|
||||
match res {
|
||||
Res::Def(DefKind::Struct, id) => Some(cx.tcx.adt_def(id).non_enum_variant()),
|
||||
Res::Def(DefKind::Variant, id) => Some(cx.tcx.adt_def(cx.tcx.parent(id)).variant_with_id(id)),
|
||||
Res::Def(DefKind::Ctor(CtorOf::Struct, _), id) => Some(cx.tcx.adt_def(cx.tcx.parent(id)).non_enum_variant()),
|
||||
Res::Def(DefKind::Struct, id) => {
|
||||
let adt = cx.tcx.adt_def(id);
|
||||
Some((adt, adt.non_enum_variant()))
|
||||
},
|
||||
Res::Def(DefKind::Variant, id) => {
|
||||
let adt = cx.tcx.adt_def(cx.tcx.parent(id));
|
||||
Some((adt, adt.variant_with_id(id)))
|
||||
},
|
||||
Res::Def(DefKind::Ctor(CtorOf::Struct, _), id) => {
|
||||
let adt = cx.tcx.adt_def(cx.tcx.parent(id));
|
||||
Some((adt, adt.non_enum_variant()))
|
||||
},
|
||||
Res::Def(DefKind::Ctor(CtorOf::Variant, _), id) => {
|
||||
let var_id = cx.tcx.parent(id);
|
||||
Some(cx.tcx.adt_def(cx.tcx.parent(var_id)).variant_with_id(var_id))
|
||||
let adt = cx.tcx.adt_def(cx.tcx.parent(var_id));
|
||||
Some((adt, adt.variant_with_id(var_id)))
|
||||
},
|
||||
Res::SelfCtor(id) => {
|
||||
let adt = cx.tcx.type_of(id).ty_adt_def().unwrap();
|
||||
Some((adt, adt.non_enum_variant()))
|
||||
},
|
||||
Res::SelfCtor(id) => Some(cx.tcx.type_of(id).ty_adt_def().unwrap().non_enum_variant()),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
|
|
@ -269,6 +269,9 @@ fn main() {
|
|||
|
||||
trait WithAssoc {
|
||||
type Assoc: ?Sized;
|
||||
fn to_assoc(&self) -> &Self::Assoc {
|
||||
panic!()
|
||||
}
|
||||
}
|
||||
impl WithAssoc for String {
|
||||
type Assoc = str;
|
||||
|
@ -281,4 +284,15 @@ fn main() {
|
|||
// Issue #9901
|
||||
fn takes_ref(_: &i32) {}
|
||||
takes_ref(*Box::new(&0i32));
|
||||
|
||||
// Issue #10384
|
||||
impl<'a> WithAssoc for &'a u32 {
|
||||
type Assoc = dyn core::fmt::Display;
|
||||
fn to_assoc(&self) -> &Self::Assoc {
|
||||
*self
|
||||
}
|
||||
}
|
||||
fn return_dyn_assoc<'a>(x: &'a &'a u32) -> &'a <&'a u32 as WithAssoc>::Assoc {
|
||||
*x
|
||||
}
|
||||
}
|
||||
|
|
|
@ -269,6 +269,9 @@ fn main() {
|
|||
|
||||
trait WithAssoc {
|
||||
type Assoc: ?Sized;
|
||||
fn to_assoc(&self) -> &Self::Assoc {
|
||||
panic!()
|
||||
}
|
||||
}
|
||||
impl WithAssoc for String {
|
||||
type Assoc = str;
|
||||
|
@ -281,4 +284,15 @@ fn main() {
|
|||
// Issue #9901
|
||||
fn takes_ref(_: &i32) {}
|
||||
takes_ref(*Box::new(&0i32));
|
||||
|
||||
// Issue #10384
|
||||
impl<'a> WithAssoc for &'a u32 {
|
||||
type Assoc = dyn core::fmt::Display;
|
||||
fn to_assoc(&self) -> &Self::Assoc {
|
||||
*self
|
||||
}
|
||||
}
|
||||
fn return_dyn_assoc<'a>(x: &'a &'a u32) -> &'a <&'a u32 as WithAssoc>::Assoc {
|
||||
*x
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue