1use core::ops::ControlFlow;
2
3use either::Either;
4use hir::{ExprKind, Param};
5use rustc_abi::FieldIdx;
6use rustc_errors::{Applicability, Diag};
7use rustc_hir::intravisit::Visitor;
8use rustc_hir::{self as hir, BindingMode, ByRef, Node};
9use rustc_middle::bug;
10use rustc_middle::hir::place::PlaceBase;
11use rustc_middle::mir::visit::PlaceContext;
12use rustc_middle::mir::{
13 self, BindingForm, Body, BorrowKind, Local, LocalDecl, LocalInfo, LocalKind, Location,
14 Mutability, Operand, Place, PlaceRef, ProjectionElem, RawPtrKind, Rvalue, Statement,
15 StatementKind, TerminatorKind,
16};
17use rustc_middle::ty::{self, InstanceKind, Ty, TyCtxt, Upcast};
18use rustc_span::{BytePos, DesugaringKind, Span, Symbol, kw, sym};
19use rustc_trait_selection::error_reporting::InferCtxtErrorExt;
20use rustc_trait_selection::infer::InferCtxtExt;
21use rustc_trait_selection::traits;
22use tracing::{debug, trace};
23
24use crate::diagnostics::BorrowedContentSource;
25use crate::{MirBorrowckCtxt, session_diagnostics};
26
27#[derive(#[automatically_derived]
impl ::core::marker::Copy for AccessKind { }Copy, #[automatically_derived]
impl ::core::clone::Clone for AccessKind {
#[inline]
fn clone(&self) -> AccessKind { *self }
}Clone, #[automatically_derived]
impl ::core::fmt::Debug for AccessKind {
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
::core::fmt::Formatter::write_str(f,
match self {
AccessKind::MutableBorrow => "MutableBorrow",
AccessKind::Mutate => "Mutate",
})
}
}Debug, #[automatically_derived]
impl ::core::cmp::Eq for AccessKind {
#[inline]
#[doc(hidden)]
#[coverage(off)]
fn assert_receiver_is_total_eq(&self) {}
}Eq, #[automatically_derived]
impl ::core::cmp::PartialEq for AccessKind {
#[inline]
fn eq(&self, other: &AccessKind) -> bool {
let __self_discr = ::core::intrinsics::discriminant_value(self);
let __arg1_discr = ::core::intrinsics::discriminant_value(other);
__self_discr == __arg1_discr
}
}PartialEq)]
28pub(crate) enum AccessKind {
29 MutableBorrow,
30 Mutate,
31}
32
33fn find_assignments(body: &Body<'_>, local: Local) -> Vec<Location> {
36 use rustc_middle::mir::visit::Visitor;
37
38 struct FindLocalAssignmentVisitor {
39 needle: Local,
40 locations: Vec<Location>,
41 }
42
43 impl<'tcx> Visitor<'tcx> for FindLocalAssignmentVisitor {
44 fn visit_local(&mut self, local: Local, place_context: PlaceContext, location: Location) {
45 if self.needle != local {
46 return;
47 }
48
49 if place_context.is_place_assignment() {
50 self.locations.push(location);
51 }
52 }
53 }
54
55 let mut visitor = FindLocalAssignmentVisitor { needle: local, locations: ::alloc::vec::Vec::new()vec![] };
56 visitor.visit_body(body);
57 visitor.locations
58}
59
60impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
61 pub(crate) fn report_mutability_error(
62 &mut self,
63 access_place: Place<'tcx>,
64 span: Span,
65 the_place_err: PlaceRef<'tcx>,
66 error_access: AccessKind,
67 location: Location,
68 ) {
69 {
use ::tracing::__macro_support::Callsite as _;
static __CALLSITE: ::tracing::callsite::DefaultCallsite =
{
static META: ::tracing::Metadata<'static> =
{
::tracing_core::metadata::Metadata::new("event compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs:69",
"rustc_borrowck::diagnostics::mutability_errors",
::tracing::Level::DEBUG,
::tracing_core::__macro_support::Option::Some("compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs"),
::tracing_core::__macro_support::Option::Some(69u32),
::tracing_core::__macro_support::Option::Some("rustc_borrowck::diagnostics::mutability_errors"),
::tracing_core::field::FieldSet::new(&["message"],
::tracing_core::callsite::Identifier(&__CALLSITE)),
::tracing::metadata::Kind::EVENT)
};
::tracing::callsite::DefaultCallsite::new(&META)
};
let enabled =
::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL
&&
::tracing::Level::DEBUG <=
::tracing::level_filters::LevelFilter::current() &&
{
let interest = __CALLSITE.interest();
!interest.is_never() &&
::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
interest)
};
if enabled {
(|value_set: ::tracing::field::ValueSet|
{
let meta = __CALLSITE.metadata();
::tracing::Event::dispatch(meta, &value_set);
;
})({
#[allow(unused_imports)]
use ::tracing::field::{debug, display, Value};
let mut iter = __CALLSITE.metadata().fields().iter();
__CALLSITE.metadata().fields().value_set(&[(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
::tracing::__macro_support::Option::Some(&format_args!("report_mutability_error(access_place={0:?}, span={1:?}, the_place_err={2:?}, error_access={3:?}, location={4:?},)",
access_place, span, the_place_err, error_access, location)
as &dyn Value))])
});
} else { ; }
};debug!(
70 "report_mutability_error(\
71 access_place={:?}, span={:?}, the_place_err={:?}, error_access={:?}, location={:?},\
72 )",
73 access_place, span, the_place_err, error_access, location,
74 );
75
76 let mut err;
77 let item_msg;
78 let reason;
79 let mut opt_source = None;
80 let access_place_desc = self.describe_any_place(access_place.as_ref());
81 {
use ::tracing::__macro_support::Callsite as _;
static __CALLSITE: ::tracing::callsite::DefaultCallsite =
{
static META: ::tracing::Metadata<'static> =
{
::tracing_core::metadata::Metadata::new("event compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs:81",
"rustc_borrowck::diagnostics::mutability_errors",
::tracing::Level::DEBUG,
::tracing_core::__macro_support::Option::Some("compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs"),
::tracing_core::__macro_support::Option::Some(81u32),
::tracing_core::__macro_support::Option::Some("rustc_borrowck::diagnostics::mutability_errors"),
::tracing_core::field::FieldSet::new(&["message"],
::tracing_core::callsite::Identifier(&__CALLSITE)),
::tracing::metadata::Kind::EVENT)
};
::tracing::callsite::DefaultCallsite::new(&META)
};
let enabled =
::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL
&&
::tracing::Level::DEBUG <=
::tracing::level_filters::LevelFilter::current() &&
{
let interest = __CALLSITE.interest();
!interest.is_never() &&
::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
interest)
};
if enabled {
(|value_set: ::tracing::field::ValueSet|
{
let meta = __CALLSITE.metadata();
::tracing::Event::dispatch(meta, &value_set);
;
})({
#[allow(unused_imports)]
use ::tracing::field::{debug, display, Value};
let mut iter = __CALLSITE.metadata().fields().iter();
__CALLSITE.metadata().fields().value_set(&[(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
::tracing::__macro_support::Option::Some(&format_args!("report_mutability_error: access_place_desc={0:?}",
access_place_desc) as &dyn Value))])
});
} else { ; }
};debug!("report_mutability_error: access_place_desc={:?}", access_place_desc);
82
83 match the_place_err {
84 PlaceRef { local, projection: [] } => {
85 item_msg = access_place_desc;
86 if access_place.as_local().is_some() {
87 reason = ", as it is not declared as mutable".to_string();
88 } else {
89 let name = self.local_name(local).expect("immutable unnamed local");
90 reason = ::alloc::__export::must_use({
::alloc::fmt::format(format_args!(", as `{0}` is not declared as mutable",
name))
})format!(", as `{name}` is not declared as mutable");
91 }
92 }
93
94 PlaceRef {
95 local,
96 projection: [proj_base @ .., ProjectionElem::Field(upvar_index, _)],
97 } => {
98 if true {
if !is_closure_like(Place::ty_from(local, proj_base, self.body,
self.infcx.tcx).ty) {
::core::panicking::panic("assertion failed: is_closure_like(Place::ty_from(local, proj_base, self.body,\n self.infcx.tcx).ty)")
};
};debug_assert!(is_closure_like(
99 Place::ty_from(local, proj_base, self.body, self.infcx.tcx).ty
100 ));
101
102 let imm_borrow_derefed = self.upvars[upvar_index.index()]
103 .place
104 .deref_tys()
105 .any(|ty| #[allow(non_exhaustive_omitted_patterns)] match ty.kind() {
ty::Ref(.., hir::Mutability::Not) => true,
_ => false,
}matches!(ty.kind(), ty::Ref(.., hir::Mutability::Not)));
106
107 if imm_borrow_derefed {
114 return;
116 } else {
117 item_msg = access_place_desc;
118 if self.is_upvar_field_projection(access_place.as_ref()).is_some() {
119 reason = ", as it is not declared as mutable".to_string();
120 } else {
121 let name = self.upvars[upvar_index.index()].to_string(self.infcx.tcx);
122 reason = ::alloc::__export::must_use({
::alloc::fmt::format(format_args!(", as `{0}` is not declared as mutable",
name))
})format!(", as `{name}` is not declared as mutable");
123 }
124 }
125 }
126
127 PlaceRef { local, projection: [ProjectionElem::Deref] }
128 if self.body.local_decls[local].is_ref_for_guard() =>
129 {
130 item_msg = access_place_desc;
131 reason = ", as it is immutable for the pattern guard".to_string();
132 }
133 PlaceRef { local, projection: [ProjectionElem::Deref] }
134 if self.body.local_decls[local].is_ref_to_static() =>
135 {
136 if access_place.projection.len() == 1 {
137 item_msg = ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("immutable static item {0}",
access_place_desc))
})format!("immutable static item {access_place_desc}");
138 reason = String::new();
139 } else {
140 item_msg = access_place_desc;
141 let local_info = self.body.local_decls[local].local_info();
142 let LocalInfo::StaticRef { def_id, .. } = *local_info else {
143 ::rustc_middle::util::bug::bug_fmt(format_args!("is_ref_to_static return true, but not ref to static?"));bug!("is_ref_to_static return true, but not ref to static?");
144 };
145 let static_name = &self.infcx.tcx.item_name(def_id);
146 reason = ::alloc::__export::must_use({
::alloc::fmt::format(format_args!(", as `{0}` is an immutable static item",
static_name))
})format!(", as `{static_name}` is an immutable static item");
147 }
148 }
149 PlaceRef { local, projection: [proj_base @ .., ProjectionElem::Deref] } => {
150 if local == ty::CAPTURE_STRUCT_LOCAL
151 && proj_base.is_empty()
152 && !self.upvars.is_empty()
153 {
154 item_msg = access_place_desc;
155 if true {
if !self.body.local_decls[ty::CAPTURE_STRUCT_LOCAL].ty.is_ref() {
::core::panicking::panic("assertion failed: self.body.local_decls[ty::CAPTURE_STRUCT_LOCAL].ty.is_ref()")
};
};debug_assert!(self.body.local_decls[ty::CAPTURE_STRUCT_LOCAL].ty.is_ref());
156 if true {
if !is_closure_like(the_place_err.ty(self.body, self.infcx.tcx).ty) {
::core::panicking::panic("assertion failed: is_closure_like(the_place_err.ty(self.body, self.infcx.tcx).ty)")
};
};debug_assert!(is_closure_like(the_place_err.ty(self.body, self.infcx.tcx).ty));
157
158 reason = if self.is_upvar_field_projection(access_place.as_ref()).is_some() {
159 ", as it is a captured variable in a `Fn` closure".to_string()
160 } else {
161 ", as `Fn` closures cannot mutate their captured variables".to_string()
162 }
163 } else {
164 let source =
165 self.borrowed_content_source(PlaceRef { local, projection: proj_base });
166 let pointer_type = source.describe_for_immutable_place(self.infcx.tcx);
167 opt_source = Some(source);
168 if let Some(desc) = self.describe_place(access_place.as_ref()) {
169 item_msg = ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("`{0}`", desc))
})format!("`{desc}`");
170 reason = match error_access {
171 AccessKind::Mutate => ::alloc::__export::must_use({
::alloc::fmt::format(format_args!(", which is behind {0}",
pointer_type))
})format!(", which is behind {pointer_type}"),
172 AccessKind::MutableBorrow => {
173 ::alloc::__export::must_use({
::alloc::fmt::format(format_args!(", as it is behind {0}",
pointer_type))
})format!(", as it is behind {pointer_type}")
174 }
175 }
176 } else {
177 item_msg = ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("data in {0}", pointer_type))
})format!("data in {pointer_type}");
178 reason = String::new();
179 }
180 }
181 }
182
183 PlaceRef {
184 local: _,
185 projection:
186 [
187 ..,
188 ProjectionElem::Index(_)
189 | ProjectionElem::ConstantIndex { .. }
190 | ProjectionElem::OpaqueCast { .. }
191 | ProjectionElem::Subslice { .. }
192 | ProjectionElem::Downcast(..)
193 | ProjectionElem::UnwrapUnsafeBinder(_),
194 ],
195 } => ::rustc_middle::util::bug::bug_fmt(format_args!("Unexpected immutable place."))bug!("Unexpected immutable place."),
196 }
197
198 {
use ::tracing::__macro_support::Callsite as _;
static __CALLSITE: ::tracing::callsite::DefaultCallsite =
{
static META: ::tracing::Metadata<'static> =
{
::tracing_core::metadata::Metadata::new("event compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs:198",
"rustc_borrowck::diagnostics::mutability_errors",
::tracing::Level::DEBUG,
::tracing_core::__macro_support::Option::Some("compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs"),
::tracing_core::__macro_support::Option::Some(198u32),
::tracing_core::__macro_support::Option::Some("rustc_borrowck::diagnostics::mutability_errors"),
::tracing_core::field::FieldSet::new(&["message"],
::tracing_core::callsite::Identifier(&__CALLSITE)),
::tracing::metadata::Kind::EVENT)
};
::tracing::callsite::DefaultCallsite::new(&META)
};
let enabled =
::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL
&&
::tracing::Level::DEBUG <=
::tracing::level_filters::LevelFilter::current() &&
{
let interest = __CALLSITE.interest();
!interest.is_never() &&
::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
interest)
};
if enabled {
(|value_set: ::tracing::field::ValueSet|
{
let meta = __CALLSITE.metadata();
::tracing::Event::dispatch(meta, &value_set);
;
})({
#[allow(unused_imports)]
use ::tracing::field::{debug, display, Value};
let mut iter = __CALLSITE.metadata().fields().iter();
__CALLSITE.metadata().fields().value_set(&[(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
::tracing::__macro_support::Option::Some(&format_args!("report_mutability_error: item_msg={0:?}, reason={1:?}",
item_msg, reason) as &dyn Value))])
});
} else { ; }
};debug!("report_mutability_error: item_msg={:?}, reason={:?}", item_msg, reason);
199
200 let act;
203 let acted_on;
204 let mut suggest = true;
205 let mut mut_error = None;
206 let mut count = 1;
207
208 let span = match error_access {
209 AccessKind::Mutate => {
210 err = self.cannot_assign(span, &(item_msg + &reason));
211 act = "assign";
212 acted_on = "written to";
213 span
214 }
215 AccessKind::MutableBorrow => {
216 act = "borrow as mutable";
217 acted_on = "borrowed as mutable";
218
219 let borrow_spans = self.borrow_spans(span, location);
220 let borrow_span = borrow_spans.args_or_use();
221 match the_place_err {
222 PlaceRef { local, projection: [] }
223 if self.body.local_decls[local].can_be_made_mutable() =>
224 {
225 let span = self.body.local_decls[local].source_info.span;
226 mut_error = Some(span);
227 if let Some((buffered_err, c)) = self.get_buffered_mut_error(span) {
228 err = buffered_err;
233 count = c + 1;
234 if count == 2 {
235 err.replace_span_with(span, false);
236 err.span_label(span, "not mutable");
237 }
238 suggest = false;
239 } else {
240 err = self.cannot_borrow_path_as_mutable_because(
241 borrow_span,
242 &item_msg,
243 &reason,
244 );
245 }
246 }
247 _ => {
248 err = self.cannot_borrow_path_as_mutable_because(
249 borrow_span,
250 &item_msg,
251 &reason,
252 );
253 }
254 }
255 if suggest {
256 borrow_spans.var_subdiag(
257 &mut err,
258 Some(mir::BorrowKind::Mut { kind: mir::MutBorrowKind::Default }),
259 |_kind, var_span| {
260 let place = self.describe_any_place(access_place.as_ref());
261 session_diagnostics::CaptureVarCause::MutableBorrowUsePlaceClosure {
262 place,
263 var_span,
264 }
265 },
266 );
267 }
268 borrow_span
269 }
270 };
271
272 {
use ::tracing::__macro_support::Callsite as _;
static __CALLSITE: ::tracing::callsite::DefaultCallsite =
{
static META: ::tracing::Metadata<'static> =
{
::tracing_core::metadata::Metadata::new("event compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs:272",
"rustc_borrowck::diagnostics::mutability_errors",
::tracing::Level::DEBUG,
::tracing_core::__macro_support::Option::Some("compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs"),
::tracing_core::__macro_support::Option::Some(272u32),
::tracing_core::__macro_support::Option::Some("rustc_borrowck::diagnostics::mutability_errors"),
::tracing_core::field::FieldSet::new(&["message"],
::tracing_core::callsite::Identifier(&__CALLSITE)),
::tracing::metadata::Kind::EVENT)
};
::tracing::callsite::DefaultCallsite::new(&META)
};
let enabled =
::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL
&&
::tracing::Level::DEBUG <=
::tracing::level_filters::LevelFilter::current() &&
{
let interest = __CALLSITE.interest();
!interest.is_never() &&
::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
interest)
};
if enabled {
(|value_set: ::tracing::field::ValueSet|
{
let meta = __CALLSITE.metadata();
::tracing::Event::dispatch(meta, &value_set);
;
})({
#[allow(unused_imports)]
use ::tracing::field::{debug, display, Value};
let mut iter = __CALLSITE.metadata().fields().iter();
__CALLSITE.metadata().fields().value_set(&[(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
::tracing::__macro_support::Option::Some(&format_args!("report_mutability_error: act={0:?}, acted_on={1:?}",
act, acted_on) as &dyn Value))])
});
} else { ; }
};debug!("report_mutability_error: act={:?}, acted_on={:?}", act, acted_on);
273
274 match the_place_err {
275 PlaceRef {
282 local,
283 projection:
284 [
285 proj_base @ ..,
286 ProjectionElem::Deref,
287 ProjectionElem::Field(field, _),
288 ProjectionElem::Deref,
289 ],
290 } => {
291 err.span_label(span, ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("cannot {0}", act))
})format!("cannot {act}"));
292
293 let place = Place::ty_from(local, proj_base, self.body, self.infcx.tcx);
294 if let Some(span) = get_mut_span_in_struct_field(self.infcx.tcx, place.ty, *field) {
295 err.span_suggestion_verbose(
296 span,
297 "consider changing this to be mutable",
298 " mut ",
299 Applicability::MaybeIncorrect,
300 );
301 }
302 }
303
304 PlaceRef { local, projection: [] }
306 if self
307 .body
308 .local_decls
309 .get(local)
310 .is_some_and(|l| mut_borrow_of_mutable_ref(l, self.local_name(local))) =>
311 {
312 let decl = &self.body.local_decls[local];
313 err.span_label(span, ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("cannot {0}", act))
})format!("cannot {act}"));
314 if let Some(mir::Statement {
315 source_info,
316 kind:
317 mir::StatementKind::Assign(box (
318 _,
319 mir::Rvalue::Ref(
320 _,
321 mir::BorrowKind::Mut { kind: mir::MutBorrowKind::Default },
322 _,
323 ),
324 )),
325 ..
326 }) = &self.body[location.block].statements.get(location.statement_index)
327 {
328 match *decl.local_info() {
329 LocalInfo::User(BindingForm::Var(mir::VarBindingForm {
330 binding_mode: BindingMode(ByRef::No, Mutability::Not),
331 opt_ty_info: Some(sp),
332 pat_span,
333 ..
334 })) => {
335 if suggest {
336 err.span_note(sp, "the binding is already a mutable borrow");
337 err.span_suggestion_verbose(
338 pat_span.shrink_to_lo(),
339 "consider making the binding mutable if you need to reborrow \
340 multiple times",
341 "mut ".to_string(),
342 Applicability::MaybeIncorrect,
343 );
344 }
345 }
346 _ => {
347 err.span_note(
348 decl.source_info.span,
349 "the binding is already a mutable borrow",
350 );
351 }
352 }
353 if let Ok(snippet) =
354 self.infcx.tcx.sess.source_map().span_to_snippet(source_info.span)
355 {
356 if snippet.starts_with("&mut ") {
357 let mut in_pat_scrutinee = false;
363 let mut is_deref_coerced = false;
364 if let Some(expr) = self.find_expr(source_info.span) {
365 let tcx = self.infcx.tcx;
366 let span = expr.span.source_callsite();
367 for (_, node) in tcx.hir_parent_iter(expr.hir_id) {
368 if let Node::Expr(parent_expr) = node {
369 match parent_expr.kind {
370 ExprKind::Match(scrutinee, ..)
371 if scrutinee
372 .span
373 .source_callsite()
374 .contains(span) =>
375 {
376 in_pat_scrutinee = true;
377 break;
378 }
379 ExprKind::Let(let_expr)
380 if let_expr
381 .init
382 .span
383 .source_callsite()
384 .contains(span) =>
385 {
386 in_pat_scrutinee = true;
387 break;
388 }
389 _ => {}
390 }
391 }
392 }
393
394 let typeck = tcx.typeck(expr.hir_id.owner.def_id);
395 is_deref_coerced =
396 typeck.expr_adjustments(expr).iter().any(|adj| {
397 #[allow(non_exhaustive_omitted_patterns)] match adj.kind {
ty::adjustment::Adjust::Deref(_) => true,
_ => false,
}matches!(adj.kind, ty::adjustment::Adjust::Deref(_))
398 });
399 }
400
401 if in_pat_scrutinee {
402 err.span_suggestion_verbose(
404 source_info
405 .span
406 .with_lo(source_info.span.lo() + BytePos(5))
407 .shrink_to_lo(),
408 "to reborrow the mutable reference, add `*`",
409 "*",
410 Applicability::MaybeIncorrect,
411 );
412 } else if is_deref_coerced {
413 err.span_suggestion_verbose(
416 source_info.span.with_hi(source_info.span.lo() + BytePos(5)),
417 "if there is only one mutable reborrow, remove the `&mut`",
418 "",
419 Applicability::MaybeIncorrect,
420 );
421 }
422 } else {
423 err.span_help(source_info.span, "try removing `&mut` here");
425 }
426 } else {
427 err.span_help(source_info.span, "try removing `&mut` here");
428 }
429 } else if decl.mutability.is_not() {
430 if #[allow(non_exhaustive_omitted_patterns)] match decl.local_info() {
LocalInfo::User(BindingForm::ImplicitSelf(hir::ImplicitSelfKind::RefMut))
=> true,
_ => false,
}matches!(
431 decl.local_info(),
432 LocalInfo::User(BindingForm::ImplicitSelf(hir::ImplicitSelfKind::RefMut))
433 ) {
434 err.note(
435 "as `Self` may be unsized, this call attempts to take `&mut &mut self`",
436 );
437 err.note("however, `&mut self` expands to `self: &mut Self`, therefore `self` cannot be borrowed mutably");
438 } else {
439 err.span_suggestion_verbose(
440 decl.source_info.span.shrink_to_lo(),
441 "consider making the binding mutable",
442 "mut ",
443 Applicability::MachineApplicable,
444 );
445 };
446 }
447 }
448
449 PlaceRef { local, projection: [] }
452 if self.body.local_decls[local].can_be_made_mutable() =>
453 {
454 let local_decl = &self.body.local_decls[local];
459 match (&local_decl.mutability, &Mutability::Not) {
(left_val, right_val) => {
if !(*left_val == *right_val) {
let kind = ::core::panicking::AssertKind::Eq;
::core::panicking::assert_failed(kind, &*left_val, &*right_val,
::core::option::Option::None);
}
}
};assert_eq!(local_decl.mutability, Mutability::Not);
460
461 if count < 10 {
462 err.span_label(span, ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("cannot {0}", act))
})format!("cannot {act}"));
463 }
464 if suggest {
465 self.construct_mut_suggestion_for_local_binding_patterns(&mut err, local);
466 let tcx = self.infcx.tcx;
467 if let ty::Closure(id, _) = *the_place_err.ty(self.body, tcx).ty.kind() {
468 self.show_mutating_upvar(tcx, id.expect_local(), the_place_err, &mut err);
469 }
470 }
471 }
472
473 PlaceRef {
475 local,
476 projection: [proj_base @ .., ProjectionElem::Field(upvar_index, _)],
477 } => {
478 if true {
if !is_closure_like(Place::ty_from(local, proj_base, self.body,
self.infcx.tcx).ty) {
::core::panicking::panic("assertion failed: is_closure_like(Place::ty_from(local, proj_base, self.body,\n self.infcx.tcx).ty)")
};
};debug_assert!(is_closure_like(
479 Place::ty_from(local, proj_base, self.body, self.infcx.tcx).ty
480 ));
481
482 let captured_place = self.upvars[upvar_index.index()];
483
484 err.span_label(span, ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("cannot {0}", act))
})format!("cannot {act}"));
485
486 let upvar_hir_id = captured_place.get_root_variable();
487
488 if let Node::Pat(pat) = self.infcx.tcx.hir_node(upvar_hir_id)
489 && let hir::PatKind::Binding(hir::BindingMode::NONE, _, upvar_ident, _) =
490 pat.kind
491 {
492 if upvar_ident.name == kw::SelfLower {
493 for (_, node) in self.infcx.tcx.hir_parent_iter(upvar_hir_id) {
494 if let Some(fn_decl) = node.fn_decl() {
495 if !#[allow(non_exhaustive_omitted_patterns)] match fn_decl.implicit_self {
hir::ImplicitSelfKind::RefImm | hir::ImplicitSelfKind::RefMut => true,
_ => false,
}matches!(
496 fn_decl.implicit_self,
497 hir::ImplicitSelfKind::RefImm | hir::ImplicitSelfKind::RefMut
498 ) {
499 err.span_suggestion_verbose(
500 upvar_ident.span.shrink_to_lo(),
501 "consider changing this to be mutable",
502 "mut ",
503 Applicability::MachineApplicable,
504 );
505 break;
506 }
507 }
508 }
509 } else {
510 err.span_suggestion_verbose(
511 upvar_ident.span.shrink_to_lo(),
512 "consider changing this to be mutable",
513 "mut ",
514 Applicability::MachineApplicable,
515 );
516 }
517 }
518
519 let tcx = self.infcx.tcx;
520 if let ty::Ref(_, ty, Mutability::Mut) = the_place_err.ty(self.body, tcx).ty.kind()
521 && let ty::Closure(id, _) = *ty.kind()
522 {
523 self.show_mutating_upvar(tcx, id.expect_local(), the_place_err, &mut err);
524 }
525 }
526
527 PlaceRef { local: _, projection: [] }
530 if self
531 .infcx
532 .tcx
533 .sess
534 .source_map()
535 .span_to_snippet(span)
536 .is_ok_and(|snippet| snippet.starts_with("&mut ")) =>
537 {
538 err.span_label(span, ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("cannot {0}", act))
})format!("cannot {act}"));
539 err.span_suggestion_verbose(
540 span.with_hi(span.lo() + BytePos(5)),
541 "try removing `&mut` here",
542 "",
543 Applicability::MaybeIncorrect,
544 );
545 }
546
547 PlaceRef { local, projection: [ProjectionElem::Deref] }
548 if self.body.local_decls[local].is_ref_for_guard() =>
549 {
550 err.span_label(span, ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("cannot {0}", act))
})format!("cannot {act}"));
551 err.note(
552 "variables bound in patterns are immutable until the end of the pattern guard",
553 );
554 }
555
556 PlaceRef { local, projection: [ProjectionElem::Deref] }
562 if self.body.local_decls[local].is_user_variable() =>
563 {
564 let local_decl = &self.body.local_decls[local];
565
566 let (pointer_sigil, pointer_desc) =
567 if local_decl.ty.is_ref() { ("&", "reference") } else { ("*const", "pointer") };
568
569 match self.local_name(local) {
570 Some(name) if !local_decl.from_compiler_desugaring() => {
571 err.span_label(
572 span,
573 ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("`{0}` is a `{1}` {2}, so it cannot be {3}",
name, pointer_sigil, pointer_desc, acted_on))
})format!(
574 "`{name}` is a `{pointer_sigil}` {pointer_desc}, so it cannot be \
575 {acted_on}",
576 ),
577 );
578
579 self.suggest_using_iter_mut(&mut err);
580 self.suggest_make_local_mut(&mut err, local, name);
581 }
582 _ => {
583 err.span_label(
584 span,
585 ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("cannot {0} through `{1}` {2}", act,
pointer_sigil, pointer_desc))
})format!("cannot {act} through `{pointer_sigil}` {pointer_desc}"),
586 );
587 }
588 }
589 }
590
591 PlaceRef { local, projection: [ProjectionElem::Deref] }
592 if local == ty::CAPTURE_STRUCT_LOCAL && !self.upvars.is_empty() =>
593 {
594 self.point_at_binding_outside_closure(&mut err, local, access_place);
595 self.expected_fn_found_fn_mut_call(&mut err, span, act);
596 }
597
598 PlaceRef { local, projection: [.., ProjectionElem::Deref] } => {
599 err.span_label(span, ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("cannot {0}", act))
})format!("cannot {act}"));
600
601 match opt_source {
602 Some(BorrowedContentSource::OverloadedDeref(ty)) => {
603 err.help(::alloc::__export::must_use({
::alloc::fmt::format(format_args!("trait `DerefMut` is required to modify through a dereference, but it is not implemented for `{0}`",
ty))
})format!(
604 "trait `DerefMut` is required to modify through a dereference, \
605 but it is not implemented for `{ty}`",
606 ));
607 }
608 Some(BorrowedContentSource::OverloadedIndex(ty)) => {
609 err.help(::alloc::__export::must_use({
::alloc::fmt::format(format_args!("trait `IndexMut` is required to modify indexed content, but it is not implemented for `{0}`",
ty))
})format!(
610 "trait `IndexMut` is required to modify indexed content, \
611 but it is not implemented for `{ty}`",
612 ));
613 self.suggest_map_index_mut_alternatives(ty, &mut err, span);
614 }
615 _ => {
616 let local = &self.body.local_decls[local];
617 match local.local_info() {
618 LocalInfo::StaticRef { def_id, .. } => {
619 let span = self.infcx.tcx.def_span(def_id);
620 err.span_label(span, ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("this `static` cannot be {0}",
acted_on))
})format!("this `static` cannot be {acted_on}"));
621 }
622 LocalInfo::ConstRef { def_id } => {
623 let span = self.infcx.tcx.def_span(def_id);
624 err.span_label(span, ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("this `const` cannot be {0}",
acted_on))
})format!("this `const` cannot be {acted_on}"));
625 }
626 LocalInfo::BlockTailTemp(_) | LocalInfo::Boring
627 if !local.source_info.span.overlaps(span) =>
628 {
629 err.span_label(
630 local.source_info.span,
631 ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("this cannot be {0}", acted_on))
})format!("this cannot be {acted_on}"),
632 );
633 }
634 _ => {}
635 }
636 }
637 }
638 }
639
640 PlaceRef { local, .. } => {
641 let local = &self.body.local_decls[local];
642 if !local.source_info.span.overlaps(span) {
643 err.span_label(local.source_info.span, ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("this cannot be {0}", acted_on))
})format!("this cannot be {acted_on}"));
644 }
645 err.span_label(span, ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("cannot {0}", act))
})format!("cannot {act}"));
646 }
647 }
648
649 if let Some(span) = mut_error {
650 self.buffer_mut_error(span, err, count);
651 } else {
652 self.buffer_error(err);
653 }
654 }
655
656 fn suggest_map_index_mut_alternatives(&self, ty: Ty<'tcx>, err: &mut Diag<'infcx>, span: Span) {
658 let Some(adt) = ty.ty_adt_def() else { return };
659 let did = adt.did();
660 if self.infcx.tcx.is_diagnostic_item(sym::HashMap, did)
661 || self.infcx.tcx.is_diagnostic_item(sym::BTreeMap, did)
662 {
663 struct SuggestIndexOperatorAlternativeVisitor<'a, 'infcx, 'tcx> {
667 assign_span: Span,
668 err: &'a mut Diag<'infcx>,
669 ty: Ty<'tcx>,
670 suggested: bool,
671 }
672 impl<'a, 'infcx, 'tcx> Visitor<'tcx> for SuggestIndexOperatorAlternativeVisitor<'a, 'infcx, 'tcx> {
673 fn visit_stmt(&mut self, stmt: &'tcx hir::Stmt<'tcx>) {
674 hir::intravisit::walk_stmt(self, stmt);
675 let expr = match stmt.kind {
676 hir::StmtKind::Semi(expr) | hir::StmtKind::Expr(expr) => expr,
677 hir::StmtKind::Let(hir::LetStmt { init: Some(expr), .. }) => expr,
678 _ => {
679 return;
680 }
681 };
682 if let hir::ExprKind::Assign(place, rv, _sp) = expr.kind
683 && let hir::ExprKind::Index(val, index, _) = place.kind
684 && (expr.span == self.assign_span || place.span == self.assign_span)
685 {
686 self.err.multipart_suggestions(
689 ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("use `.insert()` to insert a value into a `{0}`, `.get_mut()` to modify it, or the entry API for more flexibility",
self.ty))
})format!(
690 "use `.insert()` to insert a value into a `{}`, `.get_mut()` \
691 to modify it, or the entry API for more flexibility",
692 self.ty,
693 ),
694 <[_]>::into_vec(::alloc::boxed::box_new([<[_]>::into_vec(::alloc::boxed::box_new([(val.span.shrink_to_hi().with_hi(index.span.lo()),
".insert(".to_string()),
(index.span.shrink_to_hi().with_hi(rv.span.lo()),
", ".to_string()),
(rv.span.shrink_to_hi(), ")".to_string())])),
<[_]>::into_vec(::alloc::boxed::box_new([(val.span.shrink_to_lo(),
"if let Some(val) = ".to_string()),
(val.span.shrink_to_hi().with_hi(index.span.lo()),
".get_mut(".to_string()),
(index.span.shrink_to_hi().with_hi(place.span.hi()),
") { *val".to_string()),
(rv.span.shrink_to_hi(), "; }".to_string())])),
<[_]>::into_vec(::alloc::boxed::box_new([(val.span.shrink_to_lo(),
"let val = ".to_string()),
(val.span.shrink_to_hi().with_hi(index.span.lo()),
".entry(".to_string()),
(index.span.shrink_to_hi().with_hi(rv.span.lo()),
").or_insert(".to_string()),
(rv.span.shrink_to_hi(), ")".to_string())]))]))vec![
695 vec![
696 (
698 val.span.shrink_to_hi().with_hi(index.span.lo()),
699 ".insert(".to_string(),
700 ),
701 (
702 index.span.shrink_to_hi().with_hi(rv.span.lo()),
703 ", ".to_string(),
704 ),
705 (rv.span.shrink_to_hi(), ")".to_string()),
706 ],
707 vec![
708 (val.span.shrink_to_lo(), "if let Some(val) = ".to_string()),
710 (
711 val.span.shrink_to_hi().with_hi(index.span.lo()),
712 ".get_mut(".to_string(),
713 ),
714 (
715 index.span.shrink_to_hi().with_hi(place.span.hi()),
716 ") { *val".to_string(),
717 ),
718 (rv.span.shrink_to_hi(), "; }".to_string()),
719 ],
720 vec![
721 (val.span.shrink_to_lo(), "let val = ".to_string()),
723 (
724 val.span.shrink_to_hi().with_hi(index.span.lo()),
725 ".entry(".to_string(),
726 ),
727 (
728 index.span.shrink_to_hi().with_hi(rv.span.lo()),
729 ").or_insert(".to_string(),
730 ),
731 (rv.span.shrink_to_hi(), ")".to_string()),
732 ],
733 ],
734 Applicability::MachineApplicable,
735 );
736 self.suggested = true;
737 } else if let hir::ExprKind::MethodCall(_path, receiver, _, sp) = expr.kind
738 && let hir::ExprKind::Index(val, index, _) = receiver.kind
739 && receiver.span == self.assign_span
740 {
741 self.err.multipart_suggestion(
743 ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("to modify a `{0}` use `.get_mut()`",
self.ty))
})format!("to modify a `{}` use `.get_mut()`", self.ty),
744 <[_]>::into_vec(::alloc::boxed::box_new([(val.span.shrink_to_lo(),
"if let Some(val) = ".to_string()),
(val.span.shrink_to_hi().with_hi(index.span.lo()),
".get_mut(".to_string()),
(index.span.shrink_to_hi().with_hi(receiver.span.hi()),
") { val".to_string()),
(sp.shrink_to_hi(), "; }".to_string())]))vec![
745 (val.span.shrink_to_lo(), "if let Some(val) = ".to_string()),
746 (
747 val.span.shrink_to_hi().with_hi(index.span.lo()),
748 ".get_mut(".to_string(),
749 ),
750 (
751 index.span.shrink_to_hi().with_hi(receiver.span.hi()),
752 ") { val".to_string(),
753 ),
754 (sp.shrink_to_hi(), "; }".to_string()),
755 ],
756 Applicability::MachineApplicable,
757 );
758 self.suggested = true;
759 }
760 }
761 }
762 let def_id = self.body.source.def_id();
763 let Some(local_def_id) = def_id.as_local() else { return };
764 let Some(body) = self.infcx.tcx.hir_maybe_body_owned_by(local_def_id) else { return };
765
766 let mut v = SuggestIndexOperatorAlternativeVisitor {
767 assign_span: span,
768 err,
769 ty,
770 suggested: false,
771 };
772 v.visit_body(&body);
773 if !v.suggested {
774 err.help(::alloc::__export::must_use({
::alloc::fmt::format(format_args!("to modify a `{0}`, use `.get_mut()`, `.insert()` or the entry API",
ty))
})format!(
775 "to modify a `{ty}`, use `.get_mut()`, `.insert()` or the entry API",
776 ));
777 }
778 }
779 }
780
781 fn is_error_in_trait(&self, local: Local) -> (bool, bool, Option<Span>) {
791 let tcx = self.infcx.tcx;
792 if self.body.local_kind(local) != LocalKind::Arg {
793 return (false, false, None);
794 }
795 let my_def = self.body.source.def_id();
796 let Some(td) = tcx.trait_impl_of_assoc(my_def).map(|id| self.infcx.tcx.impl_trait_id(id))
797 else {
798 return (false, false, None);
799 };
800
801 let implemented_trait_item = self.infcx.tcx.trait_item_of(my_def);
802
803 (
804 true,
805 td.is_local(),
806 implemented_trait_item.and_then(|f_in_trait| {
807 let f_in_trait = f_in_trait.as_local()?;
808 if let Node::TraitItem(ti) = self.infcx.tcx.hir_node_by_def_id(f_in_trait)
809 && let hir::TraitItemKind::Fn(sig, _) = ti.kind
810 && let Some(ty) = sig.decl.inputs.get(local.index() - 1)
811 && let hir::TyKind::Ref(_, mut_ty) = ty.kind
812 && let hir::Mutability::Not = mut_ty.mutbl
813 && sig.decl.implicit_self.has_implicit_self()
814 {
815 Some(ty.span)
816 } else {
817 None
818 }
819 }),
820 )
821 }
822
823 fn construct_mut_suggestion_for_local_binding_patterns(
824 &self,
825 err: &mut Diag<'_>,
826 local: Local,
827 ) {
828 let local_decl = &self.body.local_decls[local];
829 {
use ::tracing::__macro_support::Callsite as _;
static __CALLSITE: ::tracing::callsite::DefaultCallsite =
{
static META: ::tracing::Metadata<'static> =
{
::tracing_core::metadata::Metadata::new("event compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs:829",
"rustc_borrowck::diagnostics::mutability_errors",
::tracing::Level::DEBUG,
::tracing_core::__macro_support::Option::Some("compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs"),
::tracing_core::__macro_support::Option::Some(829u32),
::tracing_core::__macro_support::Option::Some("rustc_borrowck::diagnostics::mutability_errors"),
::tracing_core::field::FieldSet::new(&["message"],
::tracing_core::callsite::Identifier(&__CALLSITE)),
::tracing::metadata::Kind::EVENT)
};
::tracing::callsite::DefaultCallsite::new(&META)
};
let enabled =
::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL
&&
::tracing::Level::DEBUG <=
::tracing::level_filters::LevelFilter::current() &&
{
let interest = __CALLSITE.interest();
!interest.is_never() &&
::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
interest)
};
if enabled {
(|value_set: ::tracing::field::ValueSet|
{
let meta = __CALLSITE.metadata();
::tracing::Event::dispatch(meta, &value_set);
;
})({
#[allow(unused_imports)]
use ::tracing::field::{debug, display, Value};
let mut iter = __CALLSITE.metadata().fields().iter();
__CALLSITE.metadata().fields().value_set(&[(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
::tracing::__macro_support::Option::Some(&format_args!("local_decl: {0:?}",
local_decl) as &dyn Value))])
});
} else { ; }
};debug!("local_decl: {:?}", local_decl);
830 let pat_span = match *local_decl.local_info() {
831 LocalInfo::User(BindingForm::Var(mir::VarBindingForm {
832 binding_mode: BindingMode(ByRef::No, Mutability::Not),
833 opt_ty_info: _,
834 opt_match_place: _,
835 pat_span,
836 introductions: _,
837 })) => pat_span,
838 _ => local_decl.source_info.span,
839 };
840
841 let def_id = self.body.source.def_id();
848 if let Some(local_def_id) = def_id.as_local()
849 && let Some(body) = self.infcx.tcx.hir_maybe_body_owned_by(local_def_id)
850 && let Some(hir_id) = (BindingFinder { span: pat_span }).visit_body(&body).break_value()
851 && let node = self.infcx.tcx.hir_node(hir_id)
852 && let hir::Node::LetStmt(hir::LetStmt {
853 pat: hir::Pat { kind: hir::PatKind::Ref(_, _, _), .. },
854 ..
855 })
856 | hir::Node::Param(Param {
857 pat: hir::Pat { kind: hir::PatKind::Ref(_, _, _), .. },
858 ..
859 }) = node
860 {
861 err.multipart_suggestion(
862 "consider changing this to be mutable",
863 <[_]>::into_vec(::alloc::boxed::box_new([(pat_span.until(local_decl.source_info.span),
"&(mut ".to_string()),
(local_decl.source_info.span.shrink_to_hi().with_hi(pat_span.hi()),
")".to_string())]))vec![
864 (pat_span.until(local_decl.source_info.span), "&(mut ".to_string()),
865 (
866 local_decl.source_info.span.shrink_to_hi().with_hi(pat_span.hi()),
867 ")".to_string(),
868 ),
869 ],
870 Applicability::MachineApplicable,
871 );
872 return;
873 }
874
875 err.span_suggestion_verbose(
876 local_decl.source_info.span.shrink_to_lo(),
877 "consider changing this to be mutable",
878 "mut ",
879 Applicability::MachineApplicable,
880 );
881 }
882
883 fn show_mutating_upvar(
885 &self,
886 tcx: TyCtxt<'_>,
887 closure_local_def_id: hir::def_id::LocalDefId,
888 the_place_err: PlaceRef<'tcx>,
889 err: &mut Diag<'_>,
890 ) {
891 let tables = tcx.typeck(closure_local_def_id);
892 if let Some((span, closure_kind_origin)) = tcx.closure_kind_origin(closure_local_def_id) {
893 let reason = if let PlaceBase::Upvar(upvar_id) = closure_kind_origin.base {
894 let upvar = ty::place_to_string_for_capture(tcx, closure_kind_origin);
895 let root_hir_id = upvar_id.var_path.hir_id;
896 let captured_places =
899 tables.closure_min_captures[&closure_local_def_id].get(&root_hir_id).unwrap();
900
901 let origin_projection = closure_kind_origin
902 .projections
903 .iter()
904 .map(|proj| proj.kind)
905 .collect::<Vec<_>>();
906 let mut capture_reason = String::new();
907 for captured_place in captured_places {
908 let captured_place_kinds = captured_place
909 .place
910 .projections
911 .iter()
912 .map(|proj| proj.kind)
913 .collect::<Vec<_>>();
914 if rustc_middle::ty::is_ancestor_or_same_capture(
915 &captured_place_kinds,
916 &origin_projection,
917 ) {
918 match captured_place.info.capture_kind {
919 ty::UpvarCapture::ByRef(
920 ty::BorrowKind::Mutable | ty::BorrowKind::UniqueImmutable,
921 ) => {
922 capture_reason = ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("mutable borrow of `{0}`", upvar))
})format!("mutable borrow of `{upvar}`");
923 }
924 ty::UpvarCapture::ByValue | ty::UpvarCapture::ByUse => {
925 capture_reason = ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("possible mutation of `{0}`",
upvar))
})format!("possible mutation of `{upvar}`");
926 }
927 _ => ::rustc_middle::util::bug::bug_fmt(format_args!("upvar `{0}` borrowed, but not mutably",
upvar))bug!("upvar `{upvar}` borrowed, but not mutably"),
928 }
929 break;
930 }
931 }
932 if capture_reason.is_empty() {
933 ::rustc_middle::util::bug::bug_fmt(format_args!("upvar `{0}` borrowed, but cannot find reason",
upvar));bug!("upvar `{upvar}` borrowed, but cannot find reason");
934 }
935 capture_reason
936 } else {
937 ::rustc_middle::util::bug::bug_fmt(format_args!("not an upvar"))bug!("not an upvar")
938 };
939 if let Some(place_name) = self.describe_place(the_place_err) {
945 err.span_label(
946 *span,
947 ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("calling `{0}` requires mutable binding due to {1}",
place_name, reason))
})format!("calling `{place_name}` requires mutable binding due to {reason}"),
948 );
949 } else if span.from_expansion() {
950 err.span_label(
951 *span,
952 ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("a call in this macro requires a mutable binding due to {0}",
reason))
})format!("a call in this macro requires a mutable binding due to {reason}",),
953 );
954 }
955 }
956 }
957
958 fn suggest_similar_mut_method_for_for_loop(&self, err: &mut Diag<'_>, span: Span) {
961 use hir::ExprKind::{AddrOf, Block, Call, MethodCall};
962 use hir::{BorrowKind, Expr};
963
964 let tcx = self.infcx.tcx;
965 struct Finder {
966 span: Span,
967 }
968
969 impl<'tcx> Visitor<'tcx> for Finder {
970 type Result = ControlFlow<&'tcx Expr<'tcx>>;
971 fn visit_expr(&mut self, e: &'tcx hir::Expr<'tcx>) -> Self::Result {
972 if e.span == self.span {
973 ControlFlow::Break(e)
974 } else {
975 hir::intravisit::walk_expr(self, e)
976 }
977 }
978 }
979 if let Some(body) = tcx.hir_maybe_body_owned_by(self.mir_def_id())
980 && let Block(block, _) = body.value.kind
981 {
982 if let ControlFlow::Break(expr) = (Finder { span }).visit_block(block)
986 && let Call(_, [expr]) = expr.kind
987 {
988 match expr.kind {
989 MethodCall(path_segment, _, _, span) => {
990 let opt_suggestions = tcx
993 .typeck(path_segment.hir_id.owner.def_id)
994 .type_dependent_def_id(expr.hir_id)
995 .and_then(|def_id| tcx.impl_of_assoc(def_id))
996 .map(|def_id| tcx.associated_items(def_id))
997 .map(|assoc_items| {
998 assoc_items
999 .in_definition_order()
1000 .map(|assoc_item_def| assoc_item_def.ident(tcx))
1001 .filter(|&ident| {
1002 let original_method_ident = path_segment.ident;
1003 original_method_ident != ident
1004 && ident.as_str().starts_with(
1005 &original_method_ident.name.to_string(),
1006 )
1007 })
1008 .map(|ident| ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("{0}()", ident))
})format!("{ident}()"))
1009 .peekable()
1010 });
1011
1012 if let Some(mut suggestions) = opt_suggestions
1013 && suggestions.peek().is_some()
1014 {
1015 err.span_suggestions(
1016 span,
1017 "use mutable method",
1018 suggestions,
1019 Applicability::MaybeIncorrect,
1020 );
1021 }
1022 }
1023 AddrOf(BorrowKind::Ref, Mutability::Not, expr) => {
1024 err.span_suggestion_verbose(
1026 expr.span.shrink_to_lo(),
1027 "use a mutable iterator instead",
1028 "mut ",
1029 Applicability::MachineApplicable,
1030 );
1031 }
1032 _ => {}
1033 }
1034 }
1035 }
1036 }
1037
1038 fn point_at_binding_outside_closure(
1040 &self,
1041 err: &mut Diag<'_>,
1042 local: Local,
1043 access_place: Place<'tcx>,
1044 ) {
1045 let place = access_place.as_ref();
1046 for (index, elem) in place.projection.into_iter().enumerate() {
1047 if let ProjectionElem::Deref = elem {
1048 if index == 0 {
1049 if self.body.local_decls[local].is_ref_for_guard() {
1050 continue;
1051 }
1052 if let LocalInfo::StaticRef { .. } = *self.body.local_decls[local].local_info()
1053 {
1054 continue;
1055 }
1056 }
1057 if let Some(field) = self.is_upvar_field_projection(PlaceRef {
1058 local,
1059 projection: place.projection.split_at(index + 1).0,
1060 }) {
1061 let var_index = field.index();
1062 let upvar = self.upvars[var_index];
1063 if let Some(hir_id) = upvar.info.capture_kind_expr_id {
1064 let node = self.infcx.tcx.hir_node(hir_id);
1065 if let hir::Node::Expr(expr) = node
1066 && let hir::ExprKind::Path(hir::QPath::Resolved(None, path)) = expr.kind
1067 && let hir::def::Res::Local(hir_id) = path.res
1068 && let hir::Node::Pat(pat) = self.infcx.tcx.hir_node(hir_id)
1069 {
1070 let name = upvar.to_string(self.infcx.tcx);
1071 err.span_label(
1072 pat.span,
1073 ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("`{0}` declared here, outside the closure",
name))
})format!("`{name}` declared here, outside the closure"),
1074 );
1075 break;
1076 }
1077 }
1078 }
1079 }
1080 }
1081 }
1082 fn expected_fn_found_fn_mut_call(&self, err: &mut Diag<'_>, sp: Span, act: &str) {
1084 err.span_label(sp, ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("cannot {0}", act))
})format!("cannot {act}"));
1085
1086 let tcx = self.infcx.tcx;
1087 let closure_id = self.mir_hir_id();
1088 let closure_span = tcx.def_span(self.mir_def_id());
1089 let fn_call_id = tcx.parent_hir_id(closure_id);
1090 let node = tcx.hir_node(fn_call_id);
1091 let def_id = tcx.hir_enclosing_body_owner(fn_call_id);
1092 let mut look_at_return = true;
1093
1094 err.span_label(closure_span, "in this closure");
1095 let get_call_details = || {
1098 let hir::Node::Expr(hir::Expr { hir_id, kind, .. }) = node else {
1099 return None;
1100 };
1101
1102 let typeck_results = tcx.typeck(def_id);
1103
1104 match kind {
1105 hir::ExprKind::Call(expr, args) => {
1106 if let Some(ty::FnDef(def_id, _)) =
1107 typeck_results.node_type_opt(expr.hir_id).as_ref().map(|ty| ty.kind())
1108 {
1109 Some((*def_id, expr.span, *args))
1110 } else {
1111 None
1112 }
1113 }
1114 hir::ExprKind::MethodCall(_, _, args, span) => typeck_results
1115 .type_dependent_def_id(*hir_id)
1116 .map(|def_id| (def_id, *span, *args)),
1117 _ => None,
1118 }
1119 };
1120
1121 if let Some((callee_def_id, call_span, call_args)) = get_call_details() {
1124 let arg_pos = call_args
1125 .iter()
1126 .enumerate()
1127 .filter(|(_, arg)| arg.hir_id == closure_id)
1128 .map(|(pos, _)| pos)
1129 .next();
1130
1131 let arg = match tcx.hir_get_if_local(callee_def_id) {
1132 Some(
1133 hir::Node::Item(hir::Item {
1134 kind: hir::ItemKind::Fn { ident, sig, .. }, ..
1135 })
1136 | hir::Node::TraitItem(hir::TraitItem {
1137 ident,
1138 kind: hir::TraitItemKind::Fn(sig, _),
1139 ..
1140 })
1141 | hir::Node::ImplItem(hir::ImplItem {
1142 ident,
1143 kind: hir::ImplItemKind::Fn(sig, _),
1144 ..
1145 }),
1146 ) => Some(
1147 arg_pos
1148 .and_then(|pos| {
1149 sig.decl.inputs.get(
1150 pos + if sig.decl.implicit_self.has_implicit_self() {
1151 1
1152 } else {
1153 0
1154 },
1155 )
1156 })
1157 .map(|arg| arg.span)
1158 .unwrap_or(ident.span),
1159 ),
1160 _ => None,
1161 };
1162 if let Some(span) = arg {
1163 err.span_label(span, "change this to accept `FnMut` instead of `Fn`");
1164 err.span_label(call_span, "expects `Fn` instead of `FnMut`");
1165 look_at_return = false;
1166 }
1167 }
1168
1169 if look_at_return && tcx.hir_get_fn_id_for_return_block(closure_id).is_some() {
1170 match tcx.hir_node_by_def_id(tcx.hir_get_parent_item(fn_call_id).def_id) {
1173 hir::Node::Item(hir::Item {
1174 kind: hir::ItemKind::Fn { ident, sig, .. }, ..
1175 })
1176 | hir::Node::TraitItem(hir::TraitItem {
1177 ident,
1178 kind: hir::TraitItemKind::Fn(sig, _),
1179 ..
1180 })
1181 | hir::Node::ImplItem(hir::ImplItem {
1182 ident,
1183 kind: hir::ImplItemKind::Fn(sig, _),
1184 ..
1185 }) => {
1186 err.span_label(ident.span, "");
1187 err.span_label(
1188 sig.decl.output.span(),
1189 "change this to return `FnMut` instead of `Fn`",
1190 );
1191 }
1192 _ => {}
1193 }
1194 }
1195 }
1196
1197 fn suggest_using_iter_mut(&self, err: &mut Diag<'_>) {
1198 let source = self.body.source;
1199 if let InstanceKind::Item(def_id) = source.instance
1200 && let Some(Node::Expr(hir::Expr { hir_id, kind, .. })) =
1201 self.infcx.tcx.hir_get_if_local(def_id)
1202 && let ExprKind::Closure(hir::Closure { kind: hir::ClosureKind::Closure, .. }) = kind
1203 && let Node::Expr(expr) = self.infcx.tcx.parent_hir_node(*hir_id)
1204 {
1205 let mut cur_expr = expr;
1206 while let ExprKind::MethodCall(path_segment, recv, _, _) = cur_expr.kind {
1207 if path_segment.ident.name == sym::iter {
1208 let res = self
1210 .infcx
1211 .tcx
1212 .typeck(path_segment.hir_id.owner.def_id)
1213 .type_dependent_def_id(cur_expr.hir_id)
1214 .and_then(|def_id| self.infcx.tcx.impl_of_assoc(def_id))
1215 .map(|def_id| self.infcx.tcx.associated_items(def_id))
1216 .map(|assoc_items| {
1217 assoc_items.filter_by_name_unhygienic(sym::iter_mut).peekable()
1218 });
1219
1220 if let Some(mut res) = res
1221 && res.peek().is_some()
1222 {
1223 err.span_suggestion_verbose(
1224 path_segment.ident.span,
1225 "you may want to use `iter_mut` here",
1226 "iter_mut",
1227 Applicability::MaybeIncorrect,
1228 );
1229 }
1230 break;
1231 } else {
1232 cur_expr = recv;
1233 }
1234 }
1235 }
1236 }
1237
1238 fn suggest_make_local_mut(&self, err: &mut Diag<'_>, local: Local, name: Symbol) {
1239 let local_decl = &self.body.local_decls[local];
1240
1241 let (pointer_sigil, pointer_desc) =
1242 if local_decl.ty.is_ref() { ("&", "reference") } else { ("*const", "pointer") };
1243
1244 let (is_trait_sig, is_local, local_trait) = self.is_error_in_trait(local);
1245
1246 if is_trait_sig && !is_local {
1247 err.span_label(
1249 local_decl.source_info.span,
1250 ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("this is an immutable {0}",
pointer_desc))
})format!("this is an immutable {pointer_desc}"),
1251 );
1252 return;
1253 }
1254
1255 if self.is_closure_arg_with_non_locally_decided_type(local) {
1257 return;
1258 }
1259
1260 let decl_span = local_decl.source_info.span;
1261
1262 let (amp_mut_sugg, local_var_ty_info) = match *local_decl.local_info() {
1263 LocalInfo::User(mir::BindingForm::ImplicitSelf(_)) => {
1264 let (span, suggestion) = suggest_ampmut_self(self.infcx.tcx, decl_span);
1265 let additional = local_trait.map(|span| suggest_ampmut_self(self.infcx.tcx, span));
1266 (AmpMutSugg::Type { span, suggestion, additional }, None)
1267 }
1268
1269 LocalInfo::User(mir::BindingForm::Var(mir::VarBindingForm {
1270 binding_mode: BindingMode(ByRef::No, _),
1271 opt_ty_info,
1272 ..
1273 })) => {
1274 let first_assignment = find_assignments(&self.body, local).first().copied();
1276 let first_assignment_stmt = first_assignment
1277 .and_then(|loc| self.body[loc.block].statements.get(loc.statement_index));
1278 {
use ::tracing::__macro_support::Callsite as _;
static __CALLSITE: ::tracing::callsite::DefaultCallsite =
{
static META: ::tracing::Metadata<'static> =
{
::tracing_core::metadata::Metadata::new("event compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs:1278",
"rustc_borrowck::diagnostics::mutability_errors",
::tracing::Level::TRACE,
::tracing_core::__macro_support::Option::Some("compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs"),
::tracing_core::__macro_support::Option::Some(1278u32),
::tracing_core::__macro_support::Option::Some("rustc_borrowck::diagnostics::mutability_errors"),
::tracing_core::field::FieldSet::new(&["first_assignment_stmt"],
::tracing_core::callsite::Identifier(&__CALLSITE)),
::tracing::metadata::Kind::EVENT)
};
::tracing::callsite::DefaultCallsite::new(&META)
};
let enabled =
::tracing::Level::TRACE <= ::tracing::level_filters::STATIC_MAX_LEVEL
&&
::tracing::Level::TRACE <=
::tracing::level_filters::LevelFilter::current() &&
{
let interest = __CALLSITE.interest();
!interest.is_never() &&
::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
interest)
};
if enabled {
(|value_set: ::tracing::field::ValueSet|
{
let meta = __CALLSITE.metadata();
::tracing::Event::dispatch(meta, &value_set);
;
})({
#[allow(unused_imports)]
use ::tracing::field::{debug, display, Value};
let mut iter = __CALLSITE.metadata().fields().iter();
__CALLSITE.metadata().fields().value_set(&[(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
::tracing::__macro_support::Option::Some(&debug(&first_assignment_stmt)
as &dyn Value))])
});
} else { ; }
};trace!(?first_assignment_stmt);
1279 let opt_assignment_rhs_span =
1280 first_assignment.map(|loc| self.body.source_info(loc).span);
1281 let mut source_span = opt_assignment_rhs_span;
1282 if let Some(mir::Statement {
1283 source_info: _,
1284 kind:
1285 mir::StatementKind::Assign(box (_, mir::Rvalue::Use(mir::Operand::Copy(place)))),
1286 ..
1287 }) = first_assignment_stmt
1288 {
1289 let local_span = self.body.local_decls[place.local].source_info.span;
1290 source_span = Some(local_span);
1293 if let Some(DesugaringKind::ForLoop) = local_span.desugaring_kind() {
1294 self.suggest_similar_mut_method_for_for_loop(err, local_span);
1296 err.span_label(
1297 local_span,
1298 ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("this iterator yields `{0}` {1}s",
pointer_sigil, pointer_desc))
})format!("this iterator yields `{pointer_sigil}` {pointer_desc}s",),
1299 );
1300 return;
1301 }
1302 }
1303
1304 if source_span.is_some_and(|s| {
1306 s.desugaring_kind().is_some() || self.infcx.tcx.sess.source_map().is_imported(s)
1307 }) {
1308 return;
1309 }
1310
1311 if name == kw::SelfLower && opt_ty_info.is_none() {
1313 let (span, suggestion) = suggest_ampmut_self(self.infcx.tcx, decl_span);
1314 (AmpMutSugg::Type { span, suggestion, additional: None }, None)
1315 } else if let Some(sugg) =
1316 suggest_ampmut(self.infcx, self.body(), first_assignment_stmt)
1317 {
1318 (sugg, opt_ty_info)
1319 } else {
1320 return;
1321 }
1322 }
1323
1324 LocalInfo::User(mir::BindingForm::Var(mir::VarBindingForm {
1325 binding_mode: BindingMode(ByRef::Yes(..), _),
1326 ..
1327 })) => {
1328 let pattern_span: Span = local_decl.source_info.span;
1329 let Some(span) = suggest_ref_mut(self.infcx.tcx, pattern_span) else {
1330 return;
1331 };
1332 (AmpMutSugg::Type { span, suggestion: "mut ".to_owned(), additional: None }, None)
1333 }
1334
1335 _ => ::core::panicking::panic("internal error: entered unreachable code")unreachable!(),
1336 };
1337
1338 let mut suggest = |suggs: Vec<_>, applicability, extra| {
1339 if suggs.iter().any(|(span, _)| self.infcx.tcx.sess.source_map().is_imported(*span)) {
1340 return;
1341 }
1342
1343 err.multipart_suggestion_verbose(
1344 ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("consider changing this to be a mutable {1}{0}{2}",
if is_trait_sig {
" in the `impl` method and the `trait` definition"
} else { "" }, pointer_desc, extra))
})format!(
1345 "consider changing this to be a mutable {pointer_desc}{}{extra}",
1346 if is_trait_sig {
1347 " in the `impl` method and the `trait` definition"
1348 } else {
1349 ""
1350 }
1351 ),
1352 suggs,
1353 applicability,
1354 );
1355 };
1356
1357 let (mut sugg, add_type_annotation_if_not_exists) = match amp_mut_sugg {
1358 AmpMutSugg::Type { span, suggestion, additional } => {
1359 let mut sugg = <[_]>::into_vec(::alloc::boxed::box_new([(span, suggestion)]))vec![(span, suggestion)];
1360 sugg.extend(additional);
1361 suggest(sugg, Applicability::MachineApplicable, "");
1362 return;
1363 }
1364 AmpMutSugg::MapGetMut { span, suggestion } => {
1365 if self.infcx.tcx.sess.source_map().is_imported(span) {
1366 return;
1367 }
1368 err.multipart_suggestion_verbose(
1369 "consider using `get_mut`",
1370 <[_]>::into_vec(::alloc::boxed::box_new([(span, suggestion)]))vec![(span, suggestion)],
1371 Applicability::MaybeIncorrect,
1372 );
1373 return;
1374 }
1375 AmpMutSugg::Expr { span, suggestion } => {
1376 (<[_]>::into_vec(::alloc::boxed::box_new([(span, suggestion)]))vec![(span, suggestion)], false)
1379 }
1380 AmpMutSugg::ChangeBinding => (::alloc::vec::Vec::new()vec![], true),
1381 };
1382
1383 let (binding_exists, span) = match local_var_ty_info {
1385 Some(ty_span) => (true, ty_span),
1389
1390 None => (false, decl_span),
1394 };
1395
1396 if !binding_exists && !add_type_annotation_if_not_exists {
1397 suggest(sugg, Applicability::MachineApplicable, "");
1398 return;
1399 }
1400
1401 let (sugg_span, sugg_str, suggest_now) = if let Ok(src) = self.infcx.tcx.sess.source_map().span_to_snippet(span)
1405 && src.starts_with("&'")
1406 && let Some(ws_pos) = src.find(char::is_whitespace)
1408 {
1409 let span = span.with_lo(span.lo() + BytePos(ws_pos as u32)).shrink_to_lo();
1410 (span, " mut".to_owned(), true)
1411 } else if binding_exists {
1413 let span = span.with_lo(span.lo() + BytePos(1)).shrink_to_lo();
1415 (span, "mut ".to_owned(), true)
1416 } else {
1417 let ty = local_decl.ty.builtin_deref(true).unwrap();
1420
1421 (span, ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("{0}mut {1}",
if local_decl.ty.is_ref() { "&" } else { "*" }, ty))
})format!("{}mut {}", if local_decl.ty.is_ref() { "&" } else { "*" }, ty), false)
1422 };
1423
1424 if suggest_now {
1425 let has_change = !sugg.is_empty();
1427 sugg.push((sugg_span, sugg_str));
1428 suggest(
1429 sugg,
1430 Applicability::MachineApplicable,
1431 if has_change { " and changing the binding's type" } else { "" },
1433 );
1434 return;
1435 } else if !sugg.is_empty() {
1436 suggest(sugg, Applicability::MachineApplicable, "");
1437 return;
1438 }
1439
1440 let def_id = self.body.source.def_id();
1441 let hir_id = if let Some(local_def_id) = def_id.as_local()
1442 && let Some(body) = self.infcx.tcx.hir_maybe_body_owned_by(local_def_id)
1443 {
1444 BindingFinder { span: sugg_span }.visit_body(&body).break_value()
1445 } else {
1446 None
1447 };
1448 let node = hir_id.map(|hir_id| self.infcx.tcx.hir_node(hir_id));
1449
1450 let Some(hir::Node::LetStmt(local)) = node else {
1451 err.span_label(
1452 sugg_span,
1453 ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("consider changing this binding\'s type to be: `{0}`",
sugg_str))
})format!("consider changing this binding's type to be: `{sugg_str}`"),
1454 );
1455 return;
1456 };
1457
1458 let tables = self.infcx.tcx.typeck(def_id.as_local().unwrap());
1459 if let Some(clone_trait) = self.infcx.tcx.lang_items().clone_trait()
1460 && let Some(expr) = local.init
1461 && let ty = tables.node_type_opt(expr.hir_id)
1462 && let Some(ty) = ty
1463 && let ty::Ref(..) = ty.kind()
1464 {
1465 match self
1466 .infcx
1467 .type_implements_trait_shallow(clone_trait, ty.peel_refs(), self.infcx.param_env)
1468 .as_deref()
1469 {
1470 Some([]) => {
1471 }
1480 None => {
1481 if let hir::ExprKind::MethodCall(segment, _rcvr, [], span) = expr.kind
1482 && segment.ident.name == sym::clone
1483 {
1484 err.span_help(
1485 span,
1486 ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("`{0}` doesn\'t implement `Clone`, so this call clones the reference `{1}`",
ty.peel_refs(), ty))
})format!(
1487 "`{}` doesn't implement `Clone`, so this call clones \
1488 the reference `{ty}`",
1489 ty.peel_refs(),
1490 ),
1491 );
1492 }
1493 let trait_ref = ty::Binder::dummy(ty::TraitRef::new(
1495 self.infcx.tcx,
1496 clone_trait,
1497 [ty.peel_refs()],
1498 ));
1499 let obligation = traits::Obligation::new(
1500 self.infcx.tcx,
1501 traits::ObligationCause::dummy(),
1502 self.infcx.param_env,
1503 trait_ref,
1504 );
1505 self.infcx.err_ctxt().suggest_derive(
1506 &obligation,
1507 err,
1508 trait_ref.upcast(self.infcx.tcx),
1509 );
1510 }
1511 Some(errors) => {
1512 if let hir::ExprKind::MethodCall(segment, _rcvr, [], span) = expr.kind
1513 && segment.ident.name == sym::clone
1514 {
1515 err.span_help(
1516 span,
1517 ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("`{0}` doesn\'t implement `Clone` because its implementations trait bounds could not be met, so this call clones the reference `{1}`",
ty.peel_refs(), ty))
})format!(
1518 "`{}` doesn't implement `Clone` because its \
1519 implementations trait bounds could not be met, so \
1520 this call clones the reference `{ty}`",
1521 ty.peel_refs(),
1522 ),
1523 );
1524 err.note(::alloc::__export::must_use({
::alloc::fmt::format(format_args!("the following trait bounds weren\'t met: {0}",
errors.iter().map(|e|
e.obligation.predicate.to_string()).collect::<Vec<_>>().join("\n")))
})format!(
1525 "the following trait bounds weren't met: {}",
1526 errors
1527 .iter()
1528 .map(|e| e.obligation.predicate.to_string())
1529 .collect::<Vec<_>>()
1530 .join("\n"),
1531 ));
1532 }
1533 for error in errors {
1535 if let traits::FulfillmentErrorCode::Select(
1536 traits::SelectionError::Unimplemented,
1537 ) = error.code
1538 && let ty::PredicateKind::Clause(ty::ClauseKind::Trait(pred)) =
1539 error.obligation.predicate.kind().skip_binder()
1540 {
1541 self.infcx.err_ctxt().suggest_derive(
1542 &error.obligation,
1543 err,
1544 error.obligation.predicate.kind().rebind(pred),
1545 );
1546 }
1547 }
1548 }
1549 }
1550 }
1551 let (changing, span, sugg) = match local.ty {
1552 Some(ty) => ("changing", ty.span, sugg_str),
1553 None => ("specifying", local.pat.span.shrink_to_hi(), ::alloc::__export::must_use({
::alloc::fmt::format(format_args!(": {0}", sugg_str))
})format!(": {sugg_str}")),
1554 };
1555 err.span_suggestion_verbose(
1556 span,
1557 ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("consider {0} this binding\'s type",
changing))
})format!("consider {changing} this binding's type"),
1558 sugg,
1559 Applicability::HasPlaceholders,
1560 );
1561 }
1562
1563 fn is_closure_arg_with_non_locally_decided_type(&self, local: Local) -> bool {
1573 if self.body.local_kind(local) != LocalKind::Arg {
1575 return false;
1576 }
1577
1578 let InstanceKind::Item(body_def_id) = self.body.source.instance else {
1580 return false;
1581 };
1582 let Some(Node::Expr(hir::Expr { hir_id: body_hir_id, kind, .. })) =
1583 self.infcx.tcx.hir_get_if_local(body_def_id)
1584 else {
1585 return false;
1586 };
1587 let ExprKind::Closure(hir::Closure { kind: hir::ClosureKind::Closure, .. }) = kind else {
1588 return false;
1589 };
1590
1591 let Node::Expr(closure_parent) = self.infcx.tcx.parent_hir_node(*body_hir_id) else {
1594 return false;
1595 };
1596 match closure_parent.kind {
1597 ExprKind::MethodCall(method, _, _, _) => self
1598 .infcx
1599 .tcx
1600 .typeck(method.hir_id.owner.def_id)
1601 .type_dependent_def_id(closure_parent.hir_id)
1602 .is_some_and(|def_id| !def_id.is_local()),
1603 ExprKind::Call(func, _) => self
1604 .infcx
1605 .tcx
1606 .typeck(func.hir_id.owner.def_id)
1607 .node_type_opt(func.hir_id)
1608 .and_then(|ty| match ty.kind() {
1609 ty::FnDef(def_id, _) => Some(def_id),
1610 _ => None,
1611 })
1612 .is_some_and(|def_id| !def_id.is_local()),
1613 _ => false,
1614 }
1615 }
1616}
1617
1618struct BindingFinder {
1619 span: Span,
1620}
1621
1622impl<'tcx> Visitor<'tcx> for BindingFinder {
1623 type Result = ControlFlow<hir::HirId>;
1624 fn visit_stmt(&mut self, s: &'tcx hir::Stmt<'tcx>) -> Self::Result {
1625 if let hir::StmtKind::Let(local) = s.kind
1626 && local.pat.span == self.span
1627 {
1628 ControlFlow::Break(local.hir_id)
1629 } else {
1630 hir::intravisit::walk_stmt(self, s)
1631 }
1632 }
1633
1634 fn visit_param(&mut self, param: &'tcx hir::Param<'tcx>) -> Self::Result {
1635 if let hir::Pat { kind: hir::PatKind::Ref(_, _, _), span, .. } = param.pat
1636 && *span == self.span
1637 {
1638 ControlFlow::Break(param.hir_id)
1639 } else {
1640 ControlFlow::Continue(())
1641 }
1642 }
1643}
1644
1645fn mut_borrow_of_mutable_ref(local_decl: &LocalDecl<'_>, local_name: Option<Symbol>) -> bool {
1646 {
use ::tracing::__macro_support::Callsite as _;
static __CALLSITE: ::tracing::callsite::DefaultCallsite =
{
static META: ::tracing::Metadata<'static> =
{
::tracing_core::metadata::Metadata::new("event compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs:1646",
"rustc_borrowck::diagnostics::mutability_errors",
::tracing::Level::DEBUG,
::tracing_core::__macro_support::Option::Some("compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs"),
::tracing_core::__macro_support::Option::Some(1646u32),
::tracing_core::__macro_support::Option::Some("rustc_borrowck::diagnostics::mutability_errors"),
::tracing_core::field::FieldSet::new(&["message"],
::tracing_core::callsite::Identifier(&__CALLSITE)),
::tracing::metadata::Kind::EVENT)
};
::tracing::callsite::DefaultCallsite::new(&META)
};
let enabled =
::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL
&&
::tracing::Level::DEBUG <=
::tracing::level_filters::LevelFilter::current() &&
{
let interest = __CALLSITE.interest();
!interest.is_never() &&
::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
interest)
};
if enabled {
(|value_set: ::tracing::field::ValueSet|
{
let meta = __CALLSITE.metadata();
::tracing::Event::dispatch(meta, &value_set);
;
})({
#[allow(unused_imports)]
use ::tracing::field::{debug, display, Value};
let mut iter = __CALLSITE.metadata().fields().iter();
__CALLSITE.metadata().fields().value_set(&[(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
::tracing::__macro_support::Option::Some(&format_args!("local_info: {0:?}, ty.kind(): {1:?}",
local_decl.local_info, local_decl.ty.kind()) as
&dyn Value))])
});
} else { ; }
};debug!("local_info: {:?}, ty.kind(): {:?}", local_decl.local_info, local_decl.ty.kind());
1647
1648 match *local_decl.local_info() {
1649 LocalInfo::User(mir::BindingForm::Var(mir::VarBindingForm {
1651 binding_mode: BindingMode(ByRef::No, Mutability::Not),
1652 ..
1653 })) => #[allow(non_exhaustive_omitted_patterns)] match local_decl.ty.kind() {
ty::Ref(_, _, hir::Mutability::Mut) => true,
_ => false,
}matches!(local_decl.ty.kind(), ty::Ref(_, _, hir::Mutability::Mut)),
1654 LocalInfo::User(mir::BindingForm::ImplicitSelf(kind)) => {
1655 kind == hir::ImplicitSelfKind::RefMut
1661 }
1662 _ if Some(kw::SelfLower) == local_name => {
1663 #[allow(non_exhaustive_omitted_patterns)] match local_decl.ty.kind() {
ty::Ref(_, _, hir::Mutability::Mut) => true,
_ => false,
}matches!(local_decl.ty.kind(), ty::Ref(_, _, hir::Mutability::Mut))
1667 }
1668 _ => false,
1669 }
1670}
1671
1672fn suggest_ampmut_self(tcx: TyCtxt<'_>, span: Span) -> (Span, String) {
1673 match tcx.sess.source_map().span_to_snippet(span) {
1674 Ok(snippet) if snippet.ends_with("self") => {
1675 (span.with_hi(span.hi() - BytePos(4)).shrink_to_hi(), "mut ".to_string())
1676 }
1677 _ => (span, "&mut self".to_string()),
1678 }
1679}
1680
1681enum AmpMutSugg {
1682 Type {
1685 span: Span,
1686 suggestion: String,
1687 additional: Option<(Span, String)>,
1688 },
1689 Expr {
1691 span: Span,
1692 suggestion: String,
1693 },
1694 MapGetMut {
1696 span: Span,
1697 suggestion: String,
1698 },
1699 ChangeBinding,
1700}
1701
1702fn suggest_ampmut<'tcx>(
1718 infcx: &crate::BorrowckInferCtxt<'tcx>,
1719 body: &Body<'tcx>,
1720 opt_assignment_rhs_stmt: Option<&Statement<'tcx>>,
1721) -> Option<AmpMutSugg> {
1722 let tcx = infcx.tcx;
1723 if let Some(rhs_stmt) = opt_assignment_rhs_stmt
1732 && let StatementKind::Assign(box (lhs, rvalue)) = &rhs_stmt.kind
1733 && let mut rhs_span = rhs_stmt.source_info.span
1734 && let Ok(mut rhs_str) = tcx.sess.source_map().span_to_snippet(rhs_span)
1735 {
1736 let mut rvalue = rvalue;
1737
1738 if let Rvalue::Ref(_, BorrowKind::Shared, place) = rvalue
1742 && place.projection.len() == 1
1743 && place.projection[0] == ProjectionElem::Deref
1744 && let Some(assign) = find_assignments(&body, place.local).first()
1745 {
1746 if let Some(user_ty_projs) = body.local_decls[lhs.local].user_ty.as_ref()
1750 && let [user_ty_proj] = user_ty_projs.contents.as_slice()
1751 && user_ty_proj.projs.is_empty()
1752 && let Either::Left(rhs_stmt_new) = body.stmt_at(*assign)
1753 && let StatementKind::Assign(box (_, rvalue_new)) = &rhs_stmt_new.kind
1754 && let rhs_span_new = rhs_stmt_new.source_info.span
1755 && let Ok(rhs_str_new) = tcx.sess.source_map().span_to_snippet(rhs_span_new)
1756 {
1757 (rvalue, rhs_span, rhs_str) = (rvalue_new, rhs_span_new, rhs_str_new);
1758 }
1759
1760 if let Either::Right(call) = body.stmt_at(*assign)
1761 && let TerminatorKind::Call {
1762 func: Operand::Constant(box const_operand), args, ..
1763 } = &call.kind
1764 && let ty::FnDef(method_def_id, method_args) = *const_operand.ty().kind()
1765 && let Some(trait_) = tcx.trait_of_assoc(method_def_id)
1766 && tcx.is_lang_item(trait_, hir::LangItem::Index)
1767 {
1768 let trait_ref = ty::TraitRef::from_assoc(
1769 tcx,
1770 tcx.require_lang_item(hir::LangItem::IndexMut, rhs_span),
1771 method_args,
1772 );
1773 if !infcx
1775 .type_implements_trait(trait_ref.def_id, trait_ref.args, infcx.param_env)
1776 .must_apply_considering_regions()
1777 {
1778 if let ty::Adt(def, _) = trait_ref.self_ty().kind()
1780 && [sym::BTreeMap, sym::HashMap]
1781 .into_iter()
1782 .any(|s| tcx.is_diagnostic_item(s, def.did()))
1783 && let [map, key] = &**args
1784 && let Ok(map) = tcx.sess.source_map().span_to_snippet(map.span)
1785 && let Ok(key) = tcx.sess.source_map().span_to_snippet(key.span)
1786 {
1787 let span = rhs_span;
1788 let suggestion = ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("{0}.get_mut({1}).unwrap()", map,
key))
})format!("{map}.get_mut({key}).unwrap()");
1789 return Some(AmpMutSugg::MapGetMut { span, suggestion });
1790 }
1791 return None;
1792 }
1793 }
1794 }
1795
1796 let sugg = match rvalue {
1797 Rvalue::Ref(_, BorrowKind::Shared, _) if let Some(ref_idx) = rhs_str.find('&') => {
1798 Some((
1800 rhs_span.with_lo(rhs_span.lo() + BytePos(ref_idx as u32 + 1)).shrink_to_lo(),
1801 "mut ".to_owned(),
1802 ))
1803 }
1804 Rvalue::RawPtr(RawPtrKind::Const, _) if let Some(const_idx) = rhs_str.find("const") => {
1805 let const_idx = const_idx as u32;
1807 Some((
1808 rhs_span
1809 .with_lo(rhs_span.lo() + BytePos(const_idx))
1810 .with_hi(rhs_span.lo() + BytePos(const_idx + "const".len() as u32)),
1811 "mut".to_owned(),
1812 ))
1813 }
1814 _ => None,
1815 };
1816
1817 if let Some((span, suggestion)) = sugg {
1818 return Some(AmpMutSugg::Expr { span, suggestion });
1819 }
1820 }
1821
1822 Some(AmpMutSugg::ChangeBinding)
1823}
1824
1825fn is_closure_like(ty: Ty<'_>) -> bool {
1827 ty.is_closure() || ty.is_coroutine() || ty.is_coroutine_closure()
1828}
1829
1830fn get_mut_span_in_struct_field<'tcx>(
1838 tcx: TyCtxt<'tcx>,
1839 ty: Ty<'tcx>,
1840 field: FieldIdx,
1841) -> Option<Span> {
1842 if let ty::Ref(_, ty, _) = ty.kind()
1844 && let ty::Adt(def, _) = ty.kind()
1845 && let field = def.all_fields().nth(field.index())?
1846 && let hir::Node::Field(field) = tcx.hir_node_by_def_id(field.did.as_local()?)
1849 && let hir::TyKind::Ref(lt, hir::MutTy { mutbl: hir::Mutability::Not, ty }) = field.ty.kind
1850 {
1851 return Some(lt.ident.span.between(ty.span));
1852 }
1853
1854 None
1855}
1856
1857fn suggest_ref_mut(tcx: TyCtxt<'_>, span: Span) -> Option<Span> {
1859 let pattern_str = tcx.sess.source_map().span_to_snippet(span).ok()?;
1860 if let Some(rest) = pattern_str.strip_prefix("ref")
1861 && rest.starts_with(rustc_lexer::is_whitespace)
1862 {
1863 let span = span.with_lo(span.lo() + BytePos(4)).shrink_to_lo();
1864 Some(span)
1865 } else {
1866 None
1867 }
1868}