Skip to main content

rustc_borrowck/diagnostics/
mutability_errors.rs

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
33/// Finds all statements that assign directly to local (i.e., X = ...) and returns their
34/// locations.
35fn 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 the place is immutable then:
108                //
109                // - Either we deref an immutable ref to get to our final place.
110                //    - We don't capture derefs of raw ptrs
111                // - Or the final place is immut because the root variable of the capture
112                //   isn't marked mut and we should suggest that to the user.
113                if imm_borrow_derefed {
114                    // If we deref an immutable ref then the suggestion here doesn't help.
115                    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        // `act` and `acted_on` are strings that let us abstract over
201        // the verbs used in some diagnostic messages.
202        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                            // We've encountered a second (or more) attempt to mutably borrow an
229                            // immutable binding, so the likely problem is with the binding
230                            // declaration, not the use. We collect these in a single diagnostic
231                            // and make the binding the primary span of the error.
232                            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            // Suggest making an existing shared borrow in a struct definition a mutable borrow.
276            //
277            // This is applicable when we have a deref of a field access to a deref of a local -
278            // something like `*((*_1).0`. The local that we get will be a reference to the
279            // struct we've got a field access of (it must be a reference since there's a deref
280            // after the field access).
281            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            // Suggest removing a `&mut` from the use of a mutable reference.
305            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                            // In calls, `&mut &mut T` may be deref-coerced to `&mut T`, and
358                            // removing the extra `&mut` is the most direct suggestion. But for
359                            // pattern-matching expressions (`match`, `if let`, `while let`), that
360                            // can easily turn into a move, so prefer suggesting an explicit
361                            // reborrow via `&mut *x` instead.
362                            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                                // Best-effort structured suggestion: insert `*` after `&mut `.
403                                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                                // We don't have access to the HIR to get accurate spans, but we
414                                // can give a best effort structured suggestion.
415                                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                            // This can occur with things like `(&mut self).foo()`.
424                            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            // We want to suggest users use `let mut` for local (user
450            // variable) mutations...
451            PlaceRef { local, projection: [] }
452                if self.body.local_decls[local].can_be_made_mutable() =>
453            {
454                // ... but it doesn't make sense to suggest it on
455                // variables that are `ref x`, `ref mut x`, `&self`,
456                // or `&mut self` (such variables are simply not
457                // mutable).
458                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            // Also suggest adding mut for upvars.
474            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            // Complete hack to approximate old AST-borrowck diagnostic: if the span starts
528            // with a mutable borrow of a local variable, then just suggest the user remove it.
529            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            // We want to point out when a `&` can be readily replaced
557            // with an `&mut`.
558            //
559            // FIXME: can this case be generalized to work for an
560            // arbitrary base for the projection?
561            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    /// Suggest `map[k] = v` => `map.insert(k, v)` and the like.
657    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            /// Walks through the HIR, looking for the corresponding span for this error.
664            /// When it finds it, see if it corresponds to assignment operator whose LHS
665            /// is an index expr.
666            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                        // val[index] = rv;
687                        // ---------- place
688                        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                                    // val.insert(index, rv);
697                                    (
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                                    // if let Some(v) = val.get_mut(index) { *v = rv; }
709                                    (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                                    // let x = val.entry(index).or_insert(rv);
722                                    (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                        // val[index].path(args..);
742                        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    /// User cannot make signature of a trait mutable without changing the
782    /// trait. So we find if this error belongs to a trait and if so we move
783    /// suggestion to the trait or disable it if it is out of scope of this crate
784    ///
785    /// The returned values are:
786    ///  - is the current item an assoc `fn` of an impl that corresponds to a trait def? if so, we
787    ///    have to suggest changing both the impl `fn` arg and the trait `fn` arg
788    ///  - is the trait from the local crate? If not, we can't suggest changing signatures
789    ///  - `Span` of the argument in the trait definition
790    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        // With ref-binding patterns, the mutability suggestion has to apply to
842        // the binding, not the reference (which would be a type error):
843        //
844        // `let &b = a;` -> `let &(mut b) = a;`
845        // or
846        // `fn foo(&x: &i32)` -> `fn foo(&(mut x): &i32)`
847        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    // Point to span of upvar making closure call that requires a mutable borrow
884    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                // We have an origin for this closure kind starting at this root variable so it's
897                // safe to unwrap here.
898                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            // Sometimes we deliberately don't store the name of a place when coming from a macro in
940            // another crate. We generally want to limit those diagnostics a little, to hide
941            // implementation details (such as those from pin!() or format!()). In that case show a
942            // slightly different error message, or none at all if something else happened. In other
943            // cases the message is likely not useful.
944            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    // Attempt to search similar mutable associated items for suggestion.
959    // In the future, attempt in all path but initially for RHS of for_loop
960    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            // `span` corresponds to the expression being iterated, find the `for`-loop desugared
983            // expression with that span in order to identify potential fixes when encountering a
984            // read-only iterator that should be mutable.
985            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                        // We have `for _ in iter.read_only_iter()`, try to
991                        // suggest `for _ in iter.mutable_iter()` instead.
992                        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                        // We have `for _ in &i`, suggest `for _ in &mut i`.
1025                        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    /// When modifying a binding from inside of an `Fn` closure, point at the binding definition.
1039    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    /// Targeted error when encountering an `FnMut` closure where an `Fn` closure was expected.
1083    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        // If the HIR node is a function or method call, get the DefId
1096        // of the callee function or method, the span, and args of the call expr
1097        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 we can detect the expression to be a function or method call where the closure was
1122        // an argument, we point at the function or method definition argument...
1123        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            // ...otherwise we are probably in the tail expression of the function, point at the
1171            // return type.
1172            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                    // Check that the type has an `iter_mut` method.
1209                    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            // Do not suggest changing the signature when the trait comes from another crate.
1248            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        // Do not suggest changing type if that is not under user control.
1256        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                // Check if the RHS is from desugaring.
1275                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                    // `&self` in async functions have a `desugaring_kind`, but the local we assign
1291                    // it with does not, so use the local_span for our checks later.
1292                    source_span = Some(local_span);
1293                    if let Some(DesugaringKind::ForLoop) = local_span.desugaring_kind() {
1294                        // On for loops, RHS points to the iterator part.
1295                        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                // Don't create labels for compiler-generated spans or spans not from users' code.
1305                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                // This could be because we're in an `async fn`.
1312                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                // `Expr` suggestions should change type annotations if they already exist (probably immut),
1377                // but do not add new type annotations.
1378                (<[_]>::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        // Find a binding's type to make mutable.
1384        let (binding_exists, span) = match local_var_ty_info {
1385            // If this is a variable binding with an explicit type,
1386            // then we will suggest changing it to be mutable.
1387            // This is `Applicability::MachineApplicable`.
1388            Some(ty_span) => (true, ty_span),
1389
1390            // Otherwise, we'll suggest *adding* an annotated type, we'll suggest
1391            // the RHS's type for that.
1392            // This is `Applicability::HasPlaceholders`.
1393            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        // If the binding already exists and is a reference with an explicit
1402        // lifetime, then we can suggest adding ` mut`. This is special-cased from
1403        // the path without an explicit lifetime.
1404        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            // Note that `&' a T` is invalid so this is correct.
1407            && 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        // If there is already a binding, we modify it to be `mut`.
1412        } else if binding_exists {
1413            // Shrink the span to just after the `&` in `&variable`.
1414            let span = span.with_lo(span.lo() + BytePos(1)).shrink_to_lo();
1415            (span, "mut ".to_owned(), true)
1416        } else {
1417            // Otherwise, suggest that the user annotates the binding; We provide the
1418            // type of the local.
1419            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            // Suggest changing `&x` to `&mut x` and changing `&T` to `&mut T` at the same time.
1426            let has_change = !sugg.is_empty();
1427            sugg.push((sugg_span, sugg_str));
1428            suggest(
1429                sugg,
1430                Applicability::MachineApplicable,
1431                // FIXME(fee1-dead) this somehow doesn't fire
1432                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                    // FIXME: This error message isn't useful, since we're just
1472                    // vaguely suggesting to clone a value that already
1473                    // implements `Clone`.
1474                    //
1475                    // A correct suggestion here would take into account the fact
1476                    // that inference may be affected by missing types on bindings,
1477                    // etc., to improve "tests/ui/borrowck/issue-91206.stderr", for
1478                    // example.
1479                }
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                    // The type doesn't implement Clone.
1494                    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                    // The type doesn't implement Clone because of unmet obligations.
1534                    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    /// Returns `true` if `local` is an argument in a closure passed to a
1564    /// function defined in another crate.
1565    ///
1566    /// For example, in the following code this function returns `true` for `x`
1567    /// since `Option::inspect()` is not defined in the current crate:
1568    ///
1569    /// ```text
1570    /// some_option.as_mut().inspect(|x| {
1571    /// ```
1572    fn is_closure_arg_with_non_locally_decided_type(&self, local: Local) -> bool {
1573        // We don't care about regular local variables, only args.
1574        if self.body.local_kind(local) != LocalKind::Arg {
1575            return false;
1576        }
1577
1578        // Make sure we are inside a closure.
1579        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        // Check if the method/function that our closure is passed to is defined
1592        // in another crate.
1593        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        // Check if mutably borrowing a mutable reference.
1650        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            // Check if the user variable is a `&mut self` and we can therefore
1656            // suggest removing the `&mut`.
1657            //
1658            // Deliberately fall into this case for all implicit self types,
1659            // so that we don't fall into the next case with them.
1660            kind == hir::ImplicitSelfKind::RefMut
1661        }
1662        _ if Some(kw::SelfLower) == local_name => {
1663            // Otherwise, check if the name is the `self` keyword - in which case
1664            // we have an explicit self. Do the same thing in this case and check
1665            // for a `self: &mut Self` to suggest removing the `&mut`.
1666            #[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 suggestion. Changes `&self` to `&mut self`, `x: &T` to `x: &mut T`,
1683    /// `ref x` to `ref mut x`, etc.
1684    Type {
1685        span: Span,
1686        suggestion: String,
1687        additional: Option<(Span, String)>,
1688    },
1689    /// Suggestion for expressions, `&x` to `&mut x`, `&x[i]` to `&mut x[i]`, etc.
1690    Expr {
1691        span: Span,
1692        suggestion: String,
1693    },
1694    /// Suggests `.get_mut` in the case of `&map[&key]` for Hash/BTreeMap.
1695    MapGetMut {
1696        span: Span,
1697        suggestion: String,
1698    },
1699    ChangeBinding,
1700}
1701
1702// When we want to suggest a user change a local variable to be a `&mut`, there
1703// are three potential "obvious" things to highlight:
1704//
1705// let ident [: Type] [= RightHandSideExpression];
1706//     ^^^^^    ^^^^     ^^^^^^^^^^^^^^^^^^^^^^^
1707//     (1.)     (2.)              (3.)
1708//
1709// We can always fallback on highlighting the first. But chances are good that
1710// the user experience will be better if we highlight one of the others if possible;
1711// for example, if the RHS is present and the Type is not, then the type is going to
1712// be inferred *from* the RHS, which means we should highlight that (and suggest
1713// that they borrow the RHS mutably).
1714//
1715// This implementation attempts to emulate AST-borrowck prioritization
1716// by trying (3.), then (2.) and finally falling back on (1.).
1717fn 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 there is a RHS and it starts with a `&` from it, then check if it is
1724    // mutable, and if not, put suggest putting `mut ` to make it mutable.
1725    // We don't have to worry about lifetime annotations here because they are
1726    // not valid when taking a reference. For example, the following is not valid Rust:
1727    //
1728    // let x: &i32 = &'a 5;
1729    //                ^^ lifetime annotation not allowed
1730    //
1731    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        // Take some special care when handling `let _x = &*_y`:
1739        // We want to know if this is part of an overloaded index, so `let x = &a[0]`,
1740        // or whether this is a usertype ascription (`let _x: &T = y`).
1741        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 this is a usertype ascription (`let _x: &T = _y`) then pierce through it as either we want
1747            // to suggest `&mut` on the expression (handled here) or we return `None` and let the caller
1748            // suggest `&mut` on the type if the expression seems fine (e.g. `let _x: &T = &mut _y`).
1749            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                // The type only implements `Index` but not `IndexMut`, we must not suggest `&mut`.
1774                if !infcx
1775                    .type_implements_trait(trait_ref.def_id, trait_ref.args, infcx.param_env)
1776                    .must_apply_considering_regions()
1777                {
1778                    // Suggest `get_mut` if type is a `BTreeMap` or `HashMap`.
1779                    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                // Shrink the span to just after the `&` in `&variable`.
1799                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                // Suggest changing `&raw const` to `&raw mut` if applicable.
1806                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
1825/// If the type is a `Coroutine`, `Closure`, or `CoroutineClosure`
1826fn is_closure_like(ty: Ty<'_>) -> bool {
1827    ty.is_closure() || ty.is_coroutine() || ty.is_coroutine_closure()
1828}
1829
1830/// Given a field that needs to be mutable, returns a span where the " mut " could go.
1831/// This function expects the local to be a reference to a struct in order to produce a span.
1832///
1833/// ```text
1834/// LL |     s: &'a   String
1835///    |           ^^^ returns a span taking up the space here
1836/// ```
1837fn get_mut_span_in_struct_field<'tcx>(
1838    tcx: TyCtxt<'tcx>,
1839    ty: Ty<'tcx>,
1840    field: FieldIdx,
1841) -> Option<Span> {
1842    // Expect our local to be a reference to a struct of some kind.
1843    if let ty::Ref(_, ty, _) = ty.kind()
1844        && let ty::Adt(def, _) = ty.kind()
1845        && let field = def.all_fields().nth(field.index())?
1846        // Now we're dealing with the actual struct that we're going to suggest a change to,
1847        // we can expect a field that is an immutable reference to a type.
1848        && 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
1857/// If possible, suggest replacing `ref` with `ref mut`.
1858fn 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}