Skip to content

Commit 6a6d6de

Browse files
author
Ariel Ben-Yehuda
authored
Rollup merge of rust-lang#40445 - estebank:issue-18150, r=jonathandturner
Point to let when modifying field of immutable variable Point at the immutable local variable when trying to modify one of its fields. Given a file: ```rust struct Foo { pub v: Vec<String> } fn main() { let f = Foo { v: Vec::new() }; f.v.push("cat".to_string()); } ``` present the following output: ``` error: cannot borrow immutable field `f.v` as mutable --> file.rs:7:13 | 6 | let f = Foo { v: Vec::new() }; | - this should be `mut` 7 | f.v.push("cat".to_string()); | ^^^ error: aborting due to previous error ``` Fix rust-lang#27593.
2 parents d050aee + 9ac628d commit 6a6d6de

File tree

3 files changed

+37
-1
lines changed

3 files changed

+37
-1
lines changed

src/librustc/middle/mem_categorization.rs

+15
Original file line numberDiff line numberDiff line change
@@ -195,6 +195,21 @@ pub struct cmt_<'tcx> {
195195
pub type cmt<'tcx> = Rc<cmt_<'tcx>>;
196196

197197
impl<'tcx> cmt_<'tcx> {
198+
pub fn get_def(&self) -> Option<ast::NodeId> {
199+
match self.cat {
200+
Categorization::Deref(ref cmt, ..) |
201+
Categorization::Interior(ref cmt, _) |
202+
Categorization::Downcast(ref cmt, _) => {
203+
if let Categorization::Local(nid) = cmt.cat {
204+
Some(nid)
205+
} else {
206+
None
207+
}
208+
}
209+
_ => None
210+
}
211+
}
212+
198213
pub fn get_field(&self, name: ast::Name) -> Option<DefId> {
199214
match self.cat {
200215
Categorization::Deref(ref cmt, ..) |

src/librustc_borrowck/borrowck/mod.rs

+19
Original file line numberDiff line numberDiff line change
@@ -662,6 +662,7 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> {
662662
pub fn bckerr_to_diag(&self, err: &BckError<'tcx>) -> DiagnosticBuilder<'a> {
663663
let span = err.span.clone();
664664
let mut immutable_field = None;
665+
let mut local_def = None;
665666

666667
let msg = &match err.code {
667668
err_mutbl => {
@@ -711,6 +712,14 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> {
711712
}
712713
None
713714
});
715+
local_def = err.cmt.get_def()
716+
.and_then(|nid| {
717+
if !self.tcx.hir.is_argument(nid) {
718+
Some(self.tcx.hir.span(nid))
719+
} else {
720+
None
721+
}
722+
});
714723

715724
format!("cannot borrow {} as mutable", descr)
716725
}
@@ -741,6 +750,11 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> {
741750
if let Some((span, msg)) = immutable_field {
742751
db.span_label(span, &msg);
743752
}
753+
if let Some(let_span) = local_def {
754+
if let Ok(snippet) = self.tcx.sess.codemap().span_to_snippet(let_span) {
755+
db.span_label(let_span, &format!("consider changing this to `mut {}`", snippet));
756+
}
757+
}
744758
db
745759
}
746760

@@ -1109,6 +1123,11 @@ before rustc 1.16, this temporary lived longer - see issue #39283 \
11091123
} else {
11101124
db.span_label(*error_span, &format!("cannot borrow mutably"));
11111125
}
1126+
} else if let Categorization::Interior(ref cmt, _) = err.cmt.cat {
1127+
if let mc::MutabilityCategory::McImmutable = cmt.mutbl {
1128+
db.span_label(*error_span,
1129+
&"cannot mutably borrow immutable field");
1130+
}
11121131
}
11131132
}
11141133
}
+3-1
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
error: cannot borrow immutable field `z.x` as mutable
22
--> $DIR/issue-39544.rs:21:18
33
|
4+
20 | let z = Z { x: X::Y };
5+
| - consider changing this to `mut z`
46
21 | let _ = &mut z.x;
5-
| ^^^
7+
| ^^^ cannot mutably borrow immutable field
68

79
error: aborting due to previous error
810

0 commit comments

Comments
 (0)