about summary refs log tree commit diff
diff options
context:
space:
mode:
authorEsteban Küber <esteban@kuber.com.ar>2017-10-11 14:38:52 -0700
committerEsteban Küber <esteban@kuber.com.ar>2017-10-11 15:56:22 -0700
commitfab6a10c00ffda25ed9ec3195b28a9f6a58150a4 (patch)
treee00a0047ca0393c577cbca27bfcca14bd5bbcd87
parentec016f80cf725a9c8a613cdcd2ac97588d5f9af2 (diff)
downloadrust-fab6a10c00ffda25ed9ec3195b28a9f6a58150a4.tar.gz
rust-fab6a10c00ffda25ed9ec3195b28a9f6a58150a4.zip
Point at immutable outer variable
When attempting to mutate an immutable outer variable from a closure,
point at the outer variable and suggest making it mutable.
-rw-r--r--src/librustc_borrowck/borrowck/mod.rs16
-rw-r--r--src/test/ui/suggestions/closure-immutable-outer-variable.rs20
-rw-r--r--src/test/ui/suggestions/closure-immutable-outer-variable.stderr10
3 files changed, 45 insertions, 1 deletions
diff --git a/src/librustc_borrowck/borrowck/mod.rs b/src/librustc_borrowck/borrowck/mod.rs
index a3f1340d429..d6f7c2aa887 100644
--- a/src/librustc_borrowck/borrowck/mod.rs
+++ b/src/librustc_borrowck/borrowck/mod.rs
@@ -759,7 +759,21 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> {
 
                 let mut db = match err.cause {
                     MutabilityViolation => {
-                        self.cannot_assign(error_span, &descr, Origin::Ast)
+                        let mut db = self.cannot_assign(error_span, &descr, Origin::Ast);
+                        if let mc::NoteClosureEnv(upvar_id) = err.cmt.note {
+                            let node_id = self.tcx.hir.hir_to_node_id(upvar_id.var_id);
+                            let sp = self.tcx.hir.span(node_id);
+                            match self.tcx.sess.codemap().span_to_snippet(sp) {
+                                Ok(snippet) => {
+                                    let msg = &format!("consider making `{}` mutable", snippet);
+                                    db.span_suggestion(sp, msg, format!("mut {}", snippet));
+                                }
+                                _ => {
+                                    db.span_help(sp, "consider making this binding mutable");
+                                }
+                            }
+                        }
+                        db
                     }
                     BorrowViolation(euv::ClosureCapture(_)) => {
                         struct_span_err!(self.tcx.sess, error_span, E0595,
diff --git a/src/test/ui/suggestions/closure-immutable-outer-variable.rs b/src/test/ui/suggestions/closure-immutable-outer-variable.rs
new file mode 100644
index 00000000000..fe8e2bc6c8e
--- /dev/null
+++ b/src/test/ui/suggestions/closure-immutable-outer-variable.rs
@@ -0,0 +1,20 @@
+// 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.
+
+// Point at the captured immutable outer variable
+
+fn foo(mut f: Box<FnMut()>) {
+    f();
+}
+
+fn main() {
+    let y = true;
+    foo(Box::new(move || y = false) as Box<_>);
+}
diff --git a/src/test/ui/suggestions/closure-immutable-outer-variable.stderr b/src/test/ui/suggestions/closure-immutable-outer-variable.stderr
new file mode 100644
index 00000000000..19f1cd07171
--- /dev/null
+++ b/src/test/ui/suggestions/closure-immutable-outer-variable.stderr
@@ -0,0 +1,10 @@
+error[E0594]: cannot assign to captured outer variable in an `FnMut` closure
+  --> $DIR/closure-immutable-outer-variable.rs:19:26
+   |
+18 |     let y = true;
+   |         - help: consider making `y` mutable: `mut y`
+19 |     foo(Box::new(move || y = false) as Box<_>);
+   |                          ^^^^^^^^^
+
+error: aborting due to previous error
+