]> git.lizzy.rs Git - rust.git/commitdiff
Point to immutable arg/fields when trying to use as &mut
authorEsteban Küber <esteban@kuber.com.ar>
Tue, 17 Jan 2017 07:42:11 +0000 (23:42 -0800)
committerEsteban Küber <esteban@kuber.com.ar>
Thu, 26 Jan 2017 18:57:23 +0000 (10:57 -0800)
Point to immutable borrow arguments and fields when trying to use them as
mutable borrows. Add label to primary span on "cannot borrow as mutable"
errors.

Present the following output when trying to access an immutable borrow's
field as mutable:

```
error[E0389]: cannot borrow data mutably in a `&` reference
  --> $DIR/issue-38147-1.rs:27:9
   |
26 | fn f(&self) {
   |      -----  use `&mut self` here to make mutable
27 |     f.s.push('x');
   |     ^^^ assignment into an immutable reference
```

And the following when trying to access an immutable struct field as mutable:

```
error: cannot borrow immutable borrowed content `*self.s` as mutable
  --> $DIR/issue-38147-3.rs:17:9
   |
12 |     s: &'a String
   |     ------------- use `&'a mut String` here to make mutable
...|
16 |     fn f(&self) {
   |          -----  use `&mut self` here to make mutable
17 |         self.s.push('x');
   |         ^^^^^^ cannot borrow as mutable
```

21 files changed:
src/librustc/hir/map/blocks.rs
src/librustc/middle/mem_categorization.rs
src/librustc/ty/mod.rs
src/librustc/ty/sty.rs
src/librustc_borrowck/borrowck/gather_loans/mod.rs
src/librustc_borrowck/borrowck/mod.rs
src/test/ui/did_you_mean/issue-38147-1.rs [new file with mode: 0644]
src/test/ui/did_you_mean/issue-38147-1.stderr [new file with mode: 0644]
src/test/ui/did_you_mean/issue-38147-2.rs [new file with mode: 0644]
src/test/ui/did_you_mean/issue-38147-2.stderr [new file with mode: 0644]
src/test/ui/did_you_mean/issue-38147-3.rs [new file with mode: 0644]
src/test/ui/did_you_mean/issue-38147-3.stderr [new file with mode: 0644]
src/test/ui/did_you_mean/issue-38147-4.rs [new file with mode: 0644]
src/test/ui/did_you_mean/issue-38147-4.stderr [new file with mode: 0644]
src/test/ui/span/borrowck-borrow-overloaded-auto-deref-mut.stderr
src/test/ui/span/borrowck-borrow-overloaded-deref-mut.stderr
src/test/ui/span/borrowck-call-is-borrow-issue-12224.stderr
src/test/ui/span/borrowck-call-method-from-mut-aliasable.stderr
src/test/ui/span/borrowck-fn-in-const-b.stderr
src/test/ui/span/borrowck-object-mutability.stderr
src/test/ui/span/mut-arg-hint.stderr

index 91e88e2c73ff892947f387eff7f606cbbfc1a94f..ff2f1dc1ba28a85f83f67d795c56ed2f50cfeaa5 100644 (file)
@@ -38,7 +38,7 @@
 ///   - The default implementation for a trait method.
 ///
 /// To construct one, use the `Code::from_node` function.
-#[derive(Copy, Clone)]
+#[derive(Copy, Clone, Debug)]
 pub struct FnLikeNode<'a> { node: map::Node<'a> }
 
 /// MaybeFnLike wraps a method that indicates if an object
index 126d43aa6900e79b87eb24c6e15420b88121819f..85902af68538f66f0e18780a03e7e43d2eb29ed2 100644 (file)
@@ -193,6 +193,63 @@ pub struct cmt_<'tcx> {
 
 pub type cmt<'tcx> = Rc<cmt_<'tcx>>;
 
+impl<'tcx> cmt_<'tcx> {
+    pub fn get_field(&self, name: ast::Name) -> Option<DefId> {
+        match self.cat {
+            Categorization::Deref(ref cmt, ..) |
+            Categorization::Interior(ref cmt, _) |
+            Categorization::Downcast(ref cmt, _) => {
+                if let Categorization::Local(_) = cmt.cat {
+                    if let ty::TyAdt(def, _) = self.ty.sty {
+                        return def.struct_variant().find_field_named(name).map(|x| x.did);
+                    }
+                    None
+                } else {
+                    cmt.get_field(name)
+                }
+            }
+            _ => None
+        }
+    }
+
+    pub fn get_field_name(&self) -> Option<ast::Name> {
+        match self.cat {
+            Categorization::Interior(_, ref ik) => {
+                if let InteriorKind::InteriorField(FieldName::NamedField(name)) = *ik {
+                    Some(name)
+                } else {
+                    None
+                }
+            }
+            Categorization::Deref(ref cmt, ..) |
+            Categorization::Downcast(ref cmt, _) => {
+                cmt.get_field_name()
+            }
+            _ => None,
+        }
+    }
+
+    pub fn get_arg_if_immutable(&self, map: &hir_map::Map) -> 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 {
+                    if let ty::TyAdt(_, _) = self.ty.sty {
+                        if let ty::TyRef(_, ty::TypeAndMut{mutbl: MutImmutable, ..}) = cmt.ty.sty {
+                            return Some(nid);
+                        }
+                    }
+                    None
+                } else {
+                    cmt.get_arg_if_immutable(map)
+                }
+            }
+            _ => None
+        }
+    }
+}
+
 pub trait ast_node {
     fn id(&self) -> ast::NodeId;
     fn span(&self) -> Span;
index 5681e8c7766231c2201c591a13cc694fb73aba38..36fc5149b40d8de66d41539e33013093c21eb45d 100644 (file)
@@ -1325,6 +1325,7 @@ pub fn for_item(tcx: TyCtxt<'a, 'tcx, 'tcx>, id: NodeId)
     }
 }
 
+#[derive(Debug)]
 pub struct VariantDef {
     /// The variant's DefId. If this is a tuple-like struct,
     /// this is the DefId of the struct's ctor.
@@ -1335,6 +1336,7 @@ pub struct VariantDef {
     pub ctor_kind: CtorKind,
 }
 
+#[derive(Debug)]
 pub struct FieldDef {
     pub did: DefId,
     pub name: Name,
index b02bb7c6e4dd803f17d796604d63d3193d9a5105..d6164e69ffd3a9656fea55571ac0e4209f011d12 100644 (file)
@@ -134,7 +134,7 @@ pub enum TypeVariants<'tcx> {
     TyRawPtr(TypeAndMut<'tcx>),
 
     /// A reference; a pointer with an associated lifetime. Written as
-    /// `&a mut T` or `&'a T`.
+    /// `&'a mut T` or `&'a T`.
     TyRef(&'tcx Region, TypeAndMut<'tcx>),
 
     /// The anonymous type of a function declaration/definition. Each
index 7f7f73d9a9678e45ab6e39c44087428b5836c78c..1783ca74a25923fdf4fcad56f6b5a29c75e93788 100644 (file)
@@ -195,7 +195,8 @@ fn check_aliasability<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>,
             bccx.report_aliasability_violation(
                         borrow_span,
                         loan_cause,
-                        mc::AliasableReason::UnaliasableImmutable);
+                        mc::AliasableReason::UnaliasableImmutable,
+                        cmt);
             Err(())
         }
         (mc::Aliasability::FreelyAliasable(alias_cause), ty::UniqueImmBorrow) |
@@ -203,7 +204,8 @@ fn check_aliasability<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>,
             bccx.report_aliasability_violation(
                         borrow_span,
                         loan_cause,
-                        alias_cause);
+                        alias_cause,
+                        cmt);
             Err(())
         }
         (..) => {
index 3464f1fa89a27c0e121459aee810c38fa273722b..4386a5bd1591d6a8fd37be17c9526bb0d6858fc2 100644 (file)
@@ -540,7 +540,7 @@ pub fn opt_loan_path<'tcx>(cmt: &mc::cmt<'tcx>) -> Option<Rc<LoanPath<'tcx>>> {
 // Errors
 
 // Errors that can occur
-#[derive(PartialEq)]
+#[derive(Debug, PartialEq)]
 pub enum bckerr_code<'tcx> {
     err_mutbl,
     /// superscope, subscope, loan cause
@@ -550,7 +550,7 @@ pub enum bckerr_code<'tcx> {
 
 // Combination of an error code and the categorization of the expression
 // that caused it
-#[derive(PartialEq)]
+#[derive(Debug, PartialEq)]
 pub struct BckError<'tcx> {
     span: Span,
     cause: AliasableViolationKind,
@@ -601,12 +601,8 @@ pub fn report(&self, err: BckError<'tcx>) {
             _ => { }
         }
 
