]> git.lizzy.rs Git - rust.git/commitdiff
Point to let when modifying field of immutable variable
authorEsteban Küber <esteban@kuber.com.ar>
Sat, 11 Mar 2017 19:11:50 +0000 (11:11 -0800)
committerEsteban Küber <esteban@kuber.com.ar>
Sat, 11 Mar 2017 22:28:29 +0000 (14:28 -0800)
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
```

src/librustc/middle/mem_categorization.rs
src/librustc_borrowck/borrowck/mod.rs
src/test/ui/did_you_mean/issue-39544.stderr

index b0c85e2ef4cd48438df7796f250cc04dd45ad477..7db206296933bc755c64c0a17952156a35de2f91 100644 (file)
@@ -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, ..) |
index 47b614a81ae251e9009fbb0543832a0082d2e19f..04036d6c6b9e7aa2c8c6a3985e4c16fe40909505 100644 (file)
@@ -659,6 +659,7 @@ pub fn span_err_with_code<S: Into<MultiSpan>>(&self, s: S, msg: &str, code: &str
     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 @@ pub fn bckerr_to_diag(&self, err: &BckError<'tcx>) -> DiagnosticBuilder<'a> {
                                 }
                                 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 @@ pub fn bckerr_to_diag(&self, err: &BckError<'tcx>) -> DiagnosticBuilder<'a> {
         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
     }
 
index c0088f39ad3e17d842dd6c43a143beeb9c911d88..1cd322efab57d2c69299f62dc72af8d1c3c58c69 100644 (file)
@@ -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;
    |                  ^^^