mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-28 17:53:56 +00:00
Auto merge of #9126 - Jarcho:auto_deref_sugg, r=Manishearth
`explicit_auto_deref` changes fixes #9123 fixes #9109 fixes #9143 fixes #9101 This avoid suggesting code which hits a rustc bug. Basically `&{x}` won't use auto-deref if the target type is `Sized`. changelog: Don't suggest using auto deref for block expressions when the target type is `Sized` changelog: Include the borrow in the suggestion for `explicit_auto_deref` changelog: Don't lint `explicit_auto_deref` on `dyn Trait` return changelog: Don't lint `explicit_auto_deref` when other adjustments are required changelog: Lint `explicit_auto_deref` in implicit return positions for closures
This commit is contained in:
commit
4912c0ece4
@ -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;
|
||||
@ -15,9 +15,9 @@ use rustc_hir::{
|
||||
use rustc_infer::infer::TyCtxtInferExt;
|
||||
use rustc_lint::{LateContext, LateLintPass};
|
||||
use rustc_middle::ty::adjustment::{Adjust, Adjustment, AutoBorrow, AutoBorrowMutability};
|
||||
use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitable, TypeckResults};
|
||||
use rustc_middle::ty::{self, Binder, BoundVariableKind, List, Ty, TyCtxt, TypeVisitable, TypeckResults};
|
||||
use rustc_session::{declare_tool_lint, impl_lint_pass};
|
||||
use rustc_span::{symbol::sym, Span, Symbol};
|
||||
use rustc_span::{symbol::sym, Span, Symbol, DUMMY_SP};
|
||||
use rustc_trait_selection::infer::InferCtxtExt;
|
||||
|
||||
declare_clippy_lint! {
|
||||
@ -183,24 +183,24 @@ enum State {
|
||||
},
|
||||
DerefedBorrow(DerefedBorrow),
|
||||
ExplicitDeref {
|
||||
// Span and id of the top-level deref expression if the parent expression is a borrow.
|
||||
deref_span_id: Option<(Span, HirId)>,
|
||||
mutability: Option<Mutability>,
|
||||
},
|
||||
ExplicitDerefField {
|
||||
name: Symbol,
|
||||
},
|
||||
Reborrow {
|
||||
deref_span: Span,
|
||||
deref_hir_id: HirId,
|
||||
mutability: Mutability,
|
||||
},
|
||||
Borrow {
|
||||
mutability: Mutability,
|
||||
},
|
||||
Borrow,
|
||||
}
|
||||
|
||||
// A reference operation considered by this lint pass
|
||||
enum RefOp {
|
||||
Method(Mutability),
|
||||
Deref,
|
||||
AddrOf,
|
||||
AddrOf(Mutability),
|
||||
}
|
||||
|
||||
struct RefPat {
|
||||
@ -263,7 +263,7 @@ impl<'tcx> LateLintPass<'tcx> for Dereferencing {
|
||||
));
|
||||
} else if position.is_deref_stable() {
|
||||
self.state = Some((
|
||||
State::ExplicitDeref { deref_span_id: None },
|
||||
State::ExplicitDeref { mutability: None },
|
||||
StateData { span: expr.span, hir_id: expr.hir_id, position },
|
||||
));
|
||||
}
|
||||
@ -289,7 +289,7 @@ impl<'tcx> LateLintPass<'tcx> for Dereferencing {
|
||||
},
|
||||
));
|
||||
},
|
||||
RefOp::AddrOf => {
|
||||
RefOp::AddrOf(mutability) => {
|
||||
// Find the number of times the borrow is auto-derefed.
|
||||
let mut iter = adjustments.iter();
|
||||
let mut deref_count = 0usize;
|
||||
@ -357,9 +357,13 @@ impl<'tcx> LateLintPass<'tcx> for Dereferencing {
|
||||
}),
|
||||
StateData { span: expr.span, hir_id: expr.hir_id, position },
|
||||
));
|
||||
} else if position.is_deref_stable() {
|
||||
} else if position.is_deref_stable()
|
||||
// Auto-deref doesn't combine with other adjustments
|
||||
&& next_adjust.map_or(true, |a| matches!(a.kind, Adjust::Deref(_) | Adjust::Borrow(_)))
|
||||
&& iter.all(|a| matches!(a.kind, Adjust::Deref(_) | Adjust::Borrow(_)))
|
||||
{
|
||||
self.state = Some((
|
||||
State::Borrow,
|
||||
State::Borrow { mutability },
|
||||
StateData {
|
||||
span: expr.span,
|
||||
hir_id: expr.hir_id,
|
||||
@ -395,7 +399,7 @@ impl<'tcx> LateLintPass<'tcx> for Dereferencing {
|
||||
data,
|
||||
));
|
||||
},
|
||||
(Some((State::DerefedBorrow(state), data)), RefOp::AddrOf) if state.count != 0 => {
|
||||
(Some((State::DerefedBorrow(state), data)), RefOp::AddrOf(_)) if state.count != 0 => {
|
||||
self.state = Some((
|
||||
State::DerefedBorrow(DerefedBorrow {
|
||||
count: state.count - 1,
|
||||
@ -404,12 +408,12 @@ impl<'tcx> LateLintPass<'tcx> for Dereferencing {
|
||||
data,
|
||||
));
|
||||
},
|
||||
(Some((State::DerefedBorrow(state), data)), RefOp::AddrOf) => {
|
||||
(Some((State::DerefedBorrow(state), data)), RefOp::AddrOf(mutability)) => {
|
||||
let position = data.position;
|
||||
report(cx, expr, State::DerefedBorrow(state), data);
|
||||
if position.is_deref_stable() {
|
||||
self.state = Some((
|
||||
State::Borrow,
|
||||
State::Borrow { mutability },
|
||||
StateData {
|
||||
span: expr.span,
|
||||
hir_id: expr.hir_id,
|
||||
@ -430,43 +434,28 @@ impl<'tcx> LateLintPass<'tcx> for Dereferencing {
|
||||
));
|
||||
} else if position.is_deref_stable() {
|
||||
self.state = Some((
|
||||
State::ExplicitDeref { deref_span_id: None },
|
||||
State::ExplicitDeref { mutability: None },
|
||||
StateData { span: expr.span, hir_id: expr.hir_id, position },
|
||||
));
|
||||
}
|
||||
},
|
||||
|
||||
(Some((State::Borrow, data)), RefOp::Deref) => {
|
||||
(Some((State::Borrow { mutability }, data)), RefOp::Deref) => {
|
||||
if typeck.expr_ty(sub_expr).is_ref() {
|
||||
self.state = Some((
|
||||
State::Reborrow {
|
||||
deref_span: expr.span,
|
||||
deref_hir_id: expr.hir_id,
|
||||
},
|
||||
data,
|
||||
));
|
||||
self.state = Some((State::Reborrow { mutability }, data));
|
||||
} else {
|
||||
self.state = Some((
|
||||
State::ExplicitDeref {
|
||||
deref_span_id: Some((expr.span, expr.hir_id)),
|
||||
mutability: Some(mutability),
|
||||
},
|
||||
data,
|
||||
));
|
||||
}
|
||||
},
|
||||
(
|
||||
Some((
|
||||
State::Reborrow {
|
||||
deref_span,
|
||||
deref_hir_id,
|
||||
},
|
||||
data,
|
||||
)),
|
||||
RefOp::Deref,
|
||||
) => {
|
||||
(Some((State::Reborrow { mutability }, data)), RefOp::Deref) => {
|
||||
self.state = Some((
|
||||
State::ExplicitDeref {
|
||||
deref_span_id: Some((deref_span, deref_hir_id)),
|
||||
mutability: Some(mutability),
|
||||
},
|
||||
data,
|
||||
));
|
||||
@ -573,7 +562,7 @@ fn try_parse_ref_op<'tcx>(
|
||||
ExprKind::Unary(UnOp::Deref, sub_expr) if !typeck.expr_ty(sub_expr).is_unsafe_ptr() => {
|
||||
return Some((RefOp::Deref, sub_expr));
|
||||
},
|
||||
ExprKind::AddrOf(BorrowKind::Ref, _, sub_expr) => return Some((RefOp::AddrOf, sub_expr)),
|
||||
ExprKind::AddrOf(BorrowKind::Ref, mutability, sub_expr) => return Some((RefOp::AddrOf(mutability), sub_expr)),
|
||||
_ => return None,
|
||||
};
|
||||
if tcx.is_diagnostic_item(sym::deref_method, def_id) {
|
||||
@ -609,18 +598,21 @@ enum Position {
|
||||
Postfix,
|
||||
Deref,
|
||||
/// Any other location which will trigger auto-deref to a specific time.
|
||||
DerefStable(i8),
|
||||
/// Contains the precedence of the parent expression and whether the target type is sized.
|
||||
DerefStable(i8, bool),
|
||||
/// Any other location which will trigger auto-reborrowing.
|
||||
/// Contains the precedence of the parent expression.
|
||||
ReborrowStable(i8),
|
||||
/// Contains the precedence of the parent expression.
|
||||
Other(i8),
|
||||
}
|
||||
impl Position {
|
||||
fn is_deref_stable(self) -> bool {
|
||||
matches!(self, Self::DerefStable(_))
|
||||
matches!(self, Self::DerefStable(..))
|
||||
}
|
||||
|
||||
fn is_reborrow_stable(self) -> bool {
|
||||
matches!(self, Self::DerefStable(_) | Self::ReborrowStable(_))
|
||||
matches!(self, Self::DerefStable(..) | Self::ReborrowStable(_))
|
||||
}
|
||||
|
||||
fn can_auto_borrow(self) -> bool {
|
||||
@ -628,7 +620,7 @@ impl Position {
|
||||
}
|
||||
|
||||
fn lint_explicit_deref(self) -> bool {
|
||||
matches!(self, Self::Other(_) | Self::DerefStable(_) | Self::ReborrowStable(_))
|
||||
matches!(self, Self::Other(_) | Self::DerefStable(..) | Self::ReborrowStable(_))
|
||||
}
|
||||
|
||||
fn precedence(self) -> i8 {
|
||||
@ -639,7 +631,7 @@ impl Position {
|
||||
| Self::FieldAccess(_)
|
||||
| Self::Postfix => PREC_POSTFIX,
|
||||
Self::Deref => PREC_PREFIX,
|
||||
Self::DerefStable(p) | Self::ReborrowStable(p) | Self::Other(p) => p,
|
||||
Self::DerefStable(p, _) | Self::ReborrowStable(p) | Self::Other(p) => p,
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -659,7 +651,7 @@ fn walk_parents<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) -> (Position, &
|
||||
}
|
||||
match parent {
|
||||
Node::Local(Local { ty: Some(ty), span, .. }) if span.ctxt() == ctxt => {
|
||||
Some(binding_ty_auto_deref_stability(ty, precedence))
|
||||
Some(binding_ty_auto_deref_stability(cx, ty, precedence, List::empty()))
|
||||
},
|
||||
Node::Item(&Item {
|
||||
kind: ItemKind::Static(..) | ItemKind::Const(..),
|
||||
@ -680,11 +672,7 @@ fn walk_parents<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) -> (Position, &
|
||||
..
|
||||
}) if span.ctxt() == ctxt => {
|
||||
let ty = cx.tcx.type_of(def_id);
|
||||
Some(if ty.is_ref() {
|
||||
Position::DerefStable(precedence)
|
||||
} else {
|
||||
Position::Other(precedence)
|
||||
})
|
||||
Some(ty_auto_deref_stability(cx, ty, precedence).position_for_result(cx))
|
||||
},
|
||||
|
||||
Node::Item(&Item {
|
||||
@ -705,45 +693,38 @@ fn walk_parents<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) -> (Position, &
|
||||
span,
|
||||
..
|
||||
}) if span.ctxt() == ctxt => {
|
||||
let output = cx.tcx.fn_sig(def_id.to_def_id()).skip_binder().output();
|
||||
Some(if !output.is_ref() {
|
||||
Position::Other(precedence)
|
||||
} else if output.has_placeholders() || output.has_opaque_types() {
|
||||
Position::ReborrowStable(precedence)
|
||||
} else {
|
||||
Position::DerefStable(precedence)
|
||||
})
|
||||
let output = cx
|
||||
.tcx
|
||||
.erase_late_bound_regions(cx.tcx.fn_sig(def_id.to_def_id()).output());
|
||||
Some(ty_auto_deref_stability(cx, output, precedence).position_for_result(cx))
|
||||
},
|
||||
|
||||
Node::Expr(parent) if parent.span.ctxt() == ctxt => match parent.kind {
|
||||
ExprKind::Ret(_) => {
|
||||
let owner_id = cx.tcx.hir().body_owner(cx.enclosing_body.unwrap());
|
||||
Some(
|
||||
if let Node::Expr(Expr {
|
||||
kind: ExprKind::Closure(&Closure { fn_decl, .. }),
|
||||
..
|
||||
}) = cx.tcx.hir().get(owner_id)
|
||||
if let Node::Expr(
|
||||
closure_expr @ Expr {
|
||||
kind: ExprKind::Closure(closure),
|
||||
..
|
||||
},
|
||||
) = cx.tcx.hir().get(owner_id)
|
||||
{
|
||||
match fn_decl.output {
|
||||
FnRetTy::Return(ty) => binding_ty_auto_deref_stability(ty, precedence),
|
||||
FnRetTy::DefaultReturn(_) => Position::Other(precedence),
|
||||
}
|
||||
closure_result_position(cx, closure, cx.typeck_results().expr_ty(closure_expr), precedence)
|
||||
} else {
|
||||
let output = cx
|
||||
.tcx
|
||||
.fn_sig(cx.tcx.hir().local_def_id(owner_id))
|
||||
.skip_binder()
|
||||
.output();
|
||||
if !output.is_ref() {
|
||||
Position::Other(precedence)
|
||||
} else if output.has_placeholders() || output.has_opaque_types() {
|
||||
Position::ReborrowStable(precedence)
|
||||
} else {
|
||||
Position::DerefStable(precedence)
|
||||
}
|
||||
.erase_late_bound_regions(cx.tcx.fn_sig(cx.tcx.hir().local_def_id(owner_id)).output());
|
||||
ty_auto_deref_stability(cx, output, precedence).position_for_result(cx)
|
||||
},
|
||||
)
|
||||
},
|
||||
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)
|
||||
},
|
||||
@ -755,8 +736,9 @@ fn walk_parents<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) -> (Position, &
|
||||
.map(|(hir_ty, ty)| match hir_ty {
|
||||
// Type inference for closures can depend on how they're called. Only go by the explicit
|
||||
// types here.
|
||||
Some(ty) => binding_ty_auto_deref_stability(ty, precedence),
|
||||
None => param_auto_deref_stability(ty.skip_binder(), precedence),
|
||||
Some(hir_ty) => binding_ty_auto_deref_stability(cx, hir_ty, precedence, ty.bound_vars()),
|
||||
None => ty_auto_deref_stability(cx, cx.tcx.erase_late_bound_regions(ty), precedence)
|
||||
.position_for_arg(),
|
||||
}),
|
||||
ExprKind::MethodCall(_, args, _) => {
|
||||
let id = cx.typeck_results().type_dependent_def_id(parent.hir_id).unwrap();
|
||||
@ -797,7 +779,12 @@ fn walk_parents<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) -> (Position, &
|
||||
Position::MethodReceiver
|
||||
}
|
||||
} else {
|
||||
param_auto_deref_stability(cx.tcx.fn_sig(id).skip_binder().inputs()[i], precedence)
|
||||
ty_auto_deref_stability(
|
||||
cx,
|
||||
cx.tcx.erase_late_bound_regions(cx.tcx.fn_sig(id).input(i)),
|
||||
precedence,
|
||||
)
|
||||
.position_for_arg()
|
||||
}
|
||||
})
|
||||
},
|
||||
@ -808,7 +795,9 @@ fn walk_parents<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) -> (Position, &
|
||||
.find(|f| f.expr.hir_id == child_id)
|
||||
.zip(variant)
|
||||
.and_then(|(field, variant)| variant.fields.iter().find(|f| f.name == field.ident.name))
|
||||
.map(|field| param_auto_deref_stability(cx.tcx.type_of(field.did), precedence))
|
||||
.map(|field| {
|
||||
ty_auto_deref_stability(cx, cx.tcx.type_of(field.did), precedence).position_for_arg()
|
||||
})
|
||||
},
|
||||
ExprKind::Field(child, name) if child.hir_id == e.hir_id => Some(Position::FieldAccess(name.name)),
|
||||
ExprKind::Unary(UnOp::Deref, child) if child.hir_id == e.hir_id => Some(Position::Deref),
|
||||
@ -831,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.
|
||||
@ -840,7 +849,12 @@ fn walk_parents<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) -> (Position, &
|
||||
//
|
||||
// Here `y1` and `y2` would resolve to different types, so the type `&Box<_>` is not stable when
|
||||
// switching to auto-dereferencing.
|
||||
fn binding_ty_auto_deref_stability(ty: &hir::Ty<'_>, precedence: i8) -> Position {
|
||||
fn binding_ty_auto_deref_stability<'tcx>(
|
||||
cx: &LateContext<'tcx>,
|
||||
ty: &'tcx hir::Ty<'_>,
|
||||
precedence: i8,
|
||||
binder_args: &'tcx List<BoundVariableKind>,
|
||||
) -> Position {
|
||||
let TyKind::Rptr(_, ty) = &ty.kind else {
|
||||
return Position::Other(precedence);
|
||||
};
|
||||
@ -870,21 +884,33 @@ fn binding_ty_auto_deref_stability(ty: &hir::Ty<'_>, precedence: i8) -> Position
|
||||
{
|
||||
Position::ReborrowStable(precedence)
|
||||
} else {
|
||||
Position::DerefStable(precedence)
|
||||
Position::DerefStable(
|
||||
precedence,
|
||||
cx.tcx
|
||||
.erase_late_bound_regions(Binder::bind_with_vars(
|
||||
cx.typeck_results().node_type(ty.ty.hir_id),
|
||||
binder_args,
|
||||
))
|
||||
.is_sized(cx.tcx.at(DUMMY_SP), cx.param_env.without_caller_bounds()),
|
||||
)
|
||||
}
|
||||
},
|
||||
TyKind::Slice(_)
|
||||
| TyKind::Array(..)
|
||||
| TyKind::BareFn(_)
|
||||
| TyKind::Never
|
||||
TyKind::Slice(_) => Position::DerefStable(precedence, false),
|
||||
TyKind::Array(..) | TyKind::Ptr(_) | TyKind::BareFn(_) => Position::DerefStable(precedence, true),
|
||||
TyKind::Never
|
||||
| TyKind::Tup(_)
|
||||
| TyKind::Ptr(_)
|
||||
| TyKind::TraitObject(..)
|
||||
| TyKind::Path(_) => Position::DerefStable(precedence),
|
||||
TyKind::OpaqueDef(..)
|
||||
| TyKind::Infer
|
||||
| TyKind::Typeof(..)
|
||||
| TyKind::Err => Position::ReborrowStable(precedence),
|
||||
| TyKind::Path(_) => Position::DerefStable(
|
||||
precedence,
|
||||
cx.tcx
|
||||
.erase_late_bound_regions(Binder::bind_with_vars(
|
||||
cx.typeck_results().node_type(ty.ty.hir_id),
|
||||
binder_args,
|
||||
))
|
||||
.is_sized(cx.tcx.at(DUMMY_SP), cx.param_env.without_caller_bounds()),
|
||||
),
|
||||
TyKind::OpaqueDef(..) | TyKind::Infer | TyKind::Typeof(..) | TyKind::TraitObject(..) | TyKind::Err => {
|
||||
Position::ReborrowStable(precedence)
|
||||
},
|
||||
};
|
||||
}
|
||||
}
|
||||
@ -920,10 +946,39 @@ fn ty_contains_infer(ty: &hir::Ty<'_>) -> bool {
|
||||
v.0
|
||||
}
|
||||
|
||||
struct TyPosition<'tcx> {
|
||||
position: Position,
|
||||
ty: Option<Ty<'tcx>>,
|
||||
}
|
||||
impl From<Position> for TyPosition<'_> {
|
||||
fn from(position: Position) -> Self {
|
||||
Self { position, ty: None }
|
||||
}
|
||||
}
|
||||
impl<'tcx> TyPosition<'tcx> {
|
||||
fn new_deref_stable_for_result(precedence: i8, ty: Ty<'tcx>) -> Self {
|
||||
Self {
|
||||
position: Position::ReborrowStable(precedence),
|
||||
ty: Some(ty),
|
||||
}
|
||||
}
|
||||
fn position_for_result(self, cx: &LateContext<'tcx>) -> Position {
|
||||
match (self.position, self.ty) {
|
||||
(Position::ReborrowStable(precedence), Some(ty)) => {
|
||||
Position::DerefStable(precedence, ty.is_sized(cx.tcx.at(DUMMY_SP), cx.param_env))
|
||||
},
|
||||
(position, _) => position,
|
||||
}
|
||||
}
|
||||
fn position_for_arg(self) -> Position {
|
||||
self.position
|
||||
}
|
||||
}
|
||||
|
||||
// Checks whether a type is stable when switching to auto dereferencing,
|
||||
fn param_auto_deref_stability(ty: Ty<'_>, precedence: i8) -> Position {
|
||||
fn ty_auto_deref_stability<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>, precedence: i8) -> TyPosition<'tcx> {
|
||||
let ty::Ref(_, mut ty, _) = *ty.kind() else {
|
||||
return Position::Other(precedence);
|
||||
return Position::Other(precedence).into();
|
||||
};
|
||||
|
||||
loop {
|
||||
@ -932,35 +987,38 @@ fn param_auto_deref_stability(ty: Ty<'_>, precedence: i8) -> Position {
|
||||
ty = ref_ty;
|
||||
continue;
|
||||
},
|
||||
ty::Infer(_)
|
||||
| ty::Error(_)
|
||||
| ty::Param(_)
|
||||
| ty::Bound(..)
|
||||
| ty::Opaque(..)
|
||||
| ty::Placeholder(_)
|
||||
| ty::Dynamic(..) => Position::ReborrowStable(precedence),
|
||||
ty::Adt(..) if ty.has_placeholders() || ty.has_param_types_or_consts() => {
|
||||
Position::ReborrowStable(precedence)
|
||||
ty::Param(_) => TyPosition::new_deref_stable_for_result(precedence, ty),
|
||||
ty::Infer(_) | ty::Error(_) | ty::Bound(..) | ty::Opaque(..) | ty::Placeholder(_) | ty::Dynamic(..) => {
|
||||
Position::ReborrowStable(precedence).into()
|
||||
},
|
||||
ty::Adt(..)
|
||||
| ty::Bool
|
||||
ty::Adt(..) if ty.has_placeholders() || ty.has_opaque_types() => {
|
||||
Position::ReborrowStable(precedence).into()
|
||||
},
|
||||
ty::Adt(_, substs) if substs.has_param_types_or_consts() => {
|
||||
TyPosition::new_deref_stable_for_result(precedence, ty)
|
||||
},
|
||||
ty::Bool
|
||||
| ty::Char
|
||||
| ty::Int(_)
|
||||
| ty::Uint(_)
|
||||
| ty::Float(_)
|
||||
| ty::Foreign(_)
|
||||
| ty::Str
|
||||
| ty::Array(..)
|
||||
| ty::Slice(..)
|
||||
| ty::Float(_)
|
||||
| ty::RawPtr(..)
|
||||
| ty::FnPtr(_) => Position::DerefStable(precedence, true).into(),
|
||||
ty::Str | ty::Slice(..) => Position::DerefStable(precedence, false).into(),
|
||||
ty::Adt(..)
|
||||
| ty::Foreign(_)
|
||||
| ty::FnDef(..)
|
||||
| ty::FnPtr(_)
|
||||
| ty::Closure(..)
|
||||
| ty::Generator(..)
|
||||
| ty::GeneratorWitness(..)
|
||||
| ty::Closure(..)
|
||||
| ty::Never
|
||||
| ty::Tuple(_)
|
||||
| ty::Projection(_) => Position::DerefStable(precedence),
|
||||
| ty::Projection(_) => Position::DerefStable(
|
||||
precedence,
|
||||
ty.is_sized(cx.tcx.at(DUMMY_SP), cx.param_env.without_caller_bounds()),
|
||||
)
|
||||
.into(),
|
||||
};
|
||||
}
|
||||
}
|
||||
@ -1040,34 +1098,64 @@ fn report<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, state: State, data
|
||||
diag.span_suggestion(data.span, "change this to", sugg, app);
|
||||
});
|
||||
},
|
||||
State::ExplicitDeref { deref_span_id } => {
|
||||
let (span, hir_id, precedence) = if let Some((span, hir_id)) = deref_span_id
|
||||
State::ExplicitDeref { mutability } => {
|
||||
if matches!(
|
||||
expr.kind,
|
||||
ExprKind::Block(..)
|
||||
| ExprKind::ConstBlock(_)
|
||||
| ExprKind::If(..)
|
||||
| ExprKind::Loop(..)
|
||||
| ExprKind::Match(..)
|
||||
) && matches!(data.position, Position::DerefStable(_, true))
|
||||
{
|
||||
// Rustc bug: auto deref doesn't work on block expression when targeting sized types.
|
||||
return;
|
||||
}
|
||||
|
||||
let (prefix, precedence) = if let Some(mutability) = mutability
|
||||
&& !cx.typeck_results().expr_ty(expr).is_ref()
|
||||
{
|
||||
(span, hir_id, PREC_PREFIX)
|
||||
let prefix = match mutability {
|
||||
Mutability::Not => "&",
|
||||
Mutability::Mut => "&mut ",
|
||||
};
|
||||
(prefix, 0)
|
||||
} else {
|
||||
(data.span, data.hir_id, data.position.precedence())
|
||||
("", data.position.precedence())
|
||||
};
|
||||
span_lint_hir_and_then(
|
||||
cx,
|
||||
EXPLICIT_AUTO_DEREF,
|
||||
hir_id,
|
||||
span,
|
||||
data.hir_id,
|
||||
data.span,
|
||||
"deref which would be done by auto-deref",
|
||||
|diag| {
|
||||
let mut app = Applicability::MachineApplicable;
|
||||
let (snip, snip_is_macro) = snippet_with_context(cx, expr.span, span.ctxt(), "..", &mut app);
|
||||
let (snip, snip_is_macro) = snippet_with_context(cx, expr.span, data.span.ctxt(), "..", &mut app);
|
||||
let sugg =
|
||||
if !snip_is_macro && expr.precedence().order() < precedence && !has_enclosing_paren(&snip) {
|
||||
format!("({})", snip)
|
||||
format!("{}({})", prefix, snip)
|
||||
} else {
|
||||
snip.into()
|
||||
format!("{}{}", prefix, snip)
|
||||
};
|
||||
diag.span_suggestion(span, "try this", sugg, app);
|
||||
diag.span_suggestion(data.span, "try this", sugg, app);
|
||||
},
|
||||
);
|
||||
},
|
||||
State::ExplicitDerefField { .. } => {
|
||||
if matches!(
|
||||
expr.kind,
|
||||
ExprKind::Block(..)
|
||||
| ExprKind::ConstBlock(_)
|
||||
| ExprKind::If(..)
|
||||
| ExprKind::Loop(..)
|
||||
| ExprKind::Match(..)
|
||||
) && matches!(data.position, Position::DerefStable(_, true))
|
||||
{
|
||||
// Rustc bug: auto deref doesn't work on block expression when targeting sized types.
|
||||
return;
|
||||
}
|
||||
|
||||
span_lint_hir_and_then(
|
||||
cx,
|
||||
EXPLICIT_AUTO_DEREF,
|
||||
@ -1081,7 +1169,7 @@ fn report<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, state: State, data
|
||||
},
|
||||
);
|
||||
},
|
||||
State::Borrow | State::Reborrow { .. } => (),
|
||||
State::Borrow { .. } | State::Reborrow { .. } => (),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -503,7 +503,7 @@ pub fn all_predicates_of(tcx: TyCtxt<'_>, id: DefId) -> impl Iterator<Item = &(P
|
||||
pub enum ExprFnSig<'tcx> {
|
||||
Sig(Binder<'tcx, FnSig<'tcx>>, Option<DefId>),
|
||||
Closure(Option<&'tcx FnDecl<'tcx>>, Binder<'tcx, FnSig<'tcx>>),
|
||||
Trait(Binder<'tcx, Ty<'tcx>>, Option<Binder<'tcx, Ty<'tcx>>>),
|
||||
Trait(Binder<'tcx, Ty<'tcx>>, Option<Binder<'tcx, Ty<'tcx>>>, Option<DefId>),
|
||||
}
|
||||
impl<'tcx> ExprFnSig<'tcx> {
|
||||
/// Gets the argument type at the given offset. This will return `None` when the index is out of
|
||||
@ -518,7 +518,7 @@ impl<'tcx> ExprFnSig<'tcx> {
|
||||
}
|
||||
},
|
||||
Self::Closure(_, sig) => Some(sig.input(0).map_bound(|ty| ty.tuple_fields()[i])),
|
||||
Self::Trait(inputs, _) => Some(inputs.map_bound(|ty| ty.tuple_fields()[i])),
|
||||
Self::Trait(inputs, _, _) => Some(inputs.map_bound(|ty| ty.tuple_fields()[i])),
|
||||
}
|
||||
}
|
||||
|
||||
@ -541,7 +541,7 @@ impl<'tcx> ExprFnSig<'tcx> {
|
||||
decl.and_then(|decl| decl.inputs.get(i)),
|
||||
sig.input(0).map_bound(|ty| ty.tuple_fields()[i]),
|
||||
)),
|
||||
Self::Trait(inputs, _) => Some((None, inputs.map_bound(|ty| ty.tuple_fields()[i]))),
|
||||
Self::Trait(inputs, _, _) => Some((None, inputs.map_bound(|ty| ty.tuple_fields()[i]))),
|
||||
}
|
||||
}
|
||||
|
||||
@ -550,12 +550,16 @@ impl<'tcx> ExprFnSig<'tcx> {
|
||||
pub fn output(self) -> Option<Binder<'tcx, Ty<'tcx>>> {
|
||||
match self {
|
||||
Self::Sig(sig, _) | Self::Closure(_, sig) => Some(sig.output()),
|
||||
Self::Trait(_, output) => output,
|
||||
Self::Trait(_, output, _) => output,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn predicates_id(&self) -> Option<DefId> {
|
||||
if let ExprFnSig::Sig(_, id) = *self { id } else { None }
|
||||
if let ExprFnSig::Sig(_, id) | ExprFnSig::Trait(_, _, id) = *self {
|
||||
id
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -568,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());
|
||||
}
|
||||
@ -580,7 +585,7 @@ fn ty_sig<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Option<ExprFnSig<'tcx>>
|
||||
Some(ExprFnSig::Closure(decl, subs.as_closure().sig()))
|
||||
},
|
||||
ty::FnDef(id, subs) => Some(ExprFnSig::Sig(cx.tcx.bound_fn_sig(id).subst(cx.tcx, subs), Some(id))),
|
||||
ty::Opaque(id, _) => ty_sig(cx, cx.tcx.type_of(id)),
|
||||
ty::Opaque(id, _) => sig_from_bounds(cx, ty, cx.tcx.item_bounds(id), cx.tcx.opt_parent(id)),
|
||||
ty::FnPtr(sig) => Some(ExprFnSig::Sig(sig, None)),
|
||||
ty::Dynamic(bounds, _) => {
|
||||
let lang_items = cx.tcx.lang_items();
|
||||
@ -594,26 +599,31 @@ fn ty_sig<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Option<ExprFnSig<'tcx>>
|
||||
.projection_bounds()
|
||||
.find(|p| lang_items.fn_once_output().map_or(false, |id| id == p.item_def_id()))
|
||||
.map(|p| p.map_bound(|p| p.term.ty().unwrap()));
|
||||
Some(ExprFnSig::Trait(bound.map_bound(|b| b.substs.type_at(0)), output))
|
||||
Some(ExprFnSig::Trait(bound.map_bound(|b| b.substs.type_at(0)), output, None))
|
||||
},
|
||||
_ => None,
|
||||
}
|
||||
},
|
||||
ty::Projection(proj) => match cx.tcx.try_normalize_erasing_regions(cx.param_env, ty) {
|
||||
Ok(normalized_ty) if normalized_ty != ty => ty_sig(cx, normalized_ty),
|
||||
_ => sig_for_projection(cx, proj).or_else(|| sig_from_bounds(cx, ty)),
|
||||
_ => sig_for_projection(cx, proj).or_else(|| sig_from_bounds(cx, ty, cx.param_env.caller_bounds(), None)),
|
||||
},
|
||||
ty::Param(_) => sig_from_bounds(cx, ty),
|
||||
ty::Param(_) => sig_from_bounds(cx, ty, cx.param_env.caller_bounds(), None),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
fn sig_from_bounds<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Option<ExprFnSig<'tcx>> {
|
||||
fn sig_from_bounds<'tcx>(
|
||||
cx: &LateContext<'tcx>,
|
||||
ty: Ty<'tcx>,
|
||||
predicates: &'tcx [Predicate<'tcx>],
|
||||
predicates_id: Option<DefId>,
|
||||
) -> Option<ExprFnSig<'tcx>> {
|
||||
let mut inputs = None;
|
||||
let mut output = None;
|
||||
let lang_items = cx.tcx.lang_items();
|
||||
|
||||
for (pred, _) in all_predicates_of(cx.tcx, cx.typeck_results().hir_owner.to_def_id()) {
|
||||
for pred in predicates {
|
||||
match pred.kind().skip_binder() {
|
||||
PredicateKind::Trait(p)
|
||||
if (lang_items.fn_trait() == Some(p.def_id())
|
||||
@ -621,11 +631,12 @@ fn sig_from_bounds<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Option<ExprFnS
|
||||
|| lang_items.fn_once_trait() == Some(p.def_id()))
|
||||
&& p.self_ty() == ty =>
|
||||
{
|
||||
if inputs.is_some() {
|
||||
let i = pred.kind().rebind(p.trait_ref.substs.type_at(1));
|
||||
if inputs.map_or(false, |inputs| i != inputs) {
|
||||
// Multiple different fn trait impls. Is this even allowed?
|
||||
return None;
|
||||
}
|
||||
inputs = Some(pred.kind().rebind(p.trait_ref.substs.type_at(1)));
|
||||
inputs = Some(i);
|
||||
},
|
||||
PredicateKind::Projection(p)
|
||||
if Some(p.projection_ty.item_def_id) == lang_items.fn_once_output()
|
||||
@ -641,7 +652,7 @@ fn sig_from_bounds<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Option<ExprFnS
|
||||
}
|
||||
}
|
||||
|
||||
inputs.map(|ty| ExprFnSig::Trait(ty, output))
|
||||
inputs.map(|ty| ExprFnSig::Trait(ty, output, predicates_id))
|
||||
}
|
||||
|
||||
fn sig_for_projection<'tcx>(cx: &LateContext<'tcx>, ty: ProjectionTy<'tcx>) -> Option<ExprFnSig<'tcx>> {
|
||||
@ -661,14 +672,15 @@ fn sig_for_projection<'tcx>(cx: &LateContext<'tcx>, ty: ProjectionTy<'tcx>) -> O
|
||||
|| lang_items.fn_mut_trait() == Some(p.def_id())
|
||||
|| lang_items.fn_once_trait() == Some(p.def_id())) =>
|
||||
{
|
||||
if inputs.is_some() {
|
||||
let i = pred
|
||||
.map_bound(|pred| pred.kind().rebind(p.trait_ref.substs.type_at(1)))
|
||||
.subst(cx.tcx, ty.substs);
|
||||
|
||||
if inputs.map_or(false, |inputs| inputs != i) {
|
||||
// Multiple different fn trait impls. Is this even allowed?
|
||||
return None;
|
||||
}
|
||||
inputs = Some(
|
||||
pred.map_bound(|pred| pred.kind().rebind(p.trait_ref.substs.type_at(1)))
|
||||
.subst(cx.tcx, ty.substs),
|
||||
);
|
||||
inputs = Some(i);
|
||||
},
|
||||
PredicateKind::Projection(p) if Some(p.projection_ty.item_def_id) == lang_items.fn_once_output() => {
|
||||
if output.is_some() {
|
||||
@ -684,7 +696,7 @@ fn sig_for_projection<'tcx>(cx: &LateContext<'tcx>, ty: ProjectionTy<'tcx>) -> O
|
||||
}
|
||||
}
|
||||
|
||||
inputs.map(|ty| ExprFnSig::Trait(ty, output))
|
||||
inputs.map(|ty| ExprFnSig::Trait(ty, output, None))
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
|
@ -1,5 +1,6 @@
|
||||
// run-rustfix
|
||||
|
||||
#![feature(closure_lifetime_binder)]
|
||||
#![warn(clippy::explicit_auto_deref)]
|
||||
#![allow(
|
||||
dead_code,
|
||||
@ -67,6 +68,8 @@ fn main() {
|
||||
let s = String::new();
|
||||
|
||||
let _: &str = &s;
|
||||
let _: &str = &{ String::new() };
|
||||
let _: &str = &mut { String::new() };
|
||||
let _ = &*s; // Don't lint. Inferred type would change.
|
||||
let _: &_ = &*s; // Don't lint. Inferred type would change.
|
||||
|
||||
@ -215,4 +218,52 @@ fn main() {
|
||||
let s = &"str";
|
||||
let _ = || return *s;
|
||||
let _ = || -> &'static str { return s };
|
||||
|
||||
struct X;
|
||||
struct Y(X);
|
||||
impl core::ops::Deref for Y {
|
||||
type Target = X;
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
let _: &X = &*{ Y(X) };
|
||||
let _: &X = &*match 0 {
|
||||
#[rustfmt::skip]
|
||||
0 => { Y(X) },
|
||||
_ => panic!(),
|
||||
};
|
||||
let _: &X = &*if true { Y(X) } else { panic!() };
|
||||
|
||||
fn deref_to_u<U, T: core::ops::Deref<Target = U>>(x: &T) -> &U {
|
||||
x
|
||||
}
|
||||
|
||||
let _ = |x: &'static Box<dyn Iterator<Item = u32>>| -> &'static dyn Iterator<Item = u32> { &**x };
|
||||
fn ret_any(x: &Box<dyn std::any::Any>) -> &dyn std::any::Any {
|
||||
&**x
|
||||
}
|
||||
|
||||
let x = String::new();
|
||||
let _: *const str = &*x;
|
||||
|
||||
struct S7([u32; 1]);
|
||||
impl core::ops::Deref for S7 {
|
||||
type Target = [u32; 1];
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
let x = S7([0]);
|
||||
let _: &[u32] = &*x;
|
||||
|
||||
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
|
||||
};
|
||||
}
|
||||
|
@ -1,5 +1,6 @@
|
||||
// run-rustfix
|
||||
|
||||
#![feature(closure_lifetime_binder)]
|
||||
#![warn(clippy::explicit_auto_deref)]
|
||||
#![allow(
|
||||
dead_code,
|
||||
@ -67,6 +68,8 @@ fn main() {
|
||||
let s = String::new();
|
||||
|
||||
let _: &str = &*s;
|
||||
let _: &str = &*{ String::new() };
|
||||
let _: &str = &mut *{ String::new() };
|
||||
let _ = &*s; // Don't lint. Inferred type would change.
|
||||
let _: &_ = &*s; // Don't lint. Inferred type would change.
|
||||
|
||||
@ -215,4 +218,52 @@ fn main() {
|
||||
let s = &"str";
|
||||
let _ = || return *s;
|
||||
let _ = || -> &'static str { return *s };
|
||||
|
||||
struct X;
|
||||
struct Y(X);
|
||||
impl core::ops::Deref for Y {
|
||||
type Target = X;
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
let _: &X = &*{ Y(X) };
|
||||
let _: &X = &*match 0 {
|
||||
#[rustfmt::skip]
|
||||
0 => { Y(X) },
|
||||
_ => panic!(),
|
||||
};
|
||||
let _: &X = &*if true { Y(X) } else { panic!() };
|
||||
|
||||
fn deref_to_u<U, T: core::ops::Deref<Target = U>>(x: &T) -> &U {
|
||||
&**x
|
||||
}
|
||||
|
||||
let _ = |x: &'static Box<dyn Iterator<Item = u32>>| -> &'static dyn Iterator<Item = u32> { &**x };
|
||||
fn ret_any(x: &Box<dyn std::any::Any>) -> &dyn std::any::Any {
|
||||
&**x
|
||||
}
|
||||
|
||||
let x = String::new();
|
||||
let _: *const str = &*x;
|
||||
|
||||
struct S7([u32; 1]);
|
||||
impl core::ops::Deref for S7 {
|
||||
type Target = [u32; 1];
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
let x = S7([0]);
|
||||
let _: &[u32] = &*x;
|
||||
|
||||
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
|
||||
};
|
||||
}
|
||||
|
@ -1,202 +1,238 @@
|
||||
error: deref which would be done by auto-deref
|
||||
--> $DIR/explicit_auto_deref.rs:69:20
|
||||
--> $DIR/explicit_auto_deref.rs:70:19
|
||||
|
|
||||
LL | let _: &str = &*s;
|
||||
| ^^ help: try this: `s`
|
||||
| ^^^ help: try this: `&s`
|
||||
|
|
||||
= note: `-D clippy::explicit-auto-deref` implied by `-D warnings`
|
||||
|
||||
error: deref which would be done by auto-deref
|
||||
--> $DIR/explicit_auto_deref.rs:73:12
|
||||
--> $DIR/explicit_auto_deref.rs:71:19
|
||||
|
|
||||
LL | let _: &str = &*{ String::new() };
|
||||
| ^^^^^^^^^^^^^^^^^^^ help: try this: `&{ String::new() }`
|
||||
|
||||
error: deref which would be done by auto-deref
|
||||
--> $DIR/explicit_auto_deref.rs:72:19
|
||||
|
|
||||
LL | let _: &str = &mut *{ String::new() };
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `&mut { String::new() }`
|
||||
|
||||
error: deref which would be done by auto-deref
|
||||
--> $DIR/explicit_auto_deref.rs:76:11
|
||||
|
|
||||
LL | f_str(&*s);
|
||||
| ^^ help: try this: `s`
|
||||
| ^^^ help: try this: `&s`
|
||||
|
||||
error: deref which would be done by auto-deref
|
||||
--> $DIR/explicit_auto_deref.rs:77:14
|
||||
--> $DIR/explicit_auto_deref.rs:80:13
|
||||
|
|
||||
LL | f_str_t(&*s, &*s); // Don't lint second param.
|
||||
| ^^ help: try this: `s`
|
||||
| ^^^ help: try this: `&s`
|
||||
|
||||
error: deref which would be done by auto-deref
|
||||
--> $DIR/explicit_auto_deref.rs:80:25
|
||||
--> $DIR/explicit_auto_deref.rs:83:24
|
||||
|
|
||||
LL | let _: &Box<i32> = &**b;
|
||||
| ^^^ help: try this: `b`
|
||||
| ^^^^ help: try this: `&b`
|
||||
|
||||
error: deref which would be done by auto-deref
|
||||
--> $DIR/explicit_auto_deref.rs:86:8
|
||||
--> $DIR/explicit_auto_deref.rs:89:7
|
||||
|
|
||||
LL | c(&*s);
|
||||
| ^^ help: try this: `s`
|
||||
| ^^^ help: try this: `&s`
|
||||
|
||||
error: deref which would be done by auto-deref
|
||||
--> $DIR/explicit_auto_deref.rs:92:9
|
||||
--> $DIR/explicit_auto_deref.rs:95:9
|
||||
|
|
||||
LL | &**x
|
||||
| ^^^^ help: try this: `x`
|
||||
|
||||
error: deref which would be done by auto-deref
|
||||
--> $DIR/explicit_auto_deref.rs:96:11
|
||||
--> $DIR/explicit_auto_deref.rs:99:11
|
||||
|
|
||||
LL | { &**x }
|
||||
| ^^^^ help: try this: `x`
|
||||
|
||||
error: deref which would be done by auto-deref
|
||||
--> $DIR/explicit_auto_deref.rs:100:9
|
||||
--> $DIR/explicit_auto_deref.rs:103:9
|
||||
|
|
||||
LL | &**{ x }
|
||||
| ^^^^^^^^ help: try this: `{ x }`
|
||||
|
||||
error: deref which would be done by auto-deref
|
||||
--> $DIR/explicit_auto_deref.rs:104:9
|
||||
--> $DIR/explicit_auto_deref.rs:107:9
|
||||
|
|
||||
LL | &***x
|
||||
| ^^^^^ help: try this: `x`
|
||||
|
||||
error: deref which would be done by auto-deref
|
||||
--> $DIR/explicit_auto_deref.rs:121:13
|
||||
--> $DIR/explicit_auto_deref.rs:124:12
|
||||
|
|
||||
LL | f1(&*x);
|
||||
| ^^ help: try this: `x`
|
||||
| ^^^ help: try this: `&x`
|
||||
|
||||
error: deref which would be done by auto-deref
|
||||
--> $DIR/explicit_auto_deref.rs:122:13
|
||||
--> $DIR/explicit_auto_deref.rs:125:12
|
||||
|
|
||||
LL | f2(&*x);
|
||||
| ^^ help: try this: `x`
|
||||
| ^^^ help: try this: `&x`
|
||||
|
||||
error: deref which would be done by auto-deref
|
||||
--> $DIR/explicit_auto_deref.rs:123:13
|
||||
--> $DIR/explicit_auto_deref.rs:126:12
|
||||
|
|
||||
LL | f3(&*x);
|
||||
| ^^ help: try this: `x`
|
||||
| ^^^ help: try this: `&x`
|
||||
|
||||
error: deref which would be done by auto-deref
|
||||
--> $DIR/explicit_auto_deref.rs:124:28
|
||||
--> $DIR/explicit_auto_deref.rs:127:27
|
||||
|
|
||||
LL | f4.callable_str()(&*x);
|
||||
| ^^ help: try this: `x`
|
||||
| ^^^ help: try this: `&x`
|
||||
|
||||
error: deref which would be done by auto-deref
|
||||
--> $DIR/explicit_auto_deref.rs:125:13
|
||||
--> $DIR/explicit_auto_deref.rs:128:12
|
||||
|
|
||||
LL | f5(&*x);
|
||||
| ^^ help: try this: `x`
|
||||
| ^^^ help: try this: `&x`
|
||||
|
||||
error: deref which would be done by auto-deref
|
||||
--> $DIR/explicit_auto_deref.rs:126:13
|
||||
--> $DIR/explicit_auto_deref.rs:129:12
|
||||
|
|
||||
LL | f6(&*x);
|
||||
| ^^ help: try this: `x`
|
||||
| ^^^ help: try this: `&x`
|
||||
|
||||
error: deref which would be done by auto-deref
|
||||
--> $DIR/explicit_auto_deref.rs:127:28
|
||||
--> $DIR/explicit_auto_deref.rs:130:27
|
||||
|
|
||||
LL | f7.callable_str()(&*x);
|
||||
| ^^ help: try this: `x`
|
||||
| ^^^ help: try this: `&x`
|
||||
|
||||
error: deref which would be done by auto-deref
|
||||
--> $DIR/explicit_auto_deref.rs:128:26
|
||||
--> $DIR/explicit_auto_deref.rs:131:25
|
||||
|
|
||||
LL | f8.callable_t()(&*x);
|
||||
| ^^ help: try this: `x`
|
||||
| ^^^ help: try this: `&x`
|
||||
|
||||
error: deref which would be done by auto-deref
|
||||
--> $DIR/explicit_auto_deref.rs:129:13
|
||||
--> $DIR/explicit_auto_deref.rs:132:12
|
||||
|
|
||||
LL | f9(&*x);
|
||||
| ^^ help: try this: `x`
|
||||
| ^^^ help: try this: `&x`
|
||||
|
||||
error: deref which would be done by auto-deref
|
||||
--> $DIR/explicit_auto_deref.rs:130:14
|
||||
--> $DIR/explicit_auto_deref.rs:133:13
|
||||
|
|
||||
LL | f10(&*x);
|
||||
| ^^ help: try this: `x`
|
||||
| ^^^ help: try this: `&x`
|
||||
|
||||
error: deref which would be done by auto-deref
|
||||
--> $DIR/explicit_auto_deref.rs:131:27
|
||||
--> $DIR/explicit_auto_deref.rs:134:26
|
||||
|
|
||||
LL | f11.callable_t()(&*x);
|
||||
| ^^ help: try this: `x`
|
||||
| ^^^ help: try this: `&x`
|
||||
|
||||
error: deref which would be done by auto-deref
|
||||
--> $DIR/explicit_auto_deref.rs:135:17
|
||||
--> $DIR/explicit_auto_deref.rs:138:16
|
||||
|
|
||||
LL | let _ = S1(&*s);
|
||||
| ^^ help: try this: `s`
|
||||
| ^^^ help: try this: `&s`
|
||||
|
||||
error: deref which would be done by auto-deref
|
||||
--> $DIR/explicit_auto_deref.rs:140:22
|
||||
--> $DIR/explicit_auto_deref.rs:143:21
|
||||
|
|
||||
LL | let _ = S2 { s: &*s };
|
||||
| ^^ help: try this: `s`
|
||||
| ^^^ help: try this: `&s`
|
||||
|
||||
error: deref which would be done by auto-deref
|
||||
--> $DIR/explicit_auto_deref.rs:156:30
|
||||
--> $DIR/explicit_auto_deref.rs:159:30
|
||||
|
|
||||
LL | let _ = Self::S1(&**s);
|
||||
| ^^^^ help: try this: `s`
|
||||
|
||||
error: deref which would be done by auto-deref
|
||||
--> $DIR/explicit_auto_deref.rs:157:35
|
||||
--> $DIR/explicit_auto_deref.rs:160:35
|
||||
|
|
||||
LL | let _ = Self::S2 { s: &**s };
|
||||
| ^^^^ help: try this: `s`
|
||||
|
||||
error: deref which would be done by auto-deref
|
||||
--> $DIR/explicit_auto_deref.rs:160:21
|
||||
--> $DIR/explicit_auto_deref.rs:163:20
|
||||
|
|
||||
LL | let _ = E1::S1(&*s);
|
||||
| ^^ help: try this: `s`
|
||||
| ^^^ help: try this: `&s`
|
||||
|
||||
error: deref which would be done by auto-deref
|
||||
--> $DIR/explicit_auto_deref.rs:161:26
|
||||
--> $DIR/explicit_auto_deref.rs:164:25
|
||||
|
|
||||
LL | let _ = E1::S2 { s: &*s };
|
||||
| ^^ help: try this: `s`
|
||||
| ^^^ help: try this: `&s`
|
||||
|
||||
error: deref which would be done by auto-deref
|
||||
--> $DIR/explicit_auto_deref.rs:179:13
|
||||
--> $DIR/explicit_auto_deref.rs:182:13
|
||||
|
|
||||
LL | let _ = (*b).foo;
|
||||
| ^^^^ help: try this: `b`
|
||||
|
||||
error: deref which would be done by auto-deref
|
||||
--> $DIR/explicit_auto_deref.rs:180:13
|
||||
--> $DIR/explicit_auto_deref.rs:183:13
|
||||
|
|
||||
LL | let _ = (**b).foo;
|
||||
| ^^^^^ help: try this: `b`
|
||||
|
||||
error: deref which would be done by auto-deref
|
||||
--> $DIR/explicit_auto_deref.rs:195:19
|
||||
--> $DIR/explicit_auto_deref.rs:198:19
|
||||
|
|
||||
LL | let _ = f_str(*ref_str);
|
||||
| ^^^^^^^^ help: try this: `ref_str`
|
||||
|
||||
error: deref which would be done by auto-deref
|
||||
--> $DIR/explicit_auto_deref.rs:197:19
|
||||
--> $DIR/explicit_auto_deref.rs:200:19
|
||||
|
|
||||
LL | let _ = f_str(**ref_ref_str);
|
||||
| ^^^^^^^^^^^^^ help: try this: `ref_ref_str`
|
||||
|
||||
error: deref which would be done by auto-deref
|
||||
--> $DIR/explicit_auto_deref.rs:207:13
|
||||
--> $DIR/explicit_auto_deref.rs:210:13
|
||||
|
|
||||
LL | f_str(&&*ref_str); // `needless_borrow` will suggest removing both references
|
||||
| ^^^^^^^^ help: try this: `ref_str`
|
||||
|
||||
error: deref which would be done by auto-deref
|
||||
--> $DIR/explicit_auto_deref.rs:208:12
|
||||
--> $DIR/explicit_auto_deref.rs:211:12
|
||||
|
|
||||
LL | f_str(&&**ref_str); // `needless_borrow` will suggest removing only one reference
|
||||
| ^^^^^^^^^^ help: try this: `ref_str`
|
||||
|
||||
error: deref which would be done by auto-deref
|
||||
--> $DIR/explicit_auto_deref.rs:217:41
|
||||
--> $DIR/explicit_auto_deref.rs:220:41
|
||||
|
|
||||
LL | let _ = || -> &'static str { return *s };
|
||||
| ^^ help: try this: `s`
|
||||
|
||||
error: aborting due to 33 previous errors
|
||||
error: deref which would be done by auto-deref
|
||||
--> $DIR/explicit_auto_deref.rs:239:9
|
||||
|
|
||||
LL | &**x
|
||||
| ^^^^ help: try this: `x`
|
||||
|
||||
error: deref which would be done by auto-deref
|
||||
--> $DIR/explicit_auto_deref.rs:262:8
|
||||
|
|
||||
LL | c1(*x);
|
||||
| ^^ help: try this: `x`
|
||||
|
||||
error: deref which would be done by auto-deref
|
||||
--> $DIR/explicit_auto_deref.rs:265:20
|
||||
|
|
||||
LL | return *x;
|
||||
| ^^ help: try this: `x`
|
||||
|
||||
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
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user