review comments and make test run-rustfix
This commit is contained in:
parent
ec98df4bb6
commit
4438b3211f
4 changed files with 100 additions and 84 deletions
|
@ -822,82 +822,72 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
expr: &hir::Expr<'_>,
|
expr: &hir::Expr<'_>,
|
||||||
error: Option<TypeError<'tcx>>,
|
error: Option<TypeError<'tcx>>,
|
||||||
) -> bool {
|
) -> bool {
|
||||||
let Some(TypeError::Sorts(ExpectedFound { expected, found })) = error else { return false };
|
if let Some(TypeError::Sorts(ExpectedFound { expected, found })) = error
|
||||||
let ty::Ref(_, inner, hir::Mutability::Not) = expected.kind() else { return false };
|
&& let ty::Ref(_, inner, hir::Mutability::Not) = expected.kind()
|
||||||
if !self.can_eq(self.param_env, *inner, found) {
|
|
||||||
// The difference between the expected and found values isn't one level of borrowing.
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
// We have an `ident = expr;` assignment.
|
|
||||||
let hir::Node::Expr(hir::Expr { kind: hir::ExprKind::Assign(lhs, rhs, _), .. }) =
|
|
||||||
self.tcx.parent_hir_node(expr.hir_id)
|
|
||||||
else {
|
|
||||||
return false;
|
|
||||||
};
|
|
||||||
if rhs.hir_id != expr.hir_id || expected.is_closure() {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
// We are assigning to some binding.
|
|
||||||
let hir::ExprKind::Path(hir::QPath::Resolved(
|
|
||||||
None,
|
|
||||||
hir::Path { res: hir::def::Res::Local(hir_id), .. },
|
|
||||||
)) = lhs.kind
|
|
||||||
else {
|
|
||||||
return false;
|
|
||||||
};
|
|
||||||
let hir::Node::Pat(pat) = self.tcx.hir_node(*hir_id) else { return false };
|
|
||||||
// The pattern we have is an fn argument.
|
|
||||||
let hir::Node::Param(hir::Param { ty_span, .. }) = self.tcx.parent_hir_node(pat.hir_id)
|
|
||||||
else {
|
|
||||||
return false;
|
|
||||||
};
|
|
||||||
let item = self.tcx.hir().get_parent_item(pat.hir_id);
|
|
||||||
let item = self.tcx.hir_owner_node(item);
|
|
||||||
let Some(fn_decl) = item.fn_decl() else { return false };
|
|
||||||
|
|
||||||
// We have a mutable binding in the argument.
|
// The difference between the expected and found values is one level of borrowing.
|
||||||
let hir::PatKind::Binding(hir::BindingMode::MUT, _hir_id, ident, _) = pat.kind else {
|
&& self.can_eq(self.param_env, *inner, found)
|
||||||
return false;
|
|
||||||
};
|
|
||||||
|
|
||||||
// Look for the type corresponding to the argument pattern we have in the argument list.
|
// We have an `ident = expr;` assignment.
|
||||||
let Some(ty_sugg) = fn_decl
|
&& let hir::Node::Expr(hir::Expr { kind: hir::ExprKind::Assign(lhs, rhs, _), .. }) =
|
||||||
.inputs
|
self.tcx.parent_hir_node(expr.hir_id)
|
||||||
.iter()
|
&& rhs.hir_id == expr.hir_id
|
||||||
.filter_map(|ty| {
|
|
||||||
if ty.span == *ty_span
|
// We are assigning to some binding.
|
||||||
&& let hir::TyKind::Ref(lt, mut_ty) = ty.kind
|
&& let hir::ExprKind::Path(hir::QPath::Resolved(
|
||||||
{
|
None,
|
||||||
// `&'name Ty` -> `&'name mut Ty` or `&Ty` -> `&mut Ty`
|
hir::Path { res: hir::def::Res::Local(hir_id), .. },
|
||||||
Some((
|
)) = lhs.kind
|
||||||
mut_ty.ty.span.shrink_to_lo(),
|
&& let hir::Node::Pat(pat) = self.tcx.hir_node(*hir_id)
|
||||||
format!(
|
|
||||||
"{}mut ",
|
// The pattern we have is an fn argument.
|
||||||
if lt.ident.span.lo() == lt.ident.span.hi() { "" } else { " " }
|
&& let hir::Node::Param(hir::Param { ty_span, .. }) =
|
||||||
),
|
self.tcx.parent_hir_node(pat.hir_id)
|
||||||
))
|
&& let item = self.tcx.hir().get_parent_item(pat.hir_id)
|
||||||
} else {
|
&& let item = self.tcx.hir_owner_node(item)
|
||||||
None
|
&& let Some(fn_decl) = item.fn_decl()
|
||||||
}
|
|
||||||
})
|
// We have a mutable binding in the argument.
|
||||||
.next()
|
&& let hir::PatKind::Binding(hir::BindingMode::MUT, _hir_id, ident, _) = pat.kind
|
||||||
else {
|
|
||||||
return false;
|
// Look for the type corresponding to the argument pattern we have in the argument list.
|
||||||
};
|
&& let Some(ty_sugg) = fn_decl
|
||||||
let sugg = vec![
|
.inputs
|
||||||
ty_sugg,
|
.iter()
|
||||||
(pat.span.until(ident.span), String::new()),
|
.filter_map(|ty| {
|
||||||
(lhs.span.shrink_to_lo(), "*".to_string()),
|
if ty.span == *ty_span
|
||||||
];
|
&& let hir::TyKind::Ref(lt, x) = ty.kind
|
||||||
// We suggest changing the argument from `mut ident: &Ty` to `ident: &'_ mut Ty` and the
|
{
|
||||||
// assignment from `ident = val;` to `*ident = val;`.
|
// `&'name Ty` -> `&'name mut Ty` or `&Ty` -> `&mut Ty`
|
||||||
err.multipart_suggestion_verbose(
|
Some((
|
||||||
"you might have meant to mutate the pointed at value being passed in, instead of \
|
x.ty.span.shrink_to_lo(),
|
||||||
changing the reference in the local binding",
|
format!(
|
||||||
sugg,
|
"{}mut ",
|
||||||
Applicability::MaybeIncorrect,
|
if lt.ident.span.lo() == lt.ident.span.hi() { "" } else { " " }
|
||||||
);
|
),
|
||||||
return true;
|
))
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.next()
|
||||||
|
{
|
||||||
|
let sugg = vec![
|
||||||
|
ty_sugg,
|
||||||
|
(pat.span.until(ident.span), String::new()),
|
||||||
|
(lhs.span.shrink_to_lo(), "*".to_string()),
|
||||||
|
];
|
||||||
|
// We suggest changing the argument from `mut ident: &Ty` to `ident: &'_ mut Ty` and the
|
||||||
|
// assignment from `ident = val;` to `*ident = val;`.
|
||||||
|
err.multipart_suggestion_verbose(
|
||||||
|
"you might have meant to mutate the pointed at value being passed in, instead of \
|
||||||
|
changing the reference in the local binding",
|
||||||
|
sugg,
|
||||||
|
Applicability::MaybeIncorrect,
|
||||||
|
);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
false
|
||||||
}
|
}
|
||||||
|
|
||||||
fn annotate_alternative_method_deref(
|
fn annotate_alternative_method_deref(
|
||||||
|
|
|
@ -0,0 +1,22 @@
|
||||||
|
//@ run-rustfix
|
||||||
|
#![deny(unused_assignments, unused_variables)]
|
||||||
|
struct Object;
|
||||||
|
|
||||||
|
fn change_object(object: &mut Object) { //~ HELP you might have meant to mutate
|
||||||
|
let object2 = Object;
|
||||||
|
*object = object2; //~ ERROR mismatched types
|
||||||
|
}
|
||||||
|
|
||||||
|
fn change_object2(object: &mut Object) { //~ ERROR variable `object` is assigned to, but never used
|
||||||
|
//~^ HELP you might have meant to mutate
|
||||||
|
let object2 = Object;
|
||||||
|
*object = object2;
|
||||||
|
//~^ ERROR `object2` does not live long enough
|
||||||
|
//~| ERROR value assigned to `object` is never read
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let mut object = Object;
|
||||||
|
change_object(&mut object);
|
||||||
|
change_object2(&mut object);
|
||||||
|
}
|
|
@ -1,12 +1,14 @@
|
||||||
|
//@ run-rustfix
|
||||||
#![deny(unused_assignments, unused_variables)]
|
#![deny(unused_assignments, unused_variables)]
|
||||||
struct Object;
|
struct Object;
|
||||||
|
|
||||||
fn change_object(mut object: &Object) {
|
fn change_object(mut object: &Object) { //~ HELP you might have meant to mutate
|
||||||
let object2 = Object;
|
let object2 = Object;
|
||||||
object = object2; //~ ERROR mismatched types
|
object = object2; //~ ERROR mismatched types
|
||||||
}
|
}
|
||||||
|
|
||||||
fn change_object2(mut object: &Object) { //~ ERROR variable `object` is assigned to, but never used
|
fn change_object2(mut object: &Object) { //~ ERROR variable `object` is assigned to, but never used
|
||||||
|
//~^ HELP you might have meant to mutate
|
||||||
let object2 = Object;
|
let object2 = Object;
|
||||||
object = &object2;
|
object = &object2;
|
||||||
//~^ ERROR `object2` does not live long enough
|
//~^ ERROR `object2` does not live long enough
|
||||||
|
@ -14,7 +16,7 @@ fn change_object2(mut object: &Object) { //~ ERROR variable `object` is assigned
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let object = Object;
|
let mut object = Object;
|
||||||
change_object(&object);
|
change_object(&mut object);
|
||||||
change_object2(&object);
|
change_object2(&mut object);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
error[E0308]: mismatched types
|
error[E0308]: mismatched types
|
||||||
--> $DIR/mut-arg-of-borrowed-type-meant-to-be-arg-of-mut-borrow.rs:6:14
|
--> $DIR/mut-arg-of-borrowed-type-meant-to-be-arg-of-mut-borrow.rs:7:14
|
||||||
|
|
|
|
||||||
LL | fn change_object(mut object: &Object) {
|
LL | fn change_object(mut object: &Object) {
|
||||||
| ------- expected due to this parameter type
|
| ------- expected due to this parameter type
|
||||||
|
@ -15,41 +15,43 @@ LL ~ *object = object2;
|
||||||
|
|
|
|
||||||
|
|
||||||
error: value assigned to `object` is never read
|
error: value assigned to `object` is never read
|
||||||
--> $DIR/mut-arg-of-borrowed-type-meant-to-be-arg-of-mut-borrow.rs:11:5
|
--> $DIR/mut-arg-of-borrowed-type-meant-to-be-arg-of-mut-borrow.rs:13:5
|
||||||
|
|
|
|
||||||
LL | object = &object2;
|
LL | object = &object2;
|
||||||
| ^^^^^^
|
| ^^^^^^
|
||||||
|
|
|
|
||||||
note: the lint level is defined here
|
note: the lint level is defined here
|
||||||
--> $DIR/mut-arg-of-borrowed-type-meant-to-be-arg-of-mut-borrow.rs:1:9
|
--> $DIR/mut-arg-of-borrowed-type-meant-to-be-arg-of-mut-borrow.rs:2:9
|
||||||
|
|
|
|
||||||
LL | #![deny(unused_assignments, unused_variables)]
|
LL | #![deny(unused_assignments, unused_variables)]
|
||||||
| ^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^
|
||||||
help: you might have meant to mutate the pointed at value being passed in, instead of changing the reference in the local binding
|
help: you might have meant to mutate the pointed at value being passed in, instead of changing the reference in the local binding
|
||||||
|
|
|
|
||||||
LL ~ fn change_object2(object: &mut Object) {
|
LL ~ fn change_object2(object: &mut Object) {
|
||||||
|
LL |
|
||||||
LL | let object2 = Object;
|
LL | let object2 = Object;
|
||||||
LL ~ *object = object2;
|
LL ~ *object = object2;
|
||||||
|
|
|
|
||||||
|
|
||||||
error: variable `object` is assigned to, but never used
|
error: variable `object` is assigned to, but never used
|
||||||
--> $DIR/mut-arg-of-borrowed-type-meant-to-be-arg-of-mut-borrow.rs:9:23
|
--> $DIR/mut-arg-of-borrowed-type-meant-to-be-arg-of-mut-borrow.rs:10:23
|
||||||
|
|
|
|
||||||
LL | fn change_object2(mut object: &Object) {
|
LL | fn change_object2(mut object: &Object) {
|
||||||
| ^^^^^^
|
| ^^^^^^
|
||||||
|
|
|
|
||||||
= note: consider using `_object` instead
|
= note: consider using `_object` instead
|
||||||
note: the lint level is defined here
|
note: the lint level is defined here
|
||||||
--> $DIR/mut-arg-of-borrowed-type-meant-to-be-arg-of-mut-borrow.rs:1:29
|
--> $DIR/mut-arg-of-borrowed-type-meant-to-be-arg-of-mut-borrow.rs:2:29
|
||||||
|
|
|
|
||||||
LL | #![deny(unused_assignments, unused_variables)]
|
LL | #![deny(unused_assignments, unused_variables)]
|
||||||
| ^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
error[E0597]: `object2` does not live long enough
|
error[E0597]: `object2` does not live long enough
|
||||||
--> $DIR/mut-arg-of-borrowed-type-meant-to-be-arg-of-mut-borrow.rs:11:14
|
--> $DIR/mut-arg-of-borrowed-type-meant-to-be-arg-of-mut-borrow.rs:13:14
|
||||||
|
|
|
|
||||||
LL | fn change_object2(mut object: &Object) {
|
LL | fn change_object2(mut object: &Object) {
|
||||||
| - let's call the lifetime of this reference `'1`
|
| - let's call the lifetime of this reference `'1`
|
||||||
|
LL |
|
||||||
LL | let object2 = Object;
|
LL | let object2 = Object;
|
||||||
| ------- binding `object2` declared here
|
| ------- binding `object2` declared here
|
||||||
LL | object = &object2;
|
LL | object = &object2;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue