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::def_id::DefId;
8use rustc_hir::intravisit::Visitor;
9use rustc_hir::{self as hir, BindingMode, ByRef, Node};
10use rustc_middle::bug;
11use rustc_middle::hir::place::PlaceBase;
12use rustc_middle::mir::visit::PlaceContext;
13use rustc_middle::mir::{
14    self, BindingForm, Body, BorrowKind, Local, LocalDecl, LocalInfo, LocalKind, Location,
15    Mutability, Operand, Place, PlaceRef, ProjectionElem, RawPtrKind, Rvalue, Statement,
16    StatementKind, TerminatorKind,
17};
18use rustc_middle::ty::{self, InstanceKind, Ty, TyCtxt, Upcast};
19use rustc_span::{BytePos, DesugaringKind, Span, Symbol, kw, sym};
20use rustc_trait_selection::error_reporting::InferCtxtErrorExt;
21use rustc_trait_selection::infer::InferCtxtExt;
22use rustc_trait_selection::traits;
23use tracing::{debug, trace};
24
25use crate::diagnostics::BorrowedContentSource;
26use crate::{MirBorrowckCtxt, session_diagnostics};
27
28#[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_fields_are_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)]
29pub(crate) enum AccessKind {
30    MutableBorrow,
31    Mutate,
32}
33
34/// Finds all statements that assign directly to local (i.e., X = ...) and returns their
35/// locations.
36fn find_assignments(body: &Body<'_>, local: Local) -> Vec<Location> {
37    use rustc_middle::mir::visit::Visitor;
38
39    struct FindLocalAssignmentVisitor {
40        needle: Local,
41        locations: Vec<Location>,
42    }
43
44    impl<'tcx> Visitor<'tcx> for FindLocalAssignmentVisitor {
45        fn visit_local(&mut self, local: Local, place_context: PlaceContext, location: Location) {
46            if self.needle != local {
47                return;
48            }
49
50            if place_context.is_place_assignment() {
51                self.locations.push(location);
52            }
53        }
54    }
55
56    let mut visitor = FindLocalAssignmentVisitor { needle: local, locations: ::alloc::vec::Vec::new()vec![] };
57    visitor.visit_body(body);
58    visitor.locations
59}
60
61impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
62    pub(crate) fn report_mutability_error(
63        &mut self,
64        access_place: Place<'tcx>,
65        span: Span,
66        the_place_err: PlaceRef<'tcx>,
67        error_access: AccessKind,
68        location: Location,
69    ) {
70        {
    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:70",
                        "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(70u32),
                        ::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!(
71            "report_mutability_error(\
72                access_place={:?}, span={:?}, the_place_err={:?}, error_access={:?}, location={:?},\
73            )",
74            access_place, span, the_place_err, error_access, location,
75        );
76
77        let mut err;
78        let item_msg;
79        let reason;
80        let mut opt_source = None;
81        let access_place_desc = self.describe_any_place(access_place.as_ref());
82        {
    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:82",
                        "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(82u32),
                        ::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);
83
84        match the_place_err {
85            PlaceRef { local, projection: [] } => {
86                item_msg = access_place_desc;
87                if access_place.as_local().is_some() {
88                    reason = ", as it is not declared as mutable".to_string();
89                } else {
90                    let name = self.local_name(local).expect("immutable unnamed local");
91                    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");
92                }
93            }
94
95            PlaceRef {
96                local,
97                projection: [proj_base @ .., ProjectionElem::Field(upvar_index, _)],
98            } => {
99                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(
100                    Place::ty_from(local, proj_base, self.body, self.infcx.tcx).ty
101                ));
102
103                let imm_borrow_derefed = self.upvars[upvar_index.index()]
104                    .place
105                    .deref_tys()
106                    .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)));
107
108                // If the place is immutable then:
109                //
110                // - Either we deref an immutable ref to get to our final place.
111                //    - We don't capture derefs of raw ptrs
112                // - Or the final place is immut because the root variable of the capture
113                //   isn't marked mut and we should suggest that to the user.
114                if imm_borrow_derefed {
115                    // If we deref an immutable ref then the suggestion here doesn't help.
116                    return;
117                } else {
118                    item_msg = access_place_desc;
119                    if self.is_upvar_field_projection(access_place.as_ref()).is_some() {
120                        reason = ", as it is not declared as mutable".to_string();
121                    } else {
122                        let name = self.upvars[upvar_index.index()].to_string(self.infcx.tcx);
123                        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");
124                    }
125                }
126            }
127
128            PlaceRef { local, projection: [ProjectionElem::Deref] }
129                if self.body.local_decls[local].is_ref_for_guard() =>
130            {
131                item_msg = access_place_desc;
132                reason = ", as it is immutable for the pattern guard".to_string();
133            }
134            PlaceRef { local, projection: [ProjectionElem::Deref] }
135                if self.body.local_decls[local].is_ref_to_static() =>
136            {
137                if access_place.projection.len() == 1 {
138                    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}");
139                    reason = String::new();
140                } else {
141                    item_msg = access_place_desc;
142                    let local_info = self.body.local_decls[local].local_info();
143                    let LocalInfo::StaticRef { def_id, .. } = *local_info else {
144                        ::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?");
145                    };
146                    let static_name = &self.infcx.tcx.item_name(def_id);
147                    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");
148                }
149            }
150            PlaceRef { local, projection: [proj_base @ .., ProjectionElem::Deref] } => {
151                if local == ty::CAPTURE_STRUCT_LOCAL
152                    && proj_base.is_empty()
153                    && !self.upvars.is_empty()
154                {
155                    item_msg = access_place_desc;
156                    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());
157                    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));
158
159                    reason = if self.is_upvar_field_projection(access_place.as_ref()).is_some() {
160                        ", as it is a captured variable in a `Fn` closure".to_string()
161                    } else {
162                        ", as `Fn` closures cannot mutate their captured variables".to_string()
163                    }
164                } else {
165                    let source =
166                        self.borrowed_content_source(PlaceRef { local, projection: proj_base });
167                    let pointer_type = source.describe_for_immutable_place(self.infcx.tcx);
168                    opt_source = Some(source);
169                    if let Some(desc) = self.describe_place(access_place.as_ref()) {
170                        item_msg = ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("`{0}`", desc))
    })format!("`{desc}`");
171                        reason = match error_access {
172                            AccessKind::Mutate => ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!(", which is behind {0}",
                pointer_type))
    })format!(", which is behind {pointer_type}"),
173                            AccessKind::MutableBorrow => {
174                                ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!(", as it is behind {0}",
                pointer_type))
    })format!(", as it is behind {pointer_type}")
175                            }
176                        }
177                    } else {
178                        item_msg = ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("data in {0}", pointer_type))
    })format!("data in {pointer_type}");
179                        reason = String::new();
180                    }
181                }
182            }
183
184            PlaceRef {
185                local: _,
186                projection:
187                    [
188                        ..,
189                        ProjectionElem::Index(_)
190                        | ProjectionElem::ConstantIndex { .. }
191                        | ProjectionElem::OpaqueCast { .. }
192                        | ProjectionElem::Subslice { .. }
193                        | ProjectionElem::Downcast(..)
194                        | ProjectionElem::UnwrapUnsafeBinder(_),
195                    ],
196            } => ::rustc_middle::util::bug::bug_fmt(format_args!("Unexpected immutable place."))bug!("Unexpected immutable place."),
197        }
198
199        {
    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:199",
                        "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(199u32),
                        ::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);
200
201        // `act` and `acted_on` are strings that let us abstract over
202        // the verbs used in some diagnostic messages.
203        let act;
204        let acted_on;
205        let mut suggest = true;
206        let mut mut_error = None;
207        let mut count = 1;
208
209        let span = match error_access {
210            AccessKind::Mutate => {
211                err = self.cannot_assign(span, &(item_msg + &reason));
212                act = "assign";
213                acted_on = "written to";
214                span
215            }
216            AccessKind::MutableBorrow => {
217                act = "borrow as mutable";
218                acted_on = "borrowed as mutable";
219
220                let borrow_spans = self.borrow_spans(span, location);
221                let borrow_span = borrow_spans.args_or_use();
222                match the_place_err {
223                    PlaceRef { local, projection: [] }
224                        if self.body.local_decls[local].can_be_made_mutable() =>
225                    {
226                        let span = self.body.local_decls[local].source_info.span;
227                        mut_error = Some(span);
228                        if let Some((buffered_err, c)) = self.get_buffered_mut_error(span) {
229                            // We've encountered a second (or more) attempt to mutably borrow an
230                            // immutable binding, so the likely problem is with the binding
231                            // declaration, not the use. We collect these in a single diagnostic
232                            // and make the binding the primary span of the error.
233                            err = buffered_err;
234                            count = c + 1;
235                            if count == 2 {
236                                err.replace_span_with(span, false);
237                                err.span_label(span, "not mutable");
238                            }
239                            suggest = false;
240                        } else {
241                            err = self.cannot_borrow_path_as_mutable_because(
242                                borrow_span,
243                                &item_msg,
244                                &reason,
245                            );
246                        }
247                    }
248                    _ => {
249                        err = self.cannot_borrow_path_as_mutable_because(
250                            borrow_span,
251                            &item_msg,
252                            &reason,
253                        );
254                    }
255                }
256                if suggest {
257                    borrow_spans.var_subdiag(
258                        &mut err,
259                        Some(mir::BorrowKind::Mut { kind: mir::MutBorrowKind::Default }),
260                        |_kind, var_span| {
261                            let place = self.describe_any_place(access_place.as_ref());
262                            session_diagnostics::CaptureVarCause::MutableBorrowUsePlaceClosure {
263                                place,
264                                var_span,
265                            }
266                        },
267                    );
268                }
269                borrow_span
270            }
271        };
272
273        {
    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:273",
                        "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(273u32),
                        ::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);