-        // General fallback.
-        let span = err.span.clone();
-        let mut db = self.struct_span_err(
-            err.span,
-            &self.bckerr_to_string(&err));
-        self.note_and_explain_bckerr(&mut db, err, span);
+        let mut db = self.bckerr_to_diag(&err);
+        self.note_and_explain_bckerr(&mut db, err);
         db.emit();
     }
 
@@ -771,8 +767,11 @@ pub fn span_err_with_code<S: Into<MultiSpan>>(&self, s: S, msg: &str, code: &str
         self.tcx.sess.span_err_with_code(s, msg, code);
     }
 
-    pub fn bckerr_to_string(&self, err: &BckError<'tcx>) -> String {
-        match err.code {
+    pub fn bckerr_to_diag(&self, err: &BckError<'tcx>) -> DiagnosticBuilder<'a> {
+        let span = err.span.clone();
+        let mut immutable_field = None;
+
+        let msg = &match err.code {
             err_mutbl => {
                 let descr = match err.cmt.note {
                     mc::NoteClosureEnv(_) | mc::NoteUpvarRef(_) => {
@@ -783,6 +782,7 @@ pub fn bckerr_to_string(&self, err: &BckError<'tcx>) -> String {
                             format!("{} {}",
                                     err.cmt.mutbl.to_user_str(),
                                     self.cmt_to_string(&err.cmt))
+
                         }
                         Some(lp) => {
                             format!("{} {} `{}`",
@@ -807,6 +807,19 @@ pub fn bckerr_to_string(&self, err: &BckError<'tcx>) -> String {
                     BorrowViolation(euv::AutoUnsafe) |
                     BorrowViolation(euv::ForLoop) |
                     BorrowViolation(euv::MatchDiscriminant) => {
+                        // Check for this field's definition to see if it is an immutable reference
+                        // and suggest making it mutable if that is the case.
+                        immutable_field = err.cmt.get_field_name()
+                            .and_then(|name| err.cmt.get_field(name))
+                            .and_then(|did| self.tcx.hir.as_local_node_id(did))
+                            .and_then(|nid| {
+                                if let hir_map::Node::NodeField(ref field) = self.tcx.hir.get(nid) {
+                                    return self.suggest_mut_for_immutable(&field.ty)
+                                        .map(|msg| (self.tcx.hir.span(nid), msg));
+                                }
+                                None
+                            });
+
                         format!("cannot borrow {} as mutable", descr)
                     }
                     BorrowViolation(euv::ClosureInvocation) => {
@@ -830,13 +843,20 @@ pub fn bckerr_to_string(&self, err: &BckError<'tcx>) -> String {
                          its contents can be safely reborrowed",
                         descr)
             }
+        };
+
+        let mut db = self.struct_span_err(span, msg);
+        if let Some((span, msg)) = immutable_field {
+            db.span_label(span, &msg);
         }
+        db
     }
 
     pub fn report_aliasability_violation(&self,
                                          span: Span,
                                          kind: AliasableViolationKind,
-                                         cause: mc::AliasableReason) {
+                                         cause: mc::AliasableReason,
+                                         cmt: mc::cmt<'tcx>) {
         let mut is_closure = false;
         let prefix = match kind {
             MutabilityViolation => {
@@ -903,6 +923,9 @@ pub fn report_aliasability_violation(&self,
                     self.tcx.sess, span, E0389,
                     "{} in a `&` reference", prefix);
                 e.span_label(span, &"assignment into an immutable reference");
+                if let Some(nid) = cmt.get_arg_if_immutable(&self.tcx.hir) {
+                    self.immutable_argument_should_be_mut(nid, &mut e);
+                }
                 e
             }
         };
@@ -913,6 +936,55 @@ pub fn report_aliasability_violation(&self,
         err.emit();
     }
 
+    /// Given a type, if it is an immutable reference, return a suggestion to make it mutable
+    fn suggest_mut_for_immutable(&self, pty: &hir::Ty) -> Option<String> {
+        // Check wether the argument is an immutable reference
+        if let hir::TyRptr(opt_lifetime, hir::MutTy {
+            mutbl: hir::Mutability::MutImmutable,
+            ref ty
+        }) = pty.node {
+            // Account for existing lifetimes when generating the message
+            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) {
+                            return Some(format!("use `&{} mut {}` here to make mutable",
+                                                lifetime_snippet,
+                                                snippet));
+                    }
+                }
+            } else if let Ok(snippet) = self.tcx.sess.codemap().span_to_snippet(pty.span) {
+                if snippet.starts_with("&") {
+                    return Some(format!("use `{}` here to make mutable",
+                                        snippet.replace("&", "&mut ")));
+                }
+            } else {
+                bug!("couldn't find a snippet for span: {:?}", pty.span);
+            }
+        }
+        None
+    }
+
+    fn immutable_argument_should_be_mut(&self, nid: ast::NodeId, db: &mut DiagnosticBuilder) {
+        let parent = self.tcx.hir.get_parent_node(nid);
+        let parent_node = self.tcx.hir.get(parent);
+
+        // The parent node is like a fn
+        if let Some(fn_like) = FnLikeNode::from_node(parent_node) {
+            // `nid`'s parent's `Body`
+            let fn_body = self.tcx.hir.body(fn_like.body());
+            // Get the position of `nid` in the arguments list
+            let arg_pos = fn_body.arguments.iter().position(|arg| arg.pat.id == nid);
+            if let Some(i) = arg_pos {
+                // The argument's `Ty`
+                let arg_ty = &fn_like.decl().inputs[i];
+                if let Some(msg) = self.suggest_mut_for_immutable(&arg_ty) {
+                    db.span_label(arg_ty.span, &msg);
+                }
+            }
+        }
+    }
+
     fn report_out_of_scope_escaping_closure_capture(&self,
                                                     err: &BckError<'tcx>,
                                                     capture_span: Span)
@@ -961,8 +1033,8 @@ fn region_end_span(&self, region: &'tcx ty::Region) -> Option<Span> {
         }
     }
 
-    pub fn note_and_explain_bckerr(&self, db: &mut DiagnosticBuilder, err: BckError<'tcx>,
-        error_span: Span) {
+    pub fn note_and_explain_bckerr(&self, db: &mut DiagnosticBuilder, err: BckError<'tcx>) {
+        let error_span = err.span.clone();
         match err.code {
             err_mutbl => self.note_and_explain_mutbl_error(db, &err, &error_span),
             err_out_of_scope(super_scope, sub_scope, cause) => {
@@ -1103,41 +1175,13 @@ fn note_and_explain_mutbl_error(&self, db: &mut DiagnosticBuilder, err: &BckErro
                 }
             }
             _ => {
-                if let Categorization::Deref(ref inner_cmt, ..) = err.cmt.cat {
-                    if let Categorization::Local(local_id) = inner_cmt.cat {
-                        let parent = self.tcx.hir.get_parent_node(local_id);
-
-                        if let Some(fn_like) = FnLikeNode::from_node(self.tcx.hir.get(parent)) {
-                            if let Some(i) = self.tcx.hir.body(fn_like.body()).arguments.iter()
-                                                     .position(|arg| arg.pat.id == local_id) {
-                                let arg_ty = &fn_like.decl().inputs[i];
-                                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 ")));
-                                        }
-                                    }
-                                }
-                            }
+                if let Categorization::Deref(..) = err.cmt.cat {
+                    db.span_label(*error_span, &"cannot borrow as mutable");
+                    if let Some(local_id) = err.cmt.get_arg_if_immutable(&self.tcx.hir) {
+                        self.immutable_argument_should_be_mut(local_id, db);
+                    } else if let Categorization::Deref(ref inner_cmt, ..) = err.cmt.cat {
+                        if let Categorization::Local(local_id) = inner_cmt.cat {
+                            self.immutable_argument_should_be_mut(local_id, db);
                         }
                     }
                 } else if let Categorization::Local(local_id) = err.cmt.cat {
diff --git a/src/test/ui/did_you_mean/issue-38147-1.rs b/src/test/ui/did_you_mean/issue-38147-1.rs
new file mode 100644 (file)
index 0000000..136921d
--- /dev/null
@@ -0,0 +1,31 @@
+// Copyright 2017 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.
+
+struct Pass<'a> {
+    s: &'a mut String
+}
+
+impl<'a> Pass<'a> {
+    fn f(&mut self) {
+        self.s.push('x');
+    }
+}
+
+struct Foo<'a> {
+    s: &'a mut String
+}
+
+impl<'a> Foo<'a> {
+    fn f(&self) {
+        self.s.push('x');
+    }
+}
+
+fn main() {}
diff --git a/src/test/ui/did_you_mean/issue-38147-1.stderr b/src/test/ui/did_you_mean/issue-38147-1.stderr
new file mode 100644 (file)
index 0000000..e9f2b1d
--- /dev/null
@@ -0,0 +1,10 @@
+error[E0389]: cannot borrow data mutably in a `&` reference
+  --> $DIR/issue-38147-1.rs:27:9
+   |
+26 |     fn f(&self) {
+   |          ----- use `&mut self` here to make mutable
+27 |         self.s.push('x');
+   |         ^^^^^^ assignment into an immutable reference
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/did_you_mean/issue-38147-2.rs b/src/test/ui/did_you_mean/issue-38147-2.rs
new file mode 100644 (file)
index 0000000..a5d533e
--- /dev/null
@@ -0,0 +1,21 @@
+// Copyright 2017 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.
+
+struct Bar<'a> {
+    s: &'a String
+}
+
+impl<'a> Bar<'a> {
+    fn f(&mut self) {
+        self.s.push('x');
+    }
+}
+
+fn main() {}
diff --git a/src/test/ui/did_you_mean/issue-38147-2.stderr b/src/test/ui/did_you_mean/issue-38147-2.stderr
new file mode 100644 (file)
index 0000000..fdaf0cd
--- /dev/null
@@ -0,0 +1,11 @@
+error: cannot borrow immutable borrowed content `*self.s` as mutable
+  --> $DIR/issue-38147-2.rs:17:9
+   |
+12 |     s: &'a String
+   |     ------------- use `&'a mut String` here to make mutable
+...
+17 |         self.s.push('x');
+   |         ^^^^^^ cannot borrow as mutable
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/did_you_mean/issue-38147-3.rs b/src/test/ui/did_you_mean/issue-38147-3.rs
new file mode 100644 (file)
index 0000000..5e8f2d3
--- /dev/null
@@ -0,0 +1,21 @@
+// Copyright 2017 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.
+
+struct Qux<'a> {
+    s: &'a String
+}
+
+impl<'a> Qux<'a> {
+    fn f(&self) {
+        self.s.push('x');
+    }
+}
+
+fn main() {}
diff --git a/src/test/ui/did_you_mean/issue-38147-3.stderr b/src/test/ui/did_you_mean/issue-38147-3.stderr
new file mode 100644 (file)
index 0000000..d2280fa
--- /dev/null
@@ -0,0 +1,13 @@
+error: cannot borrow immutable borrowed content `*self.s` as mutable
+  --> $DIR/issue-38147-3.rs:17:9
+   |
+12 |     s: &'a String
+   |     ------------- use `&'a mut String` here to make mutable
+...
+16 |     fn f(&self) {
+   |          ----- use `&mut self` here to make mutable
+17 |         self.s.push('x');
+   |         ^^^^^^ cannot borrow as mutable
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/did_you_mean/issue-38147-4.rs b/src/test/ui/did_you_mean/issue-38147-4.rs
new file mode 100644 (file)
index 0000000..4eb20ce
--- /dev/null
@@ -0,0 +1,19 @@
+// Copyright 2017 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.
+
+struct Foo<'a> {
+    s: &'a mut String
+}
+
+fn f(x: usize, f: &Foo) {
+    f.s.push('x');
+}
+
+fn main() {}
diff --git a/src/test/ui/did_you_mean/issue-38147-4.stderr b/src/test/ui/did_you_mean/issue-38147-4.stderr
new file mode 100644 (file)
index 0000000..9a8853f
--- /dev/null
@@ -0,0 +1,10 @@
+error[E0389]: cannot borrow data mutably in a `&` reference
+  --> $DIR/issue-38147-4.rs:16:5
+   |
+15 | fn f(x: usize, f: &Foo) {
+   |                   ---- use `&mut Foo` here to make mutable
+16 |     f.s.push('x');
+   |     ^^^ assignment into an immutable reference
+
+error: aborting due to previous error
+
index 1109351bff8394e2393388777f27304478173e67..b83a6aaebf3232026db99be66a7af5d9ebccf1e6 100644 (file)
@@ -12,7 +12,7 @@ error: cannot borrow immutable borrowed content `*x` as mutable
 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
-   |          ^
+   |          ^ cannot borrow as mutable
 
 error[E0499]: cannot borrow `*x` as mutable more than once at a time
   --> $DIR/borrowck-borrow-overloaded-auto-deref-mut.rs:88:19
@@ -38,7 +38,7 @@ error: cannot borrow immutable borrowed content `*x` as mutable
 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
-    |     ^
+    |     ^ cannot borrow as mutable
 
 error[E0499]: cannot borrow `*x` as mutable more than once at a time
    --> $DIR/borrowck-borrow-overloaded-auto-deref-mut.rs:111:5
@@ -64,7 +64,7 @@ error: cannot borrow immutable borrowed content `*x` as mutable
 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
-    |     ^
+    |     ^ cannot borrow as mutable
 
 error: cannot borrow immutable argument `x` as mutable
    --> $DIR/borrowck-borrow-overloaded-auto-deref-mut.rs:139:6
@@ -80,7 +80,7 @@ error: cannot borrow immutable borrowed content `*x` as mutable
 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
-    |      ^
+    |      ^ cannot borrow as mutable
 
 error: aborting due to 10 previous errors
 
index a5b70459161415f7d5b01061e6a8fb99f0e3a947..af954a4d7924f1bada77d8e0be10738ad34af0dc 100644 (file)
@@ -12,7 +12,7 @@ error: cannot borrow immutable borrowed content `*x` as mutable
 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
-   |           ^^
+   |           ^^ cannot borrow as mutable
 
 error: cannot borrow immutable argument `x` as mutable
   --> $DIR/borrowck-borrow-overloaded-deref-mut.rs:59:6
@@ -28,7 +28,7 @@ error: cannot borrow immutable borrowed content `*x` as mutable
 62 | fn assign2<'a>(x: &'a Own<isize>) {
    |                   -------------- use `&'a mut Own<isize>` here to make mutable
 63 |     **x = 3; //~ ERROR cannot borrow
-   |      ^^
+   |      ^^ cannot borrow as mutable
 
 error: aborting due to 4 previous errors
 
index 16bb60013674fded9dff9fa8c615eeaec9f2b1e7..f2f0e027f0161927da53cdb4f77f8dfe8e445a53 100644 (file)
@@ -17,13 +17,15 @@ error: cannot borrow immutable borrowed content `*f` as mutable
 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
-   |     ^^^^
+   |     ^^^^ cannot borrow as mutable
 
 error: cannot borrow immutable `Box` content `*f.f` as mutable
   --> $DIR/borrowck-call-is-borrow-issue-12224.rs:44:5
    |
+43 | fn test4(f: &Test) {
+   |             ----- use `&mut Test` here to make mutable
 44 |     f.f.call_mut(()) //~ ERROR: cannot borrow immutable `Box` content `*f.f` as mutable
-   |     ^^^
+   |     ^^^ cannot borrow as mutable
 
 error[E0504]: cannot move `f` into closure because it is borrowed
   --> $DIR/borrowck-call-is-borrow-issue-12224.rs:63:13
index a1af1ca7408a280a8545fabc3a931e366f44ae81..2349bfaf75e6f4fe37c3fde7703a554142b6ad4a 100644 (file)
@@ -5,7 +5,7 @@ error: cannot borrow immutable borrowed content `*x` as mutable
    |         ---- use `&mut Foo` here to make mutable
 26 |     x.f();
 27 |     x.h(); //~ ERROR cannot borrow
-   |     ^
+   |     ^ cannot borrow as mutable
 
 error: aborting due to previous error
 
index 41f549c708a29577fb5f6455adff14ebad554d49..251a9e4aa57555730d0a988b08fd59cf839cd035 100644 (file)
@@ -4,7 +4,7 @@ error: cannot borrow immutable borrowed content `*x` as mutable
 16 |     fn broken(x: &Vec<String>) {
    |                  ------------ use `&mut Vec<String>` here to make mutable
 17 |         x.push(format!("this is broken"));
-   |         ^
+   |         ^ cannot borrow as mutable
 
 error: aborting due to previous error
 
index 32e4da18056ff58f2a7b8c0cb54791da9f5a5dbe..4ef1cb9c239e4ba3fe0ee5ce5a944714c8689ed4 100644 (file)
@@ -5,13 +5,13 @@ error: cannot borrow immutable borrowed content `*x` as mutable
    |                         ---- use `&mut Foo` here to make mutable
 18 |     x.borrowed();
 19 |     x.borrowed_mut(); //~ ERROR cannot borrow
-   |     ^
+   |     ^ cannot borrow as mutable
 
 error: cannot borrow immutable `Box` content `*x` as mutable
   --> $DIR/borrowck-object-mutability.rs:29:5
    |
 29 |     x.borrowed_mut(); //~ ERROR cannot borrow
-   |     ^
+   |     ^ cannot borrow as mutable
 
 error: aborting due to 2 previous errors
 
index 58f66c1358437132e9236fb7a0c6b3e677bcd297..e4ed062214715a823bc4ca1613bd4fab2a04a0cf 100644 (file)
@@ -4,7 +4,7 @@ error: cannot borrow immutable borrowed content `*a` as mutable
 17 | pub fn foo<'a>(mut a: &'a String) {
    |                       ---------- use `&'a mut String` here to make mutable
 18 |     a.push_str("foo");
-   |     ^
+   |     ^ cannot borrow as mutable
 
 error: cannot borrow immutable borrowed content `*a` as mutable
   --> $DIR/mut-arg-hint.rs:13:9
@@ -12,7 +12,7 @@ error: cannot borrow immutable borrowed content `*a` as mutable
 12 |     fn foo(mut a: &String) {
    |                   ------- use `&mut String` here to make mutable
 13 |         a.push_str("bar");
-   |         ^
+   |         ^ cannot borrow as mutable
 
 error: cannot borrow immutable borrowed content `*a` as mutable
   --> $DIR/mut-arg-hint.rs:25:9
@@ -20,7 +20,7 @@ error: cannot borrow immutable borrowed content `*a` as mutable
 24 |     pub fn foo(mut a: &String) {
    |                       ------- use `&mut String` here to make mutable
 25 |         a.push_str("foo");
-   |         ^
+   |         ^ cannot borrow as mutable
 
 error: aborting due to 3 previous errors