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