274
275        match the_place_err {
276            // Suggest making an existing shared borrow in a struct definition a mutable borrow.
277            //
278            // This is applicable when we have a deref of a field access to a deref of a local -
279            // something like `*((*_1).0`. The local that we get will be a reference to the
280            // struct we've got a field access of (it must be a reference since there's a deref
281            // after the field access).
282            PlaceRef {
283                local,
284                projection:
285                    [
286                        proj_base @ ..,
287                        ProjectionElem::Deref,
288                        ProjectionElem::Field(field, _),
289                        ProjectionElem::Deref,
290                    ],
291            } => {
292                err.span_label(span, ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("cannot {0}", act))
    })format!("cannot {act}"));
293
294                let place = Place::ty_from(local, proj_base, self.body, self.infcx.tcx);
295                if let Some(span) = get_mut_span_in_struct_field(self.infcx.tcx, place.ty, *field) {
296                    err.span_suggestion_verbose(
297                        span,
298                        "consider changing this to be mutable",
299                        " mut ",
300                        Applicability::MaybeIncorrect,
301                    );
302                }
303            }
304
305            // Suggest removing a `&mut` from the use of a mutable reference.
306            PlaceRef { local, projection: [] }
307                if self
308                    .body
309                    .local_decls
310                    .get(local)
311                    .is_some_and(|l| mut_borrow_of_mutable_ref(l, self.local_name(local))) =>
312            {
313                let decl = &self.body.local_decls[local];
314                err.span_label(span, ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("cannot {0}", act))
    })format!("cannot {act}"));
315                if let Some(mir::Statement {
316                    source_info,
317                    kind:
318                        mir::StatementKind::Assign(box (
319                            _,
320                            mir::Rvalue::Ref(
321                                _,
322                                mir::BorrowKind::Mut { kind: mir::MutBorrowKind::Default },
323                                _,
324                            ),
325                        )),
326                    ..
327                }) = &self.body[location.block].statements.get(location.statement_index)
328                {
329                    match *decl.local_info() {
330                        LocalInfo::User(BindingForm::Var(mir::VarBindingForm {
331                            binding_mode: BindingMode(ByRef::No, Mutability::Not),
332                            opt_ty_info: Some(sp),
333                            pat_span,
334                            ..
335                        })) => {
336                            if suggest {
337                                err.span_note(sp, "the binding is already a mutable borrow");
338                                err.span_suggestion_verbose(
339                                    pat_span.shrink_to_lo(),
340                                    "consider making the binding mutable if you need to reborrow \
341                                     multiple times",
342                                    "mut ".to_string(),
343                                    Applicability::MaybeIncorrect,
344                                );
345                            }
346                        }
347                        _ => {
348                            err.span_note(
349                                decl.source_info.span,
350                                "the binding is already a mutable borrow",
351                            );
352                        }
353                    }
354                    if let Ok(snippet) =
355                        self.infcx.tcx.sess.source_map().span_to_snippet(source_info.span)
356                    {
357                        if snippet.starts_with("&mut ") {
358                            // In calls, `&mut &mut T` may be deref-coerced to `&mut T`, and
359                            // removing the extra `&mut` is the most direct suggestion. But for
360                            // pattern-matching expressions (`match`, `if let`, `while let`), that
361                            // can easily turn into a move, so prefer suggesting an explicit
362                            // reborrow via `&mut *x` instead.
363                            let mut in_pat_scrutinee = false;
364                            let mut is_deref_coerced = false;
365                            if let Some(expr) = self.find_expr(source_info.span) {
366                                let tcx = self.infcx.tcx;
367                                let span = expr.span.source_callsite();
368                                for (_, node) in tcx.hir_parent_iter(expr.hir_id) {
369                                    if let Node::Expr(parent_expr) = node {
370                                        match parent_expr.kind {
371                                            ExprKind::Match(scrutinee, ..)
372                                                if scrutinee
373                                                    .span
374                                                    .source_callsite()
375                                                    .contains(span) =>
376                                            {
377                                                in_pat_scrutinee = true;
378                                                break;
379                                            }
380                                            ExprKind::Let(let_expr)
381                                                if let_expr
382                                                    .init
383                                                    .span
384                                                    .source_callsite()
385                                                    .contains(span) =>
386                                            {
387                                                in_pat_scrutinee = true;
388                                                break;
389                                            }
390                                            _ => {}
391                                        }
392                                    }
393                                }
394
395                                let typeck = tcx.typeck(expr.hir_id.owner.def_id);
396                                is_deref_coerced =
397                                    typeck.expr_adjustments(expr).iter().any(|adj| {
398                                        #[allow(non_exhaustive_omitted_patterns)] match adj.kind {
    ty::adjustment::Adjust::Deref(_) => true,
    _ => false,
}matches!(adj.kind, ty::adjustment::Adjust::Deref(_))
399                                    });
400                            }
401
402                            if in_pat_scrutinee {
403                                // Best-effort structured suggestion: insert `*` after `&mut `.
404                                err.span_suggestion_verbose(
405                                    source_info
406                                        .span
407                                        .with_lo(source_info.span.lo() + BytePos(5))
408                                        .shrink_to_lo(),
409                                    "to reborrow the mutable reference, add `*`",
410                                    "*",
411                                    Applicability::MaybeIncorrect,
412                                );
413                            } else if is_deref_coerced {
414                                // We don't have access to the HIR to get accurate spans, but we
415                                // can give a best effort structured suggestion.
416                                err.span_suggestion_verbose(
417                                    source_info.span.with_hi(source_info.span.lo() + BytePos(5)),
418                                    "if there is only one mutable reborrow, remove the `&mut`",
419                                    "",
420                                    Applicability::MaybeIncorrect,
421                                );
422                            }
423                        } else {
424                            // This can occur with things like `(&mut self).foo()`.
425                            err.span_help(source_info.span, "try removing `&mut` here");
426                        }
427                    } else {
428                        err.span_help(source_info.span, "try removing `&mut` here");
429                    }
430                } else if decl.mutability.is_not() {
431                    if #[allow(non_exhaustive_omitted_patterns)] match decl.local_info() {
    LocalInfo::User(BindingForm::ImplicitSelf(hir::ImplicitSelfKind::RefMut))
        => true,
    _ => false,
}matches!(
432                        decl.local_info(),
433                        LocalInfo::User(BindingForm::ImplicitSelf(hir::ImplicitSelfKind::RefMut))
434                    ) {
435                        err.note(
436                            "as `Self` may be unsized, this call attempts to take `&mut &mut self`",
437                        );
438                        err.note("however, `&mut self` expands to `self: &mut Self`, therefore `self` cannot be borrowed mutably");
439                    } else {
440                        err.span_suggestion_verbose(
441                            decl.source_info.span.shrink_to_lo(),
442                            "consider making the binding mutable",
443                            "mut ",
444                            Applicability::MachineApplicable,
445                        );
446                    };
447                }
448            }
449
450            // We want to suggest users use `let mut` for local (user
451            // variable) mutations...
452            PlaceRef { local, projection: [] }
453                if self.body.local_decls[local].can_be_made_mutable() =>
454            {
455                // ... but it doesn't make sense to suggest it on
456                // variables that are `ref x`, `ref mut x`, `&self`,
457                // or `&mut self` (such variables are simply not
458                // mutable).
459                let local_decl = &self.body.local_decls[local];
460                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);
461
462                if count < 10 {
463                    err.span_label(span, ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("cannot {0}", act))
    })format!("cannot {act}"));
464                }
465                if suggest {
466                    self.construct_mut_suggestion_for_local_binding_patterns(&mut err, local);
467                    let tcx = self.infcx.tcx;
468                    if let ty::Closure(id, _) = *the_place_err.ty(self.body, tcx).ty.kind() {
469                        self.show_mutating_upvar(tcx, id.expect_local(), the_place_err, &mut err);
470                    }
471                }
472            }
473
474            // Also suggest adding mut for upvars.
475            PlaceRef {
476                local,
477                projection: [proj_base @ .., ProjectionElem::Field(upvar_index, _)],
478            } => {
479                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(
480                    Place::ty_from(local, proj_base, self.body, self.infcx.tcx).ty
481                ));
482
483                let captured_place = self.upvars[upvar_index.index()];
484
485                err.span_label(span, ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("cannot {0}", act))
    })format!("cannot {act}"));
486
487                let upvar_hir_id = captured_place.get_root_variable();
488
489                if let Node::Pat(pat) = self.infcx.tcx.hir_node(upvar_hir_id)
490                    && let hir::PatKind::Binding(hir::BindingMode::NONE, _, upvar_ident, _) =
491                        pat.kind
492                {
493                    if upvar_ident.name == kw::SelfLower {
494                        for (_, node) in self.infcx.tcx.hir_parent_iter(upvar_hir_id) {
495                            if let Some(fn_decl) = node.fn_decl() {
496                                if !#[allow(non_exhaustive_omitted_patterns)] match fn_decl.implicit_self() {
    hir::ImplicitSelfKind::RefImm | hir::ImplicitSelfKind::RefMut => true,
    _ => false,
}matches!(
497                                    fn_decl.implicit_self(),
498                                    hir::ImplicitSelfKind::RefImm | hir::ImplicitSelfKind::RefMut
499                                ) {
500                                    err.span_suggestion_verbose(
501                                        upvar_ident.span.shrink_to_lo(),
502                                        "consider changing this to be mutable",
503                                        "mut ",
504                                        Applicability::MachineApplicable,
505                                    );
506                                    break;
507                                }
508                            }
509                        }
510                    } else {
511                        err.span_suggestion_verbose(
512                            upvar_ident.span.shrink_to_lo(),
513                            "consider changing this to be mutable",
514                            "mut ",
515                            Applicability::MachineApplicable,
516                        );
517                    }
518                }
519
520                let tcx = self.infcx.tcx;
521                if let ty::Ref(_, ty, Mutability::Mut) = the_place_err.ty(self.body, tcx).ty.kind()
522                    && let ty::Closure(id, _) = *ty.kind()
523                {
524                    self.show_mutating_upvar(tcx, id.expect_local(), the_place_err, &mut err);
525                }
526            }
527
528            // Complete hack to approximate old AST-borrowck diagnostic: if the span starts
529            // with a mutable borrow of a local variable, then just suggest the user remove it.
530            PlaceRef { local: _, projection: [] }
531                if self
532                    .infcx
533                    .tcx
534                    .sess
535                    .source_map()
536                    .span_to_snippet(span)
537                    .is_ok_and(|snippet| snippet.starts_with("&mut ")) =>
538            {
539                err.span_label(span, ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("cannot {0}", act))
    })format!("cannot {act}"));
540                err.span_suggestion_verbose(
541                    span.with_hi(span.lo() + BytePos(5)),
542                    "try removing `&mut` here",
543                    "",
544                    Applicability::MaybeIncorrect,
545                );
546            }
547
548            PlaceRef { local, projection: [ProjectionElem::Deref] }
549                if self.body.local_decls[local].is_ref_for_guard() =>
550            {
551                err.span_label(span, ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("cannot {0}", act))
    })format!("cannot {act}"));
552                err.note(
553                    "variables bound in patterns are immutable until the end of the pattern guard",
554                );
555            }
556
557            // We want to point out when a `&` can be readily replaced
558            // with an `&mut`.
559            //
560            // FIXME: can this case be generalized to work for an
561            // arbitrary base for the projection?
562            PlaceRef { local, projection: [ProjectionElem::Deref] }
563                if self.body.local_decls[local].is_user_variable() =>
564            {
565                let local_decl = &self.body.local_decls[local];
566
567                let (pointer_sigil, pointer_desc) =
568                    if local_decl.ty.is_ref() { ("&", "reference") } else { ("*const", "pointer") };
569
570                match self.local_name(local) {
571                    Some(name) if !local_decl.from_compiler_desugaring() => {
572                        err.span_label(
573                            span,
574                            ::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!(
575                                "`{name}` is a `{pointer_sigil}` {pointer_desc}, so it cannot be \
576                                 {acted_on}",
577                            ),
578                        );
579
580                        self.suggest_using_iter_mut(&mut err);
581                        self.suggest_make_local_mut(&mut err, local, name);
582                    }
583                    _ => {
584                        err.span_label(
585                            span,
586                            ::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}"),
587                        );
588                    }
589                }
590            }
591
592            PlaceRef { local, projection: [ProjectionElem::Deref] }
593                if local == ty::CAPTURE_STRUCT_LOCAL && !self.upvars.is_empty() =>
594            {
595                self.point_at_binding_outside_closure(&mut err, local, access_place);
596                self.expected_fn_found_fn_mut_call(&mut err, span, act);
597            }
598
599            PlaceRef { local, projection: [.., ProjectionElem::Deref] } => {
600                err.span_label(span, ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("cannot {0}", act))
    })format!("cannot {act}"));
601
602                match opt_source {
603                    Some(BorrowedContentSource::OverloadedDeref(ty)) => {
604                        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!(
605                            "trait `DerefMut` is required to modify through a dereference, \
606                             but it is not implemented for `{ty}`",
607                        ));
608                    }
609                    Some(BorrowedContentSource::OverloadedIndex(ty)) => {
610                        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!(
611                            "trait `IndexMut` is required to modify indexed content, \
612                             but it is not implemented for `{ty}`",
613                        ));
614                        self.suggest_map_index_mut_alternatives(ty, &mut err, span);
615                    }
616                    _ => {
617                        let local = &self.body.local_decls[local];
618                        match *local.local_info() {
619                            LocalInfo::StaticRef { def_id, .. } => {
620                                let span = self.infcx.tcx.def_span(def_id);
621                                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}"));
622                            }
623                            LocalInfo::ConstRef { def_id } => {
624                                let span = self.infcx.tcx.def_span(def_id);
625                                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}"));
626                            }
627                            LocalInfo::BlockTailTemp(_) | LocalInfo::Boring
628                                if !local.source_info.span.overlaps(span) =>
629                            {
630                                err.span_label(
631                                    local.source_info.span,
632                                    ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("this cannot be {0}", acted_on))
    })format!("this cannot be {acted_on}"),
633                                );
634                            }
635                            _ => {}
636                        }
637                    }
638                }
639            }
640
641            PlaceRef { local, .. } => {
642                let local = &self.body.local_decls[local];
643                if !local.source_info.span.overlaps(span) {
644                    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}"));
645                }
646                err.span_label(span, ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("cannot {0}", act))
    })format!("cannot {act}"));
