mirror of
https://github.com/rust-lang/rust.git
synced 2025-02-05 19:43:24 +00:00
borrowck: consolidate mut
suggestions
This converts all of borrowck's `mut` suggestions to a new `mc::ImmutabilityBlame` API instead of the current mix of various hacks. Fixes #35937. Fixes #40823.
This commit is contained in:
parent
49c67bd632
commit
50728e5245
@ -194,76 +194,75 @@ pub struct cmt_<'tcx> {
|
||||
|
||||
pub type cmt<'tcx> = Rc<cmt_<'tcx>>;
|
||||
|
||||
pub enum ImmutabilityBlame<'tcx> {
|
||||
ImmLocal(ast::NodeId),
|
||||
ClosureEnv(ast::NodeId),
|
||||
LocalDeref(ast::NodeId),
|
||||
AdtFieldDeref(&'tcx ty::AdtDef, &'tcx ty::FieldDef)
|
||||
}
|
||||
|
||||
impl<'tcx> cmt_<'tcx> {
|
||||
pub fn get_def(&self) -> Option<ast::NodeId> {
|
||||
match self.cat {
|
||||
Categorization::Deref(ref cmt, ..) |
|
||||
Categorization::Interior(ref cmt, _) |
|
||||
Categorization::Downcast(ref cmt, _) => {
|
||||
if let Categorization::Local(nid) = cmt.cat {
|
||||
Some(nid)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
fn resolve_field(&self, field_name: FieldName) -> (&'tcx ty::AdtDef, &'tcx ty::FieldDef)
|
||||
{
|
||||
let adt_def = self.ty.ty_adt_def().unwrap_or_else(|| {
|
||||
bug!("interior cmt {:?} is not an ADT", self)
|
||||
});
|
||||
let variant_def = match self.cat {
|
||||
Categorization::Downcast(_, variant_did) => {
|
||||
adt_def.variant_with_id(variant_did)
|
||||
}
|
||||
_ => None
|
||||
}
|
||||
_ => {
|
||||
assert!(adt_def.is_univariant());
|
||||
&adt_def.variants[0]
|
||||
}
|
||||
};
|
||||
let field_def = match field_name {
|
||||
NamedField(name) => variant_def.field_named(name),
|
||||
PositionalField(idx) => &variant_def.fields[idx]
|
||||
};
|
||||
(adt_def, field_def)
|
||||
}
|
||||
|
||||
pub fn get_field(&self, name: ast::Name) -> Option<DefId> {
|
||||
pub fn immutability_blame(&self) -> Option<ImmutabilityBlame<'tcx>> {
|
||||
match self.cat {
|
||||
Categorization::Deref(ref cmt, ..) |
|
||||
Categorization::Interior(ref cmt, _) |
|
||||
Categorization::Downcast(ref cmt, _) => {
|
||||
if let Categorization::Local(_) = cmt.cat {
|
||||
if let ty::TyAdt(def, _) = self.ty.sty {
|
||||
if def.is_struct() {
|
||||
return def.struct_variant().find_field_named(name).map(|x| x.did);
|
||||
Categorization::Deref(ref base_cmt, _, BorrowedPtr(ty::ImmBorrow, _)) |
|
||||
Categorization::Deref(ref base_cmt, _, Implicit(ty::ImmBorrow, _)) => {
|
||||
// try to figure out where the immutable reference came from
|
||||
match base_cmt.cat {
|
||||
Categorization::Local(node_id) =>
|
||||
Some(ImmutabilityBlame::LocalDeref(node_id)),
|
||||
Categorization::Interior(ref base_cmt, InteriorField(field_name)) => {
|
||||
let (adt_def, field_def) = base_cmt.resolve_field(field_name);
|
||||
Some(ImmutabilityBlame::AdtFieldDeref(adt_def, field_def))
|
||||
}
|
||||
Categorization::Upvar(Upvar { id, .. }) => {
|
||||
if let NoteClosureEnv(..) = self.note {
|
||||
Some(ImmutabilityBlame::ClosureEnv(id.closure_expr_id))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
None
|
||||
} else {
|
||||
cmt.get_field(name)
|
||||
_ => None
|
||||
}
|
||||
}
|
||||
_ => None
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_field_name(&self) -> Option<ast::Name> {
|
||||
match self.cat {
|
||||
Categorization::Interior(_, ref ik) => {
|
||||
if let InteriorKind::InteriorField(FieldName::NamedField(name)) = *ik {
|
||||
Some(name)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
Categorization::Local(node_id) => {
|
||||
Some(ImmutabilityBlame::ImmLocal(node_id))
|
||||
}
|
||||
Categorization::Deref(ref cmt, ..) |
|
||||
Categorization::Downcast(ref cmt, _) => {
|
||||
cmt.get_field_name()
|
||||
Categorization::Rvalue(..) |
|
||||
Categorization::Upvar(..) |
|
||||
Categorization::Deref(.., UnsafePtr(..)) => {
|
||||
// This should not be reachable up to inference limitations.
|
||||
None
|
||||
}
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_arg_if_immutable(&self, map: &hir_map::Map) -> Option<ast::NodeId> {
|
||||
match self.cat {
|
||||
Categorization::Deref(ref cmt, ..) |
|
||||
Categorization::Interior(ref cmt, _) |
|
||||
Categorization::Downcast(ref cmt, _) => {
|
||||
if let Categorization::Local(nid) = cmt.cat {
|
||||
if let ty::TyAdt(_, _) = self.ty.sty {
|
||||
if let ty::TyRef(_, ty::TypeAndMut{mutbl: MutImmutable, ..}) = cmt.ty.sty {
|
||||
return Some(nid);
|
||||
}
|
||||
}
|
||||
None
|
||||
} else {
|
||||
cmt.get_arg_if_immutable(map)
|
||||
}
|
||||
Categorization::Interior(ref base_cmt, _) |
|
||||
Categorization::Downcast(ref base_cmt, _) |
|
||||
Categorization::Deref(ref base_cmt, _, _) => {
|
||||
base_cmt.immutability_blame()
|
||||
}
|
||||
Categorization::StaticItem => {
|
||||
// Do we want to do something here?
|
||||
None
|
||||
}
|
||||
_ => None
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1282,9 +1281,6 @@ pub enum Aliasability {
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
pub enum AliasableReason {
|
||||
AliasableBorrowed,
|
||||
AliasableClosure(ast::NodeId), // Aliasable due to capture Fn closure env
|
||||
AliasableOther,
|
||||
UnaliasableImmutable, // Created as needed upon seeing ImmutableUnique
|
||||
AliasableStatic,
|
||||
AliasableStaticMut,
|
||||
}
|
||||
@ -1324,23 +1320,13 @@ impl<'tcx> cmt_<'tcx> {
|
||||
Categorization::Deref(ref b, _, Implicit(ty::MutBorrow, _)) |
|
||||
Categorization::Deref(ref b, _, BorrowedPtr(ty::UniqueImmBorrow, _)) |
|
||||
Categorization::Deref(ref b, _, Implicit(ty::UniqueImmBorrow, _)) |
|
||||
Categorization::Deref(ref b, _, Unique) |
|
||||
Categorization::Downcast(ref b, _) |
|
||||
Categorization::Interior(ref b, _) => {
|
||||
// Aliasability depends on base cmt
|
||||
b.freely_aliasable()
|
||||
}
|
||||
|
||||
Categorization::Deref(ref b, _, Unique) => {
|
||||
let sub = b.freely_aliasable();
|
||||
if b.mutbl.is_mutable() {
|
||||
// Aliasability depends on base cmt alone
|
||||
sub
|
||||
} else {
|
||||
// Do not allow mutation through an immutable box.
|
||||
ImmutableUnique(Box::new(sub))
|
||||
}
|
||||
}
|
||||
|
||||
Categorization::Rvalue(..) |
|
||||
Categorization::Local(..) |
|
||||
Categorization::Upvar(..) |
|
||||
@ -1356,13 +1342,9 @@ impl<'tcx> cmt_<'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
Categorization::Deref(ref base, _, BorrowedPtr(ty::ImmBorrow, _)) |
|
||||
Categorization::Deref(ref base, _, Implicit(ty::ImmBorrow, _)) => {
|
||||
match base.cat {
|
||||
Categorization::Upvar(Upvar{ id, .. }) =>
|
||||
FreelyAliasable(AliasableClosure(id.closure_expr_id)),
|
||||
_ => FreelyAliasable(AliasableBorrowed)
|
||||
}
|
||||
Categorization::Deref(_, _, BorrowedPtr(ty::ImmBorrow, _)) |
|
||||
Categorization::Deref(_, _, Implicit(ty::ImmBorrow, _)) => {
|
||||
FreelyAliasable(AliasableBorrowed)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -188,14 +188,6 @@ fn check_aliasability<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>,
|
||||
// user knows what they're doing in these cases.
|
||||
Ok(())
|
||||
}
|
||||
(mc::Aliasability::ImmutableUnique(_), ty::MutBorrow) => {
|
||||
bccx.report_aliasability_violation(
|
||||
borrow_span,
|
||||
loan_cause,
|
||||
mc::AliasableReason::UnaliasableImmutable,
|
||||
cmt);
|
||||
Err(())
|
||||
}
|
||||
(mc::Aliasability::FreelyAliasable(alias_cause), ty::UniqueImmBorrow) |
|
||||
(mc::Aliasability::FreelyAliasable(alias_cause), ty::MutBorrow) => {
|
||||
bccx.report_aliasability_violation(
|
||||
@ -510,4 +502,3 @@ impl<'a, 'tcx> GatherLoanCtxt<'a, 'tcx> {
|
||||
self.move_error_collector.report_potential_errors(self.bccx);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -34,6 +34,7 @@ use rustc::hir::def_id::DefId;
|
||||
use rustc::middle::expr_use_visitor as euv;
|
||||
use rustc::middle::mem_categorization as mc;
|
||||
use rustc::middle::mem_categorization::Categorization;
|
||||
use rustc::middle::mem_categorization::ImmutabilityBlame;
|
||||
use rustc::middle::region;
|
||||
use rustc::ty::{self, TyCtxt};
|
||||
|
||||
@ -41,6 +42,7 @@ use std::fmt;
|
||||
use std::rc::Rc;
|
||||
use std::hash::{Hash, Hasher};
|
||||
use syntax::ast;
|
||||
use syntax::symbol::keywords;
|
||||
use syntax_pos::{MultiSpan, Span};
|
||||
use errors::DiagnosticBuilder;
|
||||
|
||||
@ -659,12 +661,10 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> {
|
||||
self.tcx.sess.span_err_with_code(s, msg, code);
|
||||
}
|
||||
|
||||
pub fn bckerr_to_diag(&self, err: &BckError<'tcx>) -> DiagnosticBuilder<'a> {
|
||||
fn bckerr_to_diag(&self, err: &BckError<'tcx>) -> DiagnosticBuilder<'a> {
|
||||
let span = err.span.clone();
|
||||
let mut immutable_field = None;
|
||||
let mut local_def = None;
|
||||
|
||||
let msg = &match err.code {
|
||||
let msg = match err.code {
|
||||
err_mutbl => {
|
||||
let descr = match err.cmt.note {
|
||||
mc::NoteClosureEnv(_) | mc::NoteUpvarRef(_) => {
|
||||
@ -700,27 +700,6 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> {
|
||||
BorrowViolation(euv::AutoUnsafe) |
|
||||
BorrowViolation(euv::ForLoop) |
|
||||
BorrowViolation(euv::MatchDiscriminant) => {
|
||||
// Check for this field's definition to see if it is an immutable reference
|
||||
// and suggest making it mutable if that is the case.
|
||||
immutable_field = err.cmt.get_field_name()
|
||||
.and_then(|name| err.cmt.get_field(name))
|
||||
.and_then(|did| self.tcx.hir.as_local_node_id(did))
|
||||
.and_then(|nid| {
|
||||
if let hir_map::Node::NodeField(ref field) = self.tcx.hir.get(nid) {
|
||||
return self.suggest_mut_for_immutable(&field.ty)
|
||||
.map(|msg| (self.tcx.hir.span(nid), msg));
|
||||
}
|
||||
None
|
||||
});
|
||||
local_def = err.cmt.get_def()
|
||||
.and_then(|nid| {
|
||||
if !self.tcx.hir.is_argument(nid) {
|
||||
Some(self.tcx.hir.span(nid))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
});
|
||||
|
||||
format!("cannot borrow {} as mutable", descr)
|
||||
}
|
||||
BorrowViolation(euv::ClosureInvocation) => {
|
||||
@ -746,16 +725,7 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> {
|
||||
}
|
||||
};
|
||||
|
||||
let mut db = self.struct_span_err(span, msg);
|
||||
if let Some((span, msg)) = immutable_field {
|
||||
db.span_label(span, &msg);
|
||||
}
|
||||
if let Some(let_span) = local_def {
|
||||
if let Ok(snippet) = self.tcx.sess.codemap().span_to_snippet(let_span) {
|
||||
db.span_label(let_span, &format!("consider changing this to `mut {}`", snippet));
|
||||
}
|
||||
}
|
||||
db
|
||||
self.struct_span_err(span, &msg)
|
||||
}
|
||||
|
||||
pub fn report_aliasability_violation(&self,
|
||||
@ -788,34 +758,7 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> {
|
||||
}
|
||||
};
|
||||
|
||||
let mut err = match cause {
|
||||
mc::AliasableOther => {
|
||||
struct_span_err!(
|
||||
self.tcx.sess, span, E0385,
|
||||
"{} in an aliasable location", prefix)
|
||||
}
|
||||
mc::AliasableReason::UnaliasableImmutable => {
|
||||
struct_span_err!(
|
||||
self.tcx.sess, span, E0386,
|
||||
"{} in an immutable container", prefix)
|
||||
}
|
||||
mc::AliasableClosure(id) => {
|
||||
let mut err = struct_span_err!(
|
||||
self.tcx.sess, span, E0387,
|
||||
"{} in a captured outer variable in an `Fn` closure", prefix);
|
||||
if let BorrowViolation(euv::ClosureCapture(_)) = kind {
|
||||
// The aliasability violation with closure captures can
|
||||
// happen for nested closures, so we know the enclosing
|
||||
// closure incorrectly accepts an `Fn` while it needs to
|
||||
// be `FnMut`.
|
||||
span_help!(&mut err, self.tcx.hir.span(id),
|
||||
"consider changing this to accept closures that implement `FnMut`");
|
||||
} else {
|
||||
span_help!(&mut err, self.tcx.hir.span(id),
|
||||
"consider changing this closure to take self by mutable reference");
|
||||
}
|
||||
err
|
||||
}
|
||||
match cause {
|
||||
mc::AliasableStatic |
|
||||
mc::AliasableStaticMut => {
|
||||
// This path cannot occur. It happens when we have an
|
||||
@ -826,17 +769,38 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> {
|
||||
// ignored.
|
||||
span_bug!(span, "aliasability violation for static `{}`", prefix)
|
||||
}
|
||||
mc::AliasableBorrowed => {
|
||||
let mut e = struct_span_err!(
|
||||
mc::AliasableBorrowed => {}
|
||||
};
|
||||
let blame = cmt.immutability_blame();
|
||||
let mut err = match blame {
|
||||
Some(ImmutabilityBlame::ClosureEnv(id)) => {
|
||||
let mut err = struct_span_err!(
|
||||
self.tcx.sess, span, E0387,
|
||||
"{} in a captured outer variable in an `Fn` closure", prefix);
|
||||
|
||||
// FIXME: the distinction between these 2 messages looks wrong.
|
||||
let help = if let BorrowViolation(euv::ClosureCapture(_)) = kind {
|
||||
// The aliasability violation with closure captures can
|
||||
// happen for nested closures, so we know the enclosing
|
||||
// closure incorrectly accepts an `Fn` while it needs to
|
||||
// be `FnMut`.
|
||||
"consider changing this to accept closures that implement `FnMut`"
|
||||
|
||||
} else {
|
||||
"consider changing this closure to take self by mutable reference"
|
||||
};
|
||||
err.span_help(self.tcx.hir.span(id), help);
|
||||
err
|
||||
}
|
||||
_ => {
|
||||
let mut err = struct_span_err!(
|
||||
self.tcx.sess, span, E0389,
|
||||
"{} in a `&` reference", prefix);
|
||||
e.span_label(span, &"assignment into an immutable reference");
|
||||
if let Some(nid) = cmt.get_arg_if_immutable(&self.tcx.hir) {
|
||||
self.immutable_argument_should_be_mut(nid, &mut e);
|
||||
}
|
||||
e
|
||||
err.span_label(span, &"assignment into an immutable reference");
|
||||
err
|
||||
}
|
||||
};
|
||||
self.note_immutability_blame(&mut err, blame);
|
||||
|
||||
if is_closure {
|
||||
err.help("closures behind references must be called via `&mut`");
|
||||
@ -873,8 +837,20 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> {
|
||||
None
|
||||
}
|
||||
|
||||
fn immutable_argument_should_be_mut(&self, nid: ast::NodeId, db: &mut DiagnosticBuilder) {
|
||||
let parent = self.tcx.hir.get_parent_node(nid);
|
||||
fn local_binding_mode(&self, node_id: ast::NodeId) -> hir::BindingMode {
|
||||
let pat = match self.tcx.hir.get(node_id) {
|
||||
hir_map::Node::NodeLocal(pat) => pat,
|
||||
node => bug!("bad node for local: {:?}", node)
|
||||
};
|
||||
|
||||
match pat.node {
|
||||
hir::PatKind::Binding(mode, ..) => mode,
|
||||
_ => bug!("local is not a binding: {:?}", pat)
|
||||
}
|
||||
}
|
||||
|
||||
fn local_ty(&self, node_id: ast::NodeId) -> Option<&hir::Ty> {
|
||||
let parent = self.tcx.hir.get_parent_node(node_id);
|
||||
let parent_node = self.tcx.hir.get(parent);
|
||||
|
||||
// The parent node is like a fn
|
||||
@ -882,12 +858,72 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> {
|
||||
// `nid`'s parent's `Body`
|
||||
let fn_body = self.tcx.hir.body(fn_like.body());
|
||||
// Get the position of `nid` in the arguments list
|
||||
let arg_pos = fn_body.arguments.iter().position(|arg| arg.pat.id == nid);
|
||||
let arg_pos = fn_body.arguments.iter().position(|arg| arg.pat.id == node_id);
|
||||
if let Some(i) = arg_pos {
|
||||
// The argument's `Ty`
|
||||
let arg_ty = &fn_like.decl().inputs[i];
|
||||
if let Some(msg) = self.suggest_mut_for_immutable(&arg_ty) {
|
||||
db.span_label(arg_ty.span, &msg);
|
||||
Some(&fn_like.decl().inputs[i])
|
||||
} else {
|
||||
None
|
||||
}
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
fn note_immutability_blame(&self,
|
||||
db: &mut DiagnosticBuilder,
|
||||
blame: Option<ImmutabilityBlame>) {
|
||||
match blame {
|
||||
None => {}
|
||||
Some(ImmutabilityBlame::ClosureEnv(_)) => {}
|
||||
Some(ImmutabilityBlame::ImmLocal(node_id)) => {
|
||||
let let_span = self.tcx.hir.span(node_id);
|
||||
if let hir::BindingMode::BindByValue(..) = self.local_binding_mode(node_id) {
|
||||
if let Ok(snippet) = self.tcx.sess.codemap().span_to_snippet(let_span) {
|
||||
if self.tcx.hir.name(node_id) == keywords::SelfValue.name() &&
|
||||
snippet != "self" {
|
||||
// avoid suggesting `mut &self`.
|
||||
return
|
||||
}
|
||||
db.span_label(
|
||||
let_span,
|
||||
&format!("consider changing this to `mut {}`", snippet)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
Some(ImmutabilityBlame::LocalDeref(node_id)) => {
|
||||
let let_span = self.tcx.hir.span(node_id);
|
||||
match self.local_binding_mode(node_id) {
|
||||
hir::BindingMode::BindByRef(..) => {
|
||||
let snippet = self.tcx.sess.codemap().span_to_snippet(let_span);
|
||||
if let Ok(snippet) = snippet {
|
||||
db.span_label(
|
||||
let_span,
|
||||
&format!("consider changing this to `{}`",
|
||||
snippet.replace("ref ", "ref mut "))
|
||||
);
|
||||
}
|
||||
}
|
||||
hir::BindingMode::BindByValue(..) => {
|
||||
if let Some(local_ty) = self.local_ty(node_id) {
|
||||
if let Some(msg) = self.suggest_mut_for_immutable(local_ty) {
|
||||
db.span_label(local_ty.span, &msg);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Some(ImmutabilityBlame::AdtFieldDeref(_, field)) => {
|
||||
let node_id = match self.tcx.hir.as_local_node_id(field.did) {
|
||||
Some(node_id) => node_id,
|
||||
None => return
|
||||
};
|
||||
|
||||
if let hir_map::Node::NodeField(ref field) = self.tcx.hir.get(node_id) {
|
||||
if let Some(msg) = self.suggest_mut_for_immutable(&field.ty) {
|
||||
db.span_label(field.ty.span, &msg);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -941,10 +977,13 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn note_and_explain_bckerr(&self, db: &mut DiagnosticBuilder, err: BckError<'tcx>) {
|
||||
fn note_and_explain_bckerr(&self, db: &mut DiagnosticBuilder, err: BckError<'tcx>) {
|
||||
let error_span = err.span.clone();
|
||||
match err.code {
|
||||
err_mutbl => self.note_and_explain_mutbl_error(db, &err, &error_span),
|
||||
err_mutbl => {
|
||||
self.note_and_explain_mutbl_error(db, &err, &error_span);
|
||||
self.note_immutability_blame(db, err.cmt.immutability_blame());
|
||||
}
|
||||
err_out_of_scope(super_scope, sub_scope, cause) => {
|
||||
let (value_kind, value_msg) = match err.cmt.cat {
|
||||
mc::Categorization::Rvalue(..) =>
|
||||
@ -1096,13 +1135,6 @@ before rustc 1.16, this temporary lived longer - see issue #39283 \
|
||||
_ => {
|
||||
if let Categorization::Deref(..) = err.cmt.cat {
|
||||
db.span_label(*error_span, &"cannot borrow as mutable");
|
||||
if let Some(local_id) = err.cmt.get_arg_if_immutable(&self.tcx.hir) {
|
||||
self.immutable_argument_should_be_mut(local_id, db);
|
||||
} else if let Categorization::Deref(ref inner_cmt, ..) = err.cmt.cat {
|
||||
if let Categorization::Local(local_id) = inner_cmt.cat {
|
||||
self.immutable_argument_should_be_mut(local_id, db);
|
||||
}
|
||||
}
|
||||
} else if let Categorization::Local(local_id) = err.cmt.cat {
|
||||
let span = self.tcx.hir.span(local_id);
|
||||
if let Ok(snippet) = self.tcx.sess.codemap().span_to_snippet(span) {
|
||||
@ -1110,14 +1142,6 @@ before rustc 1.16, this temporary lived longer - see issue #39283 \
|
||||
db.span_label(*error_span, &format!("cannot reborrow mutably"));
|
||||
db.span_label(*error_span, &format!("try removing `&mut` here"));
|
||||
} else {
|
||||
if snippet.starts_with("ref ") {
|
||||
db.span_label(span, &format!("use `{}` here to make mutable",
|
||||
snippet.replace("ref ", "ref mut ")));
|
||||
} else if snippet != "self" {
|
||||
db.span_label(span,
|
||||
&format!("use `mut {}` here to make mutable",
|
||||
snippet));
|
||||
}
|
||||
db.span_label(*error_span, &format!("cannot borrow mutably"));
|
||||
}
|
||||
} else {
|
||||
|
@ -198,7 +198,7 @@ fn main() {
|
||||
```
|
||||
"##,
|
||||
|
||||
E0386: r##"
|
||||
/*E0386: r##"
|
||||
This error occurs when an attempt is made to mutate the target of a mutable
|
||||
reference stored inside an immutable container.
|
||||
|
||||
@ -228,7 +228,7 @@ let x: i64 = 1;
|
||||
let y: Box<Cell<_>> = Box::new(Cell::new(x));
|
||||
y.set(2);
|
||||
```
|
||||
"##,
|
||||
"##,*/
|
||||
|
||||
E0387: r##"
|
||||
This error occurs when an attempt is made to mutate or mutably reference data
|
||||
@ -1117,6 +1117,6 @@ fn main() {
|
||||
}
|
||||
|
||||
register_diagnostics! {
|
||||
E0385, // {} in an aliasable location
|
||||
// E0385, // {} in an aliasable location
|
||||
E0524, // two closures require unique access to `..` at the same time
|
||||
}
|
||||
|
@ -27,7 +27,7 @@ fn main() {
|
||||
x; //~ value moved here
|
||||
|
||||
let y = Int(2);
|
||||
//~^use `mut y` here to make mutable
|
||||
//~^ consider changing this to `mut y`
|
||||
y //~ error: cannot borrow immutable local variable `y` as mutable
|
||||
//~| cannot borrow
|
||||
+=
|
||||
|
@ -23,7 +23,7 @@ fn indirect_write_to_imm_box() {
|
||||
let mut x: isize = 1;
|
||||
let y: Box<_> = box &mut x;
|
||||
let p = &y;
|
||||
***p = 2; //~ ERROR cannot assign to data in an immutable container
|
||||
***p = 2; //~ ERROR cannot assign to data in a `&` reference
|
||||
drop(p);
|
||||
}
|
||||
|
||||
@ -43,7 +43,6 @@ fn borrow_in_var_from_var_via_imm_box() {
|
||||
let p = &y;
|
||||
let q = &***p;
|
||||
**y = 2; //~ ERROR cannot assign to `**y` because it is borrowed
|
||||
//~^ ERROR cannot assign to data in an immutable container
|
||||
drop(p);
|
||||
drop(q);
|
||||
}
|
||||
@ -64,7 +63,6 @@ fn borrow_in_var_from_field_via_imm_box() {
|
||||
let p = &y;
|
||||
let q = &***p;
|
||||
**y = 2; //~ ERROR cannot assign to `**y` because it is borrowed
|
||||
//~^ ERROR cannot assign to data in an immutable container
|
||||
drop(p);
|
||||
drop(q);
|
||||
}
|
||||
@ -85,7 +83,6 @@ fn borrow_in_field_from_var_via_imm_box() {
|
||||
let p = &y.a;
|
||||
let q = &***p;
|
||||
**y.a = 2; //~ ERROR cannot assign to `**y.a` because it is borrowed
|
||||
//~^ ERROR cannot assign to data in an immutable container
|
||||
drop(p);
|
||||
drop(q);
|
||||
}
|
||||
@ -106,7 +103,6 @@ fn borrow_in_field_from_field_via_imm_box() {
|
||||
let p = &y.a;
|
||||
let q = &***p;
|
||||
**y.a = 2; //~ ERROR cannot assign to `**y.a` because it is borrowed
|
||||
//~^ ERROR cannot assign to data in an immutable container
|
||||
drop(p);
|
||||
drop(q);
|
||||
}
|
||||
|
@ -12,7 +12,7 @@ fn main() {
|
||||
match op {
|
||||
Some(ref v) => { let a = &mut v; },
|
||||
//~^ ERROR:cannot borrow immutable
|
||||
//~| use `ref mut v` here to make mutable
|
||||
//~| cannot borrow mutably
|
||||
None => {},
|
||||
}
|
||||
}
|
||||
|
@ -17,7 +17,7 @@ impl S {
|
||||
}
|
||||
|
||||
fn func(arg: S) {
|
||||
//~^ here to make mutable
|
||||
//~^ consider changing this to `mut arg`
|
||||
arg.mutate();
|
||||
//~^ ERROR cannot borrow immutable argument
|
||||
//~| cannot borrow mutably
|
||||
@ -25,7 +25,7 @@ fn func(arg: S) {
|
||||
|
||||
fn main() {
|
||||
let local = S;
|
||||
//~^ here to make mutable
|
||||
//~^ consider changing this to `mut local`
|
||||
local.mutate();
|
||||
//~^ ERROR cannot borrow immutable local variable
|
||||
//~| cannot borrow mutably
|
||||
|
@ -2,7 +2,7 @@ error: cannot borrow immutable local variable `x` as mutable
|
||||
--> $DIR/huge_multispan_highlight.rs:100:18
|
||||
|
|
||||
12 | let x = "foo";
|
||||
| - use `mut x` here to make mutable
|
||||
| - consider changing this to `mut x`
|
||||
...
|
||||
100 | let y = &mut x;
|
||||
| ^ cannot borrow mutably
|
||||
|
@ -10,6 +10,8 @@ error: cannot borrow immutable argument `self` as mutable
|
||||
error: cannot borrow immutable argument `self` as mutable
|
||||
--> $DIR/issue-31424.rs:23:15
|
||||
|
|
||||
22 | fn bar(self: &mut Self) {
|
||||
| ---- consider changing this to `mut self`
|
||||
23 | (&mut self).bar();
|
||||
| ^^^^ cannot borrow mutably
|
||||
|
||||
|
31
src/test/ui/did_you_mean/issue-35937.rs
Normal file
31
src/test/ui/did_you_mean/issue-35937.rs
Normal file
@ -0,0 +1,31 @@
|
||||
// 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.
|
||||
|
||||
struct Foo {
|
||||
pub v: Vec<String>
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let f = Foo { v: Vec::new() };
|
||||
f.v.push("cat".to_string());
|
||||
}
|
||||
|
||||
|
||||
struct S {
|
||||
x: i32,
|
||||
}
|
||||
fn foo() {
|
||||
let s = S { x: 42 };
|
||||
s.x += 1;
|
||||
}
|
||||
|
||||
fn bar(s: S) {
|
||||
s.x += 1;
|
||||
}
|
26
src/test/ui/did_you_mean/issue-35937.stderr
Normal file
26
src/test/ui/did_you_mean/issue-35937.stderr
Normal file
@ -0,0 +1,26 @@
|
||||
error: cannot borrow immutable field `f.v` as mutable
|
||||
--> $DIR/issue-35937.rs:17:5
|
||||
|
|
||||
16 | let f = Foo { v: Vec::new() };
|
||||
| - consider changing this to `mut f`
|
||||
17 | f.v.push("cat".to_string());
|
||||
| ^^^ cannot mutably borrow immutable field
|
||||
|
||||
error: cannot assign to immutable field `s.x`
|
||||
--> $DIR/issue-35937.rs:26:5
|
||||
|
|
||||
25 | let s = S { x: 42 };
|
||||
| - consider changing this to `mut s`
|
||||
26 | s.x += 1;
|
||||
| ^^^^^^^^ cannot mutably borrow immutable field
|
||||
|
||||
error: cannot assign to immutable field `s.x`
|
||||
--> $DIR/issue-35937.rs:30:5
|
||||
|
|
||||
29 | fn bar(s: S) {
|
||||
| - consider changing this to `mut s`
|
||||
30 | s.x += 1;
|
||||
| ^^^^^^^^ cannot mutably borrow immutable field
|
||||
|
||||
error: aborting due to 3 previous errors
|
||||
|
@ -2,7 +2,7 @@ error: cannot borrow immutable borrowed content `*self.s` as mutable
|
||||
--> $DIR/issue-38147-2.rs:17:9
|
||||
|
|
||||
12 | s: &'a String
|
||||
| ------------- use `&'a mut String` here to make mutable
|
||||
| ---------- use `&'a mut String` here to make mutable
|
||||
...
|
||||
17 | self.s.push('x');
|
||||
| ^^^^^^ cannot borrow as mutable
|
||||
|
@ -2,10 +2,8 @@ error: cannot borrow immutable borrowed content `*self.s` as mutable
|
||||
--> $DIR/issue-38147-3.rs:17:9
|
||||
|
|
||||
12 | s: &'a String
|
||||
| ------------- use `&'a mut String` here to make mutable
|
||||
| ---------- use `&'a mut String` here to make mutable
|
||||
...
|
||||
16 | fn f(&self) {
|
||||
| ----- use `&mut self` here to make mutable
|
||||
17 | self.s.push('x');
|
||||
| ^^^^^^ cannot borrow as mutable
|
||||
|
||||
|
@ -8,15 +8,20 @@
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
enum X {
|
||||
pub enum X {
|
||||
Y
|
||||
}
|
||||
|
||||
struct Z {
|
||||
pub struct Z {
|
||||
x: X
|
||||
}
|
||||
|
||||
fn main() {
|
||||
pub fn main() {
|
||||
let z = Z { x: X::Y };
|
||||
let _ = &mut z.x;
|
||||
}
|
||||
|
||||
pub fn with_arg(z: Z, w: &Z) {
|
||||
let _ = &mut z.x;
|
||||
let _ = &mut w.x;
|
||||
}
|
||||
|
@ -6,5 +6,22 @@ error: cannot borrow immutable field `z.x` as mutable
|
||||
21 | let _ = &mut z.x;
|
||||
| ^^^ cannot mutably borrow immutable field
|
||||
|
||||
error: aborting due to previous error
|
||||
error: cannot borrow immutable field `z.x` as mutable
|
||||
--> $DIR/issue-39544.rs:25:18
|
||||
|
|
||||
24 | pub fn with_arg(z: Z, w: &Z) {
|
||||
| - consider changing this to `mut z`
|
||||
25 | let _ = &mut z.x;
|
||||
| ^^^ cannot mutably borrow immutable field
|
||||
|
||||
error: cannot borrow immutable field `w.x` as mutable
|
||||
--> $DIR/issue-39544.rs:26:18
|
||||
|
|
||||
24 | pub fn with_arg(z: Z, w: &Z) {
|
||||
| -- use `&mut Z` here to make mutable
|
||||
25 | let _ = &mut z.x;
|
||||
26 | let _ = &mut w.x;
|
||||
| ^^^ cannot mutably borrow immutable field
|
||||
|
||||
error: aborting due to 3 previous errors
|
||||
|
||||
|
14
src/test/ui/did_you_mean/issue-40823.rs
Normal file
14
src/test/ui/did_you_mean/issue-40823.rs
Normal file
@ -0,0 +1,14 @@
|
||||
// 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.
|
||||
|
||||
fn main() {
|
||||
let mut buf = &[1, 2, 3, 4];
|
||||
buf.iter_mut();
|
||||
}
|
8
src/test/ui/did_you_mean/issue-40823.stderr
Normal file
8
src/test/ui/did_you_mean/issue-40823.stderr
Normal file
@ -0,0 +1,8 @@
|
||||
error: cannot borrow immutable borrowed content `*buf` as mutable
|
||||
--> $DIR/issue-40823.rs:13:5
|
||||
|
|
||||
13 | buf.iter_mut();
|
||||
| ^^^ cannot borrow as mutable
|
||||
|
||||
error: aborting due to previous error
|
||||
|
@ -2,7 +2,7 @@ error: cannot borrow immutable argument `x` as mutable
|
||||
--> $DIR/borrowck-borrow-overloaded-auto-deref-mut.rs:63:24
|
||||
|
|
||||
62 | fn deref_mut_field1(x: Own<Point>) {
|
||||
| - use `mut x` here to make mutable
|
||||
| - consider changing this to `mut x`
|
||||
63 | let __isize = &mut x.y; //~ ERROR cannot borrow
|
||||
| ^ cannot borrow mutably
|
||||
|
||||
@ -28,7 +28,7 @@ error: cannot borrow immutable argument `x` as mutable
|
||||
--> $DIR/borrowck-borrow-overloaded-auto-deref-mut.rs:98:5
|
||||
|
|
||||
97 | fn assign_field1<'a>(x: Own<Point>) {
|
||||
| - use `mut x` here to make mutable
|
||||
| - consider changing this to `mut x`
|
||||
98 | x.y = 3; //~ ERROR cannot borrow
|
||||
| ^ cannot borrow mutably
|
||||
|
||||
@ -54,7 +54,7 @@ error: cannot borrow immutable argument `x` as mutable
|
||||
--> $DIR/borrowck-borrow-overloaded-auto-deref-mut.rs:119:5
|
||||
|
|
||||
118 | fn deref_mut_method1(x: Own<Point>) {
|
||||
| - use `mut x` here to make mutable
|
||||
| - consider changing this to `mut x`
|
||||
119 | x.set(0, 0); //~ ERROR cannot borrow
|
||||
| ^ cannot borrow mutably
|
||||
|
||||
@ -70,7 +70,7 @@ error: cannot borrow immutable argument `x` as mutable
|
||||
--> $DIR/borrowck-borrow-overloaded-auto-deref-mut.rs:139:6
|
||||
|
|
||||
138 | fn assign_method1<'a>(x: Own<Point>) {
|
||||
| - use `mut x` here to make mutable
|
||||
| - consider changing this to `mut x`
|
||||
139 | *x.y_mut() = 3; //~ ERROR cannot borrow
|
||||
| ^ cannot borrow mutably
|
||||
|
||||
|
@ -2,7 +2,7 @@ error: cannot borrow immutable argument `x` as mutable
|
||||
--> $DIR/borrowck-borrow-overloaded-deref-mut.rs:39:25
|
||||
|
|
||||
38 | fn deref_mut1(x: Own<isize>) {
|
||||
| - use `mut x` here to make mutable
|
||||
| - consider changing this to `mut x`
|
||||
39 | let __isize = &mut *x; //~ ERROR cannot borrow
|
||||
| ^ cannot borrow mutably
|
||||
|
||||
@ -18,7 +18,7 @@ error: cannot borrow immutable argument `x` as mutable
|
||||
--> $DIR/borrowck-borrow-overloaded-deref-mut.rs:59:6
|
||||
|
|
||||
58 | fn assign1<'a>(x: Own<isize>) {
|
||||
| - use `mut x` here to make mutable
|
||||
| - consider changing this to `mut x`
|
||||
59 | *x = 3; //~ ERROR cannot borrow
|
||||
| ^ cannot borrow mutably
|
||||
|
||||
|
@ -10,6 +10,9 @@ error: cannot borrow immutable borrowed content `*x` as mutable
|
||||
error: cannot borrow immutable `Box` content `*x` as mutable
|
||||
--> $DIR/borrowck-object-mutability.rs:29:5
|
||||
|
|
||||
27 | fn owned_receiver(x: Box<Foo>) {
|
||||
| - consider changing this to `mut x`
|
||||
28 | x.borrowed();
|
||||
29 | x.borrowed_mut(); //~ ERROR cannot borrow
|
||||
| ^ cannot borrow as mutable
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user