Skip to content
New issue

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

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

Already on GitHub? # to your account

Provide structured suggestion for binding needing type on E0594 #107646

Merged
merged 2 commits into from
Feb 5, 2023
Merged
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
63 changes: 57 additions & 6 deletions compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -606,12 +606,63 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
}
}
Some((false, err_label_span, message)) => {
err.span_label(
err_label_span,
&format!(
"consider changing this binding's type to be: `{message}`"
),
);
struct BindingFinder {
span: Span,
hir_id: Option<hir::HirId>,
}

impl<'tcx> Visitor<'tcx> for BindingFinder {
fn visit_stmt(&mut self, s: &'tcx hir::Stmt<'tcx>) {
if let hir::StmtKind::Local(local) = s.kind {
if local.pat.span == self.span {
self.hir_id = Some(local.hir_id);
}
}
hir::intravisit::walk_stmt(self, s);
}
}
let hir_map = self.infcx.tcx.hir();
let def_id = self.body.source.def_id();
let hir_id = hir_map.local_def_id_to_hir_id(def_id.expect_local());
let node = hir_map.find(hir_id);
let hir_id = if let Some(hir::Node::Item(item)) = node
&& let hir::ItemKind::Fn(.., body_id) = item.kind
{
let body = hir_map.body(body_id);
let mut v = BindingFinder {
span: err_label_span,
hir_id: None,
};
v.visit_body(body);
v.hir_id
} else {
None
};
if let Some(hir_id) = hir_id
&& let Some(hir::Node::Local(local)) = hir_map.find(hir_id)
{
let (changing, span, sugg) = match local.ty {
Some(ty) => ("changing", ty.span, message),
None => (
"specifying",
local.pat.span.shrink_to_hi(),
format!(": {message}"),
),
};
err.span_suggestion_verbose(
span,
&format!("consider {changing} this binding's type"),
sugg,
Applicability::HasPlaceholders,
);
} else {
err.span_label(
err_label_span,
&format!(
"consider changing this binding's type to be: `{message}`"
),
);
}
}
None => {}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
error[E0594]: cannot assign to `**t1`, which is behind a `&` reference
--> $DIR/borrowck-borrow-mut-base-ptr-in-aliasable-loc.rs:9:5
|
LL | let t1 = t0;
| -- consider changing this binding's type to be: `&mut &mut isize`
LL | let p: &isize = &**t0;
LL | **t1 = 22;
| ^^^^^^^^^ `t1` is a `&` reference, so the data it refers to cannot be written
|
help: consider specifying this binding's type
|
LL | let t1: &mut &mut isize = t0;
| +++++++++++++++++

