compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs RUST 4,820 lines View on github.com → Search inside
File is large — showing lines 1–2,000 of 4,820.
1// ignore-tidy-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::def::{DefKind, Res};14use rustc_hir::intravisit::{Visitor, walk_block, walk_expr};15use rustc_hir::{16    CoroutineDesugaring, CoroutineKind, CoroutineSource, LangItem, PatField, find_attr,17};18use rustc_middle::bug;19use rustc_middle::hir::nested_filter::OnlyBodies;20use rustc_middle::mir::{21    self, AggregateKind, BindingForm, BorrowKind, ClearCrossCrate, ConstraintCategory,22    FakeBorrowKind, FakeReadCause, LocalDecl, LocalInfo, LocalKind, Location, MutBorrowKind,23    Operand, Place, PlaceRef, PlaceTy, ProjectionElem, Rvalue, Statement, StatementKind,24    Terminator, TerminatorKind, VarBindingForm, VarDebugInfoContents,25};26use rustc_middle::ty::print::PrintTraitRefExt as _;27use rustc_middle::ty::{28    self, PredicateKind, Ty, TyCtxt, TypeSuperVisitable, TypeVisitor, Upcast,29    suggest_constraining_type_params,30};31use rustc_mir_dataflow::move_paths::{InitKind, MoveOutIndex, MovePathIndex};32use rustc_span::def_id::{DefId, LocalDefId};33use rustc_span::hygiene::DesugaringKind;34use rustc_span::{BytePos, ExpnKind, Ident, MacroKind, Span, Symbol, kw, sym};35use rustc_trait_selection::error_reporting::InferCtxtErrorExt;36use rustc_trait_selection::error_reporting::traits::FindExprBySpan;37use rustc_trait_selection::error_reporting::traits::call_kind::CallKind;38use rustc_trait_selection::infer::InferCtxtExt;39use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt as _;40use rustc_trait_selection::traits::{41    Obligation, ObligationCause, ObligationCtxt, supertrait_def_ids,42};43use tracing::{debug, instrument};4445use super::explain_borrow::{BorrowExplanation, LaterUseKind};46use super::{DescribePlaceOpt, RegionName, RegionNameSource, UseSpans};47use crate::borrow_set::{BorrowData, TwoPhaseActivation};48use crate::diagnostics::conflict_errors::StorageDeadOrDrop::LocalStorageDead;49use crate::diagnostics::{CapturedMessageOpt, call_kind, find_all_local_uses};50use crate::{InitializationRequiringAction, MirBorrowckCtxt, WriteKind, borrowck_errors};5152#[derive(Debug)]53struct MoveSite {54    /// Index of the "move out" that we found. The `MoveData` can55    /// then tell us where the move occurred.56    moi: MoveOutIndex,5758    /// `true` if we traversed a back edge while walking from the point59    /// of error to the move site.60    traversed_back_edge: bool,61}6263/// Which case a StorageDeadOrDrop is for.64#[derive(Copy, Clone, PartialEq, Eq, Debug)]65enum StorageDeadOrDrop<'tcx> {66    LocalStorageDead,67    BoxedStorageDead,68    Destructor(Ty<'tcx>),69}7071impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {72    pub(crate) fn report_use_of_moved_or_uninitialized(73        &mut self,74        location: Location,75        desired_action: InitializationRequiringAction,76        (moved_place, used_place, span): (PlaceRef<'tcx>, PlaceRef<'tcx>, Span),77        mpi: MovePathIndex,78    ) {79        debug!(80            "report_use_of_moved_or_uninitialized: location={:?} desired_action={:?} \81             moved_place={:?} used_place={:?} span={:?} mpi={:?}",82            location, desired_action, moved_place, used_place, span, mpi83        );8485        let use_spans =86            self.move_spans(moved_place, location).or_else(|| self.borrow_spans(span, location));87        let span = use_spans.args_or_use();8889        let (move_site_vec, maybe_reinitialized_locations) = self.get_moved_indexes(location, mpi);90        debug!(91            "report_use_of_moved_or_uninitialized: move_site_vec={:?} use_spans={:?}",92            move_site_vec, use_spans93        );94        let move_out_indices: Vec<_> =95            move_site_vec.iter().map(|move_site| move_site.moi).collect();9697        if move_out_indices.is_empty() {98            let root_local = used_place.local;99100            if !self.uninitialized_error_reported.insert(root_local) {101                debug!(102                    "report_use_of_moved_or_uninitialized place: error about {:?} suppressed",103                    root_local104                );105                return;106            }107108            let err = self.report_use_of_uninitialized(109                mpi,110                used_place,111                moved_place,112                desired_action,113                span,114                use_spans,115            );116            self.buffer_error(err);117        } else {118            if let Some((reported_place, _)) = self.has_move_error(&move_out_indices) {119                if used_place.is_prefix_of(*reported_place) {120                    debug!(121                        "report_use_of_moved_or_uninitialized place: error suppressed mois={:?}",122                        move_out_indices123                    );124                    return;125                }126            }127128            let is_partial_move = move_site_vec.iter().any(|move_site| {129                let move_out = self.move_data.moves[(*move_site).moi];130                let moved_place = &self.move_data.move_paths[move_out.path].place;131                // `*(_1)` where `_1` is a `Box` is actually a move out.132                let is_box_move = moved_place.as_ref().projection == [ProjectionElem::Deref]133                    && self.body.local_decls[moved_place.local].ty.is_box();134135                !is_box_move136                    && used_place != moved_place.as_ref()137                    && used_place.is_prefix_of(moved_place.as_ref())138            });139140            let partial_str = if is_partial_move { "partial " } else { "" };141            let partially_str = if is_partial_move { "partially " } else { "" };142143            let (on_move_message, on_move_label, on_move_notes) = if let ty::Adt(item_def, args) =144                self.body.local_decls[moved_place.local].ty.kind()145                && let Some(Some(directive)) = find_attr!(self.infcx.tcx, item_def.did(), OnMove { directive, .. }  => directive)146            {147                let this = self.infcx.tcx.item_name(item_def.did()).to_string();148                let mut generic_args: Vec<_> = self149                    .infcx150                    .tcx151                    .generics_of(item_def.did())152                    .own_params153                    .iter()154                    .filter_map(|param| Some((param.name, args[param.index as usize].to_string())))155                    .collect();156                generic_args.push((kw::SelfUpper, this.clone()));157158                let args = FormatArgs { this, generic_args, .. };159                let CustomDiagnostic { message, label, notes, parent_label: _ } =160                    directive.eval(None, &args);161162                (message, label, notes)163            } else {164                (None, None, Vec::new())165            };166167            let mut err = self.cannot_act_on_moved_value(168                span,169                desired_action.as_noun(),170                partially_str,171                self.describe_place_with_options(172                    moved_place,173                    DescribePlaceOpt { including_downcast: true, including_tuple_field: true },174                ),175                on_move_message,176            );177178            for note in on_move_notes {179                err.note(note);180            }181182            let reinit_spans = maybe_reinitialized_locations183                .iter()184                .take(3)185                .map(|loc| {186                    self.move_spans(self.move_data.move_paths[mpi].place.as_ref(), *loc)187                        .args_or_use()188                })189                .collect::<Vec<Span>>();190191            let reinits = maybe_reinitialized_locations.len();192            if reinits == 1 {193                err.span_label(reinit_spans[0], "this reinitialization might get skipped");194            } else if reinits > 1 {195                err.span_note(196                    MultiSpan::from_spans(reinit_spans),197                    if reinits <= 3 {198                        format!("these {reinits} reinitializations might get skipped")199                    } else {200                        format!(201                            "these 3 reinitializations and {} other{} might get skipped",202                            reinits - 3,203                            if reinits == 4 { "" } else { "s" }204                        )205                    },206                );207            }208209            let closure = self.add_moved_or_invoked_closure_note(location, used_place, &mut err);210211            let mut is_loop_move = false;212            let mut seen_spans = FxIndexSet::default();213214            for move_site in &move_site_vec {215                let move_out = self.move_data.moves[(*move_site).moi];216                let moved_place = &self.move_data.move_paths[move_out.path].place;217218                let move_spans = self.move_spans(moved_place.as_ref(), move_out.source);219                let move_span = move_spans.args_or_use();220221                let is_move_msg = move_spans.for_closure();222223                let is_loop_message = location == move_out.source || move_site.traversed_back_edge;224225                if location == move_out.source {226                    is_loop_move = true;227                }228229                let mut has_suggest_reborrow = false;230                if !seen_spans.contains(&move_span) {231                    self.suggest_ref_or_clone(232                        mpi,233                        &mut err,234                        move_spans,235                        moved_place.as_ref(),236                        &mut has_suggest_reborrow,237                        closure,238                    );239240                    let msg_opt = CapturedMessageOpt {241                        is_partial_move,242                        is_loop_message,243                        is_move_msg,244                        is_loop_move,245                        has_suggest_reborrow,246                        maybe_reinitialized_locations_is_empty: maybe_reinitialized_locations247                            .is_empty(),248                    };249                    self.explain_captures(250                        &mut err,251                        span,252                        move_span,253                        move_spans,254                        *moved_place,255                        msg_opt,256                    );257                }258                seen_spans.insert(move_span);259            }260261            use_spans.var_path_only_subdiag(&mut err, desired_action);262263            if !is_loop_move {264                err.span_label(265                    span,266                    format!(267                        "value {} here after {partial_str}move",268                        desired_action.as_verb_in_past_tense(),269                    ),270                );271            }272273            let ty = used_place.ty(self.body, self.infcx.tcx).ty;274            let needs_note = match ty.kind() {275                ty::Closure(id, _) => {276                    self.infcx.tcx.closure_kind_origin(id.expect_local()).is_none()277                }278                _ => true,279            };280281            let mpi = self.move_data.moves[move_out_indices[0]].path;282            let place = &self.move_data.move_paths[mpi].place;283            let ty = place.ty(self.body, self.infcx.tcx).ty;284285            if self.infcx.param_env.caller_bounds().iter().any(|c| {286                c.as_trait_clause().is_some_and(|pred| {287                    pred.skip_binder().self_ty() == ty && self.infcx.tcx.is_fn_trait(pred.def_id())288                })289            }) {290                // Suppress the next suggestion since we don't want to put more bounds onto291                // something that already has `Fn`-like bounds (or is a closure), so we can't292                // restrict anyways.293            } else {294                let copy_did = self.infcx.tcx.require_lang_item(LangItem::Copy, span);295                self.suggest_adding_bounds(&mut err, ty, copy_did, span);296            }297298            let opt_name = self.describe_place_with_options(299                place.as_ref(),300                DescribePlaceOpt { including_downcast: true, including_tuple_field: true },301            );302            let note_msg = match opt_name {303                Some(name) => format!("`{name}`"),304                None => "value".to_owned(),305            };306            if needs_note {307                if let Some(local) = place.as_local() {308                    let span = self.body.local_decls[local].source_info.span;309                    if let Some(on_move_label) = on_move_label {310                        err.span_label(span, on_move_label);311                    } else {312                        err.subdiagnostic(crate::session_diagnostics::TypeNoCopy::Label {313                            is_partial_move,314                            ty,315                            place: &note_msg,316                            span,317                        });318                    }319                } else {320                    err.subdiagnostic(crate::session_diagnostics::TypeNoCopy::Note {321                        is_partial_move,322                        ty,323                        place: &note_msg,324                    });325                };326            }327328            if let UseSpans::FnSelfUse {329                kind: CallKind::DerefCoercion { deref_target_span, deref_target_ty, .. },330                ..331            } = use_spans332            {333                err.note(format!(334                    "{} occurs due to deref coercion to `{deref_target_ty}`",335                    desired_action.as_noun(),336                ));337338                // Check first whether the source is accessible (issue #87060)339                if let Some(deref_target_span) = deref_target_span340                    && self.infcx.tcx.sess.source_map().is_span_accessible(deref_target_span)341                {342                    err.span_note(deref_target_span, "deref defined here");343                }344            }345346            self.buffer_move_error(move_out_indices, (used_place, err));347        }348    }349350    fn suggest_ref_or_clone(351        &self,352        mpi: MovePathIndex,353        err: &mut Diag<'infcx>,354        move_spans: UseSpans<'tcx>,355        moved_place: PlaceRef<'tcx>,356        has_suggest_reborrow: &mut bool,357        moved_or_invoked_closure: bool,358    ) {359        let move_span = match move_spans {360            UseSpans::ClosureUse { capture_kind_span, .. } => capture_kind_span,361            _ => move_spans.args_or_use(),362        };363        struct ExpressionFinder<'hir> {364            expr_span: Span,365            expr: Option<&'hir hir::Expr<'hir>>,366            pat: Option<&'hir hir::Pat<'hir>>,367            parent_pat: Option<&'hir hir::Pat<'hir>>,368            tcx: TyCtxt<'hir>,369        }370        impl<'hir> Visitor<'hir> for ExpressionFinder<'hir> {371            type NestedFilter = OnlyBodies;372373            fn maybe_tcx(&mut self) -> Self::MaybeTyCtxt {374                self.tcx375            }376377            fn visit_expr(&mut self, e: &'hir hir::Expr<'hir>) {378                if e.span == self.expr_span {379                    self.expr = Some(e);380                }381                hir::intravisit::walk_expr(self, e);382            }383            fn visit_pat(&mut self, p: &'hir hir::Pat<'hir>) {384                if p.span == self.expr_span {385                    self.pat = Some(p);386                }387                if let hir::PatKind::Binding(hir::BindingMode::NONE, _, i, sub) = p.kind {388                    if i.span == self.expr_span || p.span == self.expr_span {389                        self.pat = Some(p);390                    }391                    // Check if we are in a situation of `ident @ ident` where we want to suggest392                    // `ref ident @ ref ident` or `ref ident @ Struct { ref ident }`.393                    if let Some(subpat) = sub394                        && self.pat.is_none()395                    {396                        self.visit_pat(subpat);397                        if self.pat.is_some() {398                            self.parent_pat = Some(p);399                        }400                        return;401                    }402                }403                hir::intravisit::walk_pat(self, p);404            }405        }406        let tcx = self.infcx.tcx;407        if let Some(body) = tcx.hir_maybe_body_owned_by(self.mir_def_id()) {408            let expr = body.value;409            let place = &self.move_data.move_paths[mpi].place;410            let span = place.as_local().map(|local| self.body.local_decls[local].source_info.span);411            let mut finder = ExpressionFinder {412                expr_span: move_span,413                expr: None,414                pat: None,415                parent_pat: None,416                tcx,417            };418            finder.visit_expr(expr);419            if let Some(span) = span420                && let Some(expr) = finder.expr421            {422                for (_, expr) in tcx.hir_parent_iter(expr.hir_id) {423                    if let hir::Node::Expr(expr) = expr {424                        if expr.span.contains(span) {425                            // If the let binding occurs within the same loop, then that426                            // loop isn't relevant, like in the following, the outermost `loop`427                            // doesn't play into `x` being moved.428                            // ```429                            // loop {430                            //     let x = String::new();431                            //     loop {432                            //         foo(x);433                            //     }434                            // }435                            // ```436                            break;437                        }438                        if let hir::ExprKind::Loop(.., loop_span) = expr.kind {439                            err.span_label(loop_span, "inside of this loop");440                        }441                    }442                }443                let typeck = self.infcx.tcx.typeck(self.mir_def_id());444                let parent = self.infcx.tcx.parent_hir_node(expr.hir_id);445                let (def_id, args, offset) = if let hir::Node::Expr(parent_expr) = parent446                    && let hir::ExprKind::MethodCall(_, _, args, _) = parent_expr.kind447                {448                    let def_id = typeck.type_dependent_def_id(parent_expr.hir_id);449                    (def_id, args, 1)450                } else if let hir::Node::Expr(parent_expr) = parent451                    && let hir::ExprKind::Call(call, args) = parent_expr.kind452                    && let ty::FnDef(def_id, _) = typeck.node_type(call.hir_id).kind()453                {454                    (Some(*def_id), args, 0)455                } else {456                    (None, &[][..], 0)457                };458                let ty = place.ty(self.body, self.infcx.tcx).ty;459460                let mut can_suggest_clone = true;461                if let Some(def_id) = def_id462                    && let Some(pos) = args.iter().position(|arg| arg.hir_id == expr.hir_id)463                {464                    // The move occurred as one of the arguments to a function call. Is that465                    // argument generic? `def_id` can't be a closure here, so using `fn_sig` is fine466                    let arg_param = if self.infcx.tcx.def_kind(def_id).is_fn_like()467                        && let sig =468                            self.infcx.tcx.fn_sig(def_id).instantiate_identity().skip_binder()469                        && let Some(arg_ty) = sig.inputs().get(pos + offset)470                        && let ty::Param(arg_param) = arg_ty.kind()471                    {472                        Some(arg_param)473                    } else {474                        None475                    };476477                    // If the moved value is a mut reference, it is used in a478                    // generic function and it's type is a generic param, it can be479                    // reborrowed to avoid moving.480                    // for example:481                    // struct Y(u32);482                    // x's type is '& mut Y' and it is used in `fn generic<T>(x: T) {}`.483                    if let ty::Ref(_, _, hir::Mutability::Mut) = ty.kind()484                        && arg_param.is_some()485                    {486                        *has_suggest_reborrow = true;487                        self.suggest_reborrow(err, expr.span, moved_place);488                        return;489                    }490491                    // If the moved place is used generically by the callee and a reference to it492                    // would still satisfy any bounds on its type, suggest borrowing.493                    if let Some(&param) = arg_param494                        && let hir::Node::Expr(call_expr) = parent495                        && let Some(ref_mutability) = self.suggest_borrow_generic_arg(496                            err,497                            typeck,498                            call_expr,499                            def_id,500                            param,501                            moved_place,502                            pos + offset,503                            ty,504                            expr.span,505                        )506                    {507                        can_suggest_clone = ref_mutability.is_mut();508                    } else if let Some(local_def_id) = def_id.as_local()509                        && let node = self.infcx.tcx.hir_node_by_def_id(local_def_id)510                        && let Some(fn_decl) = node.fn_decl()511                        && let Some(ident) = node.ident()512                        && let Some(arg) = fn_decl.inputs.get(pos + offset)513                    {514                        // If we can't suggest borrowing in the call, but the function definition515                        // is local, instead offer changing the function to borrow that argument.516                        let mut span: MultiSpan = arg.span.into();517                        span.push_span_label(518                            arg.span,519                            "this parameter takes ownership of the value".to_string(),520                        );521                        let descr = match node.fn_kind() {522                            Some(hir::intravisit::FnKind::ItemFn(..)) | None => "function",523                            Some(hir::intravisit::FnKind::Method(..)) => "method",524                            Some(hir::intravisit::FnKind::Closure) => "closure",525                        };526                        span.push_span_label(ident.span, format!("in this {descr}"));527                        err.span_note(528                            span,529                            format!(530                                "consider changing this parameter type in {descr} `{ident}` to \531                                 borrow instead if owning the value isn't necessary",532                            ),533                        );534                    }535                }536                if let hir::Node::Expr(parent_expr) = parent537                    && let hir::ExprKind::Call(call_expr, _) = parent_expr.kind538                    && let hir::ExprKind::Path(qpath) = call_expr.kind539                    && tcx.qpath_is_lang_item(qpath, LangItem::IntoIterIntoIter)540                {541                    // Do not suggest `.clone()` in a `for` loop, we already suggest borrowing.542                } else if let UseSpans::FnSelfUse { kind: CallKind::Normal { .. }, .. } = move_spans543                {544                    // We already suggest cloning for these cases in `explain_captures`.545                } else if moved_or_invoked_closure {546                    // Do not suggest `closure.clone()()`.547                } else if let UseSpans::ClosureUse {548                    closure_kind:549                        ClosureKind::Coroutine(CoroutineKind::Desugared(_, CoroutineSource::Block)),550                    ..551                } = move_spans552                    && can_suggest_clone553                {554                    self.suggest_cloning(err, place.as_ref(), ty, expr, Some(move_spans));555                } else if self.suggest_hoisting_call_outside_loop(err, expr) && can_suggest_clone {556                    // The place where the type moves would be misleading to suggest clone.557                    // #121466558                    self.suggest_cloning(err, place.as_ref(), ty, expr, Some(move_spans));559                }560            }561562            self.suggest_ref_for_dbg_args(expr, place, move_span, err);563564            // it's useless to suggest inserting `ref` when the span don't comes from local code565            if let Some(pat) = finder.pat566                && !move_span.is_dummy()567                && !self.infcx.tcx.sess.source_map().is_imported(move_span)568            {569                let mut sugg = vec![(pat.span.shrink_to_lo(), "ref ".to_string())];570                if let Some(pat) = finder.parent_pat {571                    sugg.insert(0, (pat.span.shrink_to_lo(), "ref ".to_string()));572                }573                err.multipart_suggestion(574                    "borrow this binding in the pattern to avoid moving the value",575                    sugg,576                    Applicability::MachineApplicable,577                );578            }579        }580    }581582    // for dbg!(x) which may take ownership, suggest dbg!(&x) instead583    fn suggest_ref_for_dbg_args(584        &self,585        body: &hir::Expr<'_>,586        place: &Place<'tcx>,587        move_span: Span,588        err: &mut Diag<'infcx>,589    ) {590        let var_info = self.body.var_debug_info.iter().find(|info| match info.value {591            VarDebugInfoContents::Place(ref p) => p == place,592            _ => false,593        });594        let Some(var_info) = var_info else { return };595        let arg_name = var_info.name;596        struct MatchArgFinder<'tcx> {597            tcx: TyCtxt<'tcx>,598            move_span: Span,599            arg_name: Symbol,600            match_arg_span: Option<Span> = None,601        }602        impl Visitor<'_> for MatchArgFinder<'_> {603            fn visit_expr(&mut self, e: &hir::Expr<'_>) {604                // dbg! is expanded into a match pattern, we need to find the right argument span605                if let hir::ExprKind::Match(scrutinee, ..) = &e.kind606                    && let hir::ExprKind::Tup(args) = scrutinee.kind607                    && e.span.macro_backtrace().any(|expn| {608                        expn.macro_def_id.is_some_and(|macro_def_id| {609                            self.tcx.is_diagnostic_item(sym::dbg_macro, macro_def_id)610                        })611                    })612                {613                    for arg in args {614                        if let hir::ExprKind::Path(hir::QPath::Resolved(615                            _,616                            path @ Path { segments: [seg], .. },617                        )) = &arg.kind618                            && seg.ident.name == self.arg_name619                            && self.move_span.source_equal(arg.span)620                        {621                            self.match_arg_span = Some(path.span);622                            return;623                        }624                    }625                }626                hir::intravisit::walk_expr(self, e);627            }628        }629630        let mut finder = MatchArgFinder { tcx: self.infcx.tcx, move_span, arg_name, .. };631        finder.visit_expr(body);632        if let Some(macro_arg_span) = finder.match_arg_span {633            err.span_suggestion_verbose(634                macro_arg_span.shrink_to_lo(),635                "consider borrowing instead of transferring ownership",636                "&",637                Applicability::MachineApplicable,638            );639        }640    }641642    pub(crate) fn suggest_reborrow(643        &self,644        err: &mut Diag<'infcx>,645        span: Span,646        moved_place: PlaceRef<'tcx>,647    ) {648        err.span_suggestion_verbose(649            span.shrink_to_lo(),650            format!(651                "consider creating a fresh reborrow of {} here",652                self.describe_place(moved_place)653                    .map(|n| format!("`{n}`"))654                    .unwrap_or_else(|| "the mutable reference".to_string()),655            ),656            "&mut *",657            Applicability::MachineApplicable,658        );659    }660661    /// If a place is used after being moved as an argument to a function, the function is generic662    /// in that argument, and a reference to the argument's type would still satisfy the function's663    /// bounds, suggest borrowing. This covers, e.g., borrowing an `impl Fn()` argument being passed664    /// in an `impl FnOnce()` position.665    /// Returns `Some(mutability)` when suggesting to borrow with mutability `mutability`, or `None`666    /// if no suggestion is made.667    fn suggest_borrow_generic_arg(668        &self,669        err: &mut Diag<'_>,670        typeck: &ty::TypeckResults<'tcx>,671        call_expr: &hir::Expr<'tcx>,672        callee_did: DefId,673        param: ty::ParamTy,674        moved_place: PlaceRef<'tcx>,675        moved_arg_pos: usize,676        moved_arg_ty: Ty<'tcx>,677        place_span: Span,678    ) -> Option<ty::Mutability> {679        let tcx = self.infcx.tcx;680        let sig = tcx.fn_sig(callee_did).instantiate_identity().skip_binder();681        let clauses = tcx.predicates_of(callee_did);682683        let generic_args = match call_expr.kind {684            // For method calls, generic arguments are attached to the call node.685            hir::ExprKind::MethodCall(..) => typeck.node_args_opt(call_expr.hir_id)?,686            // For normal calls, generic arguments are in the callee's type.687            // This diagnostic is only run for `FnDef` callees.688            hir::ExprKind::Call(callee, _)689                if let &ty::FnDef(_, args) = typeck.node_type(callee.hir_id).kind() =>690            {691                args692            }693            _ => return None,694        };695696        // First, is there at least one method on one of `param`'s trait bounds?697        // This keeps us from suggesting borrowing the argument to `mem::drop`, e.g.698        if !clauses.instantiate_identity(tcx).predicates.iter().any(|clause| {699            clause.as_trait_clause().is_some_and(|tc| {700                tc.self_ty().skip_binder().is_param(param.index)701                    && tc.polarity() == ty::PredicatePolarity::Positive702                    && supertrait_def_ids(tcx, tc.def_id())703                        .flat_map(|trait_did| tcx.associated_items(trait_did).in_definition_order())704                        .any(|item| item.is_method())705            })706        }) {707            return None;708        }709710        // Try borrowing a shared reference first, then mutably.711        if let Some(mutbl) = [ty::Mutability::Not, ty::Mutability::Mut].into_iter().find(|&mutbl| {712            let re = self.infcx.tcx.lifetimes.re_erased;713            let ref_ty = Ty::new_ref(self.infcx.tcx, re, moved_arg_ty, mutbl);714715            // Ensure that substituting `ref_ty` in the callee's signature doesn't break716            // other inputs or the return type.717            let new_args = tcx.mk_args_from_iter(generic_args.iter().enumerate().map(718                |(i, arg)| {719                    if i == param.index as usize { ref_ty.into() } else { arg }720                },721            ));722            let can_subst = |ty: Ty<'tcx>| {723                // Normalize before comparing to see through type aliases and projections.724                let old_ty = ty::EarlyBinder::bind(ty).instantiate(tcx, generic_args);725                let new_ty = ty::EarlyBinder::bind(ty).instantiate(tcx, new_args);726                if let Ok(old_ty) = tcx.try_normalize_erasing_regions(727                    self.infcx.typing_env(self.infcx.param_env),728                    old_ty,729                ) && let Ok(new_ty) = tcx.try_normalize_erasing_regions(730                    self.infcx.typing_env(self.infcx.param_env),731                    new_ty,732                ) {733                    old_ty == new_ty734                } else {735                    false736                }737            };738            if !can_subst(sig.output())739                || sig740                    .inputs()741                    .iter()742                    .enumerate()743                    .any(|(i, &input_ty)| i != moved_arg_pos && !can_subst(input_ty))744            {745                return false;746            }747748            // Test the callee's predicates, substituting in `ref_ty` for the moved argument type.749            clauses.instantiate(tcx, new_args).predicates.iter().all(|clause| {750                // Normalize before testing to see through type aliases and projections.751                let normalized = tcx752                    .try_normalize_erasing_regions(753                        self.infcx.typing_env(self.infcx.param_env),754                        *clause,755                    )756                    .unwrap_or_else(|_| clause.skip_norm_wip());757                self.infcx.predicate_must_hold_modulo_regions(&Obligation::new(758                    tcx,759                    ObligationCause::dummy(),760                    self.infcx.param_env,761                    normalized,762                ))763            })764        }) {765            let place_desc = if let Some(desc) = self.describe_place(moved_place) {766                format!("`{desc}`")767            } else {768                "here".to_owned()769            };770            err.span_suggestion_verbose(771                place_span.shrink_to_lo(),772                format!("consider {}borrowing {place_desc}", mutbl.mutably_str()),773                mutbl.ref_prefix_str(),774                Applicability::MaybeIncorrect,775            );776            Some(mutbl)777        } else {778            None779        }780    }781782    fn report_use_of_uninitialized(783        &self,784        mpi: MovePathIndex,785        used_place: PlaceRef<'tcx>,786        moved_place: PlaceRef<'tcx>,787        desired_action: InitializationRequiringAction,788        span: Span,789        use_spans: UseSpans<'tcx>,790    ) -> Diag<'infcx> {791        // We need all statements in the body where the binding was assigned to later find all792        // the branching code paths where the binding *wasn't* assigned to.793        let inits = &self.move_data.init_path_map[mpi];794        let move_path = &self.move_data.move_paths[mpi];795        let decl_span = self.body.local_decls[move_path.place.local].source_info.span;796        let mut spans_set = FxIndexSet::default();797        for init_idx in inits {798            let init = &self.move_data.inits[*init_idx];799            let span = init.span(self.body);800            if !span.is_dummy() {801                spans_set.insert(span);802            }803        }804        let spans: Vec<_> = spans_set.into_iter().collect();805806        let (name, desc) = match self.describe_place_with_options(807            moved_place,808            DescribePlaceOpt { including_downcast: true, including_tuple_field: true },809        ) {810            Some(name) => (format!("`{name}`"), format!("`{name}` ")),811            None => ("the variable".to_string(), String::new()),812        };813        let path = match self.describe_place_with_options(814            used_place,815            DescribePlaceOpt { including_downcast: true, including_tuple_field: true },816        ) {817            Some(name) => format!("`{name}`"),818            None => "value".to_string(),819        };820821        // We use the statements were the binding was initialized, and inspect the HIR to look822        // for the branching codepaths that aren't covered, to point at them.823        let tcx = self.infcx.tcx;824        let body = tcx.hir_body_owned_by(self.mir_def_id());825        let mut visitor = ConditionVisitor { tcx, spans, name, errors: vec![] };826        visitor.visit_body(&body);827        let spans = visitor.spans;828829        let mut show_assign_sugg = false;830        let isnt_initialized = if let InitializationRequiringAction::PartialAssignment831        | InitializationRequiringAction::Assignment = desired_action832        {833            // The same error is emitted for bindings that are *sometimes* initialized and the ones834            // that are *partially* initialized by assigning to a field of an uninitialized835            // binding. We differentiate between them for more accurate wording here.836            "isn't fully initialized"837        } else if !spans.iter().any(|i| {838            // We filter these to avoid misleading wording in cases like the following,839            // where `x` has an `init`, but it is in the same place we're looking at:840            // ```841            // let x;842            // x += 1;843            // ```844            !i.contains(span)845            // We filter these to avoid incorrect main message on `match-cfg-fake-edges.rs`846            && !visitor847                .errors848                .iter()849                .map(|(sp, _)| *sp)850                .any(|sp| span < sp && !sp.contains(span))851        }) {852            show_assign_sugg = true;853            "isn't initialized"854        } else {855            "is possibly-uninitialized"856        };857858        let used = desired_action.as_general_verb_in_past_tense();859        let mut err = struct_span_code_err!(860            self.dcx(),861            span,862            E0381,863            "{used} binding {desc}{isnt_initialized}"864        );865        use_spans.var_path_only_subdiag(&mut err, desired_action);866867        if let InitializationRequiringAction::PartialAssignment868        | InitializationRequiringAction::Assignment = desired_action869        {870            err.help(871                "partial initialization isn't supported, fully initialize the binding with a \872                 default value and mutate it, or use `std::mem::MaybeUninit`",873            );874        }875        err.span_label(span, format!("{path} {used} here but it {isnt_initialized}"));876877        let mut shown = false;878        for (sp, label) in visitor.errors {879            if sp < span && !sp.overlaps(span) {880                // When we have a case like `match-cfg-fake-edges.rs`, we don't want to mention881                // match arms coming after the primary span because they aren't relevant:882                // ```883                // let x;884                // match y {885                //     _ if { x = 2; true } => {}886                //     _ if {887                //         x; //~ ERROR888                //         false889                //     } => {}890                //     _ => {} // We don't want to point to this.891                // };892                // ```893                err.span_label(sp, label);894                shown = true;895            }896        }897        if !shown {898            for sp in &spans {899                if *sp < span && !sp.overlaps(span) {900                    err.span_label(*sp, "binding initialized here in some conditions");901                }902            }903        }904905        err.span_label(decl_span, "binding declared here but left uninitialized");906        if show_assign_sugg {907            struct LetVisitor {908                decl_span: Span,909                sugg: Option<(Span, bool)>,910            }911912            impl<'v> Visitor<'v> for LetVisitor {913                fn visit_stmt(&mut self, ex: &'v hir::Stmt<'v>) {914                    if self.sugg.is_some() {915                        return;916                    }917918                    // FIXME: We make sure that this is a normal top-level binding,919                    // but we could suggest `todo!()` for all uninitialized bindings in the pattern920                    if let hir::StmtKind::Let(hir::LetStmt { span, ty, init: None, pat, .. }) =921                        &ex.kind922                        && let hir::PatKind::Binding(binding_mode, ..) = pat.kind923                        && span.contains(self.decl_span)924                    {925                        // Insert after the whole binding pattern so suggestions stay valid for926                        // bindings with `@` subpatterns like `ref mut x @ v`.927                        let strip_ref = matches!(binding_mode.0, hir::ByRef::Yes(..));928                        self.sugg =929                            ty.map_or(Some((pat.span, strip_ref)), |ty| Some((ty.span, strip_ref)));930                    }931                    hir::intravisit::walk_stmt(self, ex);932                }933            }934935            let mut visitor = LetVisitor { decl_span, sugg: None };936            visitor.visit_body(&body);937            if let Some((span, strip_ref)) = visitor.sugg {938                self.suggest_assign_value(&mut err, moved_place, span, strip_ref);939            }940        }941        err942    }943944    fn suggest_assign_value(945        &self,946        err: &mut Diag<'_>,947        moved_place: PlaceRef<'tcx>,948        sugg_span: Span,949        strip_ref: bool,950    ) {951        let mut ty = moved_place.ty(self.body, self.infcx.tcx).ty;952        if strip_ref && let ty::Ref(_, inner, _) = ty.kind() {953            ty = *inner;954        }955        debug!("ty: {:?}, kind: {:?}", ty, ty.kind());956957        let Some(assign_value) = self.infcx.err_ctxt().ty_kind_suggestion(self.infcx.param_env, ty)958        else {959            return;960        };961962        err.span_suggestion_verbose(963            sugg_span.shrink_to_hi(),964            "consider assigning a value",965            format!(" = {assign_value}"),966            Applicability::MaybeIncorrect,967        );968    }969970    /// In a move error that occurs on a call within a loop, we try to identify cases where cloning971    /// the value would lead to a logic error. We infer these cases by seeing if the moved value is972    /// part of the logic to break the loop, either through an explicit `break` or if the expression973    /// is part of a `while let`.974    fn suggest_hoisting_call_outside_loop(&self, err: &mut Diag<'_>, expr: &hir::Expr<'_>) -> bool {975        let tcx = self.infcx.tcx;976        let mut can_suggest_clone = true;977978        // If the moved value is a locally declared binding, we'll look upwards on the expression979        // tree until the scope where it is defined, and no further, as suggesting to move the980        // expression beyond that point would be illogical.981        let local_hir_id = if let hir::ExprKind::Path(hir::QPath::Resolved(982            _,983            hir::Path { res: hir::def::Res::Local(local_hir_id), .. },984        )) = expr.kind985        {986            Some(local_hir_id)987        } else {988            // This case would be if the moved value comes from an argument binding, we'll just989            // look within the entire item, that's fine.990            None991        };992993        /// This will allow us to look for a specific `HirId`, in our case `local_hir_id` where the994        /// binding was declared, within any other expression. We'll use it to search for the995        /// binding declaration within every scope we inspect.996        struct Finder {997            hir_id: hir::HirId,998        }999        impl<'hir> Visitor<'hir> for Finder {1000            type Result = ControlFlow<()>;1001            fn visit_pat(&mut self, pat: &'hir hir::Pat<'hir>) -> Self::Result {1002                if pat.hir_id == self.hir_id {1003                    return ControlFlow::Break(());1004                }1005                hir::intravisit::walk_pat(self, pat)1006            }1007            fn visit_expr(&mut self, ex: &'hir hir::Expr<'hir>) -> Self::Result {1008                if ex.hir_id == self.hir_id {1009                    return ControlFlow::Break(());1010                }1011                hir::intravisit::walk_expr(self, ex)1012            }1013        }1014        // The immediate HIR parent of the moved expression. We'll look for it to be a call.1015        let mut parent = None;1016        // The top-most loop where the moved expression could be moved to a new binding.1017        let mut outer_most_loop: Option<&hir::Expr<'_>> = None;1018        for (_, node) in tcx.hir_parent_iter(expr.hir_id) {1019            let e = match node {1020                hir::Node::Expr(e) => e,1021                hir::Node::LetStmt(hir::LetStmt { els: Some(els), .. }) => {1022                    let mut finder = BreakFinder { found_breaks: vec![], found_continues: vec![] };1023                    finder.visit_block(els);1024                    if !finder.found_breaks.is_empty() {1025                        // Don't suggest clone as it could be will likely end in an infinite1026                        // loop.1027                        // let Some(_) = foo(non_copy.clone()) else { break; }1028                        // ---                       ^^^^^^^^         -----1029                        can_suggest_clone = false;1030                    }1031                    continue;1032                }1033                _ => continue,1034            };1035            if let Some(&hir_id) = local_hir_id {1036                if (Finder { hir_id }).visit_expr(e).is_break() {1037                    // The current scope includes the declaration of the binding we're accessing, we1038                    // can't look up any further for loops.1039                    break;1040                }1041            }1042            if parent.is_none() {1043                parent = Some(e);1044            }1045            match e.kind {1046                hir::ExprKind::Let(_) => {1047                    match tcx.parent_hir_node(e.hir_id) {1048                        hir::Node::Expr(hir::Expr {1049                            kind: hir::ExprKind::If(cond, ..), ..1050                        }) => {1051                            if (Finder { hir_id: expr.hir_id }).visit_expr(cond).is_break() {1052                                // The expression where the move error happened is in a `while let`1053                                // condition Don't suggest clone as it will likely end in an1054                                // infinite loop.1055                                // while let Some(_) = foo(non_copy.clone()) { }1056                                // ---------                       ^^^^^^^^1057                                can_suggest_clone = false;1058                            }1059                        }1060                        _ => {}1061                    }1062                }1063                hir::ExprKind::Loop(..) => {1064                    outer_most_loop = Some(e);1065                }1066                _ => {}1067            }1068        }1069        let loop_count: usize = tcx1070            .hir_parent_iter(expr.hir_id)1071            .map(|(_, node)| match node {1072                hir::Node::Expr(hir::Expr { kind: hir::ExprKind::Loop(..), .. }) => 1,1073                _ => 0,1074            })1075            .sum();10761077        let sm = tcx.sess.source_map();1078        if let Some(in_loop) = outer_most_loop {1079            let mut finder = BreakFinder { found_breaks: vec![], found_continues: vec![] };1080            finder.visit_expr(in_loop);1081            // All of the spans for `break` and `continue` expressions.1082            let spans = finder1083                .found_breaks1084                .iter()1085                .chain(finder.found_continues.iter())1086                .map(|(_, span)| *span)1087                .filter(|span| {1088                    !matches!(1089                        span.desugaring_kind(),1090                        Some(DesugaringKind::ForLoop | DesugaringKind::WhileLoop)1091                    )1092                })1093                .collect::<Vec<Span>>();1094            // All of the spans for the loops above the expression with the move error.1095            let loop_spans: Vec<_> = tcx1096                .hir_parent_iter(expr.hir_id)1097                .filter_map(|(_, node)| match node {1098                    hir::Node::Expr(hir::Expr { span, kind: hir::ExprKind::Loop(..), .. }) => {1099                        Some(*span)1100                    }1101                    _ => None,1102                })1103                .collect();1104            // It is possible that a user written `break` or `continue` is in the wrong place. We1105            // point them out at the user for them to make a determination. (#92531)1106            if !spans.is_empty() && loop_count > 1 {1107                // Getting fancy: if the spans of the loops *do not* overlap, we only use the line1108                // number when referring to them. If there *are* overlaps (multiple loops on the1109                // same line) then we use the more verbose span output (`file.rs:col:ll`).1110                let mut lines: Vec<_> =1111                    loop_spans.iter().map(|sp| sm.lookup_char_pos(sp.lo()).line).collect();1112                lines.sort();1113                lines.dedup();1114                let fmt_span = |span: Span| {1115                    if lines.len() == loop_spans.len() {1116                        format!("line {}", sm.lookup_char_pos(span.lo()).line)1117                    } else {1118                        sm.span_to_diagnostic_string(span)1119                    }1120                };1121                let mut spans: MultiSpan = spans.into();1122                // Point at all the `continue`s and explicit `break`s in the relevant loops.1123                for (desc, elements) in [1124                    ("`break` exits", &finder.found_breaks),1125                    ("`continue` advances", &finder.found_continues),1126                ] {1127                    for (destination, sp) in elements {1128                        if let Ok(hir_id) = destination.target_id1129                            && let hir::Node::Expr(expr) = tcx.hir_node(hir_id)1130                            && !matches!(1131                                sp.desugaring_kind(),1132                                Some(DesugaringKind::ForLoop | DesugaringKind::WhileLoop)1133                            )1134                        {1135                            spans.push_span_label(1136                                *sp,1137                                format!("this {desc} the loop at {}", fmt_span(expr.span)),1138                            );1139                        }1140                    }1141                }1142                // Point at all the loops that are between this move and the parent item.1143                for span in loop_spans {1144                    spans.push_span_label(sm.guess_head_span(span), "");1145                }11461147                // note: verify that your loop breaking logic is correct1148                //   --> $DIR/nested-loop-moved-value-wrong-continue.rs:41:171149                //    |1150                // 28 |     for foo in foos {1151                //    |     ---------------1152                // ...1153                // 33 |         for bar in &bars {1154                //    |         ----------------1155                // ...1156                // 41 |                 continue;1157                //    |                 ^^^^^^^^ this `continue` advances the loop at line 331158                err.span_note(spans, "verify that your loop breaking logic is correct");1159            }1160            if let Some(parent) = parent1161                && let hir::ExprKind::MethodCall(..) | hir::ExprKind::Call(..) = parent.kind1162            {1163                // FIXME: We could check that the call's *parent* takes `&mut val` to make the1164                // suggestion more targeted to the `mk_iter(val).next()` case. Maybe do that only to1165                // check for whether to suggest `let value` or `let mut value`.11661167                let span = in_loop.span;1168                if !finder.found_breaks.is_empty()1169                    && let Ok(value) = sm.span_to_snippet(parent.span)1170                {1171                    // We know with high certainty that this move would affect the early return of a1172                    // loop, so we suggest moving the expression with the move out of the loop.1173                    let indent = if let Some(indent) = sm.indentation_before(span) {1174                        format!("\n{indent}")1175                    } else {1176                        " ".to_string()1177                    };1178                    err.multipart_suggestion(1179                        "consider moving the expression out of the loop so it is only moved once",1180                        vec![1181                            (span.shrink_to_lo(), format!("let mut value = {value};{indent}")),1182                            (parent.span, "value".to_string()),1183                        ],1184                        Applicability::MaybeIncorrect,1185                    );1186                }1187            }1188        }1189        can_suggest_clone1190    }11911192    /// We have `S { foo: val, ..base }`, and we suggest instead writing1193    /// `S { foo: val, bar: base.bar.clone(), .. }` when valid.1194    fn suggest_cloning_on_functional_record_update(1195        &self,1196        err: &mut Diag<'_>,1197        ty: Ty<'tcx>,1198        expr: &hir::Expr<'_>,1199    ) {1200        let typeck_results = self.infcx.tcx.typeck(self.mir_def_id());1201        let hir::ExprKind::Struct(struct_qpath, fields, hir::StructTailExpr::Base(base)) =1202            expr.kind1203        else {1204            return;1205        };1206        let hir::QPath::Resolved(_, path) = struct_qpath else { return };1207        let hir::def::Res::Def(_, def_id) = path.res else { return };1208        let Some(expr_ty) = typeck_results.node_type_opt(expr.hir_id) else { return };1209        let ty::Adt(def, args) = expr_ty.kind() else { return };1210        let hir::ExprKind::Path(hir::QPath::Resolved(None, path)) = base.kind else { return };1211        let (hir::def::Res::Local(_)1212        | hir::def::Res::Def(1213            DefKind::Const { .. }1214            | DefKind::ConstParam1215            | DefKind::Static { .. }1216            | DefKind::AssocConst { .. },1217            _,1218        )) = path.res1219        else {1220            return;1221        };1222        let Ok(base_str) = self.infcx.tcx.sess.source_map().span_to_snippet(base.span) else {1223            return;1224        };12251226        // 1. look for the fields of type `ty`.1227        // 2. check if they are clone and add them to suggestion1228        // 3. check if there are any values left to `..` and remove it if not1229        // 4. emit suggestion to clone the field directly as `bar: base.bar.clone()`12301231        let mut final_field_count = fields.len();1232        let Some(variant) = def.variants().iter().find(|variant| variant.def_id == def_id) else {1233            // When we have an enum, look for the variant that corresponds to the variant the user1234            // wrote.1235            return;1236        };1237        let mut sugg = vec![];1238        for field in &variant.fields {1239            // In practice unless there are more than one field with the same type, we'll be1240            // suggesting a single field at a type, because we don't aggregate multiple borrow1241            // checker errors involving the functional record update syntax into a single one.1242            let field_ty = field.ty(self.infcx.tcx, args);1243            let ident = field.ident(self.infcx.tcx);1244            if field_ty == ty && fields.iter().all(|field| field.ident.name != ident.name) {1245                // Suggest adding field and cloning it.1246                sugg.push(format!("{ident}: {base_str}.{ident}.clone()"));1247                final_field_count += 1;1248            }1249        }1250        let (span, sugg) = match fields {1251            [.., last] => (1252                if final_field_count == variant.fields.len() {1253                    // We'll remove the `..base` as there aren't any fields left.1254                    last.span.shrink_to_hi().with_hi(base.span.hi())1255                } else {1256                    last.span.shrink_to_hi()1257                },1258                format!(", {}", sugg.join(", ")),1259            ),1260            // Account for no fields in suggestion span.1261            [] => (1262                expr.span.with_lo(struct_qpath.span().hi()),1263                if final_field_count == variant.fields.len() {1264                    // We'll remove the `..base` as there aren't any fields left.1265                    format!(" {{ {} }}", sugg.join(", "))1266                } else {1267                    format!(" {{ {}, ..{base_str} }}", sugg.join(", "))1268                },1269            ),1270        };1271        let prefix = if !self.implements_clone(ty) {1272            let msg = format!("`{ty}` doesn't implement `Copy` or `Clone`");1273            if let ty::Adt(def, _) = ty.kind() {1274                err.span_note(self.infcx.tcx.def_span(def.did()), msg);1275            } else {1276                err.note(msg);1277            }1278            format!("if `{ty}` implemented `Clone`, you could ")1279        } else {1280            String::new()1281        };1282        let msg = format!(1283            "{prefix}clone the value from the field instead of using the functional record update \1284             syntax",1285        );1286        err.span_suggestion_verbose(span, msg, sugg, Applicability::MachineApplicable);1287    }12881289    pub(crate) fn suggest_cloning(1290        &self,1291        err: &mut Diag<'_>,1292        place: PlaceRef<'tcx>,1293        ty: Ty<'tcx>,1294        expr: &'tcx hir::Expr<'tcx>,1295        use_spans: Option<UseSpans<'tcx>>,1296    ) {1297        if let hir::ExprKind::Struct(_, _, hir::StructTailExpr::Base(_)) = expr.kind {1298            // We have `S { foo: val, ..base }`. In `check_aggregate_rvalue` we have a single1299            // `Location` that covers both the `S { ... }` literal, all of its fields and the1300            // `base`. If the move happens because of `S { foo: val, bar: base.bar }` the `expr`1301            //  will already be correct. Instead, we see if we can suggest writing.1302            self.suggest_cloning_on_functional_record_update(err, ty, expr);1303            return;1304        }13051306        if self.implements_clone(ty) {1307            if self.in_move_closure(expr) {1308                if let Some(name) = self.describe_place(place) {1309                    self.suggest_clone_of_captured_var_in_move_closure(err, &name, use_spans);1310                }1311            } else {1312                self.suggest_cloning_inner(err, ty, expr);1313            }1314        } else if let ty::Adt(def, args) = ty.kind()1315            && let Some(local_did) = def.did().as_local()1316            && def.variants().iter().all(|variant| {1317                variant1318                    .fields1319                    .iter()1320                    .all(|field| self.implements_clone(field.ty(self.infcx.tcx, args)))1321            })1322        {1323            let ty_span = self.infcx.tcx.def_span(def.did());1324            let mut span: MultiSpan = ty_span.into();1325            let mut derive_clone = false;1326            self.infcx.tcx.for_each_relevant_impl(1327                self.infcx.tcx.lang_items().clone_trait().unwrap(),1328                ty,1329                |def_id| {1330                    if self.infcx.tcx.is_automatically_derived(def_id) {1331                        derive_clone = true;1332                        span.push_span_label(1333                            self.infcx.tcx.def_span(def_id),1334                            "derived `Clone` adds implicit bounds on type parameters",1335                        );1336                        if let Some(generics) = self.infcx.tcx.hir_get_generics(local_did) {1337                            for param in generics.params {1338                                if let hir::GenericParamKind::Type { .. } = param.kind {1339                                    span.push_span_label(1340                                        param.span,1341                                        format!(1342                                            "introduces an implicit `{}: Clone` bound",1343                                            param.name.ident()1344                                        ),1345                                    );1346                                }1347                            }1348                        }1349                    }1350                },1351            );1352            let msg = if !derive_clone {1353                span.push_span_label(1354                    ty_span,1355                    format!(1356                        "consider {}implementing `Clone` for this type",1357                        if derive_clone { "manually " } else { "" }1358                    ),1359                );1360                format!("if `{ty}` implemented `Clone`, you could clone the value")1361            } else {1362                format!("if all bounds were met, you could clone the value")1363            };1364            span.push_span_label(expr.span, "you could clone this value");1365            err.span_note(span, msg);1366            if derive_clone {1367                err.help("consider manually implementing `Clone` to avoid undesired bounds");1368            }1369        } else if let ty::Param(param) = ty.kind()1370            && let Some(_clone_trait_def) = self.infcx.tcx.lang_items().clone_trait()1371            && let generics = self.infcx.tcx.generics_of(self.mir_def_id())1372            && let generic_param = generics.type_param(*param, self.infcx.tcx)1373            && let param_span = self.infcx.tcx.def_span(generic_param.def_id)1374            && if let Some(UseSpans::FnSelfUse { kind, .. }) = use_spans1375                && let CallKind::FnCall { fn_trait_id, self_ty } = kind1376                && let ty::Param(_) = self_ty.kind()1377                && ty == self_ty1378                && self.infcx.tcx.fn_trait_kind_from_def_id(fn_trait_id).is_some()1379            {1380                // Do not suggest `F: FnOnce() + Clone`.1381                false1382            } else {1383                true1384            }1385        {1386            let mut span: MultiSpan = param_span.into();1387            span.push_span_label(1388                param_span,1389                "consider constraining this type parameter with `Clone`",1390            );1391            span.push_span_label(expr.span, "you could clone this value");1392            err.span_help(1393                span,1394                format!("if `{ty}` implemented `Clone`, you could clone the value"),1395            );1396        } else if let ty::Adt(_, _) = ty.kind()1397            && let Some(clone_trait) = self.infcx.tcx.lang_items().clone_trait()1398        {1399            // For cases like `Option<NonClone>`, where `Option<T>: Clone` if `T: Clone`, we point1400            // at the types that should be `Clone`.1401            let ocx = ObligationCtxt::new_with_diagnostics(self.infcx);1402            let cause = ObligationCause::misc(expr.span, self.mir_def_id());1403            ocx.register_bound(cause, self.infcx.param_env, ty, clone_trait);1404            let errors = ocx.evaluate_obligations_error_on_ambiguity();1405            if errors.iter().all(|error| {1406                match error.obligation.predicate.as_clause().and_then(|c| c.as_trait_clause()) {1407                    Some(clause) => match clause.self_ty().skip_binder().kind() {1408                        ty::Adt(def, _) => def.did().is_local() && clause.def_id() == clone_trait,1409                        _ => false,1410                    },1411                    None => false,1412                }1413            }) {1414                let mut type_spans = vec![];1415                let mut types = FxIndexSet::default();1416                for clause in errors1417                    .iter()1418                    .filter_map(|e| e.obligation.predicate.as_clause())1419                    .filter_map(|c| c.as_trait_clause())1420                {1421                    let ty::Adt(def, _) = clause.self_ty().skip_binder().kind() else { continue };1422                    type_spans.push(self.infcx.tcx.def_span(def.did()));1423                    types.insert(1424                        self.infcx1425                            .tcx1426                            .short_string(clause.self_ty().skip_binder(), &mut err.long_ty_path()),1427                    );1428                }1429                let mut span: MultiSpan = type_spans.clone().into();1430                for sp in type_spans {1431                    span.push_span_label(sp, "consider implementing `Clone` for this type");1432                }1433                span.push_span_label(expr.span, "you could clone this value");1434                let types: Vec<_> = types.into_iter().collect();1435                let msg = match &types[..] {1436                    [only] => format!("`{only}`"),1437                    [head @ .., last] => format!(1438                        "{} and `{last}`",1439                        head.iter().map(|t| format!("`{t}`")).collect::<Vec<_>>().join(", ")1440                    ),1441                    [] => unreachable!(),1442                };1443                err.span_note(1444                    span,1445                    format!("if {msg} implemented `Clone`, you could clone the value"),1446                );1447            }1448        }1449    }14501451    pub(crate) fn implements_clone(&self, ty: Ty<'tcx>) -> bool {1452        let Some(clone_trait_def) = self.infcx.tcx.lang_items().clone_trait() else { return false };1453        self.infcx1454            .type_implements_trait(clone_trait_def, [ty], self.infcx.param_env)1455            .must_apply_modulo_regions()1456    }14571458    /// Given an expression, check if it is a method call `foo.clone()`, where `foo` and1459    /// `foo.clone()` both have the same type, returning the span for `.clone()` if so.1460    pub(crate) fn clone_on_reference(&self, expr: &hir::Expr<'_>) -> Option<Span> {1461        let typeck_results = self.infcx.tcx.typeck(self.mir_def_id());1462        if let hir::ExprKind::MethodCall(segment, rcvr, args, span) = expr.kind1463            && let Some(expr_ty) = typeck_results.node_type_opt(expr.hir_id)1464            && let Some(rcvr_ty) = typeck_results.node_type_opt(rcvr.hir_id)1465            && rcvr_ty == expr_ty1466            && segment.ident.name == sym::clone1467            && args.is_empty()1468        {1469            Some(span)1470        } else {1471            None1472        }1473    }14741475    fn in_move_closure(&self, expr: &hir::Expr<'_>) -> bool {1476        for (_, node) in self.infcx.tcx.hir_parent_iter(expr.hir_id) {1477            if let hir::Node::Expr(hir::Expr { kind: hir::ExprKind::Closure(closure), .. }) = node1478                && let hir::CaptureBy::Value { .. } = closure.capture_clause1479            {1480                // `move || x.clone()` will not work. FIXME: suggest `let y = x.clone(); move || y`1481                return true;1482            }1483        }1484        false1485    }14861487    fn suggest_cloning_inner(1488        &self,1489        err: &mut Diag<'_>,1490        ty: Ty<'tcx>,1491        expr: &hir::Expr<'_>,1492    ) -> bool {1493        let tcx = self.infcx.tcx;14941495        // Don't suggest `.clone()` in a derive macro expansion.1496        if let ExpnKind::Macro(MacroKind::Derive, _) = self.body.span.ctxt().outer_expn_data().kind1497        {1498            return false;1499        }1500        if let Some(_) = self.clone_on_reference(expr) {1501            // Avoid redundant clone suggestion already suggested in `explain_captures`.1502            // See `tests/ui/moves/needs-clone-through-deref.rs`1503            return false;1504        }1505        // We don't want to suggest `.clone()` in a move closure, since the value has already been1506        // captured.1507        if self.in_move_closure(expr) {1508            return false;1509        }1510        // We also don't want to suggest cloning a closure itself, since the value has already been1511        // captured.1512        if let hir::ExprKind::Closure(_) = expr.kind {1513            return false;1514        }1515        // Try to find predicates on *generic params* that would allow copying `ty`1516        let mut suggestion =1517            if let Some(symbol) = tcx.hir_maybe_get_struct_pattern_shorthand_field(expr) {1518                format!(": {symbol}.clone()")1519            } else {1520                ".clone()".to_owned()1521            };1522        let mut sugg = Vec::with_capacity(2);1523        let mut inner_expr = expr;1524        let mut is_raw_ptr = false;1525        let typeck_result = self.infcx.tcx.typeck(self.mir_def_id());1526        // Remove uses of `&` and `*` when suggesting `.clone()`.1527        while let hir::ExprKind::AddrOf(.., inner) | hir::ExprKind::Unary(hir::UnOp::Deref, inner) =1528            &inner_expr.kind1529        {1530            if let hir::ExprKind::AddrOf(_, hir::Mutability::Mut, _) = inner_expr.kind {1531                // We assume that `&mut` refs are desired for their side-effects, so cloning the1532                // value wouldn't do what the user wanted.1533                return false;1534            }1535            inner_expr = inner;1536            if let Some(inner_type) = typeck_result.node_type_opt(inner.hir_id) {1537                if matches!(inner_type.kind(), ty::RawPtr(..)) {1538                    is_raw_ptr = true;1539                    break;1540                }1541            }1542        }1543        // Cloning the raw pointer doesn't make sense in some cases and would cause a type mismatch1544        // error. (see #126863)1545        if inner_expr.span.lo() != expr.span.lo() && !is_raw_ptr {1546            // Remove "(*" or "(&"1547            sugg.push((expr.span.with_hi(inner_expr.span.lo()), String::new()));1548        }1549        // Check whether `expr` is surrounded by parentheses or not.1550        let span = if inner_expr.span.hi() != expr.span.hi() {1551            // Account for `(*x)` to suggest `x.clone()`.1552            if is_raw_ptr {1553                expr.span.shrink_to_hi()1554            } else {1555                // Remove the close parenthesis ")"1556                expr.span.with_lo(inner_expr.span.hi())1557            }1558        } else {1559            if is_raw_ptr {1560                sugg.push((expr.span.shrink_to_lo(), "(".to_string()));1561                suggestion = ").clone()".to_string();1562            }1563            expr.span.shrink_to_hi()1564        };1565        sugg.push((span, suggestion));1566        let msg = if let ty::Adt(def, _) = ty.kind()1567            && [tcx.get_diagnostic_item(sym::Arc), tcx.get_diagnostic_item(sym::Rc)]1568                .contains(&Some(def.did()))1569        {1570            "clone the value to increment its reference count"1571        } else {1572            "consider cloning the value if the performance cost is acceptable"1573        };1574        err.multipart_suggestion(msg, sugg, Applicability::MachineApplicable);1575        true1576    }15771578    fn suggest_adding_bounds(&self, err: &mut Diag<'_>, ty: Ty<'tcx>, def_id: DefId, span: Span) {1579        let tcx = self.infcx.tcx;1580        let generics = tcx.generics_of(self.mir_def_id());15811582        let Some(hir_generics) =1583            tcx.hir_get_generics(tcx.typeck_root_def_id_local(self.mir_def_id()))1584        else {1585            return;1586        };1587        // Try to find predicates on *generic params* that would allow copying `ty`1588        let ocx = ObligationCtxt::new_with_diagnostics(self.infcx);1589        let cause = ObligationCause::misc(span, self.mir_def_id());15901591        ocx.register_bound(cause, self.infcx.param_env, ty, def_id);1592        let errors = ocx.evaluate_obligations_error_on_ambiguity();15931594        // Only emit suggestion if all required predicates are on generic1595        let predicates: Result<Vec<_>, _> = errors1596            .into_iter()1597            .map(|err| match err.obligation.predicate.kind().skip_binder() {1598                PredicateKind::Clause(ty::ClauseKind::Trait(predicate)) => {1599                    match *predicate.self_ty().kind() {1600                        ty::Param(param_ty) => Ok((1601                            generics.type_param(param_ty, tcx),1602                            predicate.trait_ref.print_trait_sugared().to_string(),1603                            Some(predicate.trait_ref.def_id),1604                        )),1605                        _ => Err(()),1606                    }1607                }1608                _ => Err(()),1609            })1610            .collect();16111612        if let Ok(predicates) = predicates {1613            suggest_constraining_type_params(1614                tcx,1615                hir_generics,1616                err,1617                predicates.iter().map(|(param, constraint, def_id)| {1618                    (param.name.as_str(), &**constraint, *def_id)1619                }),1620                None,1621            );1622        }1623    }16241625    pub(crate) fn report_move_out_while_borrowed(1626        &mut self,1627        location: Location,1628        (place, span): (Place<'tcx>, Span),1629        borrow: &BorrowData<'tcx>,1630    ) {1631        debug!(1632            "report_move_out_while_borrowed: location={:?} place={:?} span={:?} borrow={:?}",1633            location, place, span, borrow1634        );1635        let value_msg = self.describe_any_place(place.as_ref());1636        let borrow_msg = self.describe_any_place(borrow.borrowed_place.as_ref());16371638        let borrow_spans = self.retrieve_borrow_spans(borrow);1639        let borrow_span = borrow_spans.args_or_use();16401641        let move_spans = self.move_spans(place.as_ref(), location);1642        let span = move_spans.args_or_use();16431644        let mut err = self.cannot_move_when_borrowed(1645            span,1646            borrow_span,1647            &self.describe_any_place(place.as_ref()),1648            &borrow_msg,1649            &value_msg,1650        );1651        self.note_due_to_edition_2024_opaque_capture_rules(borrow, &mut err);16521653        borrow_spans.var_path_only_subdiag(&mut err, crate::InitializationRequiringAction::Borrow);16541655        move_spans.var_subdiag(&mut err, None, |kind, var_span| {1656            use crate::session_diagnostics::CaptureVarCause::*;1657            match kind {1658                hir::ClosureKind::Coroutine(_) => MoveUseInCoroutine { var_span },1659                hir::ClosureKind::Closure | hir::ClosureKind::CoroutineClosure(_) => {1660                    MoveUseInClosure { var_span }1661                }1662            }1663        });16641665        self.explain_why_borrow_contains_point(location, borrow, None)1666            .add_explanation_to_diagnostic(&self, &mut err, "", Some(borrow_span), None);1667        self.suggest_copy_for_type_in_cloned_ref(&mut err, place);1668        let typeck_results = self.infcx.tcx.typeck(self.mir_def_id());1669        if let Some(expr) = self.find_expr(borrow_span) {1670            // This is a borrow span, so we want to suggest cloning the referent.1671            if let hir::ExprKind::AddrOf(_, _, borrowed_expr) = expr.kind1672                && let Some(ty) = typeck_results.expr_ty_opt(borrowed_expr)1673            {1674                self.suggest_cloning(&mut err, place.as_ref(), ty, borrowed_expr, Some(move_spans));1675            } else if typeck_results.expr_adjustments(expr).first().is_some_and(|adj| {1676                matches!(1677                    adj.kind,1678                    ty::adjustment::Adjust::Borrow(ty::adjustment::AutoBorrow::Ref(1679                        ty::adjustment::AutoBorrowMutability::Not1680                            | ty::adjustment::AutoBorrowMutability::Mut {1681                                allow_two_phase_borrow: ty::adjustment::AllowTwoPhase::No1682                            }1683                    ))1684                )1685            }) && let Some(ty) = typeck_results.expr_ty_opt(expr)1686            {1687                self.suggest_cloning(&mut err, place.as_ref(), ty, expr, Some(move_spans));1688            }1689        }1690        self.buffer_error(err);1691    }16921693    pub(crate) fn report_use_while_mutably_borrowed(1694        &self,1695        location: Location,1696        (place, _span): (Place<'tcx>, Span),1697        borrow: &BorrowData<'tcx>,1698    ) -> Diag<'infcx> {1699        let borrow_spans = self.retrieve_borrow_spans(borrow);1700        let borrow_span = borrow_spans.args_or_use();17011702        // Conflicting borrows are reported separately, so only check for move1703        // captures.1704        let use_spans = self.move_spans(place.as_ref(), location);1705        let span = use_spans.var_or_use();17061707        // If the attempted use is in a closure then we do not care about the path span of the1708        // place we are currently trying to use we call `var_span_label` on `borrow_spans` to1709        // annotate if the existing borrow was in a closure.1710        let mut err = self.cannot_use_when_mutably_borrowed(1711            span,1712            &self.describe_any_place(place.as_ref()),1713            borrow_span,1714            &self.describe_any_place(borrow.borrowed_place.as_ref()),1715        );1716        self.note_due_to_edition_2024_opaque_capture_rules(borrow, &mut err);17171718        borrow_spans.var_subdiag(&mut err, Some(borrow.kind), |kind, var_span| {1719            use crate::session_diagnostics::CaptureVarCause::*;1720            let place = &borrow.borrowed_place;1721            let desc_place = self.describe_any_place(place.as_ref());1722            match kind {1723                hir::ClosureKind::Coroutine(_) => {1724                    BorrowUsePlaceCoroutine { place: desc_place, var_span, is_single_var: true }1725                }1726                hir::ClosureKind::Closure | hir::ClosureKind::CoroutineClosure(_) => {1727                    BorrowUsePlaceClosure { place: desc_place, var_span, is_single_var: true }1728                }1729            }1730        });17311732        self.explain_why_borrow_contains_point(location, borrow, None)1733            .add_explanation_to_diagnostic(&self, &mut err, "", None, None);1734        err1735    }17361737    pub(crate) fn report_conflicting_borrow(1738        &self,1739        location: Location,1740        (place, span): (Place<'tcx>, Span),1741        gen_borrow_kind: BorrowKind,1742        issued_borrow: &BorrowData<'tcx>,1743    ) -> Diag<'infcx> {1744        let issued_spans = self.retrieve_borrow_spans(issued_borrow);1745        let issued_span = issued_spans.args_or_use();17461747        let borrow_spans = self.borrow_spans(span, location);1748        let span = borrow_spans.args_or_use();17491750        let container_name = if issued_spans.for_coroutine() || borrow_spans.for_coroutine() {1751            "coroutine"1752        } else {1753            "closure"1754        };17551756        let (desc_place, msg_place, msg_borrow, union_type_name) =1757            self.describe_place_for_conflicting_borrow(place, issued_borrow.borrowed_place);17581759        let explanation = self.explain_why_borrow_contains_point(location, issued_borrow, None);1760        let second_borrow_desc = if explanation.is_explained() { "second " } else { "" };17611762        // FIXME: supply non-"" `opt_via` when appropriate1763        let first_borrow_desc;1764        let mut err = match (gen_borrow_kind, issued_borrow.kind) {1765            (1766                BorrowKind::Shared | BorrowKind::Fake(FakeBorrowKind::Deep),1767                BorrowKind::Mut { kind: MutBorrowKind::Default | MutBorrowKind::TwoPhaseBorrow },1768            ) => {1769                first_borrow_desc = "mutable ";1770                let mut err = self.cannot_reborrow_already_borrowed(1771                    span,1772                    &desc_place,1773                    &msg_place,1774                    "immutable",1775                    issued_span,1776                    "it",1777                    "mutable",1778                    &msg_borrow,1779                    None,1780                );1781                self.suggest_slice_method_if_applicable(1782                    &mut err,1783                    place,1784                    issued_borrow.borrowed_place,1785                    span,1786                    issued_span,1787                );1788                err1789            }1790            (1791                BorrowKind::Mut { kind: MutBorrowKind::Default | MutBorrowKind::TwoPhaseBorrow },1792                BorrowKind::Shared | BorrowKind::Fake(FakeBorrowKind::Deep),1793            ) => {1794                first_borrow_desc = "immutable ";1795                let mut err = self.cannot_reborrow_already_borrowed(1796                    span,1797                    &desc_place,1798                    &msg_place,1799                    "mutable",1800                    issued_span,1801                    "it",1802                    "immutable",1803                    &msg_borrow,1804                    None,1805                );1806                self.suggest_slice_method_if_applicable(1807                    &mut err,1808                    place,1809                    issued_borrow.borrowed_place,1810                    span,1811                    issued_span,1812                );1813                self.suggest_binding_for_closure_capture_self(&mut err, &issued_spans);1814                self.suggest_using_closure_argument_instead_of_capture(1815                    &mut err,1816                    issued_borrow.borrowed_place,1817                    &issued_spans,1818                );1819                err1820            }18211822            (1823                BorrowKind::Mut { kind: MutBorrowKind::Default | MutBorrowKind::TwoPhaseBorrow },1824                BorrowKind::Mut { kind: MutBorrowKind::Default | MutBorrowKind::TwoPhaseBorrow },1825            ) => {1826                first_borrow_desc = "first ";1827                let mut err = self.cannot_mutably_borrow_multiply(1828                    span,1829                    &desc_place,1830                    &msg_place,1831                    issued_span,1832                    &msg_borrow,1833                    None,1834                );1835                self.suggest_slice_method_if_applicable(1836                    &mut err,1837                    place,1838                    issued_borrow.borrowed_place,1839                    span,1840                    issued_span,1841                );1842                self.suggest_using_closure_argument_instead_of_capture(1843                    &mut err,1844                    issued_borrow.borrowed_place,1845                    &issued_spans,1846                );1847                self.explain_iterator_advancement_in_for_loop_if_applicable(1848                    &mut err,1849                    span,1850                    &issued_spans,1851                );1852                err1853            }18541855            (1856                BorrowKind::Mut { kind: MutBorrowKind::ClosureCapture },1857                BorrowKind::Mut { kind: MutBorrowKind::ClosureCapture },1858            ) => {1859                first_borrow_desc = "first ";1860                self.cannot_uniquely_borrow_by_two_closures(span, &desc_place, issued_span, None)1861            }18621863            (BorrowKind::Mut { .. }, BorrowKind::Fake(FakeBorrowKind::Shallow)) => {1864                if let Some(immutable_section_description) =1865                    self.classify_immutable_section(issued_borrow.assigned_place)1866                {1867                    let mut err = self.cannot_mutate_in_immutable_section(1868                        span,1869                        issued_span,1870                        &desc_place,1871                        immutable_section_description,1872                        "mutably borrow",1873                    );1874                    borrow_spans.var_subdiag(1875                        &mut err,1876                        Some(BorrowKind::Mut { kind: MutBorrowKind::ClosureCapture }),1877                        |kind, var_span| {1878                            use crate::session_diagnostics::CaptureVarCause::*;1879                            match kind {1880                                hir::ClosureKind::Coroutine(_) => BorrowUsePlaceCoroutine {1881                                    place: desc_place,1882                                    var_span,1883                                    is_single_var: true,1884                                },1885                                hir::ClosureKind::Closure1886                                | hir::ClosureKind::CoroutineClosure(_) => BorrowUsePlaceClosure {1887                                    place: desc_place,1888                                    var_span,1889                                    is_single_var: true,1890                                },1891                            }1892                        },1893                    );1894                    return err;1895                } else {1896                    first_borrow_desc = "immutable ";1897                    self.cannot_reborrow_already_borrowed(1898                        span,1899                        &desc_place,1900                        &msg_place,1901                        "mutable",1902                        issued_span,1903                        "it",1904                        "immutable",1905                        &msg_borrow,1906                        None,1907                    )1908                }1909            }19101911            (BorrowKind::Mut { kind: MutBorrowKind::ClosureCapture }, _) => {1912                first_borrow_desc = "first ";1913                self.cannot_uniquely_borrow_by_one_closure(1914                    span,1915                    container_name,1916                    &desc_place,1917                    "",1918                    issued_span,1919                    "it",1920                    "",1921                    None,1922                )1923            }19241925            (1926                BorrowKind::Shared | BorrowKind::Fake(FakeBorrowKind::Deep),1927                BorrowKind::Mut { kind: MutBorrowKind::ClosureCapture },1928            ) => {1929                first_borrow_desc = "first ";1930                self.cannot_reborrow_already_uniquely_borrowed(1931                    span,1932                    container_name,1933                    &desc_place,1934                    "",1935                    "immutable",1936                    issued_span,1937                    "",1938                    None,1939                    second_borrow_desc,1940                )1941            }19421943            (BorrowKind::Mut { .. }, BorrowKind::Mut { kind: MutBorrowKind::ClosureCapture }) => {1944                first_borrow_desc = "first ";1945                self.cannot_reborrow_already_uniquely_borrowed(1946                    span,1947                    container_name,1948                    &desc_place,1949                    "",1950                    "mutable",1951                    issued_span,1952                    "",1953                    None,1954                    second_borrow_desc,1955                )1956            }19571958            (1959                BorrowKind::Shared | BorrowKind::Fake(FakeBorrowKind::Deep),1960                BorrowKind::Shared | BorrowKind::Fake(_),1961            )1962            | (1963                BorrowKind::Fake(FakeBorrowKind::Shallow),1964                BorrowKind::Mut { .. } | BorrowKind::Shared | BorrowKind::Fake(_),1965            ) => {1966                unreachable!()1967            }1968        };1969        self.note_due_to_edition_2024_opaque_capture_rules(issued_borrow, &mut err);19701971        if issued_spans == borrow_spans {1972            borrow_spans.var_subdiag(&mut err, Some(gen_borrow_kind), |kind, var_span| {1973                use crate::session_diagnostics::CaptureVarCause::*;1974                match kind {1975                    hir::ClosureKind::Coroutine(_) => BorrowUsePlaceCoroutine {1976                        place: desc_place,1977                        var_span,1978                        is_single_var: false,1979                    },1980                    hir::ClosureKind::Closure | hir::ClosureKind::CoroutineClosure(_) => {1981                        BorrowUsePlaceClosure { place: desc_place, var_span, is_single_var: false }1982                    }1983                }1984            });1985        } else {1986            issued_spans.var_subdiag(&mut err, Some(issued_borrow.kind), |kind, var_span| {1987                use crate::session_diagnostics::CaptureVarCause::*;1988                let borrow_place = &issued_borrow.borrowed_place;1989                let borrow_place_desc = self.describe_any_place(borrow_place.as_ref());1990                match kind {1991                    hir::ClosureKind::Coroutine(_) => {1992                        FirstBorrowUsePlaceCoroutine { place: borrow_place_desc, var_span }1993                    }1994                    hir::ClosureKind::Closure | hir::ClosureKind::CoroutineClosure(_) => {1995                        FirstBorrowUsePlaceClosure { place: borrow_place_desc, var_span }1996                    }1997                }1998            });19992000            borrow_spans.var_subdiag(&mut err, Some(gen_borrow_kind), |kind, var_span| {

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.