about summary refs log tree commit diff
diff options
context:
space:
mode:
authorBrian Koropoff <bkoropoff@gmail.com>2014-10-25 21:46:24 -0700
committerBrian Koropoff <bkoropoff@gmail.com>2014-10-25 21:46:24 -0700
commit7129f172aee6d5143ca36d81defd47dd0c113ce3 (patch)
treea7771ddda9f63233ee49d77cb29468116bd93cb8
parent1062955b46950114ed3a0a71c043e9644afdce48 (diff)
downloadrust-7129f172aee6d5143ca36d81defd47dd0c113ce3.tar.gz
rust-7129f172aee6d5143ca36d81defd47dd0c113ce3.zip
Improve diagnostics that result from the fix for #18335
-rw-r--r--src/librustc/middle/borrowck/check_loans.rs29
-rw-r--r--src/librustc/middle/borrowck/mod.rs21
2 files changed, 37 insertions, 13 deletions
diff --git a/src/librustc/middle/borrowck/check_loans.rs b/src/librustc/middle/borrowck/check_loans.rs
index 5d984168a31..bdcf01b21ab 100644
--- a/src/librustc/middle/borrowck/check_loans.rs
+++ b/src/librustc/middle/borrowck/check_loans.rs
@@ -777,13 +777,28 @@ impl<'a, 'tcx> CheckLoanCtxt<'a, 'tcx> {
         // Otherwise, just a plain error.
         match assignee_cmt.note {
             mc::NoteClosureEnv(upvar_id) => {
-                self.bccx.span_err(
-                    assignment_span,
-                    format!("cannot assign to {}",
-                            self.bccx.cmt_to_string(&*assignee_cmt)).as_slice());
-                self.bccx.span_note(
-                    self.tcx().map.span(upvar_id.closure_expr_id),
-                    "consider changing this closure to take self by mutable reference");
+                // 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 assignee_cmt.upvar().unwrap().cat {
+                    mc::cat_upvar(mc::Upvar { kind, .. }) => kind,
+                    _ => unreachable!()
+                };
+                if kind == ty::FnUnboxedClosureKind {
+                    self.bccx.span_err(
+                        assignment_span,
+                        format!("cannot assign to {}",
+                                self.bccx.cmt_to_string(&*assignee_cmt)).as_slice());
+                    self.bccx.span_note(
+                        self.tcx().map.span(upvar_id.closure_expr_id),
+                        "consider changing this closure to take self by mutable reference");
+                } else {
+                    self.bccx.span_err(
+                        assignment_span,
+                        format!("cannot assign to {} {}",
+                                assignee_cmt.mutbl.to_user_str(),
+                                self.bccx.cmt_to_string(&*assignee_cmt)).as_slice());
+                }
             }
             _ => match opt_loan_path(&assignee_cmt) {
                 Some(lp) => {
diff --git a/src/librustc/middle/borrowck/mod.rs b/src/librustc/middle/borrowck/mod.rs
index 850c6008706..06249b956b6 100644
--- a/src/librustc/middle/borrowck/mod.rs
+++ b/src/librustc/middle/borrowck/mod.rs
@@ -626,7 +626,7 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> {
         match err.code {
             err_mutbl => {
                 let descr = match err.cmt.note {
-                    mc::NoteClosureEnv(_) => {
+                    mc::NoteClosureEnv(_) | mc::NoteUpvarRef(_) => {
                         self.cmt_to_string(&*err.cmt)
                     }
                     _ => match opt_loan_path(&err.cmt) {
@@ -762,11 +762,20 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> {
         match code {
             err_mutbl(..) => {
                 match err.cmt.note {
-                    mc::NoteClosureEnv(upvar_id) => {
-                        self.tcx.sess.span_note(
-                            self.tcx.map.span(upvar_id.closure_expr_id),
-                            "consider changing this closure to take \
-                             self by mutable reference");
+                    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 {
+                            mc::cat_upvar(mc::Upvar { kind, .. }) => kind,
+                            _ => unreachable!()
+                        };
+                        if kind == ty::FnUnboxedClosureKind {
+                            self.tcx.sess.span_note(
+                                self.tcx.map.span(upvar_id.closure_expr_id),
+                                "consider changing this closure to take \
+                                 self by mutable reference");
+                        }
                     }
                     _ => {}
                 }