error[E0502]: cannot borrow `**t0` as immutable because it is also borrowed as mutable
--> $DIR/borrowck-borrow-mut-base-ptr-in-aliasable-loc.rs:14:21
Expand Down
6 changes: 3 additions & 3 deletions tests/ui/borrowck/issue-85765.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
fn main() {
let mut test = Vec::new();
let rofl: &Vec<Vec<i32>> = &mut test;
//~^ NOTE consider changing this binding's type to be
//~^ HELP consider changing this binding's type
rofl.push(Vec::new());
//~^ ERROR cannot borrow `*rofl` as mutable, as it is behind a `&` reference
//~| NOTE `rofl` is a `&` reference, so the data it refers to cannot be borrowed as mutable
Expand All @@ -15,14 +15,14 @@ fn main() {

#[rustfmt::skip]
let x: &usize = &mut{0};
//~^ NOTE consider changing this binding's type to be
//~^ HELP consider changing this binding's type
*x = 1;
//~^ ERROR cannot assign to `*x`, which is behind a `&` reference
//~| NOTE `x` is a `&` reference, so the data it refers to cannot be written

#[rustfmt::skip]
let y: &usize = &mut(0);
//~^ NOTE consider changing this binding's type to be
//~^ HELP consider changing this binding's type
*y = 1;
//~^ ERROR cannot assign to `*y`, which is behind a `&` reference
//~| NOTE `y` is a `&` reference, so the data it refers to cannot be written
Expand Down
24 changes: 15 additions & 9 deletions tests/ui/borrowck/issue-85765.stderr
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
error[E0596]: cannot borrow `*rofl` as mutable, as it is behind a `&` reference
--> $DIR/issue-85765.rs:5:5
|
LL | let rofl: &Vec<Vec<i32>> = &mut test;
| ---- consider changing this binding's type to be: `&mut Vec<Vec<i32>>`
LL |
LL | rofl.push(Vec::new());
| ^^^^^^^^^^^^^^^^^^^^^ `rofl` is a `&` reference, so the data it refers to cannot be borrowed as mutable
|
help: consider changing this binding's type
|
LL | let rofl: &mut Vec<Vec<i32>> = &mut test;
| ~~~~~~~~~~~~~~~~~~

error[E0594]: cannot assign to `*r`, which is behind a `&` reference
--> $DIR/issue-85765.rs:12:5
Expand All @@ -21,20 +23,24 @@ LL | let r = &mut mutvar;
error[E0594]: cannot assign to `*x`, which is behind a `&` reference
--> $DIR/issue-85765.rs:19:5
|
LL | let x: &usize = &mut{0};
| - consider changing this binding's type to be: `&mut usize`
LL |
LL | *x = 1;
| ^^^^^^ `x` is a `&` reference, so the data it refers to cannot be written
|
help: consider changing this binding's type
|
LL | let x: &mut usize = &mut{0};
| ~~~~~~~~~~

error[E0594]: cannot assign to `*y`, which is behind a `&` reference
--> $DIR/issue-85765.rs:26:5
|
LL | let y: &usize = &mut(0);
| - consider changing this binding's type to be: `&mut usize`
LL |
LL | *y = 1;
| ^^^^^^ `y` is a `&` reference, so the data it refers to cannot be written
|
help: consider changing this binding's type
|
LL | let y: &mut usize = &mut(0);
| ~~~~~~~~~~

error: aborting due to 4 previous errors

Expand Down
2 changes: 1 addition & 1 deletion tests/ui/borrowck/issue-91206.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ impl TestClient {
fn main() {
let client = TestClient;
let inner = client.get_inner_ref();
//~^ NOTE consider changing this binding's type to be
//~^ HELP consider specifying this binding's type
inner.clear();
//~^ ERROR cannot borrow `*inner` as mutable, as it is behind a `&` reference [E0596]
//~| NOTE `inner` is a `&` reference, so the data it refers to cannot be borrowed as mutable
Expand Down
8 changes: 5 additions & 3 deletions tests/ui/borrowck/issue-91206.stderr
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
error[E0596]: cannot borrow `*inner` as mutable, as it is behind a `&` reference
--> $DIR/issue-91206.rs:13:5
|
LL | let inner = client.get_inner_ref();
| ----- consider changing this binding's type to be: `&mut Vec<usize>`
LL |
LL | inner.clear();
| ^^^^^^^^^^^^^ `inner` is a `&` reference, so the data it refers to cannot be borrowed as mutable
|
help: consider specifying this binding's type
|
LL | let inner: &mut Vec<usize> = client.get_inner_ref();
| +++++++++++++++++

error: aborting due to previous error

Expand Down
7 changes: 5 additions & 2 deletions tests/ui/borrowck/issue-92015.stderr
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
error[E0594]: cannot assign to `*foo`, which is behind a `&` reference
--> $DIR/issue-92015.rs:6:5
|
LL | let foo = Some(&0).unwrap();
| --- consider changing this binding's type to be: `&mut i32`
LL | *foo = 1;
| ^^^^^^^^ `foo` is a `&` reference, so the data it refers to cannot be written
|
help: consider specifying this binding's type
|
LL | let foo: &mut i32 = Some(&0).unwrap();
| ++++++++++

error: aborting due to previous error

Expand Down
1 change: 1 addition & 0 deletions tests/ui/issues/issue-51515.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ fn main() {
*foo = 32;
//~^ ERROR cannot assign to `*foo`, which is behind a `&` reference
let bar = foo;
//~^ HELP consider specifying this binding's type
*bar = 64;
//~^ ERROR cannot assign to `*bar`, which is behind a `&` reference
}
9 changes: 6 additions & 3 deletions tests/ui/issues/issue-51515.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,15 @@ LL | let foo = &mut 16;
| ~~~~~~~

error[E0594]: cannot assign to `*bar`, which is behind a `&` reference
--> $DIR/issue-51515.rs:8:5
--> $DIR/issue-51515.rs:9:5
|
LL | let bar = foo;
| --- consider changing this binding's type to be: `&mut i32`
LL | *bar = 64;
| ^^^^^^^^^ `bar` is a `&` reference, so the data it refers to cannot be written
|
help: consider specifying this binding's type
|
LL | let bar: &mut i32 = foo;
| ++++++++++

error: aborting due to 2 previous errors

Expand Down