summaryrefslogtreecommitdiffstats
path: root/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs')
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs162
1 files changed, 103 insertions, 59 deletions
diff --git a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs
index 3319a8068..45b15c2c5 100644
--- a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs
@@ -180,6 +180,9 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
// the verbs used in some diagnostic messages.
let act;
let acted_on;
+ let mut suggest = true;
+ let mut mut_error = None;
+ let mut count = 1;
let span = match error_access {
AccessKind::Mutate => {
@@ -194,15 +197,50 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
let borrow_spans = self.borrow_spans(span, location);
let borrow_span = borrow_spans.args_or_use();
- err = self.cannot_borrow_path_as_mutable_because(borrow_span, &item_msg, &reason);
- borrow_spans.var_span_label(
- &mut err,
- format!(
- "mutable borrow occurs due to use of {} in closure",
- self.describe_any_place(access_place.as_ref()),
- ),
- "mutable",
- );
+ match the_place_err {
+ PlaceRef { local, projection: [] }
+ if self.body.local_decls[local].can_be_made_mutable() =>
+ {
+ let span = self.body.local_decls[local].source_info.span;
+ mut_error = Some(span);
+ if let Some((buffer, c)) = self.get_buffered_mut_error(span) {
+ // We've encountered a second (or more) attempt to mutably borrow an
+ // immutable binding, so the likely problem is with the binding
+ // declaration, not the use. We collect these in a single diagnostic
+ // and make the binding the primary span of the error.
+ err = buffer;
+ count = c + 1;
+ if count == 2 {
+ err.replace_span_with(span, false);
+ err.span_label(span, "not mutable");
+ }
+ suggest = false;
+ } else {
+ err = self.cannot_borrow_path_as_mutable_because(
+ borrow_span,
+ &item_msg,
+ &reason,
+ );
+ }
+ }
+ _ => {
+ err = self.cannot_borrow_path_as_mutable_because(
+ borrow_span,
+ &item_msg,
+ &reason,
+ );
+ }
+ }
+ if suggest {
+ borrow_spans.var_span_label(
+ &mut err,
+ format!(
+ "mutable borrow occurs due to use of {} in closure",
+ self.describe_any_place(access_place.as_ref()),
+ ),
+ "mutable",
+ );
+ }
borrow_span
}
};
@@ -226,7 +264,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
ProjectionElem::Deref,
],
} => {
- err.span_label(span, format!("cannot {ACT}", ACT = act));
+ err.span_label(span, format!("cannot {act}"));
if let Some(span) = get_mut_span_in_struct_field(
self.infcx.tcx,
@@ -252,7 +290,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
.unwrap_or(false) =>
{
let decl = &self.body.local_decls[local];
- err.span_label(span, format!("cannot {ACT}", ACT = act));
+ err.span_label(span, format!("cannot {act}"));
if let Some(mir::Statement {
source_info,
kind:
@@ -276,7 +314,9 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
pat_span: _,
},
)))) => {
- err.span_note(sp, "the binding is already a mutable borrow");
+ if suggest {
+ err.span_note(sp, "the binding is already a mutable borrow");
+ }
}
_ => {
err.span_note(
@@ -304,20 +344,25 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
} else {
err.span_help(source_info.span, "try removing `&mut` here");
}
- } else if decl.mutability == Mutability::Not
- && !matches!(
+ } else if decl.mutability == Mutability::Not {
+ if matches!(
decl.local_info,
Some(box LocalInfo::User(ClearCrossCrate::Set(BindingForm::ImplicitSelf(
hir::ImplicitSelfKind::MutRef
- ))))
- )
- {
- err.span_suggestion_verbose(
- decl.source_info.span.shrink_to_lo(),
- "consider making the binding mutable",
- "mut ",
- Applicability::MachineApplicable,
- );
+ ),)))
+ ) {
+ err.note(
+ "as `Self` may be unsized, this call attempts to take `&mut &mut self`",
+ );
+ err.note("however, `&mut self` expands to `self: &mut Self`, therefore `self` cannot be borrowed mutably");
+ } else {
+ err.span_suggestion_verbose(
+ decl.source_info.span.shrink_to_lo(),
+ "consider making the binding mutable",
+ "mut ",
+ Applicability::MachineApplicable,
+ );
+ };
}
}
@@ -333,16 +378,20 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
let local_decl = &self.body.local_decls[local];
assert_eq!(local_decl.mutability, Mutability::Not);
- err.span_label(span, format!("cannot {ACT}", ACT = act));
- err.span_suggestion(
- local_decl.source_info.span,
- "consider changing this to be mutable",
- format!("mut {}", self.local_names[local].unwrap()),
- Applicability::MachineApplicable,
- );
- let tcx = self.infcx.tcx;
- if let ty::Closure(id, _) = *the_place_err.ty(self.body, tcx).ty.kind() {
- self.show_mutating_upvar(tcx, id.expect_local(), the_place_err, &mut err);
+ if count < 10 {
+ err.span_label(span, format!("cannot {act}"));
+ }
+ if suggest {
+ err.span_suggestion_verbose(
+ local_decl.source_info.span.shrink_to_lo(),
+ "consider changing this to be mutable",
+ "mut ".to_string(),
+ Applicability::MachineApplicable,
+ );
+ let tcx = self.infcx.tcx;
+ if let ty::Closure(id, _) = *the_place_err.ty(self.body, tcx).ty.kind() {
+ self.show_mutating_upvar(tcx, id.expect_local(), the_place_err, &mut err);
+ }
}
}
@@ -357,7 +406,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
let captured_place = &self.upvars[upvar_index.index()].place;
- err.span_label(span, format!("cannot {ACT}", ACT = act));
+ err.span_label(span, format!("cannot {act}"));
let upvar_hir_id = captured_place.get_root_variable();
@@ -397,7 +446,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
.span_to_snippet(span)
.map_or(false, |snippet| snippet.starts_with("&mut ")) =>
{
- err.span_label(span, format!("cannot {ACT}", ACT = act));
+ err.span_label(span, format!("cannot {act}"));
err.span_suggestion(
span,
"try removing `&mut` here",
@@ -409,7 +458,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
PlaceRef { local, projection: [ProjectionElem::Deref] }
if self.body.local_decls[local].is_ref_for_guard() =>
{
- err.span_label(span, format!("cannot {ACT}", ACT = act));
+ err.span_label(span, format!("cannot {act}"));
err.note(
"variables bound in patterns are immutable until the end of the pattern guard",
);
@@ -537,7 +586,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
Some((true, err_help_span, suggested_code)) => {
let (is_trait_sig, local_trait) = self.is_error_in_trait(local);
if !is_trait_sig {
- err.span_suggestion(
+ err.span_suggestion_verbose(
err_help_span,
&format!(
"consider changing this to be a mutable {pointer_desc}"
@@ -546,7 +595,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
Applicability::MachineApplicable,
);
} else if let Some(x) = local_trait {
- err.span_suggestion(
+ err.span_suggestion_verbose(
x,
&format!(
"consider changing that to be a mutable {pointer_desc}"
@@ -569,24 +618,15 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
err.span_label(
span,
format!(
- "`{NAME}` is a `{SIGIL}` {DESC}, \
- so the data it refers to cannot be {ACTED_ON}",
- NAME = name,
- SIGIL = pointer_sigil,
- DESC = pointer_desc,
- ACTED_ON = acted_on
+ "`{name}` is a `{pointer_sigil}` {pointer_desc}, \
+ so the data it refers to cannot be {acted_on}",
),
);
}
_ => {
err.span_label(
span,
- format!(
- "cannot {ACT} through `{SIGIL}` {DESC}",
- ACT = act,
- SIGIL = pointer_sigil,
- DESC = pointer_desc
- ),
+ format!("cannot {act} through `{pointer_sigil}` {pointer_desc}"),
);
}
}
@@ -599,19 +639,19 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
}
PlaceRef { local: _, projection: [.., ProjectionElem::Deref] } => {
- err.span_label(span, format!("cannot {ACT}", ACT = act));
+ err.span_label(span, format!("cannot {act}"));
match opt_source {
Some(BorrowedContentSource::OverloadedDeref(ty)) => {
err.help(&format!(
"trait `DerefMut` is required to modify through a dereference, \
- but it is not implemented for `{ty}`",
+ but it is not implemented for `{ty}`",
));
}
Some(BorrowedContentSource::OverloadedIndex(ty)) => {
err.help(&format!(
"trait `IndexMut` is required to modify indexed content, \
- but it is not implemented for `{ty}`",
+ but it is not implemented for `{ty}`",
));
self.suggest_map_index_mut_alternatives(ty, &mut err, span);
}
@@ -620,11 +660,15 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
}
_ => {
- err.span_label(span, format!("cannot {ACT}", ACT = act));
+ err.span_label(span, format!("cannot {act}"));
}
}
- self.buffer_error(err);
+ if let Some(span) = mut_error {
+ self.buffer_mut_error(span, err, count);
+ } else {
+ self.buffer_error(err);
+ }
}
fn suggest_map_index_mut_alternatives(&self, ty: Ty<'tcx>, err: &mut Diagnostic, span: Span) {
@@ -965,7 +1009,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
let hir = self.infcx.tcx.hir();
let closure_id = self.mir_hir_id();
let closure_span = self.infcx.tcx.def_span(self.mir_def_id());
- let fn_call_id = hir.get_parent_node(closure_id);
+ let fn_call_id = hir.parent_id(closure_id);
let node = hir.get(fn_call_id);
let def_id = hir.enclosing_body_owner(fn_call_id);
let mut look_at_return = true;
@@ -1050,7 +1094,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
}
}
-fn mut_borrow_of_mutable_ref(local_decl: &LocalDecl<'_>, local_name: Option<Symbol>) -> bool {
+pub fn mut_borrow_of_mutable_ref(local_decl: &LocalDecl<'_>, local_name: Option<Symbol>) -> bool {
debug!("local_info: {:?}, ty.kind(): {:?}", local_decl.local_info, local_decl.ty.kind());
match local_decl.local_info.as_deref() {
@@ -1168,7 +1212,7 @@ fn suggest_ampmut<'tcx>(
{
let lt_name = &src[1..ws_pos];
let ty = &src[ws_pos..];
- return (true, highlight_span, format!("&{} mut{}", lt_name, ty));
+ return (true, highlight_span, format!("&{lt_name} mut{ty}"));
}
let ty_mut = local_decl.ty.builtin_deref(true).unwrap();
@@ -1209,7 +1253,7 @@ fn get_mut_span_in_struct_field<'tcx>(
// Now we're dealing with the actual struct that we're going to suggest a change to,
// we can expect a field that is an immutable reference to a type.
&& let hir::Node::Field(field) = node
- && let hir::TyKind::Rptr(lt, hir::MutTy { mutbl: hir::Mutability::Not, ty }) = field.ty.kind
+ && let hir::TyKind::Ref(lt, hir::MutTy { mutbl: hir::Mutability::Not, ty }) = field.ty.kind
{
return Some(lt.ident.span.between(ty.span));
}