compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs RUST 5,013 lines View on github.com → Search inside
File is large — showing lines 1–2,000 of 5,013.
1// ignore-tidy-file-filelength23use std::iter;4use std::ops::ControlFlow;56use either::Either;7use hir::{ClosureKind, Path};8use rustc_data_structures::fx::FxIndexSet;9use rustc_errors::codes::*;10use rustc_errors::{Applicability, Diag, MultiSpan, struct_span_code_err};11use rustc_hir as hir;12use rustc_hir::attrs::diagnostic::{CustomDiagnostic, FormatArgs};13use rustc_hir::attrs::lang_items::LangItem;14use rustc_hir::def::{DefKind, Res};15use rustc_hir::intravisit::{Visitor, walk_block, walk_expr};16use rustc_hir::{CoroutineDesugaring, CoroutineKind, CoroutineSource, PatField, find_attr};17use rustc_index::bit_set::DenseBitSet;18use rustc_infer::traits::TraitErrors;19use rustc_middle::bug;20use rustc_middle::hir::nested_filter::OnlyBodies;21use rustc_middle::mir::{22    self, AggregateKind, BindingForm, BorrowKind, ClearCrossCrate, ConstraintCategory,23    FakeBorrowKind, FakeReadCause, LocalDecl, LocalInfo, LocalKind, Location, MutBorrowKind,24    Operand, Place, PlaceRef, PlaceTy, ProjectionElem, Rvalue, Statement, StatementKind,25    Terminator, TerminatorKind, VarBindingForm, VarDebugInfoContents,26};27use rustc_middle::ty::print::PrintTraitRefExt as _;28use rustc_middle::ty::{29    self, PredicateKind, RegionExt, Ty, TyCtxt, TypeSuperVisitable, TypeVisitor, Upcast,30    suggest_constraining_type_params,31};32use rustc_mir_dataflow::move_paths::{Init, InitKind, InitLocation, MoveOutIndex, MovePathIndex};33use rustc_span::def_id::{DefId, LocalDefId};34use rustc_span::hygiene::DesugaringKind;35use rustc_span::{BytePos, ExpnKind, Ident, MacroKind, Span, Symbol, kw, sym};36use rustc_trait_selection::error_reporting::InferCtxtErrorExt;37use rustc_trait_selection::error_reporting::traits::FindExprBySpan;38use rustc_trait_selection::error_reporting::traits::call_kind::CallKind;39use rustc_trait_selection::infer::InferCtxtExt;40use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt as _;41use rustc_trait_selection::traits::{42    Obligation, ObligationCause, ObligationCtxt, supertrait_def_ids,43};44use tracing::{debug, instrument};4546use super::explain_borrow::{BorrowExplanation, LaterUseKind};47use super::{DescribePlaceOpt, RegionName, RegionNameSource, UseSpans};48use crate::borrow_set::{BorrowData, TwoPhaseActivation};49use crate::consumers::OutlivesConstraint;50use crate::diagnostics::conflict_errors::StorageDeadOrDrop::LocalStorageDead;51use crate::diagnostics::{CapturedMessageOpt, call_kind, find_all_local_uses};52use crate::{InitializationRequiringAction, MirBorrowckCtxt, WriteKind, borrowck_errors};5354#[derive(Debug)]55struct MoveSite {56    /// Index of the "move out" that we found. The `MoveData` can57    /// then tell us where the move occurred.58    moi: MoveOutIndex,5960    /// `true` if we traversed a back edge while walking from the point61    /// of error to the move site.62    traversed_back_edge: bool,63}6465/// Which case a StorageDeadOrDrop is for.66#[derive(Copy, Clone, PartialEq, Eq, Debug)]67enum StorageDeadOrDrop<'tcx> {68    LocalStorageDead,69    BoxedStorageDead,70    Destructor(Ty<'tcx>),71}7273impl<'diag, 'tcx> MirBorrowckCtxt<'_, 'diag, 'tcx> {74    pub(crate) fn report_use_of_moved_or_uninitialized(75        &mut self,76        location: Location,77        desired_action: InitializationRequiringAction,78        (moved_place, used_place, span): (PlaceRef<'tcx>, PlaceRef<'tcx>, Span),79        mpi: MovePathIndex,80    ) {81        debug!(82            "report_use_of_moved_or_uninitialized: location={:?} desired_action={:?} \83             moved_place={:?} used_place={:?} span={:?} mpi={:?}",84            location, desired_action, moved_place, used_place, span, mpi85        );8687        let use_spans =88            self.move_spans(moved_place, location).or_else(|| self.borrow_spans(span, location));89        let span = use_spans.args_or_use();9091        let (move_site_vec, maybe_reinitialized_locations) = self.get_moved_indexes(location, mpi);92        debug!(93            "report_use_of_moved_or_uninitialized: move_site_vec={:?} use_spans={:?}",94            move_site_vec, use_spans95        );96        let move_out_indices: Vec<_> =97            move_site_vec.iter().map(|move_site| move_site.moi).collect();9899        if move_out_indices.is_empty() {100            let root_local = used_place.local;101102            if !self.uninitialized_error_reported.insert(root_local) {103                debug!(104                    "report_use_of_moved_or_uninitialized place: error about {:?} suppressed",105                    root_local106                );107                return;108            }109110            let err = self.report_use_of_uninitialized(111                mpi,112                used_place,113                moved_place,114                desired_action,115                location,116                span,117                use_spans,118            );119            self.buffer_error(err);120        } else {121            if let Some((reported_place, _)) = self.has_move_error(&move_out_indices) {122                if used_place.is_prefix_of(*reported_place) {123                    debug!(124                        "report_use_of_moved_or_uninitialized place: error suppressed mois={:?}",125                        move_out_indices126                    );127                    return;128                }129            }130131            let is_partial_move = move_site_vec.iter().any(|move_site| {132                let move_out = self.move_data.move_outs[(*move_site).moi];133                let moved_place = &self.move_data.move_paths[move_out.path].place;134                // `*(_1)` where `_1` is a `Box` is actually a move out.135                let is_box_move = moved_place.as_ref().projection == [ProjectionElem::Deref]136                    && self.body.local_decls[moved_place.local].ty.is_box();137138                !is_box_move139                    && used_place != moved_place.as_ref()140                    && used_place.is_prefix_of(moved_place.as_ref())141            });142143            let partial_str = if is_partial_move { "partial " } else { "" };144            let partially_str = if is_partial_move { "partially " } else { "" };145146            let (on_move_message, on_move_label, on_move_notes) = if let ty::Adt(item_def, args) =147                self.body.local_decls[moved_place.local].ty.kind()148                && let Some(Some(directive)) = find_attr!(self.infcx.tcx, item_def.did(), OnMove { directive, .. }  => directive)149            {150                let this = self.infcx.tcx.item_name(item_def.did()).to_string();151                let mut generic_args: Vec<_> = self152                    .infcx153                    .tcx154                    .generics_of(item_def.did())155                    .own_params156                    .iter()157                    .filter_map(|param| Some((param.name, args[param.index as usize].to_string())))158                    .collect();159                generic_args.push((kw::SelfUpper, this.clone()));160161                let args = FormatArgs { this, generic_args, .. };162                let CustomDiagnostic { message, label, notes, parent_label: _ } =163                    directive.eval(None, &args);164165                (message, label, notes)166            } else {167                (None, None, Vec::new())168            };169170            let mut err = self.cannot_act_on_moved_value(171                span,172                desired_action.as_noun(),173                partially_str,174                self.describe_place_with_options(175                    moved_place,176                    DescribePlaceOpt { including_downcast: true, including_tuple_field: true },177                ),178                on_move_message,179            );180181            for note in on_move_notes {182                err.note(note);183            }184185            let reinit_spans = maybe_reinitialized_locations186                .iter()187                .take(3)188                .map(|loc| {189                    self.move_spans(self.move_data.move_paths[mpi].place.as_ref(), *loc)190                        .args_or_use()191                })192                .collect::<Vec<Span>>();193194            let reinits = maybe_reinitialized_locations.len();195            if reinits == 1 {196                err.span_label(reinit_spans[0], "this reinitialization might get skipped");197            } else if reinits > 1 {198                err.span_note(199                    MultiSpan::from_spans(reinit_spans),200                    if reinits <= 3 {201                        format!("these {reinits} reinitializations might get skipped")202                    } else {203                        format!(204                            "these 3 reinitializations and {} other{} might get skipped",205                            reinits - 3,206                            if reinits == 4 { "" } else { "s" }207                        )208                    },209                );210            }211212            let closure = self.add_moved_or_invoked_closure_note(location, used_place, &mut err);213214            let mut is_loop_move = false;215            let mut seen_spans = FxIndexSet::default();216217            for move_site in &move_site_vec {218                let move_out = self.move_data.move_outs[(*move_site).moi];219                let moved_place = &self.move_data.move_paths[move_out.path].place;220221                let move_spans = self.move_spans(moved_place.as_ref(), move_out.source);222                let move_span = move_spans.args_or_use();223224                let is_move_msg = move_spans.for_closure();225226                let is_loop_message = location == move_out.source || move_site.traversed_back_edge;227228                if location == move_out.source {229                    is_loop_move = true;230                }231232                let mut has_suggest_reborrow = false;233                if !seen_spans.contains(&move_span) {234                    self.suggest_ref_or_clone(235                        mpi,236                        &mut err,237                        move_spans,238                        moved_place.as_ref(),239                        &mut has_suggest_reborrow,240                        closure,241                    );242243                    let msg_opt = CapturedMessageOpt {244                        is_partial_move,245                        is_loop_message,246                        is_move_msg,247                        is_loop_move,248                        has_suggest_reborrow,249                        maybe_reinitialized_locations_is_empty: maybe_reinitialized_locations250                            .is_empty(),251                    };252                    self.explain_captures(253                        &mut err,254                        span,255                        move_span,256                        move_spans,257                        *moved_place,258                        msg_opt,259                    );260                }261                seen_spans.insert(move_span);262            }263264            use_spans.var_path_only_subdiag(&mut err, desired_action);265266            if !is_loop_move {267                err.span_label(268                    span,269                    format!(270                        "value {} here after {partial_str}move",271                        desired_action.as_verb_in_past_tense(),272                    ),273                );274            }275276            let ty = used_place.ty(self.body, self.infcx.tcx).ty;277            let needs_note = match ty.kind() {278                ty::Closure(id, _) => {279                    self.infcx.tcx.closure_kind_origin(id.expect_local()).is_none()280                }281                _ => true,282            };283284            let mpi = self.move_data.move_outs[move_out_indices[0]].path;285            let place = &self.move_data.move_paths[mpi].place;286            let ty = place.ty(self.body, self.infcx.tcx).ty;287288            if self.infcx.param_env.caller_bounds().iter().any(|c| {289                c.as_trait_clause().is_some_and(|pred| {290                    pred.skip_binder().self_ty() == ty && self.infcx.tcx.is_fn_trait(pred.def_id())291                })292            }) {293                // Suppress the next suggestion since we don't want to put more bounds onto294                // something that already has `Fn`-like bounds (or is a closure), so we can't295                // restrict anyways.296            } else {297                let copy_did = self.infcx.tcx.require_lang_item(LangItem::Copy, span);298                self.suggest_adding_bounds(&mut err, ty, copy_did, span);299            }300301            let opt_name = self.describe_place_with_options(302                place.as_ref(),303                DescribePlaceOpt { including_downcast: true, including_tuple_field: true },304            );305            let note_msg = match opt_name {306                Some(name) => format!("`{name}`"),307                None => "value".to_owned(),308            };309            if needs_note {310                if let Some(local) = place.as_local() {311                    let span = self.body.local_decls[local].source_info.span;312                    if let Some(on_move_label) = on_move_label {313                        err.span_label(span, on_move_label);314                    } else {315                        err.subdiagnostic(crate::session_diagnostics::TypeNoCopy::Label {316                            is_partial_move,317                            ty,318                            place: &note_msg,319                            span,320                        });321                    }322                } else {323                    err.subdiagnostic(crate::session_diagnostics::TypeNoCopy::Note {324                        is_partial_move,325                        ty,326                        place: &note_msg,327                    });328                };329            }330331            if let UseSpans::FnSelfUse {332                kind: CallKind::DerefCoercion { deref_target_span, deref_target_ty, .. },333                ..334            } = use_spans335            {336                err.note(format!(337                    "{} occurs due to deref coercion to `{deref_target_ty}`",338                    desired_action.as_noun(),339                ));340341                // Check first whether the source is accessible (issue #87060)342                if let Some(deref_target_span) = deref_target_span343                    && self.infcx.tcx.sess.source_map().is_span_accessible(deref_target_span)344                {345                    err.span_note(deref_target_span, "deref defined here");346                }347            }348349            self.buffer_move_error(move_out_indices, (used_place, err));350        }351    }352353    fn suggest_ref_or_clone(354        &self,355        mpi: MovePathIndex,356        err: &mut Diag<'_>,357        move_spans: UseSpans<'tcx>,358        moved_place: PlaceRef<'tcx>,359        has_suggest_reborrow: &mut bool,360        moved_or_invoked_closure: bool,361    ) {362        let move_span = match move_spans {363            UseSpans::ClosureUse { capture_kind_span, .. } => capture_kind_span,364            _ => move_spans.args_or_use(),365        };366        struct ExpressionFinder<'hir> {367            expr_span: Span,368            expr: Option<&'hir hir::Expr<'hir>>,369            pat: Option<&'hir hir::Pat<'hir>>,370            parent_pat: Option<&'hir hir::Pat<'hir>>,371            tcx: TyCtxt<'hir>,372        }373        impl<'hir> Visitor<'hir> for ExpressionFinder<'hir> {374            type NestedFilter = OnlyBodies;375376            fn maybe_tcx(&mut self) -> Self::MaybeTyCtxt {377                self.tcx378            }379380            fn visit_expr(&mut self, e: &'hir hir::Expr<'hir>) {381                if e.span == self.expr_span {382                    self.expr = Some(e);383                }384                hir::intravisit::walk_expr(self, e);385            }386            fn visit_pat(&mut self, p: &'hir hir::Pat<'hir>) {387                if p.span == self.expr_span {388                    self.pat = Some(p);389                }390                if let hir::PatKind::Binding(hir::BindingMode::NONE, _, i, sub) = p.kind {391                    if i.span == self.expr_span || p.span == self.expr_span {392                        self.pat = Some(p);393                    }394                    // Check if we are in a situation of `ident @ ident` where we want to suggest395                    // `ref ident @ ref ident` or `ref ident @ Struct { ref ident }`.396                    if let Some(subpat) = sub397                        && self.pat.is_none()398                    {399                        self.visit_pat(subpat);400                        if self.pat.is_some() {401                            self.parent_pat = Some(p);402                        }403                        return;404                    }405                }406                hir::intravisit::walk_pat(self, p);407            }408        }409        let tcx = self.infcx.tcx;410        if let Some(body) = tcx.hir_maybe_body_owned_by(self.mir_def_id()) {411            let expr = body.value;412            let place = &self.move_data.move_paths[mpi].place;413            let span = place.as_local().map(|local| self.body.local_decls[local].source_info.span);414            let mut finder = ExpressionFinder {415                expr_span: move_span,416                expr: None,417                pat: None,418                parent_pat: None,419                tcx,420            };421            finder.visit_expr(expr);422            if let Some(span) = span423                && let Some(expr) = finder.expr424            {425                for (_, expr) in tcx.hir_parent_iter(expr.hir_id) {426                    if let hir::Node::Expr(expr) = expr {427                        if expr.span.contains(span) {428                            // If the let binding occurs within the same loop, then that429                            // loop isn't relevant, like in the following, the outermost `loop`430                            // doesn't play into `x` being moved.431                            // ```432                            // loop {433                            //     let x = String::new();434                            //     loop {435                            //         foo(x);436                            //     }437                            // }438                            // ```439                            break;440                        }441                        if let hir::ExprKind::Loop(.., loop_span) = expr.kind {442                            err.span_label(loop_span, "inside of this loop");443                        }444                    }445                }446                let typeck = self.infcx.tcx.typeck(self.mir_def_id());447                let parent = self.infcx.tcx.parent_hir_node(expr.hir_id);448                let (def_id, args, offset) = if let hir::Node::Expr(parent_expr) = parent449                    && let hir::ExprKind::MethodCall(_, _, args, _) = parent_expr.kind450                {451                    let def_id = typeck.type_dependent_def_id(parent_expr.hir_id);452                    (def_id, args, 1)453                } else if let hir::Node::Expr(parent_expr) = parent454                    && let hir::ExprKind::Call(call, args) = parent_expr.kind455                    && let ty::FnDef(def_id, _) = typeck.node_type(call.hir_id).kind()456                {457                    (Some(*def_id), args, 0)458                } else {459                    (None, &[][..], 0)460                };461                let ty = place.ty(self.body, self.infcx.tcx).ty;462463                let mut can_suggest_clone = true;464                if let Some(def_id) = def_id465                    && let Some(pos) = args.iter().position(|arg| arg.hir_id == expr.hir_id)466                {467                    // The move occurred as one of the arguments to a function call. Is that468                    // argument generic? `def_id` can't be a closure here, so using `fn_sig` is fine469                    let arg_param = if self.infcx.tcx.def_kind(def_id).is_fn_like()470                        && let sig =471                            self.infcx.tcx.fn_sig(def_id).instantiate_identity().skip_binder()472                        && let Some(arg_ty) = sig.inputs().get(pos + offset)473                        && let ty::Param(arg_param) = arg_ty.kind()474                    {475                        Some(arg_param)476                    } else {477                        None478                    };479480                    // If the moved value is a mut reference, it is used in a481                    // generic function and it's type is a generic param, it can be482                    // reborrowed to avoid moving.483                    // for example:484                    // struct Y(u32);485                    // x's type is '& mut Y' and it is used in `fn generic<T>(x: T) {}`.486                    if let ty::Ref(_, _, hir::Mutability::Mut) = ty.kind()487                        && arg_param.is_some()488                    {489                        *has_suggest_reborrow = true;490                        self.suggest_reborrow(err, expr.span, moved_place);491                        return;492                    }493494                    // If the moved place is used generically by the callee and a reference to it495                    // would still satisfy any bounds on its type, suggest borrowing.496                    if let Some(&param) = arg_param497                        && let hir::Node::Expr(call_expr) = parent498                        && let Some(ref_mutability) = self.suggest_borrow_generic_arg(499                            err,500                            typeck,501                            call_expr,502                            def_id,503                            param,504                            moved_place,505                            pos + offset,506                            ty,507                            expr.span,508                        )509                    {510                        can_suggest_clone = ref_mutability.is_mut();511                    } else if let Some(local_def_id) = def_id.as_local()512                        && let node = self.infcx.tcx.hir_node_by_def_id(local_def_id)513                        && let Some(fn_decl) = node.fn_decl()514                        && let Some(ident) = node.ident()515                        && let Some(arg) = fn_decl.inputs.get(pos + offset)516                    {517                        // If we can't suggest borrowing in the call, but the function definition518                        // is local, instead offer changing the function to borrow that argument.519                        let mut span: MultiSpan = arg.span.into();520                        span.push_span_label(521                            arg.span,522                            "this parameter takes ownership of the value".to_string(),523                        );524                        let descr = match node.fn_kind() {525                            Some(hir::intravisit::FnKind::ItemFn(..)) | None => "function",526                            Some(hir::intravisit::FnKind::Method(..)) => "method",527                            Some(hir::intravisit::FnKind::Closure) => "closure",528                        };529                        span.push_span_label(ident.span, format!("in this {descr}"));530                        err.span_note(531                            span,532                            format!(533                                "consider changing this parameter type in {descr} `{ident}` to \534                                 borrow instead if owning the value isn't necessary",535                            ),536                        );537                    }538                }539                if let hir::Node::Expr(parent_expr) = parent540                    && let hir::ExprKind::Call(call_expr, _) = parent_expr.kind541                    && let hir::ExprKind::Path(qpath) = call_expr.kind542                    && tcx.qpath_is_lang_item(qpath, LangItem::IntoIterIntoIter)543                {544                    // Do not suggest `.clone()` in a `for` loop, we already suggest borrowing.545                } else if let UseSpans::FnSelfUse { kind: CallKind::Normal { .. }, .. } = move_spans546                {547                    // We already suggest cloning for these cases in `explain_captures`.548                } else if moved_or_invoked_closure {549                    // Do not suggest `closure.clone()()`.550                } else if let UseSpans::ClosureUse {551                    closure_kind:552                        ClosureKind::Coroutine(CoroutineKind::Desugared(_, CoroutineSource::Block)),553                    ..554                } = move_spans555                    && can_suggest_clone556                {557                    self.suggest_cloning(err, place.as_ref(), ty, expr, Some(move_spans));558                } else if self.suggest_hoisting_call_outside_loop(err, expr) && can_suggest_clone {559                    // The place where the type moves would be misleading to suggest clone.560                    // #121466561                    self.suggest_cloning(err, place.as_ref(), ty, expr, Some(move_spans));562                }563            }564565            self.suggest_ref_for_dbg_args(expr, place, move_span, err);566567            // it's useless to suggest inserting `ref` when the span don't comes from local code568            if let Some(pat) = finder.pat569                && !move_span.is_dummy()570                && !self.infcx.tcx.sess.source_map().is_imported(move_span)571            {572                let mut sugg = vec![(pat.span.shrink_to_lo(), "ref ".to_string())];573                if let Some(pat) = finder.parent_pat {574                    sugg.insert(0, (pat.span.shrink_to_lo(), "ref ".to_string()));575                }576                err.multipart_suggestion(577                    "borrow this binding in the pattern to avoid moving the value",578                    sugg,579                    Applicability::MachineApplicable,580                );581            }582        }583    }584585    // for dbg!(x) which may take ownership, suggest dbg!(&x) instead586    // but here we actually do not check whether the macro name is `dbg!`587    // so that we may extend the scope a bit larger to cover more cases588    fn suggest_ref_for_dbg_args(589        &self,590        body: &hir::Expr<'_>,591        place: &Place<'tcx>,592        move_span: Span,593        err: &mut Diag<'_>,594    ) {595        let var_info = self.body.var_debug_info.iter().find(|info| match info.value {596            VarDebugInfoContents::Place(ref p) => p == place,597            _ => false,598        });599        let Some(var_info) = var_info else { return };600        let arg_name = var_info.name;601        struct MatchArgFinder {602            expr_span: Span,603            match_arg_span: Option<Span>,604            arg_name: Symbol,605        }606        impl Visitor<'_> for MatchArgFinder {607            fn visit_expr(&mut self, e: &hir::Expr<'_>) {608                // dbg! is expanded into a match pattern, we need to find the right argument span609                if let hir::ExprKind::Match(expr, ..) = &e.kind610                    && let hir::ExprKind::Path(hir::QPath::Resolved(611                        _,612                        path @ Path { segments: [seg], .. },613                    )) = &expr.kind614                    && seg.ident.name == self.arg_name615                    && self.expr_span.source_callsite().contains(expr.span)616                {617                    self.match_arg_span = Some(path.span);618                }619                hir::intravisit::walk_expr(self, e);620            }621        }622623        let mut finder = MatchArgFinder { expr_span: move_span, match_arg_span: None, arg_name };624        finder.visit_expr(body);625        if let Some(macro_arg_span) = finder.match_arg_span {626            err.span_suggestion_verbose(627                macro_arg_span.shrink_to_lo(),628                "consider borrowing instead of transferring ownership",629                "&",630                Applicability::MachineApplicable,631            );632        }633    }634635    pub(crate) fn suggest_reborrow(636        &self,637        err: &mut Diag<'_>,638        span: Span,639        moved_place: PlaceRef<'tcx>,640    ) {641        err.span_suggestion_verbose(642            span.shrink_to_lo(),643            format!(644                "consider creating a fresh reborrow of {} here",645                self.describe_place(moved_place)646                    .map(|n| format!("`{n}`"))647                    .unwrap_or_else(|| "the mutable reference".to_string()),648            ),649            "&mut *",650            Applicability::MachineApplicable,651        );652    }653654    /// If a place is used after being moved as an argument to a function, the function is generic655    /// in that argument, and a reference to the argument's type would still satisfy the function's656    /// bounds, suggest borrowing. This covers, e.g., borrowing an `impl Fn()` argument being passed657    /// in an `impl FnOnce()` position.658    /// Returns `Some(mutability)` when suggesting to borrow with mutability `mutability`, or `None`659    /// if no suggestion is made.660    fn suggest_borrow_generic_arg(661        &self,662        err: &mut Diag<'_>,663        typeck: &ty::TypeckResults<'tcx>,664        call_expr: &hir::Expr<'tcx>,665        callee_did: DefId,666        param: ty::ParamTy,667        moved_place: PlaceRef<'tcx>,668        moved_arg_pos: usize,669        moved_arg_ty: Ty<'tcx>,670        place_span: Span,671    ) -> Option<ty::Mutability> {672        let tcx = self.infcx.tcx;673        let sig = tcx.fn_sig(callee_did).instantiate_identity().skip_binder();674        let clauses = tcx.clauses_of(callee_did);675676        let generic_args = match call_expr.kind {677            // For method calls, generic arguments are attached to the call node.678            hir::ExprKind::MethodCall(..) => typeck.node_args_opt(call_expr.hir_id)?,679            // For normal calls, generic arguments are in the callee's type.680            // This diagnostic is only run for `FnDef` callees.681            hir::ExprKind::Call(callee, _)682                if let &ty::FnDef(_, args) = typeck.node_type(callee.hir_id).kind() =>683            {684                args.no_bound_vars().unwrap()685            }686            _ => return None,687        };688689        // First, is there at least one method on one of `param`'s trait bounds?690        // This keeps us from suggesting borrowing the argument to `mem::drop`, e.g.691        if !clauses.instantiate_identity(tcx).clauses.iter().any(|clause| {692            clause.as_trait_clause().is_some_and(|tc| {693                tc.self_ty().skip_binder().is_param(param.index)694                    && tc.polarity() == ty::PredicatePolarity::Positive695                    && supertrait_def_ids(tcx, tc.def_id())696                        .flat_map(|trait_did| tcx.associated_items(trait_did).in_definition_order())697                        .any(|item| item.is_method())698            })699        }) {700            return None;701        }702703        // Try borrowing a shared reference first, then mutably.704        if let Some(mutbl) = [ty::Mutability::Not, ty::Mutability::Mut].into_iter().find(|&mutbl| {705            let re = self.infcx.tcx.lifetimes.re_erased;706            let ref_ty = Ty::new_ref(self.infcx.tcx, re, moved_arg_ty, mutbl);707708            // Ensure that substituting `ref_ty` in the callee's signature doesn't break709            // other inputs or the return type.710            let new_args = tcx.mk_args_from_iter(generic_args.iter().enumerate().map(711                |(i, arg)| {712                    if i == param.index as usize { ref_ty.into() } else { arg }713                },714            ));715            let can_subst = |ty: Ty<'tcx>| {716                // Normalize before comparing to see through type aliases and projections.717                let old_ty = ty::EarlyBinder::bind(tcx, ty).instantiate(tcx, generic_args);718                let new_ty = ty::EarlyBinder::bind(tcx, ty).instantiate(tcx, new_args);719                if let Ok(old_ty) = tcx.try_normalize_erasing_regions(720                    self.infcx.typing_env(self.infcx.param_env),721                    old_ty,722                ) && let Ok(new_ty) = tcx.try_normalize_erasing_regions(723                    self.infcx.typing_env(self.infcx.param_env),724                    new_ty,725                ) {726                    old_ty == new_ty727                } else {728                    false729                }730            };731            if !can_subst(sig.output())732                || sig733                    .inputs()734                    .iter()735                    .enumerate()736                    .any(|(i, &input_ty)| i != moved_arg_pos && !can_subst(input_ty))737            {738                return false;739            }740741            // Test the callee's clauses, substituting in `ref_ty` for the moved argument type.742            clauses.instantiate(tcx, new_args).clauses.iter().all(|clause| {743                // Normalize before testing to see through type aliases and projections.744                let normalized = tcx745                    .try_normalize_erasing_regions(746                        self.infcx.typing_env(self.infcx.param_env),747                        *clause,748                    )749                    .unwrap_or_else(|_| clause.skip_norm_wip());750                self.infcx.predicate_must_hold_modulo_regions(&Obligation::new(751                    tcx,752                    ObligationCause::dummy(),753                    self.infcx.param_env,754                    normalized,755                ))756            })757        }) {758            let place_desc = if let Some(desc) = self.describe_place(moved_place) {759                format!("`{desc}`")760            } else {761                "here".to_owned()762            };763            err.span_suggestion_verbose(764                place_span.shrink_to_lo(),765                format!("consider {}borrowing {place_desc}", mutbl.mutably_str()),766                mutbl.ref_prefix_str(),767                Applicability::MaybeIncorrect,768            );769            Some(mutbl)770        } else {771            None772        }773    }774775    /// Returns `true` if the given initialization can reach the error location.776    ///777    /// This is used to determine whether an initialization should be considered778    /// when reporting diagnostics at `err_location`.779    ///780    /// The check proceeds in two stages:781    ///782    /// 1. If the initialization originates from a function argument, it is783    ///    considered reachable by definition.784    /// 2. If the initialization's basic block dominates the error block, then785    ///    every path to the error must pass through the initialization, so it is786    ///    reachable.787    /// 3. Otherwise, perform a graph traversal over the MIR control-flow graph to788    ///    determine whether any path exists from the initialization block to the789    ///    error block.790    ///791    /// The dominance check acts as a fast path for the common case, while the CFG792    /// traversal handles cases where the initialization does not dominate the793    /// error location but can still reach it through an alternate control-flow794    /// path.795    fn is_init_reachable(&self, init: &Init, err_location: mir::Location) -> bool {796        let dominators = self.body.basic_blocks.dominators();797        let init_block = match init.location {798            InitLocation::Argument(_) => return true,799            InitLocation::Statement(location) => location.block,800        };801        let err_block = err_location.block;802        if dominators.dominates(init_block, err_block) {803            return true;804        }805        // If init_block doesn't dominate error_block, check if there is any valid path from the806        // initialization block to the error block in the Control Flow Graph.807        let mut visited = DenseBitSet::new_empty(self.body.basic_blocks.len());808        let mut stack = vec![init_block];809        while let Some(block) = stack.pop() {810            if block == err_block {811                return true;812            }813            if visited.insert(block) {814                let data = &self.body.basic_blocks[block];815                for successor in data.terminator().successors() {816                    stack.push(successor);817                }818            }819        }820        false821    }822823    fn report_use_of_uninitialized(824        &self,825        mpi: MovePathIndex,826        used_place: PlaceRef<'tcx>,827        moved_place: PlaceRef<'tcx>,828        desired_action: InitializationRequiringAction,829        location: Location,830        span: Span,831        use_spans: UseSpans<'tcx>,832    ) -> Diag<'diag> {833        // We need all statements in the body where the binding was assigned to later find all834        // the branching code paths where the binding *wasn't* assigned to.835        let inits = &self.move_data.init_path_map[mpi];836        let move_path = &self.move_data.move_paths[mpi];837        let decl_span = self.body.local_decls[move_path.place.local].source_info.span;838        let mut all_init_spans_set = FxIndexSet::default();839        let mut reachable_spans_set = FxIndexSet::default();840        for init_idx in inits {841            let init = &self.move_data.inits[*init_idx];842            let span = init.span(self.body);843            if !span.is_dummy() {844                all_init_spans_set.insert(span);845                if self.is_init_reachable(init, location) {846                    reachable_spans_set.insert(span);847                }848            }849        }850        let all_init_spans: Vec<_> = all_init_spans_set.into_iter().collect();851        let reachable_spans: Vec<_> = reachable_spans_set.into_iter().collect();852853        let (name, desc) = match self.describe_place_with_options(854            moved_place,855            DescribePlaceOpt { including_downcast: true, including_tuple_field: true },856        ) {857            Some(name) => (format!("`{name}`"), format!("`{name}` ")),858            None => ("the variable".to_string(), String::new()),859        };860        let path = match self.describe_place_with_options(861            used_place,862            DescribePlaceOpt { including_downcast: true, including_tuple_field: true },863        ) {864            Some(name) => format!("`{name}`"),865            None => "value".to_string(),866        };867868        // We use the statements were the binding was initialized, and inspect the HIR to look869        // for the branching codepaths that aren't covered, to point at them.870        let tcx = self.infcx.tcx;871        let body = tcx.hir_body_owned_by(self.mir_def_id());872        let mut visitor =873            ConditionVisitor { tcx, spans: all_init_spans.clone(), name, errors: vec![] };874        visitor.visit_body(&body);875876        let mut show_assign_sugg = false;877        let isnt_initialized = if let InitializationRequiringAction::PartialAssignment878        | InitializationRequiringAction::Assignment = desired_action879        {880            // The same error is emitted for bindings that are *sometimes* initialized and the ones881            // that are *partially* initialized by assigning to a field of an uninitialized882            // binding. We differentiate between them for more accurate wording here.883            "isn't fully initialized"884        } else if !reachable_spans.iter().any(|i| {885            // We filter these to avoid misleading wording in cases like the following,886            // where `x` has an `init`, but it is in the same place we're looking at:887            // ```888            // let x;889            // x += 1;890            // ```891            !i.contains(span)892            // We filter these to avoid incorrect main message on `match-cfg-fake-edges.rs`893            && !visitor894                .errors895                .iter()896                .map(|error| error.span)897                .any(|sp| span < sp && !sp.contains(span))898        }) {899            show_assign_sugg = true;900            if all_init_spans.iter().any(|init_span| !init_span.contains(span))901                && reachable_spans.is_empty()902            {903                "isn't initialized on any path leading to this point"904            } else {905                "isn't initialized"906            }907        } else {908            "is possibly-uninitialized"909        };910911        let used = desired_action.as_general_verb_in_past_tense();912        let mut err = struct_span_code_err!(913            self.dcx(),914            span,915            E0381,916            "{used} binding {desc}{isnt_initialized}"917        );918        use_spans.var_path_only_subdiag(&mut err, desired_action);919920        if let InitializationRequiringAction::PartialAssignment921        | InitializationRequiringAction::Assignment = desired_action922        {923            err.help(924                "partial initialization isn't supported, fully initialize the binding with a \925                 default value and mutate it, or use `std::mem::MaybeUninit`",926            );927        }928        err.span_label(span, format!("{path} {used} here but it {isnt_initialized}"));929930        let mut shown = false;931        let mut shown_condition_value = false;932        for error in visitor.errors {933            if error.span < span && !error.span.overlaps(span) {934                // When we have a case like `match-cfg-fake-edges.rs`, we don't want to mention935                // match arms coming after the primary span because they aren't relevant:936                // ```937                // let x;938                // match y {939                //     _ if { x = 2; true } => {}940                //     _ if {941                //         x; //~ ERROR942                //         false943                //     } => {}944                //     _ => {} // We don't want to point to this.945                // };946                // ```947                shown_condition_value |= error.kind.describes_condition_value();948                err.span_label(error.span, error.label);949                shown = true;950            }951        }952        if !shown {953            for sp in &reachable_spans {954                if *sp < span && !sp.overlaps(span) {955                    err.span_label(*sp, "binding initialized here in some conditions");956                }957            }958        }959960        err.span_label(decl_span, "binding declared here but left uninitialized");961        if shown_condition_value {962            err.note(963                "when checking initialization, the compiler describes possible control-flow paths \964                 without evaluating whether branch conditions can actually have the values shown",965            );966        }967        if show_assign_sugg {968            struct LetVisitor {969                decl_span: Span,970                sugg: Option<(Span, bool)>,971            }972973            impl<'v> Visitor<'v> for LetVisitor {974                fn visit_stmt(&mut self, ex: &'v hir::Stmt<'v>) {975                    if self.sugg.is_some() {976                        return;977                    }978979                    // FIXME: We make sure that this is a normal top-level binding,980                    // but we could suggest `todo!()` for all uninitialized bindings in the pattern981                    if let hir::StmtKind::Let(hir::LetStmt { span, ty, init: None, pat, .. }) =982                        &ex.kind983                        && let hir::PatKind::Binding(binding_mode, ..) = pat.kind984                        && span.contains(self.decl_span)985                    {986                        // Insert after the whole binding pattern so suggestions stay valid for987                        // bindings with `@` subpatterns like `ref mut x @ v`.988                        let strip_ref = matches!(binding_mode.0, hir::ByRef::Yes(..));989                        self.sugg =990                            ty.map_or(Some((pat.span, strip_ref)), |ty| Some((ty.span, strip_ref)));991                    }992                    hir::intravisit::walk_stmt(self, ex);993                }994            }995996            let mut visitor = LetVisitor { decl_span, sugg: None };997            visitor.visit_body(&body);998            if let Some((span, strip_ref)) = visitor.sugg {999                self.suggest_assign_value(&mut err, moved_place, span, strip_ref);1000            }1001        }1002        err1003    }10041005    fn suggest_assign_value(1006        &self,1007        err: &mut Diag<'_>,1008        moved_place: PlaceRef<'tcx>,1009        sugg_span: Span,1010        strip_ref: bool,1011    ) {1012        let mut ty = moved_place.ty(self.body, self.infcx.tcx).ty;1013        if strip_ref && let ty::Ref(_, inner, _) = ty.kind() {1014            ty = *inner;1015        }1016        debug!("ty: {:?}, kind: {:?}", ty, ty.kind());10171018        let Some(assign_value) = self.infcx.err_ctxt().ty_kind_suggestion(self.infcx.param_env, ty)1019        else {1020            return;1021        };10221023        err.span_suggestion_verbose(1024            sugg_span.shrink_to_hi(),1025            "consider assigning a value",1026            format!(" = {assign_value}"),1027            Applicability::MaybeIncorrect,1028        );1029    }10301031    /// In a move error that occurs on a call within a loop, we try to identify cases where cloning1032    /// the value would lead to a logic error. We infer these cases by seeing if the moved value is1033    /// part of the logic to break the loop, either through an explicit `break` or if the expression1034    /// is part of a `while let`.1035    fn suggest_hoisting_call_outside_loop(&self, err: &mut Diag<'_>, expr: &hir::Expr<'_>) -> bool {1036        let tcx = self.infcx.tcx;1037        let mut can_suggest_clone = true;10381039        // If the moved value is a locally declared binding, we'll look upwards on the expression1040        // tree until the scope where it is defined, and no further, as suggesting to move the1041        // expression beyond that point would be illogical.1042        let local_hir_id = if let hir::ExprKind::Path(hir::QPath::Resolved(1043            _,1044            hir::Path { res: hir::def::Res::Local(local_hir_id), .. },1045        )) = expr.kind1046        {1047            Some(local_hir_id)1048        } else {1049            // This case would be if the moved value comes from an argument binding, we'll just1050            // look within the entire item, that's fine.1051            None1052        };10531054        /// This will allow us to look for a specific `HirId`, in our case `local_hir_id` where the1055        /// binding was declared, within any other expression. We'll use it to search for the1056        /// binding declaration within every scope we inspect.1057        struct Finder {1058            hir_id: hir::HirId,1059        }1060        impl<'hir> Visitor<'hir> for Finder {1061            type Result = ControlFlow<()>;1062            fn visit_pat(&mut self, pat: &'hir hir::Pat<'hir>) -> Self::Result {1063                if pat.hir_id == self.hir_id {1064                    return ControlFlow::Break(());1065                }1066                hir::intravisit::walk_pat(self, pat)1067            }1068            fn visit_expr(&mut self, ex: &'hir hir::Expr<'hir>) -> Self::Result {1069                if ex.hir_id == self.hir_id {1070                    return ControlFlow::Break(());1071                }1072                hir::intravisit::walk_expr(self, ex)1073            }1074        }1075        // The immediate HIR parent of the moved expression. We'll look for it to be a call.1076        let mut parent = None;1077        // The top-most loop where the moved expression could be moved to a new binding.1078        let mut outer_most_loop: Option<&hir::Expr<'_>> = None;1079        for (_, node) in tcx.hir_parent_iter(expr.hir_id) {1080            let e = match node {1081                hir::Node::Expr(e) => e,1082                hir::Node::LetStmt(hir::LetStmt { els: Some(els), .. }) => {1083                    let mut finder = BreakFinder { found_breaks: vec![], found_continues: vec![] };1084                    finder.visit_block(els);1085                    if !finder.found_breaks.is_empty() {1086                        // Don't suggest clone as it could be will likely end in an infinite1087                        // loop.1088                        // let Some(_) = foo(non_copy.clone()) else { break; }1089                        // ---                       ^^^^^^^^         -----1090                        can_suggest_clone = false;1091                    }1092                    continue;1093                }1094                _ => continue,1095            };1096            if let Some(&hir_id) = local_hir_id {1097                if (Finder { hir_id }).visit_expr(e).is_break() {1098                    // The current scope includes the declaration of the binding we're accessing, we1099                    // can't look up any further for loops.1100                    break;1101                }1102            }1103            if parent.is_none() {1104                parent = Some(e);1105            }1106            match e.kind {1107                hir::ExprKind::Let(_) => {1108                    match tcx.parent_hir_node(e.hir_id) {1109                        hir::Node::Expr(hir::Expr {1110                            kind: hir::ExprKind::If(cond, ..), ..1111                        }) => {1112                            if (Finder { hir_id: expr.hir_id }).visit_expr(cond).is_break() {1113                                // The expression where the move error happened is in a `while let`1114                                // condition Don't suggest clone as it will likely end in an1115                                // infinite loop.1116                                // while let Some(_) = foo(non_copy.clone()) { }1117                                // ---------                       ^^^^^^^^1118                                can_suggest_clone = false;1119                            }1120                        }1121                        _ => {}1122                    }1123                }1124                hir::ExprKind::Loop(..) => {1125                    outer_most_loop = Some(e);1126                }1127                _ => {}1128            }1129        }1130        let loop_count: usize = tcx1131            .hir_parent_iter(expr.hir_id)1132            .map(|(_, node)| match node {1133                hir::Node::Expr(hir::Expr { kind: hir::ExprKind::Loop(..), .. }) => 1,1134                _ => 0,1135            })1136            .sum();11371138        let sm = tcx.sess.source_map();1139        if let Some(in_loop) = outer_most_loop {1140            let mut finder = BreakFinder { found_breaks: vec![], found_continues: vec![] };1141            finder.visit_expr(in_loop);1142            // All of the spans for `break` and `continue` expressions.1143            let spans = finder1144                .found_breaks1145                .iter()1146                .chain(finder.found_continues.iter())1147                .map(|(_, span)| *span)1148                .filter(|span| {1149                    !matches!(1150                        span.desugaring_kind(),1151                        Some(DesugaringKind::ForLoop | DesugaringKind::WhileLoop)1152                    )1153                })1154                .collect::<Vec<Span>>();1155            // All of the spans for the loops above the expression with the move error.1156            let loop_spans: Vec<_> = tcx1157                .hir_parent_iter(expr.hir_id)1158                .filter_map(|(_, node)| match node {1159                    hir::Node::Expr(hir::Expr { span, kind: hir::ExprKind::Loop(..), .. }) => {1160                        Some(*span)1161                    }1162                    _ => None,1163                })1164                .collect();1165            // It is possible that a user written `break` or `continue` is in the wrong place. We1166            // point them out at the user for them to make a determination. (#92531)1167            if !spans.is_empty() && loop_count > 1 {1168                // Getting fancy: if the spans of the loops *do not* overlap, we only use the line1169                // number when referring to them. If there *are* overlaps (multiple loops on the1170                // same line) then we use the more verbose span output (`file.rs:col:ll`).1171                let mut lines: Vec<_> =1172                    loop_spans.iter().map(|sp| sm.lookup_char_pos(sp.lo()).line).collect();1173                lines.sort();1174                lines.dedup();1175                let fmt_span = |span: Span| {1176                    if lines.len() == loop_spans.len() {1177                        format!("line {}", sm.lookup_char_pos(span.lo()).line)1178                    } else {1179                        sm.span_to_diagnostic_string(span)1180                    }1181                };1182                let mut spans: MultiSpan = spans.into();1183                // Point at all the `continue`s and explicit `break`s in the relevant loops.1184                for (desc, elements) in [1185                    ("`break` exits", &finder.found_breaks),1186                    ("`continue` advances", &finder.found_continues),1187                ] {1188                    for (destination, sp) in elements {1189                        if let Ok(hir_id) = destination.target_id1190                            && let hir::Node::Expr(expr) = tcx.hir_node(hir_id)1191                            && !matches!(1192                                sp.desugaring_kind(),1193                                Some(DesugaringKind::ForLoop | DesugaringKind::WhileLoop)1194                            )1195                        {1196                            spans.push_span_label(1197                                *sp,1198                                format!("this {desc} the loop at {}", fmt_span(expr.span)),1199                            );1200                        }1201                    }1202                }1203                // Point at all the loops that are between this move and the parent item.1204                for span in loop_spans {1205                    spans.push_span_label(sm.guess_head_span(span), "");1206                }12071208                // note: verify that your loop breaking logic is correct1209                //   --> $DIR/nested-loop-moved-value-wrong-continue.rs:41:171210                //    |1211                // 28 |     for foo in foos {1212                //    |     ---------------1213                // ...1214                // 33 |         for bar in &bars {1215                //    |         ----------------1216                // ...1217                // 41 |                 continue;1218                //    |                 ^^^^^^^^ this `continue` advances the loop at line 331219                err.span_note(spans, "verify that your loop breaking logic is correct");1220            }1221            if let Some(parent) = parent1222                && let hir::ExprKind::MethodCall(..) | hir::ExprKind::Call(..) = parent.kind1223            {1224                // FIXME: We could check that the call's *parent* takes `&mut val` to make the1225                // suggestion more targeted to the `mk_iter(val).next()` case. Maybe do that only to1226                // check for whether to suggest `let value` or `let mut value`.12271228                let span = in_loop.span;1229                if !finder.found_breaks.is_empty()1230                    && let Ok(value) = sm.span_to_snippet(parent.span)1231                {1232                    // We know with high certainty that this move would affect the early return of a1233                    // loop, so we suggest moving the expression with the move out of the loop.1234                    let indent = if let Some(indent) = sm.indentation_before(span) {1235                        format!("\n{indent}")1236                    } else {1237                        " ".to_string()1238                    };1239                    err.multipart_suggestion(1240                        "consider moving the expression out of the loop so it is only moved once",1241                        vec![1242                            (span.shrink_to_lo(), format!("let mut value = {value};{indent}")),1243                            (parent.span, "value".to_string()),1244                        ],1245                        Applicability::MaybeIncorrect,1246                    );1247                }1248            }1249        }1250        can_suggest_clone1251    }12521253    /// We have `S { foo: val, ..base }`, and we suggest instead writing1254    /// `S { foo: val, bar: base.bar.clone(), .. }` when valid.1255    fn suggest_cloning_on_functional_record_update(1256        &self,1257        err: &mut Diag<'_>,1258        ty: Ty<'tcx>,1259        expr: &hir::Expr<'_>,1260    ) {1261        let typeck_results = self.infcx.tcx.typeck(self.mir_def_id());1262        let hir::ExprKind::Struct(struct_qpath, fields, hir::StructTailExpr::Base(base)) =1263            expr.kind1264        else {1265            return;1266        };1267        let hir::QPath::Resolved(_, path) = struct_qpath else { return };1268        let hir::def::Res::Def(_, def_id) = path.res else { return };1269        let Some(expr_ty) = typeck_results.node_type_opt(expr.hir_id) else { return };1270        let ty::Adt(def, args) = expr_ty.kind() else { return };1271        let hir::ExprKind::Path(hir::QPath::Resolved(None, path)) = base.kind else { return };1272        let (hir::def::Res::Local(_)1273        | hir::def::Res::Def(1274            DefKind::Const { .. }1275            | DefKind::ConstParam1276            | DefKind::Static { .. }1277            | DefKind::AssocConst { .. },1278            _,1279        )) = path.res1280        else {1281            return;1282        };1283        let Ok(base_str) = self.infcx.tcx.sess.source_map().span_to_snippet(base.span) else {1284            return;1285        };12861287        // 1. look for the fields of type `ty`.1288        // 2. check if they are clone and add them to suggestion1289        // 3. check if there are any values left to `..` and remove it if not1290        // 4. emit suggestion to clone the field directly as `bar: base.bar.clone()`12911292        let mut final_field_count = fields.len();1293        let Some(variant) = def.variants().iter().find(|variant| variant.def_id == def_id) else {1294            // When we have an enum, look for the variant that corresponds to the variant the user1295            // wrote.1296            return;1297        };1298        let mut sugg = vec![];1299        for field in &variant.fields {1300            // In practice unless there are more than one field with the same type, we'll be1301            // suggesting a single field at a type, because we don't aggregate multiple borrow1302            // checker errors involving the functional record update syntax into a single one.1303            let field_ty = field.ty(self.infcx.tcx, args).skip_norm_wip();1304            let ident = field.ident(self.infcx.tcx);1305            if field_ty == ty && fields.iter().all(|field| field.ident.name != ident.name) {1306                // Suggest adding field and cloning it.1307                sugg.push(format!("{ident}: {base_str}.{ident}.clone()"));1308                final_field_count += 1;1309            }1310        }1311        let (span, sugg) = match fields {1312            [.., last] => (1313                if final_field_count == variant.fields.len() {1314                    // We'll remove the `..base` as there aren't any fields left.1315                    last.span.shrink_to_hi().with_hi(base.span.hi())1316                } else {1317                    last.span.shrink_to_hi()1318                },1319                format!(", {}", sugg.join(", ")),1320            ),1321            // Account for no fields in suggestion span.1322            [] => (1323                expr.span.with_lo(struct_qpath.span().hi()),1324                if final_field_count == variant.fields.len() {1325                    // We'll remove the `..base` as there aren't any fields left.1326                    format!(" {{ {} }}", sugg.join(", "))1327                } else {1328                    format!(" {{ {}, ..{base_str} }}", sugg.join(", "))1329                },1330            ),1331        };1332        let prefix = if !self.implements_clone(ty) {1333            let msg = format!("`{ty}` doesn't implement `Copy` or `Clone`");1334            if let ty::Adt(def, _) = ty.kind() {1335                err.span_note(self.infcx.tcx.def_span(def.did()), msg);1336            } else {1337                err.note(msg);1338            }1339            format!("if `{ty}` implemented `Clone`, you could ")1340        } else {1341            String::new()1342        };1343        let msg = format!(1344            "{prefix}clone the value from the field instead of using the functional record update \1345             syntax",1346        );1347        err.span_suggestion_verbose(span, msg, sugg, Applicability::MachineApplicable);1348    }13491350    pub(crate) fn suggest_cloning(1351        &self,1352        err: &mut Diag<'_>,1353        place: PlaceRef<'tcx>,1354        ty: Ty<'tcx>,1355        expr: &'tcx hir::Expr<'tcx>,1356        use_spans: Option<UseSpans<'tcx>>,1357    ) {1358        if let hir::ExprKind::Struct(_, _, hir::StructTailExpr::Base(_)) = expr.kind {1359            // We have `S { foo: val, ..base }`. In `check_aggregate_rvalue` we have a single1360            // `Location` that covers both the `S { ... }` literal, all of its fields and the1361            // `base`. If the move happens because of `S { foo: val, bar: base.bar }` the `expr`1362            //  will already be correct. Instead, we see if we can suggest writing.1363            self.suggest_cloning_on_functional_record_update(err, ty, expr);1364            return;1365        }13661367        if self.implements_clone(ty) {1368            if self.in_move_closure(expr) {1369                if let Some(name) = self.describe_place(place) {1370                    self.suggest_clone_of_captured_var_in_move_closure(err, &name, use_spans);1371                }1372            } else {1373                self.suggest_cloning_inner(err, ty, expr);1374            }1375        } else if let ty::Adt(def, args) = ty.kind()1376            && let Some(local_did) = def.did().as_local()1377            && def.variants().iter().all(|variant| {1378                variant.fields.iter().all(|field| {1379                    self.implements_clone(field.ty(self.infcx.tcx, args).skip_norm_wip())1380                })1381            })1382        {1383            let ty_span = self.infcx.tcx.def_span(def.did());1384            let mut span: MultiSpan = ty_span.into();1385            let mut derive_clone = false;1386            self.infcx.tcx.for_each_relevant_impl(1387                self.infcx.tcx.lang_items().clone_trait().unwrap(),1388                ty,1389                |def_id| {1390                    if self.infcx.tcx.is_automatically_derived(def_id) {1391                        derive_clone = true;1392                        span.push_span_label(1393                            self.infcx.tcx.def_span(def_id),1394                            "derived `Clone` adds implicit bounds on type parameters",1395                        );1396                        if let Some(generics) = self.infcx.tcx.hir_get_generics(local_did) {1397                            for param in generics.params {1398                                if let hir::GenericParamKind::Type { .. } = param.kind {1399                                    span.push_span_label(1400                                        param.span,1401                                        format!(1402                                            "introduces an implicit `{}: Clone` bound",1403                                            param.name.ident()1404                                        ),1405                                    );1406                                }1407                            }1408                        }1409                    }1410                },1411            );1412            let msg = if !derive_clone {1413                span.push_span_label(1414                    ty_span,1415                    format!(1416                        "consider {}implementing `Clone` for this type",1417                        if derive_clone { "manually " } else { "" }1418                    ),1419                );1420                format!("if `{ty}` implemented `Clone`, you could clone the value")1421            } else {1422                format!("if all bounds were met, you could clone the value")1423            };1424            span.push_span_label(expr.span, "you could clone this value");1425            err.span_note(span, msg);1426            if derive_clone {1427                err.help("consider manually implementing `Clone` to avoid undesired bounds");1428            }1429        } else if let ty::Param(param) = ty.kind()1430            && let Some(_clone_trait_def) = self.infcx.tcx.lang_items().clone_trait()1431            && let generics = self.infcx.tcx.generics_of(self.mir_def_id())1432            && let generic_param = generics.type_param(*param, self.infcx.tcx)1433            && let param_span = self.infcx.tcx.def_span(generic_param.def_id)1434            && if let Some(UseSpans::FnSelfUse { kind, .. }) = use_spans1435                && let CallKind::FnCall { fn_trait_id, self_ty } = kind1436                && let ty::Param(_) = self_ty.kind()1437                && ty == self_ty1438                && self.infcx.tcx.fn_trait_kind_from_def_id(fn_trait_id).is_some()1439            {1440                // Do not suggest `F: FnOnce() + Clone`.1441                false1442            } else {1443                true1444            }1445        {1446            let mut span: MultiSpan = param_span.into();1447            span.push_span_label(1448                param_span,1449                "consider constraining this type parameter with `Clone`",1450            );1451            span.push_span_label(expr.span, "you could clone this value");1452            err.span_help(1453                span,1454                format!("if `{ty}` implemented `Clone`, you could clone the value"),1455            );1456        } else if let ty::Adt(_, _) = ty.kind()1457            && let Some(clone_trait) = self.infcx.tcx.lang_items().clone_trait()1458        {1459            // For cases like `Option<NonClone>`, where `Option<T>: Clone` if `T: Clone`, we point1460            // at the types that should be `Clone`.1461            let ocx = ObligationCtxt::new_with_diagnostics(self.infcx);1462            let cause = ObligationCause::misc(expr.span, self.mir_def_id());1463            ocx.register_bound(cause, self.infcx.param_env, ty, clone_trait);1464            let errors = ocx.evaluate_obligations_error_on_ambiguity();1465            if let TraitErrors::HasErrors(errors) = errors1466                && errors.iter().all(|error| {1467                    match error.obligation.predicate.as_clause().and_then(|c| c.as_trait_clause()) {1468                        Some(clause) => match clause.self_ty().skip_binder().kind() {1469                            ty::Adt(def, _) => {1470                                def.did().is_local() && clause.def_id() == clone_trait1471                            }1472                            _ => false,1473                        },1474                        None => false,1475                    }1476                })1477            {1478                let mut type_spans = vec![];1479                let mut types = FxIndexSet::default();1480                for clause in errors1481                    .iter()1482                    .filter_map(|e| e.obligation.predicate.as_clause())1483                    .filter_map(|c| c.as_trait_clause())1484                {1485                    let ty::Adt(def, _) = clause.self_ty().skip_binder().kind() else { continue };1486                    type_spans.push(self.infcx.tcx.def_span(def.did()));1487                    types.insert(1488                        self.infcx1489                            .tcx1490                            .short_string(clause.self_ty().skip_binder(), &mut err.long_ty_path()),1491                    );1492                }1493                let mut span: MultiSpan = type_spans.clone().into();1494                for sp in type_spans {1495                    span.push_span_label(sp, "consider implementing `Clone` for this type");1496                }1497                span.push_span_label(expr.span, "you could clone this value");1498                let types: Vec<_> = types.into_iter().collect();1499                let msg = match &types[..] {1500                    [only] => format!("`{only}`"),1501                    [head @ .., last] => format!(1502                        "{} and `{last}`",1503                        head.iter().map(|t| format!("`{t}`")).collect::<Vec<_>>().join(", ")1504                    ),1505                    [] => unreachable!(),1506                };1507                err.span_note(1508                    span,1509                    format!("if {msg} implemented `Clone`, you could clone the value"),1510                );1511            }1512        }1513    }15141515    pub(crate) fn implements_clone(&self, ty: Ty<'tcx>) -> bool {1516        let Some(clone_trait_def) = self.infcx.tcx.lang_items().clone_trait() else { return false };1517        self.infcx1518            .type_implements_trait(clone_trait_def, [ty], self.infcx.param_env)1519            .must_apply_modulo_regions()1520    }15211522    /// Given an expression, check if it is a method call `foo.clone()`, where `foo` and1523    /// `foo.clone()` both have the same type, returning the span for `.clone()` if so.1524    pub(crate) fn clone_on_reference(&self, expr: &hir::Expr<'_>) -> Option<Span> {1525        let typeck_results = self.infcx.tcx.typeck(self.mir_def_id());1526        if let hir::ExprKind::MethodCall(segment, rcvr, args, span) = expr.kind1527            && let Some(expr_ty) = typeck_results.node_type_opt(expr.hir_id)1528            && let Some(rcvr_ty) = typeck_results.node_type_opt(rcvr.hir_id)1529            && rcvr_ty == expr_ty1530            && segment.ident.name == sym::clone1531            && args.is_empty()1532        {1533            Some(span)1534        } else {1535            None1536        }1537    }15381539    fn in_move_closure(&self, expr: &hir::Expr<'_>) -> bool {1540        for (_, node) in self.infcx.tcx.hir_parent_iter(expr.hir_id) {1541            if let hir::Node::Expr(hir::Expr { kind: hir::ExprKind::Closure(closure), .. }) = node1542                && let hir::CaptureBy::Value { .. } = closure.capture_clause1543            {1544                // `move || x.clone()` will not work. FIXME: suggest `let y = x.clone(); move || y`1545                return true;1546            }1547        }1548        false1549    }15501551    fn suggest_cloning_inner(1552        &self,1553        err: &mut Diag<'_>,1554        ty: Ty<'tcx>,1555        expr: &hir::Expr<'_>,1556    ) -> bool {1557        let tcx = self.infcx.tcx;15581559        // Don't suggest `.clone()` in a derive macro expansion.1560        if let ExpnKind::Macro(MacroKind::Derive, _) = self.body.span.ctxt().outer_expn_data().kind1561        {1562            return false;1563        }1564        if let Some(_) = self.clone_on_reference(expr) {1565            // Avoid redundant clone suggestion already suggested in `explain_captures`.1566            // See `tests/ui/moves/needs-clone-through-deref.rs`1567            return false;1568        }1569        // We don't want to suggest `.clone()` in a move closure, since the value has already been1570        // captured.1571        if self.in_move_closure(expr) {1572            return false;1573        }1574        // We also don't want to suggest cloning a closure itself, since the value has already been1575        // captured.1576        if let hir::ExprKind::Closure(_) = expr.kind {1577            return false;1578        }1579        // Try to find predicates on *generic params* that would allow copying `ty`1580        let mut suggestion =1581            if let Some(symbol) = tcx.hir_maybe_get_struct_pattern_shorthand_field(expr) {1582                format!(": {symbol}.clone()")1583            } else {1584                ".clone()".to_owned()1585            };1586        let mut sugg = Vec::with_capacity(2);1587        let mut inner_expr = expr;1588        let mut is_raw_ptr = false;1589        let typeck_result = self.infcx.tcx.typeck(self.mir_def_id());1590        // Remove uses of `&` and `*` when suggesting `.clone()`.1591        while let hir::ExprKind::AddrOf(.., inner) | hir::ExprKind::Unary(hir::UnOp::Deref, inner) =1592            &inner_expr.kind1593        {1594            if let hir::ExprKind::AddrOf(_, hir::Mutability::Mut, _) = inner_expr.kind {1595                // We assume that `&mut` refs are desired for their side-effects, so cloning the1596                // value wouldn't do what the user wanted.1597                return false;1598            }1599            inner_expr = inner;1600            if let Some(inner_type) = typeck_result.node_type_opt(inner.hir_id) {1601                if matches!(inner_type.kind(), ty::RawPtr(..)) {1602                    is_raw_ptr = true;1603                    break;1604                }1605            }1606        }1607        // Cloning the raw pointer doesn't make sense in some cases and would cause a type mismatch1608        // error. (see #126863)1609        if inner_expr.span.lo() != expr.span.lo() && !is_raw_ptr {1610            // Remove "(*" or "(&"1611            sugg.push((expr.span.with_hi(inner_expr.span.lo()), String::new()));1612        }1613        // Check whether `expr` is surrounded by parentheses or not.1614        let span = if inner_expr.span.hi() != expr.span.hi() {1615            // Account for `(*x)` to suggest `x.clone()`.1616            if is_raw_ptr {1617                expr.span.shrink_to_hi()1618            } else {1619                // Remove the close parenthesis ")"1620                expr.span.with_lo(inner_expr.span.hi())1621            }1622        } else {1623            if is_raw_ptr {1624                sugg.push((expr.span.shrink_to_lo(), "(".to_string()));1625                suggestion = ").clone()".to_string();1626            }1627            expr.span.shrink_to_hi()1628        };1629        sugg.push((span, suggestion));1630        let msg = if let ty::Adt(def, _) = ty.kind()1631            && [tcx.get_diagnostic_item(sym::Arc), tcx.get_diagnostic_item(sym::Rc)]1632                .contains(&Some(def.did()))1633        {1634            "clone the value to increment its reference count"1635        } else {1636            "consider cloning the value if the performance cost is acceptable"1637        };1638        err.multipart_suggestion(msg, sugg, Applicability::MachineApplicable);1639        true1640    }16411642    fn suggest_adding_bounds(&self, err: &mut Diag<'_>, ty: Ty<'tcx>, def_id: DefId, span: Span) {1643        let tcx = self.infcx.tcx;1644        let generics = tcx.generics_of(self.mir_def_id());16451646        let Some(hir_generics) =1647            tcx.hir_get_generics(tcx.typeck_root_def_id_local(self.mir_def_id()))1648        else {1649            return;1650        };1651        // Try to find predicates on *generic params* that would allow copying `ty`1652        let ocx = ObligationCtxt::new_with_diagnostics(self.infcx);1653        let cause = ObligationCause::misc(span, self.mir_def_id());16541655        ocx.register_bound(cause, self.infcx.param_env, ty, def_id);1656        let errors = ocx.evaluate_obligations_error_on_ambiguity();16571658        // Only emit suggestion if all required predicates are on generic1659        let predicates: Result<Vec<_>, _> = errors1660            .into_iter()1661            .map(|err| match err.obligation.predicate.kind().skip_binder() {1662                PredicateKind::Clause(ty::ClauseKind::Trait(predicate)) => {1663                    match *predicate.self_ty().kind() {1664                        ty::Param(param_ty) => Ok((1665                            generics.type_param(param_ty, tcx),1666                            predicate.trait_ref.print_trait_sugared().to_string(),1667                            Some(predicate.trait_ref.def_id),1668                        )),1669                        _ => Err(()),1670                    }1671                }1672                _ => Err(()),1673            })1674            .collect();16751676        if let Ok(predicates) = predicates {1677            suggest_constraining_type_params(1678                tcx,1679                hir_generics,1680                err,1681                predicates.iter().map(|(param, constraint, def_id)| {1682                    (param.name.as_str(), &**constraint, *def_id)1683                }),1684                None,1685            );1686        }1687    }16881689    pub(crate) fn report_move_out_while_borrowed(1690        &mut self,1691        location: Location,1692        (place, span): (Place<'tcx>, Span),1693        borrow: &BorrowData<'tcx>,1694    ) {1695        debug!(1696            "report_move_out_while_borrowed: location={:?} place={:?} span={:?} borrow={:?}",1697            location, place, span, borrow1698        );1699        let value_msg = self.describe_any_place(place.as_ref());1700        let borrow_msg = self.describe_any_place(borrow.borrowed_place.as_ref());17011702        let borrow_spans = self.retrieve_borrow_spans(borrow);1703        let borrow_span = borrow_spans.args_or_use();17041705        let move_spans = self.move_spans(place.as_ref(), location);1706        let span = move_spans.args_or_use();17071708        let mut err = self.cannot_move_when_borrowed(1709            span,1710            borrow_span,1711            &self.describe_any_place(place.as_ref()),1712            &borrow_msg,1713            &value_msg,1714        );1715        self.note_due_to_edition_2024_opaque_capture_rules(borrow, &mut err);17161717        borrow_spans.var_path_only_subdiag(&mut err, crate::InitializationRequiringAction::Borrow);17181719        move_spans.var_subdiag(&mut err, None, |kind, var_span| {1720            use crate::session_diagnostics::CaptureVarCause::*;1721            match kind {1722                hir::ClosureKind::Coroutine(_) => MoveUseInCoroutine { var_span },1723                hir::ClosureKind::Closure | hir::ClosureKind::CoroutineClosure(_) => {1724                    MoveUseInClosure { var_span }1725                }1726            }1727        });17281729        self.explain_why_borrow_contains_point(location, borrow, None)1730            .add_explanation_to_diagnostic(&self, &mut err, "", Some(borrow_span), None);1731        self.suggest_copy_for_type_in_cloned_ref(&mut err, place);1732        let typeck_results = self.infcx.tcx.typeck(self.mir_def_id());1733        if let Some(expr) = self.find_expr(borrow_span) {1734            // This is a borrow span, so we want to suggest cloning the referent.1735            if let hir::ExprKind::AddrOf(_, _, borrowed_expr) = expr.kind1736                && let Some(ty) = typeck_results.expr_ty_opt(borrowed_expr)1737            {1738                self.suggest_cloning(&mut err, place.as_ref(), ty, borrowed_expr, Some(move_spans));1739            } else if typeck_results.expr_adjustments(expr).first().is_some_and(|adj| {1740                matches!(1741                    adj.kind,1742                    ty::adjustment::Adjust::Borrow(ty::adjustment::AutoBorrow::Ref(1743                        ty::adjustment::AutoBorrowMutability::Not1744                            | ty::adjustment::AutoBorrowMutability::Mut {1745                                allow_two_phase_borrow: ty::adjustment::AllowTwoPhase::No1746                            }1747                    ))1748                )1749            }) && let Some(ty) = typeck_results.expr_ty_opt(expr)1750            {1751                self.suggest_cloning(&mut err, place.as_ref(), ty, expr, Some(move_spans));1752            }1753        }1754        self.buffer_error(err);1755    }17561757    pub(crate) fn report_use_while_mutably_borrowed(1758        &self,1759        location: Location,1760        (place, _span): (Place<'tcx>, Span),1761        borrow: &BorrowData<'tcx>,1762    ) -> Diag<'diag> {1763        let borrow_spans = self.retrieve_borrow_spans(borrow);1764        let borrow_span = borrow_spans.args_or_use();17651766        // Conflicting borrows are reported separately, so only check for move1767        // captures.1768        let use_spans = self.move_spans(place.as_ref(), location);1769        let span = use_spans.var_or_use();17701771        // If the attempted use is in a closure then we do not care about the path span of the1772        // place we are currently trying to use we call `var_span_label` on `borrow_spans` to1773        // annotate if the existing borrow was in a closure.1774        let mut err = self.cannot_use_when_mutably_borrowed(1775            span,1776            &self.describe_any_place(place.as_ref()),1777            borrow_span,1778            &self.describe_any_place(borrow.borrowed_place.as_ref()),1779        );1780        self.note_due_to_edition_2024_opaque_capture_rules(borrow, &mut err);17811782        borrow_spans.var_subdiag(&mut err, Some(borrow.kind), |kind, var_span| {1783            use crate::session_diagnostics::CaptureVarCause::*;1784            let place = &borrow.borrowed_place;1785            let desc_place = self.describe_any_place(place.as_ref());1786            match kind {1787                hir::ClosureKind::Coroutine(_) => {1788                    BorrowUsePlaceCoroutine { place: desc_place, var_span, is_single_var: true }1789                }1790                hir::ClosureKind::Closure | hir::ClosureKind::CoroutineClosure(_) => {1791                    BorrowUsePlaceClosure { place: desc_place, var_span, is_single_var: true }1792                }1793            }1794        });17951796        self.explain_why_borrow_contains_point(location, borrow, None)1797            .add_explanation_to_diagnostic(&self, &mut err, "", None, None);1798        err1799    }18001801    pub(crate) fn report_conflicting_borrow(1802        &self,1803        location: Location,1804        (place, span): (Place<'tcx>, Span),1805        gen_borrow_kind: BorrowKind,1806        issued_borrow: &BorrowData<'tcx>,1807    ) -> Diag<'diag> {1808        let issued_spans = self.retrieve_borrow_spans(issued_borrow);1809        let issued_span = issued_spans.args_or_use();18101811        let borrow_spans = self.borrow_spans(span, location);1812        let span = borrow_spans.args_or_use();18131814        let container_name = if issued_spans.for_coroutine() || borrow_spans.for_coroutine() {1815            "coroutine"1816        } else {1817            "closure"1818        };18191820        let (desc_place, msg_place, msg_borrow, union_type_name) =1821            self.describe_place_for_conflicting_borrow(place, issued_borrow.borrowed_place);18221823        let explanation = self.explain_why_borrow_contains_point(location, issued_borrow, None);1824        let second_borrow_desc = if explanation.is_explained() { "second " } else { "" };18251826        // FIXME: supply non-"" `opt_via` when appropriate1827        let first_borrow_desc;1828        let mut err = match (gen_borrow_kind, issued_borrow.kind) {1829            (1830                BorrowKind::Shared | BorrowKind::Fake(FakeBorrowKind::Deep),1831                BorrowKind::Mut { kind: MutBorrowKind::Default | MutBorrowKind::TwoPhaseBorrow },1832            ) => {1833                first_borrow_desc = "mutable ";1834                let mut err = self.cannot_reborrow_already_borrowed(1835                    span,1836                    &desc_place,1837                    &msg_place,1838                    "immutable",1839                    issued_span,1840                    "it",1841                    "mutable",1842                    &msg_borrow,1843                    None,1844                );1845                self.suggest_slice_method_if_applicable(1846                    &mut err,1847                    place,1848                    issued_borrow.borrowed_place,1849                    span,1850                    issued_span,1851                );1852                err1853            }1854            (1855                BorrowKind::Mut { kind: MutBorrowKind::Default | MutBorrowKind::TwoPhaseBorrow },1856                BorrowKind::Shared | BorrowKind::Fake(FakeBorrowKind::Deep),1857            ) => {1858                first_borrow_desc = "immutable ";1859                let mut err = self.cannot_reborrow_already_borrowed(1860                    span,1861                    &desc_place,1862                    &msg_place,1863                    "mutable",1864                    issued_span,1865                    "it",1866                    "immutable",1867                    &msg_borrow,1868                    None,1869                );1870                self.suggest_slice_method_if_applicable(1871                    &mut err,1872                    place,1873                    issued_borrow.borrowed_place,1874                    span,1875                    issued_span,1876                );1877                self.suggest_binding_for_closure_capture_self(&mut err, &issued_spans);1878                self.suggest_using_closure_argument_instead_of_capture(1879                    &mut err,1880                    issued_borrow.borrowed_place,1881                    &issued_spans,1882                );1883                self.explain_iterator_invalidation_in_for_loop_if_applicable(1884                    &mut err,1885                    &issued_spans,1886                    place,1887                    issued_borrow.borrowed_place,1888                    issued_borrow.kind,1889                    span,1890                );1891                err1892            }18931894            (1895                BorrowKind::Mut { kind: MutBorrowKind::Default | MutBorrowKind::TwoPhaseBorrow },1896                BorrowKind::Mut { kind: MutBorrowKind::Default | MutBorrowKind::TwoPhaseBorrow },1897            ) => {1898                first_borrow_desc = "first ";1899                let mut err = self.cannot_mutably_borrow_multiply(1900                    span,1901                    &desc_place,1902                    &msg_place,1903                    issued_span,1904                    &msg_borrow,1905                    None,1906                );1907                self.suggest_slice_method_if_applicable(1908                    &mut err,1909                    place,1910                    issued_borrow.borrowed_place,1911                    span,1912                    issued_span,1913                );1914                self.explain_iterator_invalidation_in_for_loop_if_applicable(1915                    &mut err,1916                    &issued_spans,1917                    place,1918                    issued_borrow.borrowed_place,1919                    issued_borrow.kind,1920                    span,1921                );1922                self.suggest_using_closure_argument_instead_of_capture(1923                    &mut err,1924                    issued_borrow.borrowed_place,1925                    &issued_spans,1926                );1927                self.explain_iterator_advancement_in_for_loop_if_applicable(1928                    &mut err,1929                    span,1930                    &issued_spans,1931                );1932                err1933            }19341935            (1936                BorrowKind::Mut { kind: MutBorrowKind::ClosureCapture },1937                BorrowKind::Mut { kind: MutBorrowKind::ClosureCapture },1938            ) => {1939                first_borrow_desc = "first ";1940                self.cannot_uniquely_borrow_by_two_closures(span, &desc_place, issued_span, None)1941            }19421943            (BorrowKind::Mut { .. }, BorrowKind::Fake(FakeBorrowKind::Shallow)) => {1944                if let Some(immutable_section_description) =1945                    self.classify_immutable_section(issued_borrow.assigned_place)1946                {1947                    let mut err = self.cannot_mutate_in_immutable_section(1948                        span,1949                        issued_span,1950                        &desc_place,1951                        immutable_section_description,1952                        "mutably borrow",1953                    );1954                    borrow_spans.var_subdiag(1955                        &mut err,1956                        Some(BorrowKind::Mut { kind: MutBorrowKind::ClosureCapture }),1957                        |kind, var_span| {1958                            use crate::session_diagnostics::CaptureVarCause::*;1959                            match kind {1960                                hir::ClosureKind::Coroutine(_) => BorrowUsePlaceCoroutine {1961                                    place: desc_place,1962                                    var_span,1963                                    is_single_var: true,1964                                },1965                                hir::ClosureKind::Closure1966                                | hir::ClosureKind::CoroutineClosure(_) => BorrowUsePlaceClosure {1967                                    place: desc_place,1968                                    var_span,1969                                    is_single_var: true,1970                                },1971                            }1972                        },1973                    );1974                    return err;1975                } else {1976                    first_borrow_desc = "immutable ";1977                    self.cannot_reborrow_already_borrowed(1978                        span,1979                        &desc_place,1980                        &msg_place,1981                        "mutable",1982                        issued_span,1983                        "it",1984                        "immutable",1985                        &msg_borrow,1986                        None,1987                    )1988                }1989            }19901991            (BorrowKind::Mut { kind: MutBorrowKind::ClosureCapture }, _) => {1992                first_borrow_desc = "first ";1993                self.cannot_uniquely_borrow_by_one_closure(1994                    span,1995                    container_name,1996                    &desc_place,1997                    "",1998                    issued_span,1999                    "it",2000                    "",

Findings

✓ No findings reported for this file.

Get this view in your editor

Same data, no extra tab — call code_get_file + code_get_findings over MCP from Claude/Cursor/Copilot.