647            }
648        }
649
650        if let Some(span) = mut_error {
651            self.buffer_mut_error(span, err, count);
652        } else {
653            self.buffer_error(err);
654        }
655    }
656
657    /// Suggest `map[k] = v` => `map.insert(k, v)` and the like.
658    fn suggest_map_index_mut_alternatives(&self, ty: Ty<'tcx>, err: &mut Diag<'infcx>, span: Span) {
659        let Some(adt) = ty.ty_adt_def() else { return };
660        let did = adt.did();
661        if self.infcx.tcx.is_diagnostic_item(sym::HashMap, did)
662            || self.infcx.tcx.is_diagnostic_item(sym::BTreeMap, did)
663        {
664            /// Walks through the HIR, looking for the corresponding span for this error.
665            /// When it finds it, see if it corresponds to assignment operator whose LHS
666            /// is an index expr.
667            struct SuggestIndexOperatorAlternativeVisitor<'a, 'infcx, 'tcx> {
668                assign_span: Span,
669                err: &'a mut Diag<'infcx>,
670                ty: Ty<'tcx>,
671                suggested: bool,
672            }
673            impl<'a, 'infcx, 'tcx> Visitor<'tcx> for SuggestIndexOperatorAlternativeVisitor<'a, 'infcx, 'tcx> {
674                fn visit_stmt(&mut self, stmt: &'tcx hir::Stmt<'tcx>) {
675                    hir::intravisit::walk_stmt(self, stmt);
676                    let expr = match stmt.kind {
677                        hir::StmtKind::Semi(expr) | hir::StmtKind::Expr(expr) => expr,
678                        hir::StmtKind::Let(hir::LetStmt { init: Some(expr), .. }) => expr,
679                        _ => {
680                            return;
681                        }
682                    };
683                    if let hir::ExprKind::Assign(place, rv, _sp) = expr.kind
684                        && let hir::ExprKind::Index(val, index, _) = place.kind
685                        && (expr.span == self.assign_span || place.span == self.assign_span)
686                    {
687                        // val[index] = rv;
688                        // ---------- place
689                        self.err.multipart_suggestions(
690                            ::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!(
691                                "use `.insert()` to insert a value into a `{}`, `.get_mut()` \
692                                to modify it, or the entry API for more flexibility",
693                                self.ty,
694                            ),
695                            ::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
        [::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
                        [(val.span.shrink_to_hi().with_hi(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())])),
                ::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
                        [(val.span.shrink_to_lo(),
                                    "if let Some(val) = ".to_string()),
                                (val.span.shrink_to_hi().with_hi(index.span.lo()),
                                    ".get_mut(".to_string()),
                                (index.span.shrink_to_hi().with_hi(place.span.hi()),
                                    ") { *val".to_string()),
                                (rv.span.shrink_to_hi(), "; }".to_string())])),
                ::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
                        [(val.span.shrink_to_lo(), "let val = ".to_string()),
                                (val.span.shrink_to_hi().with_hi(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![
696                                vec![
697                                    // val.insert(index, rv);
698                                    (
699                                        val.span.shrink_to_hi().with_hi(index.span.lo()),
700                                        ".insert(".to_string(),
701                                    ),
702                                    (
703                                        index.span.shrink_to_hi().with_hi(rv.span.lo()),
704                                        ", ".to_string(),
705                                    ),
706                                    (rv.span.shrink_to_hi(), ")".to_string()),
707                                ],
708                                vec![
709                                    // if let Some(v) = val.get_mut(index) { *v = rv; }
710                                    (val.span.shrink_to_lo(), "if let Some(val) = ".to_string()),
711                                    (
712                                        val.span.shrink_to_hi().with_hi(index.span.lo()),
713                                        ".get_mut(".to_string(),
714                                    ),
715                                    (
716                                        index.span.shrink_to_hi().with_hi(place.span.hi()),
717                                        ") { *val".to_string(),
718                                    ),
719                                    (rv.span.shrink_to_hi(), "; }".to_string()),
720                                ],
721                                vec![
722                                    // let x = val.entry(index).or_insert(rv);
723                                    (val.span.shrink_to_lo(), "let val = ".to_string()),
724                                    (
725                                        val.span.shrink_to_hi().with_hi(index.span.lo()),
726                                        ".entry(".to_string(),
727                                    ),
728                                    (
729                                        index.span.shrink_to_hi().with_hi(rv.span.lo()),
730                                        ").or_insert(".to_string(),
731                                    ),
732                                    (rv.span.shrink_to_hi(), ")".to_string()),
733                                ],
734                            ],
735                            Applicability::MachineApplicable,
736                        );
737                        self.suggested = true;
738                    } else if let hir::ExprKind::MethodCall(_path, receiver, _, sp) = expr.kind
739                        && let hir::ExprKind::Index(val, index, _) = receiver.kind
740                        && receiver.span == self.assign_span
741                    {
742                        // val[index].path(args..);
743                        self.err.multipart_suggestion(
744                            ::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),
745                            ::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
        [(val.span.shrink_to_lo(), "if let Some(val) = ".to_string()),
                (val.span.shrink_to_hi().with_hi(index.span.lo()),
                    ".get_mut(".to_string()),
                (index.span.shrink_to_hi().with_hi(receiver.span.hi()),
                    ") { val".to_string()),
                (sp.shrink_to_hi(), "; }".to_string())]))vec![
746                                (val.span.shrink_to_lo(), "if let Some(val) = ".to_string()),
747                                (
748                                    val.span.shrink_to_hi().with_hi(index.span.lo()),
749                                    ".get_mut(".to_string(),
750                                ),
751                                (
752                                    index.span.shrink_to_hi().with_hi(receiver.span.hi()),
753                                    ") { val".to_string(),
754                                ),
755                                (sp.shrink_to_hi(), "; }".to_string()),
756                            ],
757                            Applicability::MachineApplicable,
758                        );
759                        self.suggested = true;
760                    }
761                }
762            }
763            let def_id = self.body.source.def_id();
764            let Some(local_def_id) = def_id.as_local() else { return };
765            let Some(body) = self.infcx.tcx.hir_maybe_body_owned_by(local_def_id) else { return };
766
767            let mut v = SuggestIndexOperatorAlternativeVisitor {
768                assign_span: span,
769                err,
770                ty,
771                suggested: false,
772            };
773            v.visit_body(&body);
774            if !v.suggested {
775                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!(
776                    "to modify a `{ty}`, use `.get_mut()`, `.insert()` or the entry API",
777                ));
778            }
779        }
780    }
781
782    /// User cannot make signature of a trait mutable without changing the
783    /// trait. So we find if this error belongs to a trait and if so we move
784    /// suggestion to the trait or disable it if it is out of scope of this crate
785    ///
786    /// The returned values are:
787    ///  - is the current item an assoc `fn` of an impl that corresponds to a trait def? if so, we
788    ///    have to suggest changing both the impl `fn` arg and the trait `fn` arg
789    ///  - is the trait from the local crate? If not, we can't suggest changing signatures
790    ///  - `Span` of the argument in the trait definition
791    fn is_error_in_trait(&self, local: Local) -> (bool, bool, Option<Span>) {
792        let tcx = self.infcx.tcx;
793        if self.body.local_kind(local) != LocalKind::Arg {
794            return (false, false, None);
795        }
796        let my_def = self.body.source.def_id();
797        let Some(td) = tcx.trait_impl_of_assoc(my_def).map(|id| self.infcx.tcx.impl_trait_id(id))
798        else {
799            return (false, false, None);
800        };
801
802        let implemented_trait_item = self.infcx.tcx.trait_item_of(my_def);
803
804        (
805            true,
806            td.is_local(),
807            implemented_trait_item.and_then(|f_in_trait| {
808                let f_in_trait = f_in_trait.as_local()?;
809                if let Node::TraitItem(ti) = self.infcx.tcx.hir_node_by_def_id(f_in_trait)
810                    && let hir::TraitItemKind::Fn(sig, _) = ti.kind
811                    && let Some(ty) = sig.decl.inputs.get(local.index() - 1)
812                    && let hir::TyKind::Ref(_, mut_ty) = ty.kind
813                    && let hir::Mutability::Not = mut_ty.mutbl
814                    && sig.decl.implicit_self().has_implicit_self()
815                {
816                    Some(ty.span)
817                } else {
818                    None
819                }
820            }),
821        )
822    }
823
824    fn construct_mut_suggestion_for_local_binding_patterns(
825        &self,
826        err: &mut Diag<'_>,
827        local: Local,
828    ) {
829        let local_decl = &self.body.local_decls[local];
830        {
    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:830",
                        "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(830u32),
                        ::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);
831        let pat_span = match *local_decl.local_info() {
832            LocalInfo::User(BindingForm::Var(mir::VarBindingForm {
833                binding_mode: BindingMode(ByRef::No, Mutability::Not),
834                opt_ty_info: _,
835                opt_match_place: _,
836                pat_span,
837                introductions: _,
838            })) => pat_span,
839            _ => local_decl.source_info.span,
840        };
841
842        // With ref-binding patterns, the mutability suggestion has to apply to
843        // the binding, not the reference (which would be a type error):
844        //
845        // `let &b = a;` -> `let &(mut b) = a;`
846        // or
847        // `fn foo(&x: &i32)` -> `fn foo(&(mut x): &i32)`
848        let def_id = self.body.source.def_id();
849        if let Some(local_def_id) = def_id.as_local()
850            && let Some(body) = self.infcx.tcx.hir_maybe_body_owned_by(local_def_id)
851            && let Some(hir_id) = (BindingFinder { span: pat_span }).visit_body(&body).break_value()
852            && let node = self.infcx.tcx.hir_node(hir_id)
853            && let hir::Node::LetStmt(hir::LetStmt {
854                pat: hir::Pat { kind: hir::PatKind::Ref(_, _, _), .. },
855                ..
856            })
857            | hir::Node::Param(Param {
858                pat: hir::Pat { kind: hir::PatKind::Ref(_, _, _), .. },
859                ..
860            }) = node
861        {
862            err.multipart_suggestion(
863                "consider changing this to be mutable",
864                ::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
        [(pat_span.until(local_decl.source_info.span), "&(mut ".to_string()),
                (local_decl.source_info.span.shrink_to_hi().with_hi(pat_span.hi()),
                    ")".to_string())]))vec![
865                    (pat_span.until(local_decl.source_info.span), "&(mut ".to_string()),
866                    (
867                        local_decl.source_info.span.shrink_to_hi().with_hi(pat_span.hi()),
868                        ")".to_string(),
869                    ),
870                ],
871                Applicability::MachineApplicable,
872            );
873            return;
874        }
875
876        err.span_suggestion_verbose(
877            local_decl.source_info.span.shrink_to_lo(),
878            "consider changing this to be mutable",
879            "mut ",
880            Applicability::MachineApplicable,
881        );
882    }
883
884    // Point to span of upvar making closure call that requires a mutable borrow
885    fn show_mutating_upvar(
886        &self,
887        tcx: TyCtxt<'_>,
888        closure_local_def_id: hir::def_id::LocalDefId,
889        the_place_err: PlaceRef<'tcx>,
890        err: &mut Diag<'_>,
891    ) {
892        let tables = tcx.typeck(closure_local_def_id);
893        if let Some((span, closure_kind_origin)) = tcx.closure_kind_origin(closure_local_def_id) {
894            let reason = if let PlaceBase::Upvar(upvar_id) = closure_kind_origin.base {
895                let upvar = ty::place_to_string_for_capture(tcx, closure_kind_origin);
896                let root_hir_id = upvar_id.var_path.hir_id;
897                // We have an origin for this closure kind starting at this root variable so it's
898                // safe to unwrap here.
899                let captured_places =
900                    tables.closure_min_captures[&closure_local_def_id].get(&root_hir_id).unwrap();
901
902                let origin_projection = closure_kind_origin
903                    .projections
904                    .iter()
905                    .map(|proj| proj.kind)
906                    .collect::<Vec<_>>();
907                let mut capture_reason = String::new();
908                for captured_place in captured_places {
909                    let captured_place_kinds = captured_place
910                        .place
911                        .projections
912                        .iter()
913                        .map(|proj| proj.kind)
914                        .collect::<Vec<_>>();
915                    if rustc_middle::ty::is_ancestor_or_same_capture(
916                        &captured_place_kinds,
917                        &origin_projection,
918                    ) {
919                        match captured_place.info.capture_kind {
920                            ty::UpvarCapture::ByRef(
921                                ty::BorrowKind::Mutable | ty::BorrowKind::UniqueImmutable,
922                            ) => {
923                                capture_reason = ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("mutable borrow of `{0}`", upvar))
    })format!("mutable borrow of `{upvar}`");
924                            }
925                            ty::UpvarCapture::ByValue | ty::UpvarCapture::ByUse => {
926                                capture_reason = ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("possible mutation of `{0}`",
                upvar))
    })format!("possible mutation of `{upvar}`");
927                            }
928                            _ => ::rustc_middle::util::bug::bug_fmt(format_args!("upvar `{0}` borrowed, but not mutably",
        upvar))bug!("upvar `{upvar}` borrowed, but not mutably"),
