1use core::ops::ControlFlow;
2
3use either::Either;
4use hir::{ExprKind, Param};
5use rustc_abi::FieldIdx;
6use rustc_errors::{Applicability, Diag};
7use rustc_hir::attrs::lang_items::LangItem;
8use rustc_hir::def_id::DefId;
9use rustc_hir::intravisit::Visitor;
10use rustc_hir::{self as hir, BindingMode, ByRef, Expr, Node};
11use rustc_middle::bug;
12use rustc_middle::hir::place::PlaceBase;
13use rustc_middle::mir::visit::PlaceContext;
14use rustc_middle::mir::{
15 self, BindingForm, Body, BorrowKind, Local, LocalDecl, LocalInfo, LocalKind, Location,
16 Mutability, Operand, Place, PlaceRef, ProjectionElem, RawPtrKind, Rvalue, Statement,
17 StatementKind, TerminatorKind,
18};
19use rustc_middle::ty::{self, InstanceKind, Ty, TyCtxt, Upcast};
20use rustc_span::{BytePos, DesugaringKind, Span, Symbol, kw, sym};
21use rustc_trait_selection::error_reporting::InferCtxtErrorExt;
22use rustc_trait_selection::infer::InferCtxtExt;
23use rustc_trait_selection::traits;
24use tracing::{debug, trace};
25
26use crate::diagnostics::BorrowedContentSource;
27use crate::{MirBorrowckCtxt, session_diagnostics};
28
29#[derive(#[automatically_derived]
impl ::core::marker::Copy for AccessKind { }Copy, #[automatically_derived]
#[doc(hidden)]
unsafe impl ::core::clone::TrivialClone for AccessKind { }
#[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_fields_are_eq(&self) {}
}Eq, #[automatically_derived]
impl ::core::marker::StructuralPartialEq for AccessKind { }
#[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)]
30pub(crate) enum AccessKind {
31 MutableBorrow,
32 Mutate,
33}
34
35fn find_assignments(body: &Body<'_>, local: Local) -> Vec<Location> {
38 use rustc_middle::mir::visit::Visitor;
39
40 struct FindLocalAssignmentVisitor {
41 needle: Local,
42 locations: Vec<Location>,
43 }
44
45 impl<'tcx> Visitor<'tcx> for FindLocalAssignmentVisitor {
46 fn visit_local(&mut self, local: Local, place_context: PlaceContext, location: Location) {
47 if self.needle != local {
48 return;
49 }
50
51 if place_context.is_place_assignment() {
52 self.locations.push(location);
53 }
54 }
55 }
56
57 let mut visitor = FindLocalAssignmentVisitor { needle: local, locations: ::alloc::vec::Vec::new()vec![] };
58 visitor.visit_body(body);
59 visitor.locations
60}
61
62impl<'tcx> MirBorrowckCtxt<'_, '_, 'tcx> {
63 pub(crate) fn report_mutability_error(
64 &mut self,
65 access_place: Place<'tcx>,
66 span: Span,
67 the_place_err: PlaceRef<'tcx>,
68 error_access: AccessKind,
69 location: Location,
70 ) {
71 {
use ::tracing::__macro_support::Callsite as _;
static __CALLSITE: ::tracing::callsite::DefaultCallsite =
{
static META: ::tracing::Metadata<'static> =
{
::tracing_core::metadata::Metadata::new("event /rustc-dev/cea272fa356e94bd2ee2cadf376630aa0683867a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs:71",
"rustc_borrowck::diagnostics::mutability_errors",
::tracing::Level::DEBUG,
::tracing_core::__macro_support::Option::Some("/rustc-dev/cea272fa356e94bd2ee2cadf376630aa0683867a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs"),
::tracing_core::__macro_support::Option::Some(71u32),
::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};
__CALLSITE.metadata().fields().value_set_all(&[(::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 ::tracing::field::Value))])
});
} else { ; }
};debug!(
72 "report_mutability_error(\
73 access_place={:?}, span={:?}, the_place_err={:?}, error_access={:?}, location={:?},\
74 )",
75 access_place, span, the_place_err, error_access, location,
76 );
77
78 let mut err;
79 let item_msg;
80 let reason;
81 let mut opt_source = None;
82 let access_place_desc = self.describe_any_place(access_place.as_ref());
83 {
use ::tracing::__macro_support::Callsite as _;
static __CALLSITE: ::tracing::callsite::DefaultCallsite =
{
static META: ::tracing::Metadata<'static> =
{
::tracing_core::metadata::Metadata::new("event /rustc-dev/cea272fa356e94bd2ee2cadf376630aa0683867a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs:83",
"rustc_borrowck::diagnostics::mutability_errors",
::tracing::Level::DEBUG,
::tracing_core::__macro_support::Option::Some("/rustc-dev/cea272fa356e94bd2ee2cadf376630aa0683867a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs"),
::tracing_core::__macro_support::Option::Some(83u32),
::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};
__CALLSITE.metadata().fields().value_set_all(&[(::tracing::__macro_support::Option::Some(&format_args!("report_mutability_error: access_place_desc={0:?}",
access_place_desc) as &dyn ::tracing::field::Value))])
});
} else { ; }
};debug!("report_mutability_error: access_place_desc={:?}", access_place_desc);
84
85 match the_place_err {
86 PlaceRef { local, projection: [] } => {
87 item_msg = access_place_desc;
88 if access_place.as_local().is_some() {
89 reason = ", as it is not declared as mutable".to_string();
90 } else {
91 let name = self.local_name(local).expect("immutable unnamed local");
92 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");
93 }
94 }
95
96 PlaceRef {
97 local,
98 projection: [proj_base @ .., ProjectionElem::Field(upvar_index, _)],
99 } => {
100 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(
101 Place::ty_from(local, proj_base, self.body, self.infcx.tcx).ty
102 ));
103
104 let imm_borrow_derefed = self.upvars[upvar_index.index()]
105 .place
106 .deref_tys()
107 .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)));
108
109 if imm_borrow_derefed {
116 return;
118 } else {
119 item_msg = access_place_desc;
120 if self.is_upvar_field_projection(access_place.as_ref()).is_some() {
121 reason = ", as it is not declared as mutable".to_string();
122 } else {
123 let name = self.upvars[upvar_index.index()].to_string(self.infcx.tcx);
124 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");
125 }
126 }
127 }
128
129 PlaceRef { local, projection: [ProjectionElem::Deref] }
130 if self.body.local_decls[local].is_ref_for_guard() =>
131 {
132 item_msg = access_place_desc;
133 reason = ", as it is immutable for the pattern guard".to_string();
134 }
135 PlaceRef { local, projection: [ProjectionElem::Deref] }
136 if self.body.local_decls[local].is_ref_to_static() =>
137 {
138 if access_place.projection.len() == 1 {
139 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}");
140 reason = String::new();
141 } else {
142 item_msg = access_place_desc;
143 let local_info = self.body.local_decls[local].local_info();
144 let LocalInfo::StaticRef { def_id, .. } = *local_info else {
145 ::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?");
146 };
147 let static_name = &self.infcx.tcx.item_name(def_id);
148 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");
149 }
150 }
151 PlaceRef { local, projection: [proj_base @ .., ProjectionElem::Deref] } => {
152 if local == ty::CAPTURE_STRUCT_LOCAL
153 && proj_base.is_empty()
154 && !self.upvars.is_empty()
155 {
156 item_msg = access_place_desc;
157 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());
158 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));
159
160 reason = if self.is_upvar_field_projection(access_place.as_ref()).is_some() {
161 ", as it is a captured variable in a `Fn` closure".to_string()
162 } else {
163 ", as `Fn` closures cannot mutate their captured variables".to_string()
164 }
165 } else {
166 let source =
167 self.borrowed_content_source(PlaceRef { local, projection: proj_base });
168 let pointer_type = source.describe_for_immutable_place(self.infcx.tcx);
169 opt_source = Some(source);
170 if let Some(desc) = self.describe_place(access_place.as_ref()) {
171 item_msg = ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("`{0}`", desc))
})format!("`{desc}`");
172 reason = match error_access {
173 AccessKind::Mutate => ::alloc::__export::must_use({
::alloc::fmt::format(format_args!(", which is behind {0}",
pointer_type))
})format!(", which is behind {pointer_type}"),
174 AccessKind::MutableBorrow => {
175 ::alloc::__export::must_use({
::alloc::fmt::format(format_args!(", as it is behind {0}",
pointer_type))
})format!(", as it is behind {pointer_type}")
176 }
177 }
178 } else {
179 item_msg = ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("data in {0}", pointer_type))
})format!("data in {pointer_type}");
180 reason = String::new();
181 }
182 }
183 }
184
185 PlaceRef { local: _, projection: [ProjectionElem::PhantomDeref] } => {
186 item_msg = String::new();
187 reason = String::new();
188 }
189 PlaceRef { local: _, projection: [_proj_base @ .., ProjectionElem::PhantomDeref] } => {
190 item_msg = String::new();
191 reason = String::new();
192 }
193
194 PlaceRef {
195 local: _,
196 projection:
197 [
198 ..,
199 ProjectionElem::Index(_)
200 | ProjectionElem::ConstantIndex { .. }
201 | ProjectionElem::OpaqueCast { .. }
202 | ProjectionElem::Subslice { .. }
203 | ProjectionElem::Downcast(..)
204 | ProjectionElem::UnwrapUnsafeBinder(_),
205 ],
206 } => ::rustc_middle::util::bug::bug_fmt(format_args!("Unexpected immutable place."))bug!("Unexpected immutable place."),
207 }
208
209 {
use ::tracing::__macro_support::Callsite as _;
static __CALLSITE: ::tracing::callsite::DefaultCallsite =
{
static META: ::tracing::Metadata<'static> =
{
::tracing_core::metadata::Metadata::new("event /rustc-dev/cea272fa356e94bd2ee2cadf376630aa0683867a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs:209",
"rustc_borrowck::diagnostics::mutability_errors",
::tracing::Level::DEBUG,
::tracing_core::__macro_support::Option::Some("/rustc-dev/cea272fa356e94bd2ee2cadf376630aa0683867a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs"),
::tracing_core::__macro_support::Option::Some(209u32),
::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};
__CALLSITE.metadata().fields().value_set_all(&[(::tracing::__macro_support::Option::Some(&format_args!("report_mutability_error: item_msg={0:?}, reason={1:?}",
item_msg, reason) as &dyn ::tracing::field::Value))])
});
} else { ; }
};debug!("report_mutability_error: item_msg={:?}, reason={:?}", item_msg, reason);
210
211 let act;
214 let acted_on;
215 let mut suggest = true;
216 let mut mut_error = None;
217 let mut count = 1;
218
219 let span = match error_access {
220 AccessKind::Mutate => {
221 err = self.cannot_assign(span, &(item_msg + &reason));
222 act = "assign";
223 acted_on = "written to";
224 span
225 }
226 AccessKind::MutableBorrow => {
227 act = "borrow as mutable";
228 acted_on = "borrowed as mutable";
229
230 let borrow_spans = self.borrow_spans(span, location);
231 let borrow_span = borrow_spans.args_or_use();
232 match the_place_err {
233 PlaceRef { local, projection: [] }
234 if self.body.local_decls[local].can_be_made_mutable() =>
235 {
236 let span = self.body.local_decls[local].source_info.span;
237 mut_error = Some(span);
238 if let Some((buffered_err, c)) = self.get_buffered_mut_error(span) {
239 err = buffered_err;
244 count = c + 1;
245 if count == 2 {
246 err.replace_span_with(span, false);
247 err.span_label(span, "not mutable");
248 }
249 suggest = false;
250 } else {
251 err = self.cannot_borrow_path_as_mutable_because(
252 borrow_span,
253 &item_msg,
254 &reason,
255 );
256 }
257 }
258 _ => {
259 err = self.cannot_borrow_path_as_mutable_because(
260 borrow_span,
261 &item_msg,
262 &reason,
263 );
264 }
265 }
266 if suggest {
267 borrow_spans.var_subdiag(
268 &mut err,
269 Some(mir::BorrowKind::Mut { kind: mir::MutBorrowKind::Default }),
270 |_kind, var_span| {
271 let place = self.describe_any_place(access_place.as_ref());
272 session_diagnostics::CaptureVarCause::MutableBorrowUsePlaceClosure {
273 place,
274 var_span,
275 }
276 },
277 );
278 }
279 borrow_span
280 }
281 };
282
283 {
use ::tracing::__macro_support::Callsite as _;
static __CALLSITE: ::tracing::callsite::DefaultCallsite =
{
static META: ::tracing::Metadata<'static> =
{
::tracing_core::metadata::Metadata::new("event /rustc-dev/cea272fa356e94bd2ee2cadf376630aa0683867a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs:283",
"rustc_borrowck::diagnostics::mutability_errors",
::tracing::Level::DEBUG,
::tracing_core::__macro_support::Option::Some("/rustc-dev/cea272fa356e94bd2ee2cadf376630aa0683867a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs"),
::tracing_core::__macro_support::Option::Some(283u32),
::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};
__CALLSITE.metadata().fields().value_set_all(&[(::tracing::__macro_support::Option::Some(&format_args!("report_mutability_error: act={0:?}, acted_on={1:?}",
act, acted_on) as &dyn ::tracing::field::Value))])
});
} else { ; }
};debug!("report_mutability_error: act={:?}, acted_on={:?}", act, acted_on);
284
285 match the_place_err {
286 PlaceRef {
293 local,
294 projection:
295 [
296 proj_base @ ..,
297 ProjectionElem::Deref,
298 ProjectionElem::Field(field, _),
299 ProjectionElem::Deref,
300 ],
301 } => {
302 err.span_label(span, ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("cannot {0}", act))
})format!("cannot {act}"));
303
304 let place = Place::ty_from(local, proj_base, self.body, self.infcx.tcx);
305 if let Some(span) = get_mut_span_in_struct_field(self.infcx.tcx, place.ty, *field) {
306 err.span_suggestion_verbose(
307 span,
308 "consider changing this to be mutable",
309 " mut ",
310 Applicability::MaybeIncorrect,
311 );
312 }
313 }
314
315 PlaceRef { local, projection: [] }
317 if self
318 .body
319 .local_decls
320 .get(local)
321 .is_some_and(|l| mut_borrow_of_mutable_ref(l, self.local_name(local))) =>
322 {
323 let decl = &self.body.local_decls[local];
324 err.span_label(span, ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("cannot {0}", act))
})format!("cannot {act}"));
325 if let Some(mir::Statement {
326 source_info,
327 kind:
328 mir::StatementKind::Assign((
329 _,
330 mir::Rvalue::Ref(
331 _,
332 mir::BorrowKind::Mut { kind: mir::MutBorrowKind::Default },
333 _,
334 ),
335 )),
336 ..
337 }) = &self.body[location.block].statements.get(location.statement_index)
338 {
339 match *decl.local_info() {
340 LocalInfo::User(BindingForm::Var(mir::VarBindingForm {
341 binding_mode: BindingMode(ByRef::No, Mutability::Not),
342 opt_ty_info: Some(sp),
343 pat_span,
344 ..
345 })) => {
346 if suggest {
347 err.span_note(sp, "the binding is already a mutable borrow");
348 err.span_suggestion_verbose(
349 pat_span.shrink_to_lo(),
350 "consider making the binding mutable if you need to reborrow \
351 multiple times",
352 "mut ".to_string(),
353 Applicability::MaybeIncorrect,
354 );
355 }
356 }
357 _ => {
358 err.span_note(
359 decl.source_info.span,
360 "the binding is already a mutable borrow",
361 );
362 }
363 }
364 if let Ok(snippet) =
365 self.infcx.tcx.sess.source_map().span_to_snippet(source_info.span)
366 {
367 if snippet.starts_with("&mut ") {
368 let mut in_pat_scrutinee = false;
374 let mut is_deref_coerced = false;
375 if let Some(expr) = self.find_expr(source_info.span) {
376 let tcx = self.infcx.tcx;
377 let span = expr.span.source_callsite();
378 for (_, node) in tcx.hir_parent_iter(expr.hir_id) {
379 if let Node::Expr(parent_expr) = node {
380 match parent_expr.kind {
381 ExprKind::Match(scrutinee, ..)
382 if scrutinee
383 .span
384 .source_callsite()
385 .contains(span) =>
386 {
387 in_pat_scrutinee = true;
388 break;
389 }
390 ExprKind::Let(let_expr)
391 if let_expr
392 .init
393 .span
394 .source_callsite()
395 .contains(span) =>
396 {
397 in_pat_scrutinee = true;
398 break;
399 }
400 _ => {}
401 }
402 }
403 }
404
405 let typeck = tcx.typeck(expr.hir_id.owner.def_id);
406 is_deref_coerced =
407 typeck.expr_adjustments(expr).iter().any(|adj| {
408 #[allow(non_exhaustive_omitted_patterns)] match adj.kind {
ty::adjustment::Adjust::Deref(_) => true,
_ => false,
}matches!(adj.kind, ty::adjustment::Adjust::Deref(_))
409 });
410 }
411
412 if in_pat_scrutinee {
413 err.span_suggestion_verbose(
415 source_info
416 .span
417 .with_lo(source_info.span.lo() + BytePos(5))
418 .shrink_to_lo(),
419 "to reborrow the mutable reference, add `*`",
420 "*",
421 Applicability::MaybeIncorrect,
422 );
423 } else if is_deref_coerced {
424 err.span_suggestion_verbose(
427 source_info.span.with_hi(source_info.span.lo() + BytePos(5)),
428 "if there is only one mutable reborrow, remove the `&mut`",
429 "",
430 Applicability::MaybeIncorrect,
431 );
432 }
433 } else {
434 err.span_help(source_info.span, "try removing `&mut` here");
436 }
437 } else {
438 err.span_help(source_info.span, "try removing `&mut` here");
439 }
440 } else if decl.mutability.is_not() {
441 if #[allow(non_exhaustive_omitted_patterns)] match decl.local_info() {
LocalInfo::User(BindingForm::ImplicitSelf(hir::ImplicitSelfKind::RefMut))
=> true,
_ => false,
}matches!(
442 decl.local_info(),
443 LocalInfo::User(BindingForm::ImplicitSelf(hir::ImplicitSelfKind::RefMut))
444 ) {
445 err.note(
446 "as `Self` may be unsized, this call attempts to take `&mut &mut self`",
447 );
448 err.note("however, `&mut self` expands to `self: &mut Self`, therefore `self` cannot be borrowed mutably");
449 } else {
450 err.span_suggestion_verbose(
451 decl.source_info.span.shrink_to_lo(),
452 "consider making the binding mutable",
453 "mut ",
454 Applicability::MachineApplicable,
455 );
456 };
457 }
458 }
459
460 PlaceRef { local, projection: [] }
463 if self.body.local_decls[local].can_be_made_mutable() =>
464 {
465 let local_decl = &self.body.local_decls[local];
470 {
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);
471
472 if count < 10 {
473 err.span_label(span, ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("cannot {0}", act))
})format!("cannot {act}"));
474 }
475 if suggest {
476 self.construct_mut_suggestion_for_local_binding_patterns(&mut err, local);
477 let tcx = self.infcx.tcx;
478 if let ty::Closure(id, _) = *the_place_err.ty(self.body, tcx).ty.kind() {
479 self.show_mutating_upvar(tcx, id.expect_local(), the_place_err, &mut err);
480 }
481 }
482 }
483
484 PlaceRef {
486 local,
487 projection: [proj_base @ .., ProjectionElem::Field(upvar_index, _)],
488 } => {
489 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(
490 Place::ty_from(local, proj_base, self.body, self.infcx.tcx).ty
491 ));
492
493 let captured_place = self.upvars[upvar_index.index()];
494
495 err.span_label(span, ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("cannot {0}", act))
})format!("cannot {act}"));
496
497 let upvar_hir_id = captured_place.get_root_variable();
498
499 if let Node::Pat(pat) = self.infcx.tcx.hir_node(upvar_hir_id)
500 && let hir::PatKind::Binding(hir::BindingMode::NONE, _, upvar_ident, _) =
501 pat.kind
502 {
503 if upvar_ident.name == kw::SelfLower {
504 for (_, node) in self.infcx.tcx.hir_parent_iter(upvar_hir_id) {
505 if let Some(fn_decl) = node.fn_decl() {
506 if !#[allow(non_exhaustive_omitted_patterns)] match fn_decl.implicit_self() {
hir::ImplicitSelfKind::RefImm | hir::ImplicitSelfKind::RefMut => true,
_ => false,
}matches!(
507 fn_decl.implicit_self(),
508 hir::ImplicitSelfKind::RefImm | hir::ImplicitSelfKind::RefMut
509 ) {
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 break;
517 }
518 }
519 }
520 } else {
521 err.span_suggestion_verbose(
522 upvar_ident.span.shrink_to_lo(),
523 "consider changing this to be mutable",
524 "mut ",
525 Applicability::MachineApplicable,
526 );
527 }
528 }
529
530 let tcx = self.infcx.tcx;
531 if let ty::Ref(_, ty, Mutability::Mut) = the_place_err.ty(self.body, tcx).ty.kind()
532 && let ty::Closure(id, _) = *ty.kind()
533 {
534 self.show_mutating_upvar(tcx, id.expect_local(), the_place_err, &mut err);
535 }
536 }
537
538 PlaceRef { local: _, projection: [] }
541 if self
542 .infcx
543 .tcx
544 .sess
545 .source_map()
546 .span_to_snippet(span)
547 .is_ok_and(|snippet| snippet.starts_with("&mut ")) =>
548 {
549 err.span_label(span, ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("cannot {0}", act))
})format!("cannot {act}"));
550 err.span_suggestion_verbose(
551 span.with_hi(span.lo() + BytePos(5)),
552 "try removing `&mut` here",
553 "",
554 Applicability::MaybeIncorrect,
555 );
556 }
557
558 PlaceRef { local, projection: [ProjectionElem::Deref] }
559 if self.body.local_decls[local].is_ref_for_guard() =>
560 {
561 err.span_label(span, ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("cannot {0}", act))
})format!("cannot {act}"));
562 err.note(
563 "variables bound in patterns are immutable until the end of the pattern guard",
564 );
565 }
566
567 PlaceRef { local, projection: [ProjectionElem::Deref] }
573 if self.body.local_decls[local].is_user_variable() =>
574 {
575 let local_decl = &self.body.local_decls[local];
576
577 let (pointer_sigil, pointer_desc) =
578 if local_decl.ty.is_ref() { ("&", "reference") } else { ("*const", "pointer") };
579
580 match self.local_name(local) {
581 Some(name) if !local_decl.from_compiler_desugaring() => {
582 err.span_label(
583 span,
584 ::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!(
585 "`{name}` is a `{pointer_sigil}` {pointer_desc}, so it cannot be \
586 {acted_on}",
587 ),
588 );
589
590 self.suggest_using_iter_mut(&mut err);
591 self.suggest_make_local_mut(&mut err, local, name);
592 }
593 _ => {
594 err.span_label(
595 span,
596 ::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}"),
597 );
598 }
599 }
600 }
601
602 PlaceRef { local, projection: [ProjectionElem::Deref] }
603 if local == ty::CAPTURE_STRUCT_LOCAL && !self.upvars.is_empty() =>
604 {
605 self.point_at_binding_outside_closure(&mut err, local, access_place);
606 self.expected_fn_found_fn_mut_call(&mut err, span, act);
607 }
608
609 PlaceRef { local, projection: [.., ProjectionElem::Deref] } => {
610 err.span_label(span, ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("cannot {0}", act))
})format!("cannot {act}"));
611
612 match opt_source {
613 Some(BorrowedContentSource::OverloadedDeref(ty)) => {
614 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!(
615 "trait `DerefMut` is required to modify through a dereference, \
616 but it is not implemented for `{ty}`",
617 ));
618 }
619 Some(BorrowedContentSource::OverloadedIndex(ty)) => {
620 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!(
621 "trait `IndexMut` is required to modify indexed content, \
622 but it is not implemented for `{ty}`",
623 ));
624 self.suggest_map_index_mut_alternatives(ty, &mut err, span);
625 }
626 _ => {
627 let local = &self.body.local_decls[local];
628 match *local.local_info() {
629 LocalInfo::StaticRef { def_id, .. } => {
630 let span = self.infcx.tcx.def_span(def_id);
631 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}"));
632 }
633 LocalInfo::ConstRef { def_id } => {
634 let span = self.infcx.tcx.def_span(def_id);
635 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}"));
636 }
637 LocalInfo::BlockTailTemp(_) | LocalInfo::Boring
638 if !local.source_info.span.overlaps(span) =>
639 {
640 err.span_label(
641 local.source_info.span,
642 ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("this cannot be {0}", acted_on))
})format!("this cannot be {acted_on}"),
643 );
644 }
645 _ => {}
646 }
647 }
648 }
649 }
650
651 PlaceRef { local, .. } => {
652 let local = &self.body.local_decls[local];
653 if !local.source_info.span.overlaps(span) {
654 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}"));
655 }
656 err.span_label(span, ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("cannot {0}", act))
})format!("cannot {act}"));
657 }
658 }
659
660 if let Some(span) = mut_error {
661 self.buffer_mut_error(span, err, count);
662 } else {
663 self.buffer_error(err);
664 }
665 }
666
667 fn suggest_map_index_mut_alternatives(&self, ty: Ty<'tcx>, err: &mut Diag<'_>, span: Span) {
669 let Some(adt) = ty.ty_adt_def() else { return };
670 let did = adt.did();
671 if self.infcx.tcx.is_diagnostic_item(sym::HashMap, did)
672 || self.infcx.tcx.is_diagnostic_item(sym::BTreeMap, did)
673 {
674 struct SuggestIndexOperatorAlternativeVisitor<'a, 'diag, 'tcx> {
678 assign_span: Span,
679 err: &'a mut Diag<'diag>,
680 ty: Ty<'tcx>,
681 suggested: bool,
682 infcx: &'a rustc_infer::infer::InferCtxt<'tcx>,
683 }
684
685 impl<'tcx> Visitor<'tcx> for SuggestIndexOperatorAlternativeVisitor<'_, '_, 'tcx> {
686 fn visit_stmt(&mut self, stmt: &'tcx hir::Stmt<'tcx>) {
687 hir::intravisit::walk_stmt(self, stmt);
688 let expr = match stmt.kind {
689 hir::StmtKind::Semi(expr) | hir::StmtKind::Expr(expr) => expr,
690 hir::StmtKind::Let(hir::LetStmt { init: Some(expr), .. }) => expr,
691 _ => {
692 return;
693 }
694 };
695
696 fn count_ty_refs<'tcx>(mut ty: Ty<'tcx>) -> usize {
710 let mut count = 0;
711 while let ty::Ref(_, inner_ty, _) = ty.kind() {
712 ty = *inner_ty;
713 count += 1;
714 }
715 count
716 }
717
718 fn strip_n_refs<'a, 'b>(
723 mut expr: &'a Expr<'b>,
724 n: usize,
725 ) -> Result<&'a Expr<'b>, (usize, &'a Expr<'b>)> {
726 for count in 0..n {
727 match expr {
728 Expr {
729 kind: ExprKind::AddrOf(hir::BorrowKind::Ref, _, inner),
730 ..
731 } => expr = inner,
732 _ => return Err((count, expr)),
733 }
734 }
735 Ok(expr)
736 }
737
738 let key_ty = self.ty.walk().nth(1).unwrap().expect_ty();
740
741 if let hir::ExprKind::Assign(place, rv, _sp) = expr.kind
742 && let hir::ExprKind::Index(val, index, _) = place.kind
743 && (expr.span == self.assign_span || place.span == self.assign_span)
744 {
745 let index_ty =
747 self.infcx.tcx.typeck(val.hir_id.owner.def_id).expr_ty(index);
748
749 let (borrowed_prefix, borrowed_index);
750
751 if index_ty.peel_refs() == key_ty.peel_refs() {
755 let (index_refs, key_refs) =
756 (count_ty_refs(index_ty), count_ty_refs(key_ty));
757
758 let (deref_prefix, deref_index) = if index_refs >= key_refs {
759 strip_n_refs(index, index_refs - key_refs)
761 .map(|val| ("".to_string(), val))
762 .unwrap_or_else(|(depth, val)| {
763 (
764 if key_refs == 0 {
765 "*".repeat(
766 (index_refs-key_refs).checked_sub(depth).expect("return depth from strip_n_refs should be smaller than the input")
767 )
768 } else {
769 String::new() },
771 val,
772 )
773 })
774 } else {
775 ("&".repeat(key_refs - index_refs), index)
777 };
778
779 self.err.multipart_suggestion(
780 ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("use `.insert()` to insert a value into a `{0}`",
self.ty))
})format!("use `.insert()` to insert a value into a `{}`", self.ty),
781 ::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
[(val.span.shrink_to_hi().with_hi(deref_index.span.lo()),
::alloc::__export::must_use({
::alloc::fmt::format(format_args!(".insert({0}",
deref_prefix))
})),
(deref_index.span.shrink_to_hi().with_hi(rv.span.lo()),
", ".to_string()),
(rv.span.shrink_to_hi(), ")".to_string())]))vec![
782 (
784 val.span.shrink_to_hi().with_hi(deref_index.span.lo()),
785 format!(".insert({deref_prefix}"),
786 ),
787 (
788 deref_index.span.shrink_to_hi().with_hi(rv.span.lo()),
789 ", ".to_string(),
790 ),
791 (rv.span.shrink_to_hi(), ")".to_string()),
792 ],
793 Applicability::MaybeIncorrect,
794 );
795 self.err.multipart_suggestion(
796 ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("use the entry API to modify a `{0}` for more flexibility",
self.ty))
})format!(
797 "use the entry API to modify a `{}` for more flexibility",
798 self.ty
799 ),
800 ::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
[(val.span.shrink_to_lo(), "let val = ".to_string()),
(val.span.shrink_to_hi().with_hi(deref_index.span.lo()),
::alloc::__export::must_use({
::alloc::fmt::format(format_args!(".entry({0}",
deref_prefix))
})),
(deref_index.span.shrink_to_hi().with_hi(rv.span.lo()),
").insert_entry(".to_string()),
(rv.span.shrink_to_hi(), ")".to_string())]))vec![
801 (val.span.shrink_to_lo(), "let val = ".to_string()),
803 (
804 val.span.shrink_to_hi().with_hi(deref_index.span.lo()),
805 format!(".entry({deref_prefix}"),
806 ),
807 (
808 deref_index.span.shrink_to_hi().with_hi(rv.span.lo()),
809 ").insert_entry(".to_string(),
810 ),
811 (rv.span.shrink_to_hi(), ")".to_string()),
812 ],
813 Applicability::MaybeIncorrect,
814 );
815
816 (borrowed_prefix, borrowed_index) = (
819 String::new(),
820 if index_refs > key_refs {
821 strip_n_refs(index, index_refs - key_refs - 1)
822 .unwrap_or_else(|(_depth, val)| val)
823 } else {
825 index
827 },
828 );
829 } else {
830 (borrowed_prefix, borrowed_index) = (String::new(), index)
831 }
832 self.err.multipart_suggestion(
835 ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("use `.get_mut()` to modify an existing key in a `{0}`",
self.ty))
})format!(
836 "use `.get_mut()` to modify an existing key in a `{}`",
837 self.ty,
838 ),
839 ::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
[(val.span.shrink_to_lo(), "if let Some(val) = ".to_string()),
(val.span.shrink_to_hi().with_hi(borrowed_index.span.lo()),
::alloc::__export::must_use({
::alloc::fmt::format(format_args!(".get_mut({0}",
borrowed_prefix))
})),
(borrowed_index.span.shrink_to_hi().with_hi(place.span.hi()),
") { *val".to_string()),
(rv.span.shrink_to_hi(), "; }".to_string())]))vec![
840 (val.span.shrink_to_lo(), "if let Some(val) = ".to_string()),
842 (
843 val.span.shrink_to_hi().with_hi(borrowed_index.span.lo()),
844 format!(".get_mut({borrowed_prefix}"),
845 ),
846 (
847 borrowed_index.span.shrink_to_hi().with_hi(place.span.hi()),
848 ") { *val".to_string(),
849 ),
850 (rv.span.shrink_to_hi(), "; }".to_string()),
851 ],
852 Applicability::MaybeIncorrect,
853 );
854
855 self.suggested = true;
856 } else if let hir::ExprKind::MethodCall(_path, receiver, _, sp) = expr.kind
857 && let hir::ExprKind::Index(val, index, _) = receiver.kind
858 && receiver.span == self.assign_span
859 {
860 self.err.multipart_suggestion(
862 ::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),
863 ::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
[(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![
864 (val.span.shrink_to_lo(), "if let Some(val) = ".to_string()),
865 (
866 val.span.shrink_to_hi().with_hi(index.span.lo()),
867 ".get_mut(".to_string(),
868 ),
869 (
870 index.span.shrink_to_hi().with_hi(receiver.span.hi()),
871 ") { val".to_string(),
872 ),
873 (sp.shrink_to_hi(), "; }".to_string()),
874 ],
875 Applicability::MachineApplicable,
876 );
877 self.suggested = true;
878 }
879 }
880 }
881 let def_id = self.body.source.def_id();
882 let Some(local_def_id) = def_id.as_local() else { return };
883 let Some(body) = self.infcx.tcx.hir_maybe_body_owned_by(local_def_id) else { return };
884
885 let mut v = SuggestIndexOperatorAlternativeVisitor {
886 assign_span: span,
887 err,
888 ty,
889 suggested: false,
890 infcx: self.infcx,
891 };
892 v.visit_body(&body);
893 if !v.suggested {
894 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!(
895 "to modify a `{ty}`, use `.get_mut()`, `.insert()` or the entry API",
896 ));
897 }
898 }
899 }
900
901 fn is_error_in_trait(&self, local: Local) -> (bool, bool, Option<Span>) {
911 let tcx = self.infcx.tcx;
912 if self.body.local_kind(local) != LocalKind::Arg {
913 return (false, false, None);
914 }
915 let my_def = self.body.source.def_id();
916 let Some(td) = tcx.trait_impl_of_assoc(my_def).map(|id| self.infcx.tcx.impl_trait_id(id))
917 else {
918 return (false, false, None);
919 };
920
921 let implemented_trait_item = self.infcx.tcx.trait_item_of(my_def);
922
923 (
924 true,
925 td.is_local(),
926 implemented_trait_item.and_then(|f_in_trait| {
927 let f_in_trait = f_in_trait.as_local()?;
928 if let Node::TraitItem(ti) = self.infcx.tcx.hir_node_by_def_id(f_in_trait)
929 && let hir::TraitItemKind::Fn(sig, _) = ti.kind
930 && let Some(ty) = sig.decl.inputs.get(local.index() - 1)
931 && let hir::TyKind::Ref(_, mut_ty) = ty.kind
932 && let hir::Mutability::Not = mut_ty.mutbl
933 && sig.decl.implicit_self().has_implicit_self()
934 {
935 Some(ty.span)
936 } else {
937 None
938 }
939 }),
940 )
941 }
942
943 fn construct_mut_suggestion_for_local_binding_patterns(
944 &self,
945 err: &mut Diag<'_>,
946 local: Local,
947 ) {
948 let local_decl = &self.body.local_decls[local];
949 {
use ::tracing::__macro_support::Callsite as _;
static __CALLSITE: ::tracing::callsite::DefaultCallsite =
{
static META: ::tracing::Metadata<'static> =
{
::tracing_core::metadata::Metadata::new("event /rustc-dev/cea272fa356e94bd2ee2cadf376630aa0683867a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs:949",
"rustc_borrowck::diagnostics::mutability_errors",
::tracing::Level::DEBUG,
::tracing_core::__macro_support::Option::Some("/rustc-dev/cea272fa356e94bd2ee2cadf376630aa0683867a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs"),
::tracing_core::__macro_support::Option::Some(949u32),
::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};
__CALLSITE.metadata().fields().value_set_all(&[(::tracing::__macro_support::Option::Some(&format_args!("local_decl: {0:?}",
local_decl) as &dyn ::tracing::field::Value))])
});
} else { ; }
};debug!("local_decl: {:?}", local_decl);
950 let pat_span = match *local_decl.local_info() {
951 LocalInfo::User(BindingForm::Var(mir::VarBindingForm {
952 binding_mode: BindingMode(ByRef::No, Mutability::Not),
953 opt_ty_info: _,
954 opt_match_place: _,
955 pat_span,
956 introductions: _,
957 })) => pat_span,
958 _ => local_decl.source_info.span,
959 };
960
961 let def_id = self.body.source.def_id();
968 if let Some(local_def_id) = def_id.as_local()
969 && let Some(body) = self.infcx.tcx.hir_maybe_body_owned_by(local_def_id)
970 && let Some(hir_id) = (BindingFinder { span: pat_span }).visit_body(&body).break_value()
971 && let node = self.infcx.tcx.hir_node(hir_id)
972 && let hir::Node::LetStmt(hir::LetStmt {
973 pat: hir::Pat { kind: hir::PatKind::Ref(_, _, _), .. },
974 ..
975 })
976 | hir::Node::Param(Param {
977 pat: hir::Pat { kind: hir::PatKind::Ref(_, _, _), .. },
978 ..
979 }) = node
980 {
981 err.multipart_suggestion(
982 "consider changing this to be mutable",
983 ::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
[(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![
984 (pat_span.until(local_decl.source_info.span), "&(mut ".to_string()),
985 (
986 local_decl.source_info.span.shrink_to_hi().with_hi(pat_span.hi()),
987 ")".to_string(),
988 ),
989 ],
990 Applicability::MachineApplicable,
991 );
992 return;
993 }
994
995 err.span_suggestion_verbose(
996 local_decl.source_info.span.shrink_to_lo(),
997 "consider changing this to be mutable",
998 "mut ",
999 Applicability::MachineApplicable,
1000 );
1001 }
1002
1003 fn show_mutating_upvar(
1005 &self,
1006 tcx: TyCtxt<'_>,
1007 closure_local_def_id: hir::def_id::LocalDefId,
1008 the_place_err: PlaceRef<'tcx>,
1009 err: &mut Diag<'_>,
1010 ) {
1011 let tables = tcx.typeck(closure_local_def_id);
1012 if let Some((span, closure_kind_origin)) = tcx.closure_kind_origin(closure_local_def_id) {
1013 let reason = if let PlaceBase::Upvar(upvar_id) = closure_kind_origin.base {
1014 let upvar = ty::place_to_string_for_capture(tcx, closure_kind_origin);
1015 let root_hir_id = upvar_id.var_path.hir_id;
1016 let captured_places =
1019 tables.closure_min_captures[&closure_local_def_id].get(&root_hir_id).unwrap();
1020
1021 let origin_projection = closure_kind_origin
1022 .projections
1023 .iter()
1024 .map(|proj| proj.kind)
1025 .collect::<Vec<_>>();
1026 let mut capture_reason = String::new();
1027 for captured_place in captured_places {
1028 let captured_place_kinds = captured_place
1029 .place
1030 .projections
1031 .iter()
1032 .map(|proj| proj.kind)
1033 .collect::<Vec<_>>();
1034 if rustc_middle::ty::is_ancestor_or_same_capture(
1035 &captured_place_kinds,
1036 &origin_projection,
1037 ) {
1038 match captured_place.info.capture_kind {
1039 ty::UpvarCapture::ByRef(
1040 ty::BorrowKind::Mutable | ty::BorrowKind::UniqueImmutable,
1041 ) => {
1042 capture_reason = ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("mutable borrow of `{0}`", upvar))
})format!("mutable borrow of `{upvar}`");
1043 }
1044 ty::UpvarCapture::ByValue | ty::UpvarCapture::ByUse => {
1045 capture_reason = ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("possible mutation of `{0}`",
upvar))
})format!("possible mutation of `{upvar}`");
1046 }
1047 _ => ::rustc_middle::util::bug::bug_fmt(format_args!("upvar `{0}` borrowed, but not mutably",
upvar))bug!("upvar `{upvar}` borrowed, but not mutably"),
1048 }
1049 break;
1050 }
1051 }
1052 if capture_reason.is_empty() {
1053 ::rustc_middle::util::bug::bug_fmt(format_args!("upvar `{0}` borrowed, but cannot find reason",
upvar));bug!("upvar `{upvar}` borrowed, but cannot find reason");
1054 }
1055 capture_reason
1056 } else {
1057 ::rustc_middle::util::bug::bug_fmt(format_args!("not an upvar"))bug!("not an upvar")
1058 };
1059 if let Some(place_name) = self.describe_place(the_place_err) {
1065 err.span_label(
1066 *span,
1067 ::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}"),
1068 );
1069 } else if span.from_expansion() {
1070 err.span_label(
1071 *span,
1072 ::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}",),
1073 );
1074 }
1075 }
1076 }
1077
1078 fn suggest_similar_mut_method_for_for_loop(&self, err: &mut Diag<'_>, span: Span) {
1081 use hir::ExprKind::{AddrOf, Block, Call, MethodCall};
1082 use hir::{BorrowKind, Expr};
1083
1084 let tcx = self.infcx.tcx;
1085 struct Finder {
1086 span: Span,
1087 }
1088
1089 impl<'tcx> Visitor<'tcx> for Finder {
1090 type Result = ControlFlow<&'tcx Expr<'tcx>>;
1091 fn visit_expr(&mut self, e: &'tcx hir::Expr<'tcx>) -> Self::Result {
1092 if e.span == self.span {
1093 ControlFlow::Break(e)
1094 } else {
1095 hir::intravisit::walk_expr(self, e)
1096 }
1097 }
1098 }
1099 let Some(body) = tcx.hir_maybe_body_owned_by(self.mir_def_id()) else { return };
1100 let Block(block, _) = body.value.kind else { return };
1101 let mut expr = if let ControlFlow::Break(expr) = (Finder { span }).visit_block(block)
1105 && let Call(_, [expr]) = expr.kind
1106 {
1107 expr
1108 } else {
1109 return;
1110 };
1111 loop {
1112 match expr.kind {
1113 MethodCall(path_segment, _, _, span) => {
1114 let opt_suggestions = tcx
1117 .typeck(path_segment.hir_id.owner.def_id)
1118 .type_dependent_def_id(expr.hir_id)
1119 .and_then(|def_id| tcx.impl_of_assoc(def_id))
1120 .map(|def_id| tcx.associated_items(def_id))
1121 .map(|assoc_items| {
1122 assoc_items
1123 .in_definition_order()
1124 .map(|assoc_item_def| assoc_item_def.ident(tcx))
1125 .filter(|&ident| {
1126 let original_method_ident = path_segment.ident;
1127 original_method_ident != ident
1128 && ident
1129 .as_str()
1130 .starts_with(&original_method_ident.name.to_string())
1131 })
1132 .map(|ident| ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("{0}()", ident))
})format!("{ident}()"))
1133 .peekable()
1134 });
1135
1136 if let Some(mut suggestions) = opt_suggestions
1137 && suggestions.peek().is_some()
1138 {
1139 err.span_suggestions(
1140 span,
1141 "use mutable method",
1142 suggestions,
1143 Applicability::MaybeIncorrect,
1144 );
1145 }
1146 }
1147 AddrOf(BorrowKind::Ref, Mutability::Not, expr) => {
1148 err.span_suggestion_verbose(
1150 expr.span.shrink_to_lo(),
1151 "use a mutable iterator instead",
1152 "mut ",
1153 Applicability::MachineApplicable,
1154 );
1155 }
1156 ExprKind::Path(hir::QPath::Resolved(None, path))
1157 if let hir::def::Res::Local(hir_id) = path.res
1158 && let hir::Node::LetStmt(stmt) =
1159 self.infcx.tcx.parent_hir_node(hir_id)
1160 && let Some(init) = stmt.init =>
1161 {
1162 expr = init;
1164 continue;
1165 }
1166 _ => {}
1167 }
1168 break;
1169 }
1170 }
1171
1172 fn point_at_binding_outside_closure(
1174 &self,
1175 err: &mut Diag<'_>,
1176 local: Local,
1177 access_place: Place<'tcx>,
1178 ) {
1179 let place = access_place.as_ref();
1180 for (index, elem) in place.projection.into_iter().enumerate() {
1181 if let ProjectionElem::Deref = elem {
1182 if index == 0 {
1183 if self.body.local_decls[local].is_ref_for_guard() {
1184 continue;
1185 }
1186 if let LocalInfo::StaticRef { .. } = *self.body.local_decls[local].local_info()
1187 {
1188 continue;
1189 }
1190 }
1191 if let Some(field) = self.is_upvar_field_projection(PlaceRef {
1192 local,
1193 projection: place.projection.split_at(index + 1).0,
1194 }) {
1195 let var_index = field.index();
1196 let upvar = self.upvars[var_index];
1197 if let Some(hir_id) = upvar.info.capture_kind_expr_id {
1198 let node = self.infcx.tcx.hir_node(hir_id);
1199 if let hir::Node::Expr(expr) = node
1200 && let hir::ExprKind::Path(hir::QPath::Resolved(None, path)) = expr.kind
1201 && let hir::def::Res::Local(hir_id) = path.res
1202 && let hir::Node::Pat(pat) = self.infcx.tcx.hir_node(hir_id)
1203 {
1204 let name = upvar.to_string(self.infcx.tcx);
1205 err.span_label(
1206 pat.span,
1207 ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("`{0}` declared here, outside the closure",
name))
})format!("`{name}` declared here, outside the closure"),
1208 );
1209 break;
1210 }
1211 }
1212 }
1213 }
1214 }
1215 }
1216 fn expected_fn_found_fn_mut_call(&self, err: &mut Diag<'_>, sp: Span, act: &str) {
1218 err.span_label(sp, ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("cannot {0}", act))
})format!("cannot {act}"));
1219
1220 let tcx = self.infcx.tcx;
1221 let closure_id = self.mir_hir_id();
1222 let closure_span = tcx.def_span(self.mir_def_id());
1223 let fn_call_id = tcx.parent_hir_id(closure_id);
1224 let node = tcx.hir_node(fn_call_id);
1225 let def_id = tcx.hir_enclosing_body_owner(fn_call_id);
1226 let mut look_at_return = true;
1227
1228 err.span_label(closure_span, "in this closure");
1229 let closure_arg_has_fn_trait_bound =
1230 |callee_def_id, input_index, generic_args: ty::GenericArgsRef<'tcx>| {
1231 let sig = tcx.fn_sig(callee_def_id).instantiate(tcx, generic_args).skip_binder();
1232 let Some(input_ty): Option<Ty<'tcx>> = sig.inputs().get(input_index).copied()
1233 else {
1234 return false;
1235 };
1236
1237 tcx.clauses_of(callee_def_id).instantiate(tcx, generic_args).clauses.iter().any(
1238 |clause| {
1239 clause.as_trait_clause().is_some_and(|trait_pred| {
1240 trait_pred.polarity() == ty::ClausePolarity::Positive
1241 && tcx.fn_trait_kind_from_def_id(trait_pred.def_id())
1242 == Some(ty::ClosureKind::Fn)
1243 && trait_pred.self_ty().skip_binder().peel_refs()
1244 == input_ty.peel_refs()
1245 })
1246 },
1247 )
1248 };
1249
1250 let get_call_details =
1253 || -> Option<(DefId, Span, usize, usize, ty::GenericArgsRef<'tcx>)> {
1254 let hir::Node::Expr(hir::Expr { hir_id, kind, .. }) = node else {
1255 return None;
1256 };
1257
1258 let typeck_results = tcx.typeck(def_id);
1259
1260 match kind {
1261 hir::ExprKind::Call(expr, args) => {
1262 if let Some(ty::FnDef(def_id, generic_args)) =
1263 typeck_results.node_type_opt(expr.hir_id).as_ref().map(|ty| ty.kind())
1264 {
1265 let arg_pos = args.iter().position(|arg| arg.hir_id == closure_id)?;
1266 Some((
1267 *def_id,
1268 expr.span,
1269 arg_pos,
1270 arg_pos,
1271 generic_args.no_bound_vars().unwrap(),
1272 ))
1273 } else {
1274 None
1275 }
1276 }
1277 hir::ExprKind::MethodCall(_, _, args, span) => {
1278 let arg_pos = args.iter().position(|arg| arg.hir_id == closure_id)?;
1279 let def_id = typeck_results.type_dependent_def_id(*hir_id)?;
1280 let generic_args = typeck_results.node_args_opt(*hir_id)?;
1281 Some((def_id, *span, arg_pos, arg_pos + 1, generic_args))
1282 }
1283 _ => None,
1284 }
1285 };
1286
1287 if let Some((callee_def_id, call_span, arg_pos, input_index, generic_args)) =
1290 get_call_details()
1291 {
1292 let arg = match tcx.hir_get_if_local(callee_def_id) {
1293 Some(
1294 hir::Node::Item(hir::Item {
1295 kind: hir::ItemKind::Fn { ident, sig, .. }, ..
1296 })
1297 | hir::Node::TraitItem(hir::TraitItem {
1298 ident,
1299 kind: hir::TraitItemKind::Fn(sig, _),
1300 ..
1301 })
1302 | hir::Node::ImplItem(hir::ImplItem {
1303 ident,
1304 kind: hir::ImplItemKind::Fn(sig, _),
1305 ..
1306 }),
1307 ) => Some(
1308 sig.decl
1309 .inputs
1310 .get(
1311 arg_pos
1312 + if sig.decl.implicit_self().has_implicit_self() { 1 } else { 0 },
1313 )
1314 .map(|arg| arg.span)
1315 .unwrap_or(ident.span),
1316 ),
1317 _ => None,
1318 };
1319 if let Some(span) = arg {
1320 err.span_label(span, "change this to accept `FnMut` instead of `Fn`");
1321 err.span_label(call_span, "expects `Fn` instead of `FnMut`");
1322 look_at_return = false;
1323 } else if closure_arg_has_fn_trait_bound(callee_def_id, input_index, generic_args) {
1324 err.span_label(call_span, "expects `Fn` instead of `FnMut`");
1329 look_at_return = false;
1330 }
1331 }
1332
1333 if look_at_return && tcx.hir_get_fn_id_for_return_block(closure_id).is_some() {
1334 match tcx.hir_node_by_def_id(tcx.hir_get_parent_item(fn_call_id).def_id) {
1337 hir::Node::Item(hir::Item {
1338 kind: hir::ItemKind::Fn { ident, sig, .. }, ..
1339 })
1340 | hir::Node::TraitItem(hir::TraitItem {
1341 ident,
1342 kind: hir::TraitItemKind::Fn(sig, _),
1343 ..
1344 })
1345 | hir::Node::ImplItem(hir::ImplItem {
1346 ident,
1347 kind: hir::ImplItemKind::Fn(sig, _),
1348 ..
1349 }) => {
1350 err.span_label(ident.span, "");
1351 err.span_label(
1352 sig.decl.output.span(),
1353 "change this to return `FnMut` instead of `Fn`",
1354 );
1355 }
1356 _ => {}
1357 }
1358 }
1359 }
1360
1361 fn suggest_using_iter_mut(&self, err: &mut Diag<'_>) {
1362 let source = self.body.source;
1363 if let InstanceKind::Item(def_id) = source.instance
1364 && let Some(Node::Expr(hir::Expr { hir_id, kind, .. })) =
1365 self.infcx.tcx.hir_get_if_local(def_id)
1366 && let ExprKind::Closure(hir::Closure { kind: hir::ClosureKind::Closure, .. }) = kind
1367 && let Node::Expr(expr) = self.infcx.tcx.parent_hir_node(*hir_id)
1368 {
1369 let mut cur_expr = expr;
1370 while let ExprKind::MethodCall(path_segment, recv, _, _) = cur_expr.kind {
1371 if path_segment.ident.name == sym::iter {
1372 let res = self
1374 .infcx
1375 .tcx
1376 .typeck(path_segment.hir_id.owner.def_id)
1377 .type_dependent_def_id(cur_expr.hir_id)
1378 .and_then(|def_id| self.infcx.tcx.impl_of_assoc(def_id))
1379 .map(|def_id| self.infcx.tcx.associated_items(def_id))
1380 .map(|assoc_items| {
1381 assoc_items.filter_by_name_unhygienic(sym::iter_mut).peekable()
1382 });
1383
1384 if let Some(mut res) = res
1385 && res.peek().is_some()
1386 {
1387 err.span_suggestion_verbose(
1388 path_segment.ident.span,
1389 "you may want to use `iter_mut` here",
1390 "iter_mut",
1391 Applicability::MaybeIncorrect,
1392 );
1393 }
1394 break;
1395 } else {
1396 cur_expr = recv;
1397 }
1398 }
1399 }
1400 }
1401
1402 fn suggest_make_local_mut(&self, err: &mut Diag<'_>, local: Local, name: Symbol) {
1403 let local_decl = &self.body.local_decls[local];
1404
1405 let (pointer_sigil, pointer_desc) =
1406 if local_decl.ty.is_ref() { ("&", "reference") } else { ("*const", "pointer") };
1407
1408 let (is_trait_sig, is_local, local_trait) = self.is_error_in_trait(local);
1409
1410 if is_trait_sig && !is_local {
1411 err.span_label(
1413 local_decl.source_info.span,
1414 ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("this is an immutable {0}",
pointer_desc))
})format!("this is an immutable {pointer_desc}"),
1415 );
1416 return;
1417 }
1418
1419 if self.is_closure_arg_with_non_locally_decided_type(local) {
1421 return;
1422 }
1423
1424 let decl_span = local_decl.source_info.span;
1425
1426 let (amp_mut_sugg, local_var_ty_info) = match *local_decl.local_info() {
1427 LocalInfo::User(mir::BindingForm::ImplicitSelf(_)) => {
1428 let (span, suggestion) = suggest_ampmut_self(self.infcx.tcx, decl_span);
1429 let additional = local_trait.map(|span| suggest_ampmut_self(self.infcx.tcx, span));
1430 (AmpMutSugg::Type { span, suggestion, additional }, None)
1431 }
1432
1433 LocalInfo::User(mir::BindingForm::Var(mir::VarBindingForm {
1434 binding_mode: BindingMode(ByRef::No, _),
1435 opt_ty_info,
1436 ..
1437 })) => {
1438 let first_assignment = find_assignments(&self.body, local).first().copied();
1440 let first_assignment_stmt = first_assignment
1441 .and_then(|loc| self.body[loc.block].statements.get(loc.statement_index));
1442 {
use ::tracing::__macro_support::Callsite as _;
static __CALLSITE: ::tracing::callsite::DefaultCallsite =
{
static META: ::tracing::Metadata<'static> =
{
::tracing_core::metadata::Metadata::new("event /rustc-dev/cea272fa356e94bd2ee2cadf376630aa0683867a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs:1442",
"rustc_borrowck::diagnostics::mutability_errors",
::tracing::Level::TRACE,
::tracing_core::__macro_support::Option::Some("/rustc-dev/cea272fa356e94bd2ee2cadf376630aa0683867a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs"),
::tracing_core::__macro_support::Option::Some(1442u32),
::tracing_core::__macro_support::Option::Some("rustc_borrowck::diagnostics::mutability_errors"),
::tracing_core::field::FieldSet::new(&[{
const NAME:
::tracing::__macro_support::FieldName<{
::tracing::__macro_support::FieldName::len("first_assignment_stmt")
}> =
::tracing::__macro_support::FieldName::new("first_assignment_stmt");
NAME.as_str()
}], ::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};
__CALLSITE.metadata().fields().value_set_all(&[(::tracing::__macro_support::Option::Some(&::tracing::field::debug(&first_assignment_stmt)
as &dyn ::tracing::field::Value))])
});
} else { ; }
};trace!(?first_assignment_stmt);
1443 let opt_assignment_rhs_span =
1444 first_assignment.map(|loc| self.body.source_info(loc).span);
1445 let mut source_span = opt_assignment_rhs_span;
1446 if let Some(mir::Statement {
1447 source_info: _,
1448 kind:
1449 mir::StatementKind::Assign((_, mir::Rvalue::Use(mir::Operand::Copy(place), _))),
1450 ..
1451 }) = first_assignment_stmt
1452 {
1453 let local_span = self.body.local_decls[place.local].source_info.span;
1454 source_span = Some(local_span);
1457 if let Some(DesugaringKind::ForLoop) = local_span.desugaring_kind() {
1458 self.suggest_similar_mut_method_for_for_loop(err, local_span);
1460 err.span_label(
1461 local_span,
1462 ::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",),
1463 );
1464 return;
1465 }
1466 }
1467
1468 if source_span.is_some_and(|s| {
1470 s.desugaring_kind().is_some() || self.infcx.tcx.sess.source_map().is_imported(s)
1471 }) {
1472 return;
1473 }
1474
1475 if name == kw::SelfLower && opt_ty_info.is_none() {
1477 let (span, suggestion) = suggest_ampmut_self(self.infcx.tcx, decl_span);
1478 (AmpMutSugg::Type { span, suggestion, additional: None }, None)
1479 } else if let Some(sugg) =
1480 suggest_ampmut(self.infcx, self.body(), first_assignment_stmt)
1481 {
1482 (sugg, opt_ty_info)
1483 } else {
1484 return;
1485 }
1486 }
1487
1488 LocalInfo::User(mir::BindingForm::Var(mir::VarBindingForm {
1489 binding_mode: BindingMode(ByRef::Yes(..), _),
1490 ..
1491 })) => {
1492 let pattern_span: Span = local_decl.source_info.span;
1493 let Some(span) = suggest_ref_mut(self.infcx.tcx, pattern_span) else {
1494 return;
1495 };
1496 (AmpMutSugg::Type { span, suggestion: "mut ".to_owned(), additional: None }, None)
1497 }
1498
1499 _ => ::core::panicking::panic("internal error: entered unreachable code")unreachable!(),
1500 };
1501
1502 let mut suggest = |suggs: Vec<_>, applicability, extra| {
1503 if suggs.iter().any(|(span, _)| self.infcx.tcx.sess.source_map().is_imported(*span)) {
1504 return;
1505 }
1506
1507 err.multipart_suggestion(
1508 ::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!(
1509 "consider changing this to be a mutable {pointer_desc}{}{extra}",
1510 if is_trait_sig {
1511 " in the `impl` method and the `trait` definition"
1512 } else {
1513 ""
1514 }
1515 ),
1516 suggs,
1517 applicability,
1518 );
1519 };
1520
1521 let (mut sugg, add_type_annotation_if_not_exists) = match amp_mut_sugg {
1522 AmpMutSugg::Type { span, suggestion, additional } => {
1523 let mut sugg = ::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
[(span, suggestion)]))vec![(span, suggestion)];
1524 sugg.extend(additional);
1525 suggest(sugg, Applicability::MachineApplicable, "");
1526 return;
1527 }
1528 AmpMutSugg::MapGetMut { span, suggestion } => {
1529 if self.infcx.tcx.sess.source_map().is_imported(span) {
1530 return;
1531 }
1532 err.multipart_suggestion(
1533 "consider using `get_mut`",
1534 ::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
[(span, suggestion)]))vec![(span, suggestion)],
1535 Applicability::MaybeIncorrect,
1536 );
1537 return;
1538 }
1539 AmpMutSugg::Expr { span, suggestion } => {
1540 (::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
[(span, suggestion)]))vec![(span, suggestion)], false)
1543 }
1544 AmpMutSugg::ChangeBinding => (::alloc::vec::Vec::new()vec![], true),
1545 };
1546
1547 let (binding_exists, span) = match local_var_ty_info {
1549 Some(ty_span) => (true, ty_span),
1553
1554 None => (false, decl_span),
1558 };
1559
1560 if !binding_exists && !add_type_annotation_if_not_exists {
1561 suggest(sugg, Applicability::MachineApplicable, "");
1562 return;
1563 }
1564
1565 let (sugg_span, sugg_str, suggest_now) = if let Ok(src) = self.infcx.tcx.sess.source_map().span_to_snippet(span)
1569 && src.starts_with("&'")
1570 && let Some(ws_pos) = src.find(char::is_whitespace)
1572 {
1573 let span = span.with_lo(span.lo() + BytePos(ws_pos as u32)).shrink_to_lo();
1574 (span, " mut".to_owned(), true)
1575 } else if binding_exists {
1577 let Ok(src) = self.infcx.tcx.sess.source_map().span_to_snippet(span) else {
1581 return;
1582 };
1583 let (prefix_len, replacement) = if local_decl.ty.is_ref() {
1584 (src.chars().next().map_or(0, char::len_utf8), "&mut ")
1585 } else {
1586 (src.find("const").map_or(1, |i| i + "const".len()), "*mut ")
1587 };
1588 let ws_len = src[prefix_len..].len() - src[prefix_len..].trim_start().len();
1589 let span = span.with_hi(span.lo() + BytePos((prefix_len + ws_len) as u32));
1590 (span, replacement.to_owned(), true)
1591 } else {
1592 let ty = local_decl.ty.builtin_deref(true).unwrap();
1595
1596 (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)
1597 };
1598
1599 if suggest_now {
1600 let has_change = !sugg.is_empty();
1602 sugg.push((sugg_span, sugg_str));
1603 suggest(
1604 sugg,
1605 Applicability::MachineApplicable,
1606 if has_change { " and changing the binding's type" } else { "" },
1608 );
1609 return;
1610 } else if !sugg.is_empty() {
1611 suggest(sugg, Applicability::MachineApplicable, "");
1612 return;
1613 }
1614
1615 let def_id = self.body.source.def_id();
1616 let hir_id = if let Some(local_def_id) = def_id.as_local()
1617 && let Some(body) = self.infcx.tcx.hir_maybe_body_owned_by(local_def_id)
1618 {
1619 BindingFinder { span: sugg_span }.visit_body(&body).break_value()
1620 } else {
1621 None
1622 };
1623 let node = hir_id.map(|hir_id| self.infcx.tcx.hir_node(hir_id));
1624
1625 let Some(hir::Node::LetStmt(local)) = node else {
1626 err.span_label(
1627 sugg_span,
1628 ::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}`"),
1629 );
1630 return;
1631 };
1632
1633 let tables = self.infcx.tcx.typeck(def_id.as_local().unwrap());
1634 if let Some(clone_trait) = self.infcx.tcx.lang_items().clone_trait()
1635 && let Some(expr) = local.init
1636 && let ty = tables.node_type_opt(expr.hir_id)
1637 && let Some(ty) = ty
1638 && let ty::Ref(..) = ty.kind()
1639 {
1640 match self
1641 .infcx
1642 .type_implements_trait_shallow(clone_trait, ty.peel_refs(), self.infcx.param_env)
1643 .as_ref()
1644 .map(|it| it.as_slice())
1645 {
1646 Some([]) => {
1647 }
1656 None => {
1657 if let hir::ExprKind::MethodCall(segment, _rcvr, [], span) = expr.kind
1658 && segment.ident.name == sym::clone
1659 {
1660 err.span_help(
1661 span,
1662 ::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!(
1663 "`{}` doesn't implement `Clone`, so this call clones \
1664 the reference `{ty}`",
1665 ty.peel_refs(),
1666 ),
1667 );
1668 }
1669 let trait_ref = ty::Binder::dummy(ty::TraitRef::new(
1671 self.infcx.tcx,
1672 clone_trait,
1673 [ty.peel_refs()],
1674 ));
1675 let obligation = traits::Obligation::new(
1676 self.infcx.tcx,
1677 traits::ObligationCause::dummy(),
1678 self.infcx.param_env,
1679 trait_ref,
1680 );
1681 self.infcx.err_ctxt().suggest_derive(
1682 &obligation,
1683 err,
1684 trait_ref.upcast(self.infcx.tcx),
1685 );
1686 }
1687 Some(errors) => {
1688 if let hir::ExprKind::MethodCall(segment, _rcvr, [], span) = expr.kind
1689 && segment.ident.name == sym::clone
1690 {
1691 err.span_help(
1692 span,
1693 ::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!(
1694 "`{}` doesn't implement `Clone` because its \
1695 implementations trait bounds could not be met, so \
1696 this call clones the reference `{ty}`",
1697 ty.peel_refs(),
1698 ),
1699 );
1700 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!(
1701 "the following trait bounds weren't met: {}",
1702 errors
1703 .iter()
1704 .map(|e| e.obligation.predicate.to_string())
1705 .collect::<Vec<_>>()
1706 .join("\n"),
1707 ));
1708 }
1709 for error in errors {
1711 if let traits::FulfillmentErrorCode::Select(
1712 traits::SelectionError::Unimplemented,
1713 ) = error.code
1714 && let ty::PredicateKind::Clause(ty::ClauseKind::Trait(pred)) =
1715 error.obligation.predicate.kind().skip_binder()
1716 {
1717 self.infcx.err_ctxt().suggest_derive(
1718 &error.obligation,
1719 err,
1720 error.obligation.predicate.kind().rebind(pred),
1721 );
1722 }
1723 }
1724 }
1725 }
1726 }
1727 let (changing, span, sugg) = match local.ty {
1728 Some(ty) => ("changing", ty.span, sugg_str),
1729 None => ("specifying", local.pat.span.shrink_to_hi(), ::alloc::__export::must_use({
::alloc::fmt::format(format_args!(": {0}", sugg_str))
})format!(": {sugg_str}")),
1730 };
1731 err.span_suggestion_verbose(
1732 span,
1733 ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("consider {0} this binding\'s type",
changing))
})format!("consider {changing} this binding's type"),
1734 sugg,
1735 Applicability::HasPlaceholders,
1736 );
1737 }
1738
1739 fn is_closure_arg_with_non_locally_decided_type(&self, local: Local) -> bool {
1749 if self.body.local_kind(local) != LocalKind::Arg {
1751 return false;
1752 }
1753
1754 let InstanceKind::Item(body_def_id) = self.body.source.instance else {
1756 return false;
1757 };
1758 let Some(Node::Expr(hir::Expr { hir_id: body_hir_id, kind, .. })) =
1759 self.infcx.tcx.hir_get_if_local(body_def_id)
1760 else {
1761 return false;
1762 };
1763 let ExprKind::Closure(hir::Closure { kind: hir::ClosureKind::Closure, .. }) = kind else {
1764 return false;
1765 };
1766
1767 let Node::Expr(closure_parent) = self.infcx.tcx.parent_hir_node(*body_hir_id) else {
1770 return false;
1771 };
1772 match closure_parent.kind {
1773 ExprKind::MethodCall(method, _, _, _) => self
1774 .infcx
1775 .tcx
1776 .typeck(method.hir_id.owner.def_id)
1777 .type_dependent_def_id(closure_parent.hir_id)
1778 .is_some_and(|def_id| !def_id.is_local()),
1779 ExprKind::Call(func, _) => self
1780 .infcx
1781 .tcx
1782 .typeck(func.hir_id.owner.def_id)
1783 .node_type_opt(func.hir_id)
1784 .and_then(|ty| match ty.kind() {
1785 ty::FnDef(def_id, _) => Some(def_id),
1786 _ => None,
1787 })
1788 .is_some_and(|def_id| !def_id.is_local()),
1789 _ => false,
1790 }
1791 }
1792}
1793
1794struct BindingFinder {
1795 span: Span,
1796}
1797
1798impl<'tcx> Visitor<'tcx> for BindingFinder {
1799 type Result = ControlFlow<hir::HirId>;
1800 fn visit_stmt(&mut self, s: &'tcx hir::Stmt<'tcx>) -> Self::Result {
1801 if let hir::StmtKind::Let(local) = s.kind
1802 && local.pat.span == self.span
1803 {
1804 ControlFlow::Break(local.hir_id)
1805 } else {
1806 hir::intravisit::walk_stmt(self, s)
1807 }
1808 }
1809
1810 fn visit_param(&mut self, param: &'tcx hir::Param<'tcx>) -> Self::Result {
1811 if let hir::Pat { kind: hir::PatKind::Ref(_, _, _), span, .. } = param.pat
1812 && *span == self.span
1813 {
1814 ControlFlow::Break(param.hir_id)
1815 } else {
1816 ControlFlow::Continue(())
1817 }
1818 }
1819}
1820
1821fn mut_borrow_of_mutable_ref(local_decl: &LocalDecl<'_>, local_name: Option<Symbol>) -> bool {
1822 {
use ::tracing::__macro_support::Callsite as _;
static __CALLSITE: ::tracing::callsite::DefaultCallsite =
{
static META: ::tracing::Metadata<'static> =
{
::tracing_core::metadata::Metadata::new("event /rustc-dev/cea272fa356e94bd2ee2cadf376630aa0683867a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs:1822",
"rustc_borrowck::diagnostics::mutability_errors",
::tracing::Level::DEBUG,
::tracing_core::__macro_support::Option::Some("/rustc-dev/cea272fa356e94bd2ee2cadf376630aa0683867a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs"),
::tracing_core::__macro_support::Option::Some(1822u32),
::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};
__CALLSITE.metadata().fields().value_set_all(&[(::tracing::__macro_support::Option::Some(&format_args!("local_info: {0:?}, ty.kind(): {1:?}",
local_decl.local_info, local_decl.ty.kind()) as
&dyn ::tracing::field::Value))])
});
} else { ; }
};debug!("local_info: {:?}, ty.kind(): {:?}", local_decl.local_info, local_decl.ty.kind());
1823
1824 match *local_decl.local_info() {
1825 LocalInfo::User(mir::BindingForm::Var(mir::VarBindingForm {
1827 binding_mode: BindingMode(ByRef::No, Mutability::Not),
1828 ..
1829 })) => #[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)),
1830 LocalInfo::User(mir::BindingForm::ImplicitSelf(kind)) => {
1831 kind == hir::ImplicitSelfKind::RefMut
1837 }
1838 _ if Some(kw::SelfLower) == local_name => {
1839 #[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))
1843 }
1844 _ => false,
1845 }
1846}
1847
1848fn suggest_ampmut_self(tcx: TyCtxt<'_>, span: Span) -> (Span, String) {
1849 match tcx.sess.source_map().span_to_snippet(span) {
1850 Ok(snippet) if snippet.ends_with("self") => {
1851 (span.with_hi(span.hi() - BytePos(4)).shrink_to_hi(), "mut ".to_string())
1852 }
1853 _ => (span, "&mut self".to_string()),
1854 }
1855}
1856
1857enum AmpMutSugg {
1858 Type {
1861 span: Span,
1862 suggestion: String,
1863 additional: Option<(Span, String)>,
1864 },
1865 Expr {
1867 span: Span,
1868 suggestion: String,
1869 },
1870 MapGetMut {
1872 span: Span,
1873 suggestion: String,
1874 },
1875 ChangeBinding,
1876}
1877
1878fn suggest_ampmut<'tcx>(
1894 infcx: &crate::BorrowckInferCtxt<'tcx>,
1895 body: &Body<'tcx>,
1896 opt_assignment_rhs_stmt: Option<&Statement<'tcx>>,
1897) -> Option<AmpMutSugg> {
1898 let tcx = infcx.tcx;
1899 if let Some(rhs_stmt) = opt_assignment_rhs_stmt
1908 && let StatementKind::Assign((lhs, rvalue)) = &rhs_stmt.kind
1909 && let mut rhs_span = rhs_stmt.source_info.span
1910 && let Ok(mut rhs_str) = tcx.sess.source_map().span_to_snippet(rhs_span)
1911 {
1912 let mut rvalue = rvalue;
1913
1914 if let Rvalue::Ref(_, BorrowKind::Shared, place) = rvalue
1918 && place.projection.len() == 1
1919 && place.projection[0] == ProjectionElem::Deref
1920 && let Some(assign) = find_assignments(&body, place.local).first()
1921 {
1922 if let Some(user_ty_projs) = body.local_decls[lhs.local].user_ty.as_ref()
1926 && let [user_ty_proj] = user_ty_projs.contents.as_slice()
1927 && user_ty_proj.projs.is_empty()
1928 && let Either::Left(rhs_stmt_new) = body.stmt_at(*assign)
1929 && let StatementKind::Assign((_, rvalue_new)) = &rhs_stmt_new.kind
1930 && let rhs_span_new = rhs_stmt_new.source_info.span
1931 && let Ok(rhs_str_new) = tcx.sess.source_map().span_to_snippet(rhs_span_new)
1932 {
1933 (rvalue, rhs_span, rhs_str) = (rvalue_new, rhs_span_new, rhs_str_new);
1934 }
1935
1936 if let Either::Right(call) = body.stmt_at(*assign)
1937 && let TerminatorKind::Call { func: Operand::Constant(const_operand), args, .. } =
1938 &call.kind
1939 && let ty::FnDef(method_def_id, method_args) = *const_operand.ty().kind()
1940 && let Some(trait_) = tcx.trait_of_assoc(method_def_id)
1941 && tcx.is_lang_item(trait_, LangItem::Index)
1942 {
1943 let trait_ref = ty::TraitRef::from_assoc(
1944 tcx,
1945 tcx.require_lang_item(LangItem::IndexMut, rhs_span),
1946 method_args.no_bound_vars().unwrap(),
1947 );
1948 if !infcx
1950 .type_implements_trait(trait_ref.def_id, trait_ref.args, infcx.param_env)
1951 .must_apply_considering_regions()
1952 {
1953 if let ty::Adt(def, _) = trait_ref.self_ty().kind()
1955 && [sym::BTreeMap, sym::HashMap]
1956 .into_iter()
1957 .any(|s| tcx.is_diagnostic_item(s, def.did()))
1958 && let [map, key] = &**args
1959 && let Ok(map) = tcx.sess.source_map().span_to_snippet(map.span)
1960 && let Ok(key) = tcx.sess.source_map().span_to_snippet(key.span)
1961 {
1962 let span = rhs_span;
1963 let suggestion = ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("{0}.get_mut({1}).unwrap()", map,
key))
})format!("{map}.get_mut({key}).unwrap()");
1964 return Some(AmpMutSugg::MapGetMut { span, suggestion });
1965 }
1966 return None;
1967 }
1968 }
1969 }
1970
1971 let sugg = match rvalue {
1972 Rvalue::Ref(_, BorrowKind::Shared, _) if let Some(ref_idx) = rhs_str.find('&') => {
1973 Some((
1975 rhs_span.with_lo(rhs_span.lo() + BytePos(ref_idx as u32 + 1)).shrink_to_lo(),
1976 "mut ".to_owned(),
1977 ))
1978 }
1979 Rvalue::RawPtr(RawPtrKind::Const, _) if let Some(const_idx) = rhs_str.find("const") => {
1980 let const_idx = const_idx as u32;
1982 Some((
1983 rhs_span
1984 .with_lo(rhs_span.lo() + BytePos(const_idx))
1985 .with_hi(rhs_span.lo() + BytePos(const_idx + "const".len() as u32)),
1986 "mut".to_owned(),
1987 ))
1988 }
1989 _ => None,
1990 };
1991
1992 if let Some((span, suggestion)) = sugg {
1993 return Some(AmpMutSugg::Expr { span, suggestion });
1994 }
1995 }
1996
1997 Some(AmpMutSugg::ChangeBinding)
1998}
1999
2000fn is_closure_like(ty: Ty<'_>) -> bool {
2002 ty.is_closure() || ty.is_coroutine() || ty.is_coroutine_closure()
2003}
2004
2005fn get_mut_span_in_struct_field<'tcx>(
2013 tcx: TyCtxt<'tcx>,
2014 ty: Ty<'tcx>,
2015 field: FieldIdx,
2016) -> Option<Span> {
2017 if let ty::Ref(_, ty, _) = ty.kind()
2019 && let ty::Adt(def, _) = ty.kind()
2020 && let field = def.all_fields().nth(field.index())?
2021 && let hir::Node::Field(field) = tcx.hir_node_by_def_id(field.did.as_local()?)
2024 && let hir::TyKind::Ref(lt, hir::MutTy { mutbl: hir::Mutability::Not, ty }) = field.ty.kind
2025 {
2026 return Some(lt.ident.span.between(ty.span));
2027 }
2028
2029 None
2030}
2031
2032fn suggest_ref_mut(tcx: TyCtxt<'_>, span: Span) -> Option<Span> {
2034 let pattern_str = tcx.sess.source_map().span_to_snippet(span).ok()?;
2035 if let Some(rest) = pattern_str.strip_prefix("ref")
2036 && rest.starts_with(rustc_lexer::is_whitespace)
2037 {
2038 let span = span.with_lo(span.lo() + BytePos(4)).shrink_to_lo();
2039 Some(span)
2040 } else {
2041 None
2042 }
2043}