add hint to fix error for immutable ref in arg
This commit is contained in:
parent
0b399e5e99
commit
67a24c2e18
15 changed files with 342 additions and 46 deletions
|
@ -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;
|
||||
|
@ -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(_) =>
|
||||
|
@ -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) {
|
||||
|
|
|
@ -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
src/test/ui/span/borrowck-borrow-overloaded-deref-mut.stderr
Normal file
34
src/test/ui/span/borrowck-borrow-overloaded-deref-mut.stderr
Normal file
|
@ -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
src/test/ui/span/borrowck-call-is-borrow-issue-12224.stderr
Normal file
43
src/test/ui/span/borrowck-call-is-borrow-issue-12224.stderr
Normal file
|
@ -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
|
||||
|
|
@ -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
|
||||
|
10
src/test/ui/span/borrowck-fn-in-const-b.stderr
Normal file
10
src/test/ui/span/borrowck-fn-in-const-b.stderr
Normal file
|
@ -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
src/test/ui/span/borrowck-object-mutability.stderr
Normal file
17
src/test/ui/span/borrowck-object-mutability.stderr
Normal file
|
@ -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
src/test/ui/span/mut-arg-hint.rs
Normal file
32
src/test/ui/span/mut-arg-hint.rs
Normal file
|
@ -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());
|
||||
}
|
26
src/test/ui/span/mut-arg-hint.stderr
Normal file
26
src/test/ui/span/mut-arg-hint.stderr
Normal file
|
@ -0,0 +1,26 @@
|
|||
error: cannot borrow immutable borrowed content `*a` as mutable
|
||||
--> $DIR/mut-arg-hint.rs:13:9
|
||||
|
|
||||
12 | fn foo(mut a: &String) {
|
||||
| ------- use `&mut String` here to make mutable
|
||||
13 | a.push_str("bar");
|
||||
| ^
|
||||
|
||||
error: cannot borrow immutable borrowed content `*a` as mutable
|
||||
--> $DIR/mut-arg-hint.rs:18:5
|
||||
|
|
||||
17 | pub fn foo<'a>(mut a: &'a String) {
|
||||
| ---------- use `&'a mut String` here to make mutable
|
||||
18 | a.push_str("foo");
|
||||
| ^
|
||||
|
||||
error: cannot borrow immutable borrowed content `*a` as mutable
|
||||
--> $DIR/mut-arg-hint.rs:25:9
|
||||
|
|
||||
24 | pub fn foo(mut a: &String) {
|
||||
| ------- use `&mut String` here to make mutable
|
||||
25 | a.push_str("foo");
|
||||
| ^
|
||||
|
||||
error: aborting due to 3 previous errors
|
||||
|
Loading…
Add table
Reference in a new issue