929                        }
930                        break;
931                    }
932                }
933                if capture_reason.is_empty() {
934                    ::rustc_middle::util::bug::bug_fmt(format_args!("upvar `{0}` borrowed, but cannot find reason",
        upvar));bug!("upvar `{upvar}` borrowed, but cannot find reason");
935                }
936                capture_reason
937            } else {
938                ::rustc_middle::util::bug::bug_fmt(format_args!("not an upvar"))bug!("not an upvar")
939            };
940            // Sometimes we deliberately don't store the name of a place when coming from a macro in
941            // another crate. We generally want to limit those diagnostics a little, to hide
942            // implementation details (such as those from pin!() or format!()). In that case show a
943            // slightly different error message, or none at all if something else happened. In other
944            // cases the message is likely not useful.
945            if let Some(place_name) = self.describe_place(the_place_err) {
946                err.span_label(
947                    *span,
948                    ::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}"),
949                );
950            } else if span.from_expansion() {
951                err.span_label(
952                    *span,
953                    ::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}",),
954                );
955            }
956        }
957    }
958
959    // Attempt to search similar mutable associated items for suggestion.
960    // In the future, attempt in all path but initially for RHS of for_loop
961    fn suggest_similar_mut_method_for_for_loop(&self, err: &mut Diag<'_>, span: Span) {
962        use hir::ExprKind::{AddrOf, Block, Call, MethodCall};
963        use hir::{BorrowKind, Expr};
964
965        let tcx = self.infcx.tcx;
966        struct Finder {
967            span: Span,
968        }
969
970        impl<'tcx> Visitor<'tcx> for Finder {
971            type Result = ControlFlow<&'tcx Expr<'tcx>>;
972            fn visit_expr(&mut self, e: &'tcx hir::Expr<'tcx>) -> Self::Result {
973                if e.span == self.span {
974                    ControlFlow::Break(e)
975                } else {
976                    hir::intravisit::walk_expr(self, e)
977                }
978            }
979        }
980        if let Some(body) = tcx.hir_maybe_body_owned_by(self.mir_def_id())
981            && let Block(block, _) = body.value.kind
982        {
983            // `span` corresponds to the expression being iterated, find the `for`-loop desugared
984            // expression with that span in order to identify potential fixes when encountering a
985            // read-only iterator that should be mutable.
986            if let ControlFlow::Break(expr) = (Finder { span }).visit_block(block)
987                && let Call(_, [expr]) = expr.kind
988            {
989                match expr.kind {
990                    MethodCall(path_segment, _, _, span) => {
991                        // We have `for _ in iter.read_only_iter()`, try to
992                        // suggest `for _ in iter.mutable_iter()` instead.
993                        let opt_suggestions = tcx
994                            .typeck(path_segment.hir_id.owner.def_id)
995                            .type_dependent_def_id(expr.hir_id)
996                            .and_then(|def_id| tcx.impl_of_assoc(def_id))
997                            .map(|def_id| tcx.associated_items(def_id))
998                            .map(|assoc_items| {
999                                assoc_items
1000                                    .in_definition_order()
1001                                    .map(|assoc_item_def| assoc_item_def.ident(tcx))
1002                                    .filter(|&ident| {
1003                                        let original_method_ident = path_segment.ident;
1004                                        original_method_ident != ident
1005                                            && ident.as_str().starts_with(
1006                                                &original_method_ident.name.to_string(),
1007                                            )
1008                                    })
1009                                    .map(|ident| ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("{0}()", ident))
    })format!("{ident}()"))
1010                                    .peekable()
1011                            });
1012
1013                        if let Some(mut suggestions) = opt_suggestions
1014                            && suggestions.peek().is_some()
1015                        {
1016                            err.span_suggestions(
1017                                span,
1018                                "use mutable method",
1019                                suggestions,
1020                                Applicability::MaybeIncorrect,
1021                            );
1022                        }
1023                    }
1024                    AddrOf(BorrowKind::Ref, Mutability::Not, expr) => {
1025                        // We have `for _ in &i`, suggest `for _ in &mut i`.
1026                        err.span_suggestion_verbose(
1027                            expr.span.shrink_to_lo(),
1028                            "use a mutable iterator instead",
1029                            "mut ",
1030                            Applicability::MachineApplicable,
1031                        );
1032                    }
1033                    _ => {}
1034                }
1035            }
1036        }
1037    }
1038
1039    /// When modifying a binding from inside of an `Fn` closure, point at the binding definition.
1040    fn point_at_binding_outside_closure(
1041        &self,
1042        err: &mut Diag<'_>,
1043        local: Local,
1044        access_place: Place<'tcx>,
1045    ) {
1046        let place = access_place.as_ref();
1047        for (index, elem) in place.projection.into_iter().enumerate() {
1048            if let ProjectionElem::Deref = elem {
1049                if index == 0 {
1050                    if self.body.local_decls[local].is_ref_for_guard() {
1051                        continue;
1052                    }
1053                    if let LocalInfo::StaticRef { .. } = *self.body.local_decls[local].local_info()
1054                    {
1055                        continue;
1056                    }
1057                }
1058                if let Some(field) = self.is_upvar_field_projection(PlaceRef {
1059                    local,
1060                    projection: place.projection.split_at(index + 1).0,
1061                }) {
1062                    let var_index = field.index();
1063                    let upvar = self.upvars[var_index];
1064                    if let Some(hir_id) = upvar.info.capture_kind_expr_id {
1065                        let node = self.infcx.tcx.hir_node(hir_id);
1066                        if let hir::Node::Expr(expr) = node
1067                            && let hir::ExprKind::Path(hir::QPath::Resolved(None, path)) = expr.kind
1068                            && let hir::def::Res::Local(hir_id) = path.res
1069                            && let hir::Node::Pat(pat) = self.infcx.tcx.hir_node(hir_id)
1070                        {
1071                            let name = upvar.to_string(self.infcx.tcx);
1072                            err.span_label(
1073                                pat.span,
1074                                ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("`{0}` declared here, outside the closure",
                name))
    })format!("`{name}` declared here, outside the closure"),
1075                            );
1076                            break;
1077                        }
1078                    }
1079                }
1080            }
1081        }
1082    }
1083    /// Targeted error when encountering an `FnMut` closure where an `Fn` closure was expected.
1084    fn expected_fn_found_fn_mut_call(&self, err: &mut Diag<'_>, sp: Span, act: &str) {
1085        err.span_label(sp, ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("cannot {0}", act))
    })format!("cannot {act}"));
1086
1087        let tcx = self.infcx.tcx;
1088        let closure_id = self.mir_hir_id();
1089        let closure_span = tcx.def_span(self.mir_def_id());
1090        let fn_call_id = tcx.parent_hir_id(closure_id);
1091        let node = tcx.hir_node(fn_call_id);
1092        let def_id = tcx.hir_enclosing_body_owner(fn_call_id);
1093        let mut look_at_return = true;
1094
1095        err.span_label(closure_span, "in this closure");
1096        let closure_arg_has_fn_trait_bound =
1097            |callee_def_id, input_index, generic_args: ty::GenericArgsRef<'tcx>| {
1098                let sig = tcx.fn_sig(callee_def_id).instantiate(tcx, generic_args).skip_binder();
1099                let Some(input_ty): Option<Ty<'tcx>> = sig.inputs().get(input_index).copied()
1100                else {
1101                    return false;
1102                };
1103
1104                tcx.predicates_of(callee_def_id)
1105                    .instantiate(tcx, generic_args)
1106                    .predicates
1107                    .iter()
1108                    .any(|predicate| {
1109                        predicate.as_trait_clause().is_some_and(|trait_pred| {
1110                            trait_pred.polarity() == ty::PredicatePolarity::Positive
1111                                && tcx.fn_trait_kind_from_def_id(trait_pred.def_id())
1112                                    == Some(ty::ClosureKind::Fn)
1113                                && trait_pred.self_ty().skip_binder().peel_refs()
1114                                    == input_ty.peel_refs()
1115                        })
1116                    })
1117            };
1118
1119        // If the HIR node is a function or method call, get the DefId
1120        // of the callee function or method, the span, and argument info for the call expr.
1121        let get_call_details =
1122            || -> Option<(DefId, Span, usize, usize, ty::GenericArgsRef<'tcx>)> {
1123                let hir::Node::Expr(hir::Expr { hir_id, kind, .. }) = node else {
1124                    return None;
1125                };
1126
1127                let typeck_results = tcx.typeck(def_id);
1128
1129                match kind {
1130                    hir::ExprKind::Call(expr, args) => {
1131                        if let Some(ty::FnDef(def_id, generic_args)) =
1132                            typeck_results.node_type_opt(expr.hir_id).as_ref().map(|ty| ty.kind())
1133                        {
1134                            let arg_pos = args.iter().position(|arg| arg.hir_id == closure_id)?;
1135                            Some((*def_id, expr.span, arg_pos, arg_pos, generic_args))
1136                        } else {
1137                            None
1138                        }
1139                    }
1140                    hir::ExprKind::MethodCall(_, _, args, span) => {
1141                        let arg_pos = args.iter().position(|arg| arg.hir_id == closure_id)?;
1142                        let def_id = typeck_results.type_dependent_def_id(*hir_id)?;
1143                        let generic_args = typeck_results.node_args_opt(*hir_id)?;
1144                        Some((def_id, *span, arg_pos, arg_pos + 1, generic_args))
1145                    }
1146                    _ => None,
1147                }
1148            };
1149
1150        // If we can detect the expression to be a function or method call where the closure was
1151        // an argument, we point at the function or method definition argument...
1152        if let Some((callee_def_id, call_span, arg_pos, input_index, generic_args)) =
1153            get_call_details()
1154        {
1155            let arg = match tcx.hir_get_if_local(callee_def_id) {
1156                Some(
1157                    hir::Node::Item(hir::Item {
1158                        kind: hir::ItemKind::Fn { ident, sig, .. }, ..
1159                    })
1160                    | hir::Node::TraitItem(hir::TraitItem {
1161                        ident,
1162                        kind: hir::TraitItemKind::Fn(sig, _),
1163                        ..
1164                    })
1165                    | hir::Node::ImplItem(hir::ImplItem {
1166                        ident,
1167                        kind: hir::ImplItemKind::Fn(sig, _),
1168                        ..
1169                    }),
1170                ) => Some(
1171                    sig.decl
1172                        .inputs
1173                        .get(
1174                            arg_pos
1175                                + if sig.decl.implicit_self().has_implicit_self() { 1 } else { 0 },
1176                        )
1177                        .map(|arg| arg.span)
1178                        .unwrap_or(ident.span),
1179                ),
1180                _ => None,
1181            };
1182            if let Some(span) = arg {
1183                err.span_label(span, "change this to accept `FnMut` instead of `Fn`");
1184                err.span_label(call_span, "expects `Fn` instead of `FnMut`");
1185                look_at_return = false;
1186            } else if closure_arg_has_fn_trait_bound(callee_def_id, input_index, generic_args) {
1187                // The callee is not local, so we cannot point at its argument declaration, but we
1188                // can still explain that this call site expects an `Fn` closure. Avoid falling
1189                // through to the enclosing function's return type, which is misleading in cases
1190                // like `flat_map(|_| external::map(|_| ...))`.
1191                err.span_label(call_span, "expects `Fn` instead of `FnMut`");
1192                look_at_return = false;
1193            }
1194        }
1195
1196        if look_at_return && tcx.hir_get_fn_id_for_return_block(closure_id).is_some() {
1197            // ...otherwise we are probably in the tail expression of the function, point at the
1198            // return type.
1199            match tcx.hir_node_by_def_id(tcx.hir_get_parent_item(fn_call_id).def_id) {
1200                hir::Node::Item(hir::Item {
1201                    kind: hir::ItemKind::Fn { ident, sig, .. }, ..
1202                })
1203                | hir::Node::TraitItem(hir::TraitItem {
1204                    ident,
1205                    kind: hir::TraitItemKind::Fn(sig, _),
1206                    ..
1207                })
1208                | hir::Node::ImplItem(hir::ImplItem {
1209                    ident,
1210                    kind: hir::ImplItemKind::Fn(sig, _),
1211                    ..
1212                }) => {
1213                    err.span_label(ident.span, "");
1214                    err.span_label(
1215                        sig.decl.output.span(),
1216                        "change this to return `FnMut` instead of `Fn`",
1217                    );
1218                }
1219                _ => {}
1220            }
1221        }
1222    }
1223
1224    fn suggest_using_iter_mut(&self, err: &mut Diag<'_>) {
1225        let source = self.body.source;
1226        if let InstanceKind::Item(def_id) = source.instance
1227            && let Some(Node::Expr(hir::Expr { hir_id, kind, .. })) =
1228                self.infcx.tcx.hir_get_if_local(def_id)
1229            && let ExprKind::Closure(hir::Closure { kind: hir::ClosureKind::Closure, .. }) = kind
1230            && let Node::Expr(expr) = self.infcx.tcx.parent_hir_node(*hir_id)
1231        {
1232            let mut cur_expr = expr;
1233            while let ExprKind::MethodCall(path_segment, recv, _, _) = cur_expr.kind {
1234                if path_segment.ident.name == sym::iter {
1235                    // Check that the type has an `iter_mut` method.
1236                    let res = self
1237                        .infcx
1238                        .tcx
1239                        .typeck(path_segment.hir_id.owner.def_id)
1240                        .type_dependent_def_id(cur_expr.hir_id)
1241                        .and_then(|def_id| self.infcx.tcx.impl_of_assoc(def_id))
1242                        .map(|def_id| self.infcx.tcx.associated_items(def_id))
1243                        .map(|assoc_items| {
1244                            assoc_items.filter_by_name_unhygienic(sym::iter_mut).peekable()
1245                        });
1246
1247                    if let Some(mut res) = res
1248                        && res.peek().is_some()
1249                    {
1250                        err.span_suggestion_verbose(
1251                            path_segment.ident.span,
1252                            "you may want to use `iter_mut` here",
1253                            "iter_mut",
1254                            Applicability::MaybeIncorrect,
1255                        );
1256                    }
1257                    break;
1258                } else {
1259                    cur_expr = recv;
1260                }
1261            }
1262        }
1263    }
1264
1265    fn suggest_make_local_mut(&self, err: &mut Diag<'_>, local: Local, name: Symbol) {
1266        let local_decl = &self.body.local_decls[local];
1267
1268        let (pointer_sigil, pointer_desc) =
1269            if local_decl.ty.is_ref() { ("&", "reference") } else { ("*const", "pointer") };
1270
1271        let (is_trait_sig, is_local, local_trait) = self.is_error_in_trait(local);
1272
1273        if is_trait_sig && !is_local {
1274            // Do not suggest changing the signature when the trait comes from another crate.
1275            err.span_label(
1276                local_decl.source_info.span,
1277                ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("this is an immutable {0}",
                pointer_desc))
    })format!("this is an immutable {pointer_desc}"),
