diff --git a/src/librustc/middle/borrowck/check_loans.rs b/src/librustc/middle/borrowck/check_loans.rs index 5d984168a31c..bdcf01b21abd 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 850c6008706c..06249b956b67 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"); + } } _ => {} }