Skip to content

Commit

Permalink
More precisely point out what is immutable for E0596
Browse files Browse the repository at this point in the history
  • Loading branch information
chenyukang committed Oct 8, 2023
1 parent e9addfd commit fc0abde
Show file tree
Hide file tree
Showing 7 changed files with 133 additions and 9 deletions.
52 changes: 49 additions & 3 deletions compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -506,9 +506,8 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
self.expected_fn_found_fn_mut_call(&mut err, span, act);
}

PlaceRef { local: _, projection: [.., ProjectionElem::Deref] } => {
err.span_label(span, format!("cannot {act}"));

PlaceRef { local: _, projection: [proj_base @ .., ProjectionElem::Deref] } => {
let mut span = span;
match opt_source {
Some(BorrowedContentSource::OverloadedDeref(ty)) => {
err.help(format!(
Expand All @@ -523,8 +522,15 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
));
self.suggest_map_index_mut_alternatives(ty, &mut err, span);
}
Some(BorrowedContentSource::DerefSharedRef) => {
let place_ref =
PlaceRef { local: the_place_err.local, projection: proj_base };
let ty = place_ref.ty(self.body, self.infcx.tcx).ty;
self.suggest_detailed_hint_for_ref(ty, &mut err, &mut span);
}
_ => (),
}
err.span_label(span, format!("cannot {act}"));
}

_ => {
Expand All @@ -539,6 +545,46 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
}
}

fn suggest_detailed_hint_for_ref(&self, ty: Ty<'_>, err: &mut Diagnostic, span: &mut Span) {
struct ExprFinder {
span: Span,
hir_id: Option<hir::HirId>,
}

impl<'tcx> Visitor<'tcx> for ExprFinder {
fn visit_expr(&mut self, s: &'tcx hir::Expr<'tcx>) {
if s.span.contains(self.span) {
self.hir_id = Some(s.hir_id);
}
hir::intravisit::walk_expr(self, s);
}
}
let hir_map = self.infcx.tcx.hir();
let def_id = self.body.source.def_id();
let hir_id = if let Some(local_def_id) = def_id.as_local()
&& let Some(body_id) = hir_map.maybe_body_owned_by(local_def_id) {
let body = hir_map.body(body_id);
let mut v = ExprFinder {
span: *span,
hir_id: None,
};
v.visit_body(body);
v.hir_id
} else {
None
};
let expr = if let Some(hir_id) = hir_id {
hir_map.expect_expr(hir_id)
} else {
return;
};
if let hir::ExprKind::AddrOf(hir::BorrowKind::Ref, Mutability::Mut, ex) = expr.kind
&& !matches!(ex.kind, hir::ExprKind::Unary(hir::UnOp::Deref, _) | hir::ExprKind::Field(_, _) | hir::ExprKind::Lit(_)) {
*span = ex.span;
err.span_help(ex.span, format!("this expression is of type `{}`, which is an immutable reference", ty));
}
}