1278            );
1279            return;
1280        }
1281
1282        // Do not suggest changing type if that is not under user control.
1283        if self.is_closure_arg_with_non_locally_decided_type(local) {
1284            return;
1285        }
1286
1287        let decl_span = local_decl.source_info.span;
1288
1289        let (amp_mut_sugg, local_var_ty_info) = match *local_decl.local_info() {
1290            LocalInfo::User(mir::BindingForm::ImplicitSelf(_)) => {
1291                let (span, suggestion) = suggest_ampmut_self(self.infcx.tcx, decl_span);
1292                let additional = local_trait.map(|span| suggest_ampmut_self(self.infcx.tcx, span));
1293                (AmpMutSugg::Type { span, suggestion, additional }, None)
1294            }
1295
1296            LocalInfo::User(mir::BindingForm::Var(mir::VarBindingForm {
1297                binding_mode: BindingMode(ByRef::No, _),
1298                opt_ty_info,
1299                ..
1300            })) => {
1301                // Check if the RHS is from desugaring.
1302                let first_assignment = find_assignments(&self.body, local).first().copied();
1303                let first_assignment_stmt = first_assignment
1304                    .and_then(|loc| self.body[loc.block].statements.get(loc.statement_index));
1305                {
    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:1305",
                        "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(1305u32),
                        ::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);
1306                let opt_assignment_rhs_span =
1307                    first_assignment.map(|loc| self.body.source_info(loc).span);
1308                let mut source_span = opt_assignment_rhs_span;
1309                if let Some(mir::Statement {
1310                    source_info: _,
1311                    kind:
1312                        mir::StatementKind::Assign(box (
1313                            _,
1314                            mir::Rvalue::Use(mir::Operand::Copy(place), _),
1315                        )),
1316                    ..
1317                }) = first_assignment_stmt
1318                {
1319                    let local_span = self.body.local_decls[place.local].source_info.span;
1320                    // `&self` in async functions have a `desugaring_kind`, but the local we assign
1321                    // it with does not, so use the local_span for our checks later.
1322                    source_span = Some(local_span);
1323                    if let Some(DesugaringKind::ForLoop) = local_span.desugaring_kind() {
1324                        // On for loops, RHS points to the iterator part.
1325                        self.suggest_similar_mut_method_for_for_loop(err, local_span);
1326                        err.span_label(
1327                            local_span,
1328                            ::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",),
1329                        );
1330                        return;
1331                    }
1332                }
1333
1334                // Don't create labels for compiler-generated spans or spans not from users' code.
1335                if source_span.is_some_and(|s| {
1336                    s.desugaring_kind().is_some() || self.infcx.tcx.sess.source_map().is_imported(s)
1337                }) {
1338                    return;
1339                }
1340
1341                // This could be because we're in an `async fn`.
1342                if name == kw::SelfLower && opt_ty_info.is_none() {
1343                    let (span, suggestion) = suggest_ampmut_self(self.infcx.tcx, decl_span);
1344                    (AmpMutSugg::Type { span, suggestion, additional: None }, None)
1345                } else if let Some(sugg) =
1346                    suggest_ampmut(self.infcx, self.body(), first_assignment_stmt)
1347                {
1348                    (sugg, opt_ty_info)
1349                } else {
1350                    return;
1351                }
1352            }
1353
1354            LocalInfo::User(mir::BindingForm::Var(mir::VarBindingForm {
1355                binding_mode: BindingMode(ByRef::Yes(..), _),
1356                ..
1357            })) => {
1358                let pattern_span: Span = local_decl.source_info.span;
1359                let Some(span) = suggest_ref_mut(self.infcx.tcx, pattern_span) else {
1360                    return;
1361                };
1362                (AmpMutSugg::Type { span, suggestion: "mut ".to_owned(), additional: None }, None)
1363            }
1364
1365            _ => ::core::panicking::panic("internal error: entered unreachable code")unreachable!(),
1366        };
1367
1368        let mut suggest = |suggs: Vec<_>, applicability, extra| {
1369            if suggs.iter().any(|(span, _)| self.infcx.tcx.sess.source_map().is_imported(*span)) {
1370                return;
1371            }
1372
1373            err.multipart_suggestion(
1374                ::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!(
1375                    "consider changing this to be a mutable {pointer_desc}{}{extra}",
1376                    if is_trait_sig {
1377                        " in the `impl` method and the `trait` definition"
1378                    } else {
1379                        ""
1380                    }
1381                ),
1382                suggs,
1383                applicability,
1384            );
1385        };
1386
1387        let (mut sugg, add_type_annotation_if_not_exists) = match amp_mut_sugg {
1388            AmpMutSugg::Type { span, suggestion, additional } => {
1389                let mut sugg = ::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
        [(span, suggestion)]))vec![(span, suggestion)];
1390                sugg.extend(additional);
1391                suggest(sugg, Applicability::MachineApplicable, "");
1392                return;
1393            }
1394            AmpMutSugg::MapGetMut { span, suggestion } => {
1395                if self.infcx.tcx.sess.source_map().is_imported(span) {
1396                    return;
1397                }
1398                err.multipart_suggestion(
1399                    "consider using `get_mut`",
1400                    ::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
        [(span, suggestion)]))vec![(span, suggestion)],
1401                    Applicability::MaybeIncorrect,
1402                );
1403                return;
1404            }
1405            AmpMutSugg::Expr { span, suggestion } => {
1406                // `Expr` suggestions should change type annotations if they already exist (probably immut),
1407                // but do not add new type annotations.
1408                (::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
        [(span, suggestion)]))vec![(span, suggestion)], false)
