Skip to content

Commit 0f2033b

Browse files
committed
Fix incorrect mutable suggestion information for binding in ref pattern.
For ref pattern in func param, the mutability suggestion has to apply to the binding. For example: `fn foo(&x: &i32)` -> `fn foo(&(mut x): &i32)` fixes rust-lang#122415
1 parent 6f3eb1c commit 0f2033b

8 files changed

+74
-14
lines changed

compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs

Lines changed: 27 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -728,25 +728,40 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
728728
_ => local_decl.source_info.span,
729729
};
730730

731+
// With ref-binding patterns, the mutability suggestion has to apply to
732+
// the binding, not the reference (which would be a type error):
733+
//
734+
// `let &b = a;` -> `let &(mut b) = a;`
735+
// or
736+
// `fn foo(&x: &i32)` -> `fn foo(&(mut x): &i32)`
731737
let def_id = self.body.source.def_id();
732-
let hir_id = if let Some(local_def_id) = def_id.as_local()
738+
let is_ref_binding_patterns = if let Some(local_def_id) = def_id.as_local()
733739
&& let Some(body_id) = self.infcx.tcx.hir().maybe_body_owned_by(local_def_id)
734740
{
735741
let body = self.infcx.tcx.hir().body(body_id);
736-
BindingFinder { span: pat_span }.visit_body(body).break_value()
742+
743+
if let Some(hir_id) = (BindingFinder { span: pat_span }).visit_body(body).break_value()
744+
&& let hir::Node::Local(hir::Local {
745+
pat: hir::Pat { kind: hir::PatKind::Ref(_, _), .. },
746+
..
747+
}) = self.infcx.tcx.hir_node(hir_id)
748+
{
749+
true
750+
} else {
751+
body.params.iter().any(|param| {
752+
if let hir::Pat { kind: hir::PatKind::Ref(_, _), span, .. } = param.pat
753+
&& *span == pat_span
754+
{
755+
return true;
756+
}
757+
false
758+
})
759+
}
737760
} else {
738-
None
761+
false
739762
};
740763

741-
// With ref-binding patterns, the mutability suggestion has to apply to
742-
// the binding, not the reference (which would be a type error):
743-
//
744-
// `let &b = a;` -> `let &(mut b) = a;`
745-
if let Some(hir_id) = hir_id
746-
&& let hir::Node::Local(hir::Local {
747-
pat: hir::Pat { kind: hir::PatKind::Ref(_, _), .. },
748-
..
749-
}) = self.infcx.tcx.hir_node(hir_id)
764+
if is_ref_binding_patterns
750765
&& let Ok(name) =
751766
self.infcx.tcx.sess.source_map().span_to_snippet(local_decl.source_info.span)
752767
{

src/tools/tidy/src/issues.txt

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3466,7 +3466,6 @@
34663466
"ui/pattern/issue-106552.rs",
34673467
"ui/pattern/issue-106862.rs",
34683468
"ui/pattern/issue-110508.rs",
3469-
"ui/pattern/issue-114896.rs",
34703469
"ui/pattern/issue-115599.rs",
34713470
"ui/pattern/issue-11577.rs",
34723471
"ui/pattern/issue-117626.rs",
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
//@ run-rustfix
2+
#![allow(dead_code)]
3+
4+
fn main() {
5+
fn x(a: &char) {
6+
let &(mut b) = a;
7+
b.make_ascii_uppercase();
8+
//~^ cannot borrow `b` as mutable, as it is not declared as mutable
9+
}
10+
}

tests/ui/pattern/issue-114896.rs renamed to tests/ui/pattern/patkind-ref-binding-issue-114896.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
//@ run-rustfix
2+
#![allow(dead_code)]
3+
14
fn main() {
25
fn x(a: &char) {
36
let &b = a;

tests/ui/pattern/issue-114896.stderr renamed to tests/ui/pattern/patkind-ref-binding-issue-114896.stderr

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
error[E0596]: cannot borrow `b` as mutable, as it is not declared as mutable
2-
--> $DIR/issue-114896.rs:4:9
2+
--> $DIR/patkind-ref-binding-issue-114896.rs:7:9
33
|
44
LL | let &b = a;
55
| -- help: consider changing this to be mutable: `&(mut b)`
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
//@ run-rustfix
2+
#![allow(dead_code)]
3+
4+
fn mutate(_y: &mut i32) {}
5+
6+
fn foo(&(mut x): &i32) {
7+
mutate(&mut x);
8+
//~^ ERROR cannot borrow `x` as mutable
9+
}
10+
11+
fn main() {}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
//@ run-rustfix
2+
#![allow(dead_code)]
3+
4+
fn mutate(_y: &mut i32) {}
5+
6+
fn foo(&x: &i32) {
7+
mutate(&mut x);
8+
//~^ ERROR cannot borrow `x` as mutable
9+
}
10+
11+
fn main() {}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
error[E0596]: cannot borrow `x` as mutable, as it is not declared as mutable
2+
--> $DIR/patkind-ref-binding-issue-122415.rs:7:12
3+
|
4+
LL | fn foo(&x: &i32) {
5+
| -- help: consider changing this to be mutable: `&(mut x)`
6+
LL | mutate(&mut x);
7+
| ^^^^^^ cannot borrow as mutable
8+
9+
error: aborting due to 1 previous error
10+
11+
For more information about this error, try `rustc --explain E0596`.

0 commit comments

Comments
 (0)