fn suggest_map_index_mut_alternatives(&self, ty: Ty<'tcx>, err: &mut Diagnostic, span: Span) {
let Some(adt) = ty.ty_adt_def() else { return };
let did = adt.did();
Expand Down
10 changes: 9 additions & 1 deletion tests/ui/borrowck/issue-111554.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,15 @@ error[E0596]: cannot borrow data in a `&` reference as mutable
--> $DIR/issue-111554.rs:10:16
|
LL | || bar(&mut self);
| ^^^^^^^^^ cannot borrow as mutable
| ^^^^^----
| |
| cannot borrow as mutable
|
help: this expression is of type `&Foo`, which is an immutable reference
--> $DIR/issue-111554.rs:10:21
|
LL | || bar(&mut self);
| ^^^^

error[E0596]: cannot borrow `self` as mutable, as it is not declared as mutable
--> $DIR/issue-111554.rs:21:16
Expand Down
22 changes: 22 additions & 0 deletions tests/ui/borrowck/issue_113842.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
mod some_library {
pub fn foo(_: &mut [i32]) {}
pub fn bar<'a>() -> &'a [i32] {
&[]
}
pub fn bar_mut<'a>() -> &'a mut [i32] {
&mut []
}
}

struct Foo {
pub x: i32,
}

fn foo() {
let foo = Foo { x: 0 };
let _y: &mut Foo = &mut &foo; //~ ERROR cannot borrow data in a `&` reference as mutable
}

fn main() {
some_library::foo(&mut some_library::bar()); //~ ERROR cannot borrow data in a `&` reference as mutable
}
31 changes: 31 additions & 0 deletions tests/ui/borrowck/issue_113842.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
error[E0596]: cannot borrow data in a `&` reference as mutable
--> $DIR/issue_113842.rs:17:24
|
LL | let _y: &mut Foo = &mut &foo;
| ^^^^^----
| |
| cannot borrow as mutable
|
help: this expression is of type `&Foo`, which is an immutable reference
--> $DIR/issue_113842.rs:17:29
|
LL | let _y: &mut Foo = &mut &foo;
| ^^^^

error[E0596]: cannot borrow data in a `&` reference as mutable
--> $DIR/issue_113842.rs:21:23
|
LL | some_library::foo(&mut some_library::bar());
| ^^^^^-------------------
| |
| cannot borrow as mutable
|
help: this expression is of type `&[i32]`, which is an immutable reference
--> $DIR/issue_113842.rs:21:28
|
LL | some_library::foo(&mut some_library::bar());
| ^^^^^^^^^^^^^^^^^^^

error: aborting due to 2 previous errors

For more information about this error, try `rustc --explain E0596`.
10 changes: 9 additions & 1 deletion tests/ui/let-else/let-else-binding-explicit-mut-borrow.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,15 @@ error[E0596]: cannot borrow data in a `&` reference as mutable
--> $DIR/let-else-binding-explicit-mut-borrow.rs:7:37
|
LL | let Some(n): &mut Option<i32> = &mut &Some(5i32) else {
| ^^^^^^^^^^^^^^^^ cannot borrow as mutable
| ^^^^^-----------
| |
| cannot borrow as mutable
|
help: this expression is of type `&Option<i32>`, which is an immutable reference
--> $DIR/let-else-binding-explicit-mut-borrow.rs:7:42
|
LL | let Some(n): &mut Option<i32> = &mut &Some(5i32) else {
| ^^^^^^^^^^^

error: aborting due to previous error

Expand Down
1 change: 1 addition & 0 deletions tests/ui/nll/issue-51191.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ impl Struct {
(&mut self).bar();
//~^ ERROR cannot borrow `self` as mutable, as it is not declared as mutable [E0596]
//~^^ ERROR cannot borrow data in a `&` reference as mutable [E0596]
//~^^^ HELP this expression is of type `&Struct`, which is an immutable reference
}

fn mtblref(&mut self) {
Expand Down
16 changes: 12 additions & 4 deletions tests/ui/nll/issue-51191.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -48,21 +48,29 @@ error[E0596]: cannot borrow data in a `&` reference as mutable
--> $DIR/issue-51191.rs:22:9
|
LL | (&mut self).bar();
| ^^^^^^^^^^^ cannot borrow as mutable
| ^^^^^^----^
| |
| cannot borrow as mutable
|
help: this expression is of type `&Struct`, which is an immutable reference
--> $DIR/issue-51191.rs:22:15
|
LL | (&mut self).bar();
| ^^^^

error[E0596]: cannot borrow `self` as mutable, as it is not declared as mutable
--> $DIR/issue-51191.rs:28:9
--> $DIR/issue-51191.rs:29:9
|
LL | (&mut self).bar();
| ^^^^^^^^^^^ cannot borrow as mutable
|
note: the binding is already a mutable borrow
--> $DIR/issue-51191.rs:27:16
--> $DIR/issue-51191.rs:28:16
|
LL | fn mtblref(&mut self) {
| ^^^^^^^^^
help: try removing `&mut` here
--> $DIR/issue-51191.rs:28:9
--> $DIR/issue-51191.rs:29:9
|
LL | (&mut self).bar();
| ^^^^^^^^^^^
Expand Down

0 comments on commit fc0abde

Please sign in to comment.