1409            }
1410            AmpMutSugg::ChangeBinding => (::alloc::vec::Vec::new()vec![], true),
1411        };
1412
1413        // Find a binding's type to make mutable.
1414        let (binding_exists, span) = match local_var_ty_info {
1415            // If this is a variable binding with an explicit type,
1416            // then we will suggest changing it to be mutable.
1417            // This is `Applicability::MachineApplicable`.
1418            Some(ty_span) => (true, ty_span),
1419
1420            // Otherwise, we'll suggest *adding* an annotated type, we'll suggest
1421            // the RHS's type for that.
1422            // This is `Applicability::HasPlaceholders`.
1423            None => (false, decl_span),
1424        };
1425
1426        if !binding_exists && !add_type_annotation_if_not_exists {
1427            suggest(sugg, Applicability::MachineApplicable, "");
1428            return;
1429        }
1430
1431        // If the binding already exists and is a reference with an explicit
1432        // lifetime, then we can suggest adding ` mut`. This is special-cased from
1433        // the path without an explicit lifetime.
1434        let (sugg_span, sugg_str, suggest_now) = if let Ok(src) = self.infcx.tcx.sess.source_map().span_to_snippet(span)
1435            && src.starts_with("&'")
1436            // Note that `&' a T` is invalid so this is correct.
1437            && let Some(ws_pos) = src.find(char::is_whitespace)
1438        {
1439            let span = span.with_lo(span.lo() + BytePos(ws_pos as u32)).shrink_to_lo();
1440            (span, " mut".to_owned(), true)
1441        // If there is already a binding, we modify it to be `mut`.
1442        } else if binding_exists {
1443            // Replace the sigil with the mutable version. We may be dealing
1444            // with parser recovery here and cannot assume the user actually
1445            // typed `&` or `*const`, so we compute the prefix from the snippet.
1446            let Ok(src) = self.infcx.tcx.sess.source_map().span_to_snippet(span) else {
1447                return;
1448            };
1449            let (prefix_len, replacement) = if local_decl.ty.is_ref() {
1450                (src.chars().next().map_or(0, char::len_utf8), "&mut ")
1451            } else {
1452                (src.find("const").map_or(1, |i| i + "const".len()), "*mut ")
1453            };
1454            let ws_len = src[prefix_len..].len() - src[prefix_len..].trim_start().len();
1455            let span = span.with_hi(span.lo() + BytePos((prefix_len + ws_len) as u32));
1456            (span, replacement.to_owned(), true)
1457        } else {
1458            // Otherwise, suggest that the user annotates the binding; We provide the
1459            // type of the local.
1460            let ty = local_decl.ty.builtin_deref(true).unwrap();
1461
1462            (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)
1463        };
1464
1465        if suggest_now {
1466            // Suggest changing `&x` to `&mut x` and changing `&T` to `&mut T` at the same time.
1467            let has_change = !sugg.is_empty();
1468            sugg.push((sugg_span, sugg_str));
1469            suggest(
1470                sugg,
1471                Applicability::MachineApplicable,
1472                // FIXME(fee1-dead) this somehow doesn't fire
1473                if has_change { " and changing the binding's type" } else { "" },
1474            );
1475            return;
1476        } else if !sugg.is_empty() {
1477            suggest(sugg, Applicability::MachineApplicable, "");
1478            return;
1479        }
1480
1481        let def_id = self.body.source.def_id();
1482        let hir_id = if let Some(local_def_id) = def_id.as_local()
1483            && let Some(body) = self.infcx.tcx.hir_maybe_body_owned_by(local_def_id)
1484        {
1485            BindingFinder { span: sugg_span }.visit_body(&body).break_value()
1486        } else {
1487            None
1488        };
1489        let node = hir_id.map(|hir_id| self.infcx.tcx.hir_node(hir_id));
1490
1491        let Some(hir::Node::LetStmt(local)) = node else {
1492            err.span_label(
1493                sugg_span,
1494                ::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}`"),
1495            );
1496            return;
1497        };
1498
1499        let tables = self.infcx.tcx.typeck(def_id.as_local().unwrap());
1500        if let Some(clone_trait) = self.infcx.tcx.lang_items().clone_trait()
1501            && let Some(expr) = local.init
1502            && let ty = tables.node_type_opt(expr.hir_id)
1503            && let Some(ty) = ty
1504            && let ty::Ref(..) = ty.kind()
1505        {
1506            match self
1507                .infcx
1508                .type_implements_trait_shallow(clone_trait, ty.peel_refs(), self.infcx.param_env)
1509                .as_deref()
1510            {
1511                Some([]) => {
1512                    // FIXME: This error message isn't useful, since we're just
1513                    // vaguely suggesting to clone a value that already
1514                    // implements `Clone`.
1515                    //
1516                    // A correct suggestion here would take into account the fact
1517                    // that inference may be affected by missing types on bindings,
1518                    // etc., to improve "tests/ui/borrowck/issue-91206.stderr", for
1519                    // example.
1520                }
1521                None => {
1522                    if let hir::ExprKind::MethodCall(segment, _rcvr, [], span) = expr.kind
1523                        && segment.ident.name == sym::clone
1524                    {
1525                        err.span_help(
1526                            span,
1527                            ::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!(
1528                                "`{}` doesn't implement `Clone`, so this call clones \
1529                                             the reference `{ty}`",
1530                                ty.peel_refs(),
1531                            ),
1532                        );
1533                    }
1534                    // The type doesn't implement Clone.
1535                    let trait_ref = ty::Binder::dummy(ty::TraitRef::new(
1536                        self.infcx.tcx,
1537                        clone_trait,
1538                        [ty.peel_refs()],
1539                    ));
1540                    let obligation = traits::Obligation::new(
1541                        self.infcx.tcx,
1542                        traits::ObligationCause::dummy(),
1543                        self.infcx.param_env,
1544                        trait_ref,
1545                    );
1546                    self.infcx.err_ctxt().suggest_derive(
1547                        &obligation,
1548                        err,
1549                        trait_ref.upcast(self.infcx.tcx),
1550                    );
1551                }
1552                Some(errors) => {
1553                    if let hir::ExprKind::MethodCall(segment, _rcvr, [], span) = expr.kind
1554                        && segment.ident.name == sym::clone
1555                    {
1556                        err.span_help(
1557                            span,
1558                            ::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!(
1559                                "`{}` doesn't implement `Clone` because its \
1560                                             implementations trait bounds could not be met, so \
1561                                             this call clones the reference `{ty}`",
1562                                ty.peel_refs(),
1563                            ),
1564                        );
1565                        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!(
1566                            "the following trait bounds weren't met: {}",
1567                            errors
1568                                .iter()
1569                                .map(|e| e.obligation.predicate.to_string())
1570                                .collect::<Vec<_>>()
1571                                .join("\n"),
1572                        ));
1573                    }
1574                    // The type doesn't implement Clone because of unmet obligations.
1575                    for error in errors {
1576                        if let traits::FulfillmentErrorCode::Select(
1577                            traits::SelectionError::Unimplemented,
1578                        ) = error.code
1579                            && let ty::PredicateKind::Clause(ty::ClauseKind::Trait(pred)) =
1580                                error.obligation.predicate.kind().skip_binder()
1581                        {
1582                            self.infcx.err_ctxt().suggest_derive(
1583                                &error.obligation,
1584                                err,
1585                                error.obligation.predicate.kind().rebind(pred),
1586                            );
1587                        }
1588                    }
1589                }
1590            }
1591        }
1592        let (changing, span, sugg) = match local.ty {
1593            Some(ty) => ("changing", ty.span, sugg_str),
1594            None => ("specifying", local.pat.span.shrink_to_hi(), ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!(": {0}", sugg_str))
    })format!(": {sugg_str}")),
1595        };
1596        err.span_suggestion_verbose(
1597            span,
1598            ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("consider {0} this binding\'s type",
                changing))
    })format!("consider {changing} this binding's type"),
1599            sugg,
1600            Applicability::HasPlaceholders,
1601        );
1602    }
1603
1604    /// Returns `true` if `local` is an argument in a closure passed to a
1605    /// function defined in another crate.
1606    ///
1607    /// For example, in the following code this function returns `true` for `x`
1608    /// since `Option::inspect()` is not defined in the current crate:
1609    ///
1610    /// ```text
1611    /// some_option.as_mut().inspect(|x| {
1612    /// ```
1613    fn is_closure_arg_with_non_locally_decided_type(&self, local: Local) -> bool {
1614        // We don't care about regular local variables, only args.
1615        if self.body.local_kind(local) != LocalKind::Arg {
1616            return false;
1617        }
1618
1619        // Make sure we are inside a closure.
1620        let InstanceKind::Item(body_def_id) = self.body.source.instance else {
1621            return false;
1622        };
1623        let Some(Node::Expr(hir::Expr { hir_id: body_hir_id, kind, .. })) =
1624            self.infcx.tcx.hir_get_if_local(body_def_id)
1625        else {
1626            return false;
1627        };
1628        let ExprKind::Closure(hir::Closure { kind: hir::ClosureKind::Closure, .. }) = kind else {
1629            return false;
1630        };
1631
1632        // Check if the method/function that our closure is passed to is defined
1633        // in another crate.
1634        let Node::Expr(closure_parent) = self.infcx.tcx.parent_hir_node(*body_hir_id) else {
1635            return false;
1636        };
1637        match closure_parent.kind {
1638            ExprKind::MethodCall(method, _, _, _) => self
1639                .infcx
1640                .tcx
1641                .typeck(method.hir_id.owner.def_id)
1642                .type_dependent_def_id(closure_parent.hir_id)
1643                .is_some_and(|def_id| !def_id.is_local()),
1644            ExprKind::Call(func, _) => self
1645                .infcx
1646                .tcx
1647                .typeck(func.hir_id.owner.def_id)
1648                .node_type_opt(func.hir_id)
1649                .and_then(|ty| match ty.kind() {
1650                    ty::FnDef(def_id, _) => Some(def_id),
1651                    _ => None,
1652                })
1653                .is_some_and(|def_id| !def_id.is_local()),
1654            _ => false,
1655        }
1656    }
1657}
1658
1659struct BindingFinder {
1660    span: Span,
1661}
1662
1663impl<'tcx> Visitor<'tcx> for BindingFinder {
1664    type Result = ControlFlow<hir::HirId>;
1665    fn visit_stmt(&mut self, s: &'tcx hir::Stmt<'tcx>) -> Self::Result {
1666        if let hir::StmtKind::Let(local) = s.kind
1667            && local.pat.span == self.span
1668        {
1669            ControlFlow::Break(local.hir_id)
1670        } else {
1671            hir::intravisit::walk_stmt(self, s)
1672        }
1673    }
1674
1675    fn visit_param(&mut self, param: &'tcx hir::Param<'tcx>) -> Self::Result {
1676        if let hir::Pat { kind: hir::PatKind::Ref(_, _, _), span, .. } = param.pat
1677            && *span == self.span
1678        {
1679            ControlFlow::Break(param.hir_id)
1680        } else {
1681            ControlFlow::Continue(())
1682        }
1683    }
1684}
1685
1686fn mut_borrow_of_mutable_ref(local_decl: &LocalDecl<'_>, local_name: Option<Symbol>) -> bool {
1687    {
    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:1687",
                        "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(1687u32),
                        ::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());
1688
1689    match *local_decl.local_info() {
1690        // Check if mutably borrowing a mutable reference.
1691        LocalInfo::User(mir::BindingForm::Var(mir::VarBindingForm {
1692            binding_mode: BindingMode(ByRef::No, Mutability::Not),
1693            ..
1694        })) => #[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)),
1695        LocalInfo::User(mir::BindingForm::ImplicitSelf(kind)) => {
1696            // Check if the user variable is a `&mut self` and we can therefore
1697            // suggest removing the `&mut`.
1698            //
1699            // Deliberately fall into this case for all implicit self types,
1700            // so that we don't fall into the next case with them.
1701            kind == hir::ImplicitSelfKind::RefMut
1702        }
1703        _ if Some(kw::SelfLower) == local_name => {
1704            // Otherwise, check if the name is the `self` keyword - in which case
1705            // we have an explicit self. Do the same thing in this case and check
1706            // for a `self: &mut Self` to suggest removing the `&mut`.
1707            #[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))
1708        }
1709        _ => false,
1710    }
1711}
1712
1713fn suggest_ampmut_self(tcx: TyCtxt<'_>, span: Span) -> (Span, String) {
1714    match tcx.sess.source_map().span_to_snippet(span) {
1715        Ok(snippet) if snippet.ends_with("self") => {
1716            (span.with_hi(span.hi() - BytePos(4)).shrink_to_hi(), "mut ".to_string())
1717        }
1718        _ => (span, "&mut self".to_string()),
1719    }
1720}
1721
1722enum AmpMutSugg {
1723    /// Type suggestion. Changes `&self` to `&mut self`, `x: &T` to `x: &mut T`,
1724    /// `ref x` to `ref mut x`, etc.
1725    Type {
1726        span: Span,
1727        suggestion: String,
1728        additional: Option<(Span, String)>,
1729    },
1730    /// Suggestion for expressions, `&x` to `&mut x`, `&x[i]` to `&mut x[i]`, etc.
1731    Expr {
1732        span: Span,
1733        suggestion: String,
1734    },
1735    /// Suggests `.get_mut` in the case of `&map[&key]` for Hash/BTreeMap.
1736    MapGetMut {
1737        span: Span,
1738        suggestion: String,
1739    },
1740    ChangeBinding,
1741}
1742
1743// When we want to suggest a user change a local variable to be a `&mut`, there
1744// are three potential "obvious" things to highlight:
1745//
1746// let ident [: Type] [= RightHandSideExpression];
1747//     ^^^^^    ^^^^     ^^^^^^^^^^^^^^^^^^^^^^^
1748//     (1.)     (2.)              (3.)
1749//
1750// We can always fallback on highlighting the first. But chances are good that
1751// the user experience will be better if we highlight one of the others if possible;
1752// for example, if the RHS is present and the Type is not, then the type is going to
1753// be inferred *from* the RHS, which means we should highlight that (and suggest
1754// that they borrow the RHS mutably).
1755//
1756// This implementation attempts to emulate AST-borrowck prioritization
1757// by trying (3.), then (2.) and finally falling back on (1.).
1758fn suggest_ampmut<'tcx>(
1759    infcx: &crate::BorrowckInferCtxt<'tcx>,
1760    body: &Body<'tcx>,
1761    opt_assignment_rhs_stmt: Option<&Statement<'tcx>>,
1762) -> Option<AmpMutSugg> {
1763    let tcx = infcx.tcx;
1764    // If there is a RHS and it starts with a `&` from it, then check if it is
1765    // mutable, and if not, put suggest putting `mut ` to make it mutable.
1766    // We don't have to worry about lifetime annotations here because they are
1767    // not valid when taking a reference. For example, the following is not valid Rust:
1768    //
1769    // let x: &i32 = &'a 5;
1770    //                ^^ lifetime annotation not allowed
1771    //
1772    if let Some(rhs_stmt) = opt_assignment_rhs_stmt
1773        && let StatementKind::Assign(box (lhs, rvalue)) = &rhs_stmt.kind
1774        && let mut rhs_span = rhs_stmt.source_info.span
1775        && let Ok(mut rhs_str) = tcx.sess.source_map().span_to_snippet(rhs_span)
1776    {
1777        let mut rvalue = rvalue;
1778
1779        // Take some special care when handling `let _x = &*_y`:
1780        // We want to know if this is part of an overloaded index, so `let x = &a[0]`,
1781        // or whether this is a usertype ascription (`let _x: &T = y`).
1782        if let Rvalue::Ref(_, BorrowKind::Shared, place) = rvalue
1783            && place.projection.len() == 1
1784            && place.projection[0] == ProjectionElem::Deref
1785            && let Some(assign) = find_assignments(&body, place.local).first()
1786        {
1787            // If this is a usertype ascription (`let _x: &T = _y`) then pierce through it as either we want
1788            // to suggest `&mut` on the expression (handled here) or we return `None` and let the caller
1789            // suggest `&mut` on the type if the expression seems fine (e.g. `let _x: &T = &mut _y`).
1790            if let Some(user_ty_projs) = body.local_decls[lhs.local].user_ty.as_ref()
1791                && let [user_ty_proj] = user_ty_projs.contents.as_slice()
1792                && user_ty_proj.projs.is_empty()
1793                && let Either::Left(rhs_stmt_new) = body.stmt_at(*assign)
1794                && let StatementKind::Assign(box (_, rvalue_new)) = &rhs_stmt_new.kind
1795                && let rhs_span_new = rhs_stmt_new.source_info.span
1796                && let Ok(rhs_str_new) = tcx.sess.source_map().span_to_snippet(rhs_span_new)
1797            {
1798                (rvalue, rhs_span, rhs_str) = (rvalue_new, rhs_span_new, rhs_str_new);
1799            }
1800
1801            if let Either::Right(call) = body.stmt_at(*assign)
1802                && let TerminatorKind::Call {
1803                    func: Operand::Constant(box const_operand), args, ..
1804                } = &call.kind
1805                && let ty::FnDef(method_def_id, method_args) = *const_operand.ty().kind()
1806                && let Some(trait_) = tcx.trait_of_assoc(method_def_id)
1807                && tcx.is_lang_item(trait_, hir::LangItem::Index)
1808            {
1809                let trait_ref = ty::TraitRef::from_assoc(
1810                    tcx,
1811                    tcx.require_lang_item(hir::LangItem::IndexMut, rhs_span),
1812                    method_args,
1813                );
1814                // The type only implements `Index` but not `IndexMut`, we must not suggest `&mut`.
1815                if !infcx
1816                    .type_implements_trait(trait_ref.def_id, trait_ref.args, infcx.param_env)
1817                    .must_apply_considering_regions()
1818                {
1819                    // Suggest `get_mut` if type is a `BTreeMap` or `HashMap`.
1820                    if let ty::Adt(def, _) = trait_ref.self_ty().kind()
1821                        && [sym::BTreeMap, sym::HashMap]
1822                            .into_iter()
1823                            .any(|s| tcx.is_diagnostic_item(s, def.did()))
1824                        && let [map, key] = &**args
1825                        && let Ok(map) = tcx.sess.source_map().span_to_snippet(map.span)
1826                        && let Ok(key) = tcx.sess.source_map().span_to_snippet(key.span)
1827                    {
1828                        let span = rhs_span;
1829                        let suggestion = ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("{0}.get_mut({1}).unwrap()", map,
                key))
    })format!("{map}.get_mut({key}).unwrap()");
1830                        return Some(AmpMutSugg::MapGetMut { span, suggestion });
1831                    }
1832                    return None;
1833                }
1834            }
1835        }
1836
1837        let sugg = match rvalue {
1838            Rvalue::Ref(_, BorrowKind::Shared, _) if let Some(ref_idx) = rhs_str.find('&') => {
1839                // Shrink the span to just after the `&` in `&variable`.
1840                Some((
1841                    rhs_span.with_lo(rhs_span.lo() + BytePos(ref_idx as u32 + 1)).shrink_to_lo(),
1842                    "mut ".to_owned(),
1843                ))
1844            }
1845            Rvalue::RawPtr(RawPtrKind::Const, _) if let Some(const_idx) = rhs_str.find("const") => {
1846                // Suggest changing `&raw const` to `&raw mut` if applicable.
1847                let const_idx = const_idx as u32;
1848                Some((
1849                    rhs_span
1850                        .with_lo(rhs_span.lo() + BytePos(const_idx))
1851                        .with_hi(rhs_span.lo() + BytePos(const_idx + "const".len() as u32)),
1852                    "mut".to_owned(),
1853                ))
1854            }
1855            _ => None,
1856        };
1857
1858        if let Some((span, suggestion)) = sugg {
1859            return Some(AmpMutSugg::Expr { span, suggestion });
1860        }
1861    }
1862
1863    Some(AmpMutSugg::ChangeBinding)
1864}
1865
1866/// If the type is a `Coroutine`, `Closure`, or `CoroutineClosure`
1867fn is_closure_like(ty: Ty<'_>) -> bool {
1868    ty.is_closure() || ty.is_coroutine() || ty.is_coroutine_closure()
1869}
1870
1871/// Given a field that needs to be mutable, returns a span where the " mut " could go.
1872/// This function expects the local to be a reference to a struct in order to produce a span.
1873///
1874/// ```text
1875/// LL |     s: &'a   String
1876///    |           ^^^ returns a span taking up the space here
1877/// ```
1878fn get_mut_span_in_struct_field<'tcx>(
1879    tcx: TyCtxt<'tcx>,
1880    ty: Ty<'tcx>,
1881    field: FieldIdx,
1882) -> Option<Span> {
1883    // Expect our local to be a reference to a struct of some kind.
1884    if let ty::Ref(_, ty, _) = ty.kind()
1885        && let ty::Adt(def, _) = ty.kind()
1886        && let field = def.all_fields().nth(field.index())?
1887        // Now we're dealing with the actual struct that we're going to suggest a change to,
1888        // we can expect a field that is an immutable reference to a type.
1889        && let hir::Node::Field(field) = tcx.hir_node_by_def_id(field.did.as_local()?)
1890        && let hir::TyKind::Ref(lt, hir::MutTy { mutbl: hir::Mutability::Not, ty }) = field.ty.kind
1891    {
1892        return Some(lt.ident.span.between(ty.span));
1893    }
1894
1895    None
1896}
1897
1898/// If possible, suggest replacing `ref` with `ref mut`.
1899fn suggest_ref_mut(tcx: TyCtxt<'_>, span: Span) -> Option<Span> {
1900    let pattern_str = tcx.sess.source_map().span_to_snippet(span).ok()?;
1901    if let Some(rest) = pattern_str.strip_prefix("ref")
1902        && rest.starts_with(rustc_lexer::is_whitespace)
1903    {
1904        let span = span.with_lo(span.lo() + BytePos(4)).shrink_to_lo();
1905        Some(span)
1906    } else {
1907        None
1908    }
1909}