Skip to content

Suggest removing &mut when encountering mutability error #68723

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 16 additions & 6 deletions src/librustc_mir/borrow_check/diagnostics/mutability_errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -257,12 +257,22 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
assert_eq!(local_decl.mutability, Mutability::Not);

err.span_label(span, format!("cannot {ACT}", ACT = act));
err.span_suggestion(
local_decl.source_info.span,
"consider changing this to be mutable",
format!("mut {}", self.local_names[local].unwrap()),
Applicability::MachineApplicable,
);

if let ty::Ref(_, _, Mutability::Mut) = local_decl.ty.kind {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This condition seems insufficient. You'd need to check that the expected type requires &mut T and not &mut &mut T, otherwise it seems like it would trigger on this (which is a good test to add, to ensure that this behaves correctly):

struct S;

fn bar(x: &mut &mut S) {}

fn foo() {
    let x = &mut S;
    bar(&mut x);
}

...but this makes me wonder whether this is doable in borrowck if you don't know what type is expected (seems you only know that you want to take a mutable borrow and cannot due to lack of mut on the binding. On the other hand, if you do check it in typeck, then we need to check that:

struct S;

fn bar(x: &mut S) {}

fn foo() {
    let mut x = &mut S;
    bar(&mut x);
}

still compiles... which is probably not a good idea in typeck.

err.span_suggestion(
span,
"remove the unnecessary `&mut` here",
self.local_names[local].unwrap().to_string(),
Applicability::MaybeIncorrect,
);
} else {
err.span_suggestion(
local_decl.source_info.span,
"consider changing this to be mutable",
format!("mut {}", self.local_names[local].unwrap()),
Applicability::MachineApplicable,
);
}
}

// Also suggest adding mut for upvars
Expand Down
15 changes: 15 additions & 0 deletions src/test/ui/borrowck/issue-68697-remove-mut-ref.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
// Regression test for #68697: Suggest removing `&mut x`
// when `x: &mut T` and `&mut T` is expected type

struct A;

fn bar(x: &mut A) {}

fn foo(x: &mut A) {
bar(&mut x);
//~^ ERROR: cannot borrow `x` as mutable
//~| HELP: remove the unnecessary `&mut` here
//~| SUGGESTION: x
}

fn main() {}
12 changes: 12 additions & 0 deletions src/test/ui/borrowck/issue-68697-remove-mut-ref.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
error[E0596]: cannot borrow `x` as mutable, as it is not declared as mutable
--> $DIR/issue-68697-remove-mut-ref.rs:6:9
|
LL | bar(&mut x);
| ^^^^^^
| |
| cannot borrow as mutable
| help: remove the unnecessary `&mut` here: `x`

error: aborting due to previous error

For more information about this error, try `rustc --explain E0596`.