]> git.lizzy.rs Git - rust.git/blobdiff - src/librustc/middle/borrowck/check_loans.rs
rollup merge of #18337 : bkoropoff/unboxed-imm-upvar-fixes
[rust.git] / src / librustc / middle / borrowck / check_loans.rs
index f5e849f41967da8d5b28a4b37834a44901a9d8fd..de61f4f2b404c78a46b7defe3b9d719c2e572e9c 100644 (file)
@@ -777,13 +777,28 @@ fn check_assignment(&self,
         // 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) => {
@@ -825,12 +840,20 @@ fn mark_variable_as_used_mut(this: &CheckLoanCtxt,
                     mc::cat_rvalue(..) |
                     mc::cat_static_item |
                     mc::cat_deref(_, _, mc::UnsafePtr(..)) |
-                    mc::cat_deref(_, _, mc::BorrowedPtr(..)) |
                     mc::cat_deref(_, _, mc::Implicit(..)) => {
                         assert_eq!(cmt.mutbl, mc::McDeclared);
                         return;
                     }
 
+                    mc::cat_deref(_, _, mc::BorrowedPtr(..)) => {
+                        assert_eq!(cmt.mutbl, mc::McDeclared);
+                        // We need to drill down to upvar if applicable
+                        match cmt.upvar() {
+                            Some(b) => cmt = b,
+                            None => return
+                        }
+                    }
+
                     mc::cat_deref(b, _, mc::OwnedPtr) => {
                         assert_eq!(cmt.mutbl, mc::McInherited);
                         cmt = b;