// 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 => {
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
}
};
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(
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);
+ }
}
}
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();
.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",
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",
);
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}"
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}"
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}"),
);
}
}
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);
}
}
_ => {
- 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) {
// 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));
}