about summary refs log tree commit diff
diff options
context:
space:
mode:
authorEsteban Küber <esteban@kuber.com.ar>2017-03-11 11:11:50 -0800
committerEsteban Küber <esteban@kuber.com.ar>2017-03-11 14:28:29 -0800
commit6ba494b68bede3bd8d1288f53137c8895260bec7 (patch)
tree728a1025b58b91fe6dbd443e1ef2abf655427ef9
parentf573db4f80c75f156df8a743f456bf087ec81dc2 (diff)
Point to let when modifying field of immutable variable
Point at the immutable local variable when trying to modify one of its
fields.

Given a file:

```rust
struct Foo {
    pub v: Vec<String>
}

fn main() {
    let f = Foo { v: Vec::new() };
    f.v.push("cat".to_string());
}
```

present the following output:

```
error: cannot borrow immutable field `f.v` as mutable
 --> file.rs:7:13
  |
6 |    let f = Foo { v: Vec::new() };
  |        - this should be `mut`
7 |    f.v.push("cat".to_string());
  |    ^^^

error: aborting due to previous error
```
-rw-r--r--src/librustc/middle/mem_categorization.rs15
-rw-r--r--src/librustc_borrowck/borrowck/mod.rs12
-rw-r--r--src/test/ui/did_you_mean/issue-39544.stderr2
3 files changed, 29 insertions, 0 deletions
diff --git a/src/librustc/middle/mem_categorization.rs b/src/librustc/middle/mem_categorization.rs
index b0c85e2ef4c..7db20629693 100644
--- a/src/librustc/middle/mem_categorization.rs
+++ b/src/librustc/middle/mem_categorization.rs
@@ -195,6 +195,21 @@ pub struct cmt_<'tcx> {
 pub type cmt<'tcx> = Rc<cmt_<'tcx>>;
 
 impl<'tcx> cmt_<'tcx> {
+    pub fn get_def(&self) -> Option<ast::NodeId> {
+        match self.cat {
+            Categorization::Deref(ref cmt, ..) |
+            Categorization::Interior(ref cmt, _) |
+            Categorization::Downcast(ref cmt, _) => {
+                if let Categorization::Local(nid) = cmt.cat {
+                    Some(nid)
+                } else {
+                    None
+                }
+            }
+            _ => None
+        }
+    }
+
     pub fn get_field(&self, name: ast::Name) -> Option<DefId> {
         match self.cat {
             Categorization::Deref(ref cmt, ..) |
diff --git a/src/librustc_borrowck/borrowck/mod.rs b/src/librustc_borrowck/borrowck/mod.rs
index 47b614a81ae..04036d6c6b9 100644
--- a/src/librustc_borrowck/borrowck/mod.rs
+++ b/src/librustc_borrowck/borrowck/mod.rs
@@ -659,6 +659,7 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> {
     pub fn bckerr_to_diag(&self, err: &BckError<'tcx>) -> DiagnosticBuilder<'a> {
         let span = err.span.clone();
         let mut immutable_field = None;
+        let mut local_def = None;
 
         let msg = &match err.code {
             err_mutbl => {
@@ -708,6 +709,14 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> {
                                 }
                                 None
                             });
+                        local_def = err.cmt.get_def()
+                            .and_then(|nid| {
+                                if !self.tcx.hir.is_argument(nid) {
+                                    Some(self.tcx.hir.span(nid))
+                                } else {
+                                    None
+                                }
+                            });
 
                         format!("cannot borrow {} as mutable", descr)
                     }
@@ -738,6 +747,9 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> {
         if let Some((span, msg)) = immutable_field {
             db.span_label(span, &msg);
         }
+        if let Some(span) = local_def {
+            db.span_label(span, &"this should be `mut`");
+        }
         db
     }
 
diff --git a/src/test/ui/did_you_mean/issue-39544.stderr b/src/test/ui/did_you_mean/issue-39544.stderr
index c0088f39ad3..1cd322efab5 100644
--- a/src/test/ui/did_you_mean/issue-39544.stderr
+++ b/src/test/ui/did_you_mean/issue-39544.stderr
@@ -1,6 +1,8 @@
 error: cannot borrow immutable field `z.x` as mutable
   --> $DIR/issue-39544.rs:21:18
    |
+20 |     let z = Z { x: X::Y };
+   |         - this should be `mut`
 21 |     let _ = &mut z.x;
    |                  ^^^