Skip to content

Commit

Permalink
add hint to fix error for immutable ref in arg
Browse files Browse the repository at this point in the history
  • Loading branch information
mikhail-m1 committed Nov 28, 2016
1 parent 0b399e5 commit 67a24c2
Show file tree
Hide file tree
Showing 15 changed files with 342 additions and 46 deletions.
129 changes: 83 additions & 46 deletions src/librustc_borrowck/borrowck/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ use self::InteriorKind::*;

use rustc::dep_graph::DepNode;
use rustc::hir::map as hir_map;
use rustc::hir::map::blocks::FnParts;
use rustc::hir::map::blocks::{FnParts, FnLikeNode};
use rustc::cfg;
use rustc::middle::dataflow::DataFlowContext;
use rustc::middle::dataflow::BitwiseOperator;
Expand Down Expand Up @@ -970,51 +970,8 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> {

pub fn note_and_explain_bckerr(&self, db: &mut DiagnosticBuilder, err: BckError<'tcx>,
error_span: Span) {
let code = err.code;
match code {
err_mutbl => {
match err.cmt.note {
mc::NoteClosureEnv(upvar_id) | mc::NoteUpvarRef(upvar_id) => {
// If this is an `Fn` closure, it simply can't mutate upvars.
// If it's an `FnMut` closure, the original variable was declared immutable.
// We need to determine which is the case here.
let kind = match err.cmt.upvar().unwrap().cat {
Categorization::Upvar(mc::Upvar { kind, .. }) => kind,
_ => bug!()
};
if kind == ty::ClosureKind::Fn {
db.span_help(
self.tcx.map.span(upvar_id.closure_expr_id),
"consider changing this closure to take \
self by mutable reference");
}
}
_ => {
if let Categorization::Local(local_id) = err.cmt.cat {
let span = self.tcx.map.span(local_id);
if let Ok(snippet) = self.tcx.sess.codemap().span_to_snippet(span) {
if snippet.starts_with("ref mut ") || snippet.starts_with("&mut ") {
db.span_label(error_span, &format!("cannot reborrow mutably"));
db.span_label(error_span, &format!("try removing `&mut` here"));
} else {
if snippet.starts_with("ref ") {
db.span_label(span,
&format!("use `{}` here to make mutable",
snippet.replace("ref ", "ref mut ")));
} else if snippet != "self" {
db.span_label(span,
&format!("use `mut {}` here to make mutable", snippet));
}
db.span_label(error_span, &format!("cannot borrow mutably"));
}
} else {
db.span_label(error_span, &format!("cannot borrow mutably"));
}
}
}
}
}

match err.code {
err_mutbl => self.note_and_explain_mutbl_error(db, &err, &error_span),
err_out_of_scope(super_scope, sub_scope, cause) => {
let (value_kind, value_msg) = match err.cmt.cat {
mc::Categorization::Rvalue(_) =>
Expand Down Expand Up @@ -1135,6 +1092,86 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> {
}
}

fn note_and_explain_mutbl_error(&self, db: &mut DiagnosticBuilder, err: &BckError<'tcx>,
error_span: &Span) {
match err.cmt.note {
mc::NoteClosureEnv(upvar_id) | mc::NoteUpvarRef(upvar_id) => {
// If this is an `Fn` closure, it simply can't mutate upvars.
// If it's an `FnMut` closure, the original variable was declared immutable.
// We need to determine which is the case here.
let kind = match err.cmt.upvar().unwrap().cat {
Categorization::Upvar(mc::Upvar { kind, .. }) => kind,
_ => bug!()
};
if kind == ty::ClosureKind::Fn {
db.span_help(self.tcx.map.span(upvar_id.closure_expr_id),
"consider changing this closure to take \
self by mutable reference");
}
}
_ => {
if let Categorization::Deref(ref inner_cmt, ..) = err.cmt.cat {
if let Categorization::Local(local_id) = inner_cmt.cat {
let parent = self.tcx.map.get_parent_node(local_id);
let opt_fn_decl = FnLikeNode::from_node(self.tcx.map.get(parent))
.map(|fn_like| fn_like.decl());

if let Some(fn_decl) = opt_fn_decl {
if let Some(ref arg) = fn_decl.inputs.iter()
.find(|ref arg| arg.pat.id == local_id) {
if let hir::TyRptr(
opt_lifetime,
hir::MutTy{mutbl: hir::Mutability::MutImmutable, ref ty}) =
arg.ty.node {
if let Some(lifetime) = opt_lifetime {
if let Ok(snippet) = self.tcx.sess.codemap()
.span_to_snippet(ty.span) {
if let Ok(lifetime_snippet) = self.tcx.sess.codemap()
.span_to_snippet(lifetime.span) {
db.span_label(arg.ty.span,
&format!("use `&{} mut {}` \
here to make mutable",
lifetime_snippet,
snippet));
}
}
}
else if let Ok(snippet) = self.tcx.sess.codemap()
.span_to_snippet(arg.ty.span) {
if snippet.starts_with("&") {
db.span_label(arg.ty.span,
&format!("use `{}` here to make mutable",
snippet.replace("&", "&mut ")));
}
}
}
}
}
}
} else if let Categorization::Local(local_id) = err.cmt.cat {
let span = self.tcx.map.span(local_id);
if let Ok(snippet) = self.tcx.sess.codemap().span_to_snippet(span) {
if snippet.starts_with("ref mut ") || snippet.starts_with("&mut ") {
db.span_label(*error_span, &format!("cannot reborrow mutably"));
db.span_label(*error_span, &format!("try removing `&mut` here"));
} else {
if snippet.starts_with("ref ") {
db.span_label(span, &format!("use `{}` here to make mutable",
snippet.replace("ref ", "ref mut ")));
} else if snippet != "self" {
db.span_label(span,
&format!("use `mut {}` here to make mutable",
snippet));
}
db.span_label(*error_span, &format!("cannot borrow mutably"));
}
} else {
db.span_label(*error_span, &format!("cannot borrow mutably"));
}
}
}
}
}
pub fn append_loan_path_to_string(&self,
loan_path: &LoanPath<'tcx>,
out: &mut String) {
Expand Down
86 changes: 86 additions & 0 deletions src/test/ui/span/borrowck-borrow-overloaded-auto-deref-mut.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
error: cannot borrow immutable argument `x` as mutable
--> $DIR/borrowck-borrow-overloaded-auto-deref-mut.rs:63:24
|
62 | fn deref_mut_field1(x: Own<Point>) {
| - use `mut x` here to make mutable
63 | let __isize = &mut x.y; //~ ERROR cannot borrow
| ^ cannot borrow mutably

error: cannot borrow immutable borrowed content `*x` as mutable
--> $DIR/borrowck-borrow-overloaded-auto-deref-mut.rs:75:10
|
74 | fn deref_extend_mut_field1(x: &Own<Point>) -> &mut isize {
| ----------- use `&mut Own<Point>` here to make mutable
75 | &mut x.y //~ ERROR cannot borrow
| ^

error[E0499]: cannot borrow `*x` as mutable more than once at a time
--> $DIR/borrowck-borrow-overloaded-auto-deref-mut.rs:88:19
|
87 | let _x = &mut x.x;
| - first mutable borrow occurs here
88 | let _y = &mut x.y; //~ ERROR cannot borrow
| ^ second mutable borrow occurs here
89 | }
| - first borrow ends here

error: cannot borrow immutable argument `x` as mutable
--> $DIR/borrowck-borrow-overloaded-auto-deref-mut.rs:98:5
|
97 | fn assign_field1<'a>(x: Own<Point>) {
| - use `mut x` here to make mutable
98 | x.y = 3; //~ ERROR cannot borrow
| ^ cannot borrow mutably

error: cannot borrow immutable borrowed content `*x` as mutable
--> $DIR/borrowck-borrow-overloaded-auto-deref-mut.rs:102:5
|
101 | fn assign_field2<'a>(x: &'a Own<Point>) {
| -------------- use `&'a mut Own<Point>` here to make mutable
102 | x.y = 3; //~ ERROR cannot borrow
| ^

error[E0499]: cannot borrow `*x` as mutable more than once at a time
--> $DIR/borrowck-borrow-overloaded-auto-deref-mut.rs:111:5
|
110 | let _p: &mut Point = &mut **x;
| -- first mutable borrow occurs here
111 | x.y = 3; //~ ERROR cannot borrow
| ^ second mutable borrow occurs here
112 | }
| - first borrow ends here

error: cannot borrow immutable argument `x` as mutable
--> $DIR/borrowck-borrow-overloaded-auto-deref-mut.rs:119:5
|
118 | fn deref_mut_method1(x: Own<Point>) {
| - use `mut x` here to make mutable
119 | x.set(0, 0); //~ ERROR cannot borrow
| ^ cannot borrow mutably

error: cannot borrow immutable borrowed content `*x` as mutable
--> $DIR/borrowck-borrow-overloaded-auto-deref-mut.rs:131:5
|
130 | fn deref_extend_mut_method1(x: &Own<Point>) -> &mut isize {
| ----------- use `&mut Own<Point>` here to make mutable
131 | x.y_mut() //~ ERROR cannot borrow
| ^

error: cannot borrow immutable argument `x` as mutable
--> $DIR/borrowck-borrow-overloaded-auto-deref-mut.rs:139:6
|
138 | fn assign_method1<'a>(x: Own<Point>) {
| - use `mut x` here to make mutable
139 | *x.y_mut() = 3; //~ ERROR cannot borrow
| ^ cannot borrow mutably

error: cannot borrow immutable borrowed content `*x` as mutable
--> $DIR/borrowck-borrow-overloaded-auto-deref-mut.rs:143:6
|
142 | fn assign_method2<'a>(x: &'a Own<Point>) {
| -------------- use `&'a mut Own<Point>` here to make mutable
143 | *x.y_mut() = 3; //~ ERROR cannot borrow
| ^

error: aborting due to 10 previous errors

34 changes: 34 additions & 0 deletions src/test/ui/span/borrowck-borrow-overloaded-deref-mut.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
error: cannot borrow immutable argument `x` as mutable
--> $DIR/borrowck-borrow-overloaded-deref-mut.rs:39:25
|
38 | fn deref_mut1(x: Own<isize>) {
| - use `mut x` here to make mutable
39 | let __isize = &mut *x; //~ ERROR cannot borrow
| ^ cannot borrow mutably

error: cannot borrow immutable borrowed content `*x` as mutable
--> $DIR/borrowck-borrow-overloaded-deref-mut.rs:51:11
|
50 | fn deref_extend_mut1<'a>(x: &'a Own<isize>) -> &'a mut isize {
| -------------- use `&'a mut Own<isize>` here to make mutable
51 | &mut **x //~ ERROR cannot borrow
| ^^

error: cannot borrow immutable argument `x` as mutable
--> $DIR/borrowck-borrow-overloaded-deref-mut.rs:59:6
|
58 | fn assign1<'a>(x: Own<isize>) {
| - use `mut x` here to make mutable
59 | *x = 3; //~ ERROR cannot borrow
| ^ cannot borrow mutably

error: cannot borrow immutable borrowed content `*x` as mutable
--> $DIR/borrowck-borrow-overloaded-deref-mut.rs:63:6
|
62 | fn assign2<'a>(x: &'a Own<isize>) {
| -------------- use `&'a mut Own<isize>` here to make mutable
63 | **x = 3; //~ ERROR cannot borrow
| ^^

error: aborting due to 4 previous errors

43 changes: 43 additions & 0 deletions src/test/ui/span/borrowck-call-is-borrow-issue-12224.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
error[E0499]: cannot borrow `f` as mutable more than once at a time
--> $DIR/borrowck-call-is-borrow-issue-12224.rs:23:16
|
23 | f(Box::new(|| {
| - ^^ second mutable borrow occurs here
| |
| first mutable borrow occurs here
24 | //~^ ERROR: cannot borrow `f` as mutable more than once
25 | f((Box::new(|| {})))
| - borrow occurs due to use of `f` in closure
26 | }));
| - first borrow ends here

error: cannot borrow immutable borrowed content `*f` as mutable
--> $DIR/borrowck-call-is-borrow-issue-12224.rs:36:5
|
35 | fn test2<F>(f: &F) where F: FnMut() {
| -- use `&mut F` here to make mutable
36 | (*f)(); //~ ERROR: cannot borrow immutable borrowed content `*f` as mutable
| ^^^^

error: cannot borrow immutable `Box` content `*f.f` as mutable
--> $DIR/borrowck-call-is-borrow-issue-12224.rs:44:5
|
44 | f.f.call_mut(()) //~ ERROR: cannot borrow immutable `Box` content `*f.f` as mutable
| ^^^

error[E0504]: cannot move `f` into closure because it is borrowed
--> $DIR/borrowck-call-is-borrow-issue-12224.rs:63:13
|
62 | f(Box::new(|a| {
| - borrow of `f` occurs here
63 | foo(f);
| ^ move into closure occurs here

error[E0507]: cannot move out of captured outer variable in an `FnMut` closure
--> $DIR/borrowck-call-is-borrow-issue-12224.rs:63:13
|
63 | foo(f);
| ^ cannot move out of captured outer variable in an `FnMut` closure

error: aborting due to 5 previous errors

11 changes: 11 additions & 0 deletions src/test/ui/span/borrowck-call-method-from-mut-aliasable.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
error: cannot borrow immutable borrowed content `*x` as mutable
--> $DIR/borrowck-call-method-from-mut-aliasable.rs:27:5
|
25 | fn b(x: &Foo) {
| ---- use `&mut Foo` here to make mutable
26 | x.f();
27 | x.h(); //~ ERROR cannot borrow
| ^

error: aborting due to previous error

File renamed without changes.
10 changes: 10 additions & 0 deletions src/test/ui/span/borrowck-fn-in-const-b.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
error: cannot borrow immutable borrowed content `*x` as mutable
--> $DIR/borrowck-fn-in-const-b.rs:17:9
|
16 | fn broken(x: &Vec<String>) {
| ------------ use `&mut Vec<String>` here to make mutable
17 | x.push(format!("this is broken"));
| ^

error: aborting due to previous error

17 changes: 17 additions & 0 deletions src/test/ui/span/borrowck-object-mutability.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
error: cannot borrow immutable borrowed content `*x` as mutable
--> $DIR/borrowck-object-mutability.rs:19:5
|
17 | fn borrowed_receiver(x: &Foo) {
| ---- use `&mut Foo` here to make mutable
18 | x.borrowed();
19 | x.borrowed_mut(); //~ ERROR cannot borrow
| ^

error: cannot borrow immutable `Box` content `*x` as mutable
--> $DIR/borrowck-object-mutability.rs:29:5
|
29 | x.borrowed_mut(); //~ ERROR cannot borrow
| ^

error: aborting due to 2 previous errors

32 changes: 32 additions & 0 deletions src/test/ui/span/mut-arg-hint.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

trait B {
fn foo(mut a: &String) {
a.push_str("bar");
}
}

pub fn foo<'a>(mut a: &'a String) {
a.push_str("foo");
}

struct A {}

impl A {
pub fn foo(mut a: &String) {
a.push_str("foo");
}
}

fn main() {
foo(&"a".to_string());
A::foo(&"a".to_string());
}
Loading

0 comments on commit 67a24c2

Please sign in to comment.