rustc_borrowck/diagnostics/
mod.rs

1//! Borrow checker diagnostics.
2
3use std::collections::BTreeMap;
4
5use rustc_abi::{FieldIdx, VariantIdx};
6use rustc_data_structures::fx::FxIndexMap;
7use rustc_errors::{Applicability, Diag, EmissionGuarantee, MultiSpan, listify};
8use rustc_hir::def::{CtorKind, Namespace};
9use rustc_hir::{self as hir, CoroutineKind, LangItem};
10use rustc_index::IndexSlice;
11use rustc_infer::infer::{
12    BoundRegionConversionTime, NllRegionVariableOrigin, RegionVariableOrigin,
13};
14use rustc_infer::traits::SelectionError;
15use rustc_middle::bug;
16use rustc_middle::mir::tcx::PlaceTy;
17use rustc_middle::mir::{
18    AggregateKind, CallSource, ConstOperand, ConstraintCategory, FakeReadCause, Local, LocalInfo,
19    LocalKind, Location, Operand, Place, PlaceRef, ProjectionElem, Rvalue, Statement,
20    StatementKind, Terminator, TerminatorKind, find_self_call,
21};
22use rustc_middle::ty::print::Print;
23use rustc_middle::ty::{self, Ty, TyCtxt};
24use rustc_mir_dataflow::move_paths::{InitLocation, LookupResult, MoveOutIndex};
25use rustc_span::def_id::LocalDefId;
26use rustc_span::source_map::Spanned;
27use rustc_span::{DUMMY_SP, ErrorGuaranteed, Span, Symbol, sym};
28use rustc_trait_selection::error_reporting::InferCtxtErrorExt;
29use rustc_trait_selection::error_reporting::traits::call_kind::{CallDesugaringKind, call_kind};
30use rustc_trait_selection::infer::InferCtxtExt;
31use rustc_trait_selection::traits::{
32    FulfillmentError, FulfillmentErrorCode, type_known_to_meet_bound_modulo_regions,
33};
34use tracing::debug;
35
36use super::MirBorrowckCtxt;
37use super::borrow_set::BorrowData;
38use crate::constraints::OutlivesConstraint;
39use crate::fluent_generated as fluent;
40use crate::nll::ConstraintDescription;
41use crate::session_diagnostics::{
42    CaptureArgLabel, CaptureReasonLabel, CaptureReasonNote, CaptureReasonSuggest, CaptureVarCause,
43    CaptureVarKind, CaptureVarPathUseCause, OnClosureNote,
44};
45
46mod find_all_local_uses;
47mod find_use;
48mod outlives_suggestion;
49mod region_name;
50mod var_name;
51
52mod bound_region_errors;
53mod conflict_errors;
54mod explain_borrow;
55mod move_errors;
56mod mutability_errors;
57mod opaque_suggestions;
58mod region_errors;
59
60pub(crate) use bound_region_errors::{ToUniverseInfo, UniverseInfo};
61pub(crate) use move_errors::{IllegalMoveOriginKind, MoveError};
62pub(crate) use mutability_errors::AccessKind;
63pub(crate) use outlives_suggestion::OutlivesSuggestionBuilder;
64pub(crate) use region_errors::{ErrorConstraintInfo, RegionErrorKind, RegionErrors};
65pub(crate) use region_name::{RegionName, RegionNameSource};
66pub(crate) use rustc_trait_selection::error_reporting::traits::call_kind::CallKind;
67
68pub(super) struct DescribePlaceOpt {
69    including_downcast: bool,
70
71    /// Enable/Disable tuple fields.
72    /// For example `x` tuple. if it's `true` `x.0`. Otherwise `x`
73    including_tuple_field: bool,
74}
75
76pub(super) struct IncludingTupleField(pub(super) bool);
77
78enum BufferedDiag<'infcx> {
79    Error(Diag<'infcx>),
80    NonError(Diag<'infcx, ()>),
81}
82
83impl<'infcx> BufferedDiag<'infcx> {
84    fn sort_span(&self) -> Span {
85        match self {
86            BufferedDiag::Error(diag) => diag.sort_span,
87            BufferedDiag::NonError(diag) => diag.sort_span,
88        }
89    }
90}
91
92#[derive(Default)]
93pub(crate) struct BorrowckDiagnosticsBuffer<'infcx, 'tcx> {
94    /// This field keeps track of move errors that are to be reported for given move indices.
95    ///
96    /// There are situations where many errors can be reported for a single move out (see
97    /// #53807) and we want only the best of those errors.
98    ///
99    /// The `report_use_of_moved_or_uninitialized` function checks this map and replaces the
100    /// diagnostic (if there is one) if the `Place` of the error being reported is a prefix of
101    /// the `Place` of the previous most diagnostic. This happens instead of buffering the
102    /// error. Once all move errors have been reported, any diagnostics in this map are added
103    /// to the buffer to be emitted.
104    ///
105    /// `BTreeMap` is used to preserve the order of insertions when iterating. This is necessary
106    /// when errors in the map are being re-added to the error buffer so that errors with the
107    /// same primary span come out in a consistent order.
108    buffered_move_errors: BTreeMap<Vec<MoveOutIndex>, (PlaceRef<'tcx>, Diag<'infcx>)>,
109
110    buffered_mut_errors: FxIndexMap<Span, (Diag<'infcx>, usize)>,
111
112    /// Buffer of diagnostics to be reported. A mixture of error and non-error diagnostics.
113    buffered_diags: Vec<BufferedDiag<'infcx>>,
114}
115
116impl<'infcx, 'tcx> BorrowckDiagnosticsBuffer<'infcx, 'tcx> {
117    pub(crate) fn buffer_non_error(&mut self, diag: Diag<'infcx, ()>) {
118        self.buffered_diags.push(BufferedDiag::NonError(diag));
119    }
120}
121
122impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
123    pub(crate) fn buffer_error(&mut self, diag: Diag<'infcx>) {
124        self.diags_buffer.buffered_diags.push(BufferedDiag::Error(diag));
125    }
126
127    pub(crate) fn buffer_non_error(&mut self, diag: Diag<'infcx, ()>) {
128        self.diags_buffer.buffer_non_error(diag);
129    }
130
131    pub(crate) fn buffer_move_error(
132        &mut self,
133        move_out_indices: Vec<MoveOutIndex>,
134        place_and_err: (PlaceRef<'tcx>, Diag<'infcx>),
135    ) -> bool {
136        if let Some((_, diag)) =
137            self.diags_buffer.buffered_move_errors.insert(move_out_indices, place_and_err)
138        {
139            // Cancel the old diagnostic so we don't ICE
140            diag.cancel();
141            false
142        } else {
143            true
144        }
145    }
146
147    pub(crate) fn get_buffered_mut_error(&mut self, span: Span) -> Option<(Diag<'infcx>, usize)> {
148        // FIXME(#120456) - is `swap_remove` correct?
149        self.diags_buffer.buffered_mut_errors.swap_remove(&span)
150    }
151
152    pub(crate) fn buffer_mut_error(&mut self, span: Span, diag: Diag<'infcx>, count: usize) {
153        self.diags_buffer.buffered_mut_errors.insert(span, (diag, count));
154    }
155
156    pub(crate) fn emit_errors(&mut self) -> Option<ErrorGuaranteed> {
157        let mut res = self.infcx.tainted_by_errors();
158
159        // Buffer any move errors that we collected and de-duplicated.
160        for (_, (_, diag)) in std::mem::take(&mut self.diags_buffer.buffered_move_errors) {
161            // We have already set tainted for this error, so just buffer it.
162            self.buffer_error(diag);
163        }
164        for (_, (mut diag, count)) in std::mem::take(&mut self.diags_buffer.buffered_mut_errors) {
165            if count > 10 {
166                #[allow(rustc::diagnostic_outside_of_impl)]
167                #[allow(rustc::untranslatable_diagnostic)]
168                diag.note(format!("...and {} other attempted mutable borrows", count - 10));
169            }
170            self.buffer_error(diag);
171        }
172
173        if !self.diags_buffer.buffered_diags.is_empty() {
174            self.diags_buffer.buffered_diags.sort_by_key(|buffered_diag| buffered_diag.sort_span());
175            for buffered_diag in self.diags_buffer.buffered_diags.drain(..) {
176                match buffered_diag {
177                    BufferedDiag::Error(diag) => res = Some(diag.emit()),
178                    BufferedDiag::NonError(diag) => diag.emit(),
179                }
180            }
181        }
182
183        res
184    }
185
186    pub(crate) fn has_buffered_diags(&self) -> bool {
187        self.diags_buffer.buffered_diags.is_empty()
188    }
189
190    pub(crate) fn has_move_error(
191        &self,
192        move_out_indices: &[MoveOutIndex],
193    ) -> Option<&(PlaceRef<'tcx>, Diag<'infcx>)> {
194        self.diags_buffer.buffered_move_errors.get(move_out_indices)
195    }
196}
197
198impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
199    /// Adds a suggestion when a closure is invoked twice with a moved variable or when a closure
200    /// is moved after being invoked.
201    ///
202    /// ```text
203    /// note: closure cannot be invoked more than once because it moves the variable `dict` out of
204    ///       its environment
205    ///   --> $DIR/issue-42065.rs:16:29
206    ///    |
207    /// LL |         for (key, value) in dict {
208    ///    |                             ^^^^
209    /// ```
210    #[allow(rustc::diagnostic_outside_of_impl)] // FIXME
211    pub(super) fn add_moved_or_invoked_closure_note(
212        &self,
213        location: Location,
214        place: PlaceRef<'tcx>,
215        diag: &mut Diag<'infcx>,
216    ) -> bool {
217        debug!("add_moved_or_invoked_closure_note: location={:?} place={:?}", location, place);
218        let mut target = place.local_or_deref_local();
219        for stmt in &self.body[location.block].statements[location.statement_index..] {
220            debug!("add_moved_or_invoked_closure_note: stmt={:?} target={:?}", stmt, target);
221            if let StatementKind::Assign(box (into, Rvalue::Use(from))) = &stmt.kind {
222                debug!("add_fnonce_closure_note: into={:?} from={:?}", into, from);
223                match from {
224                    Operand::Copy(place) | Operand::Move(place)
225                        if target == place.local_or_deref_local() =>
226                    {
227                        target = into.local_or_deref_local()
228                    }
229                    _ => {}
230                }
231            }
232        }
233
234        // Check if we are attempting to call a closure after it has been invoked.
235        let terminator = self.body[location.block].terminator();
236        debug!("add_moved_or_invoked_closure_note: terminator={:?}", terminator);
237        if let TerminatorKind::Call {
238            func: Operand::Constant(box ConstOperand { const_, .. }),
239            args,
240            ..
241        } = &terminator.kind
242        {
243            if let ty::FnDef(id, _) = *const_.ty().kind() {
244                debug!("add_moved_or_invoked_closure_note: id={:?}", id);
245                if self.infcx.tcx.is_lang_item(self.infcx.tcx.parent(id), LangItem::FnOnce) {
246                    let closure = match args.first() {
247                        Some(Spanned {
248                            node: Operand::Copy(place) | Operand::Move(place), ..
249                        }) if target == place.local_or_deref_local() => {
250                            place.local_or_deref_local().unwrap()
251                        }
252                        _ => return false,
253                    };
254
255                    debug!("add_moved_or_invoked_closure_note: closure={:?}", closure);
256                    if let ty::Closure(did, _) = self.body.local_decls[closure].ty.kind() {
257                        let did = did.expect_local();
258                        if let Some((span, hir_place)) = self.infcx.tcx.closure_kind_origin(did) {
259                            diag.subdiagnostic(OnClosureNote::InvokedTwice {
260                                place_name: &ty::place_to_string_for_capture(
261                                    self.infcx.tcx,
262                                    hir_place,
263                                ),
264                                span: *span,
265                            });
266                            return true;
267                        }
268                    }
269                }
270            }
271        }
272
273        // Check if we are just moving a closure after it has been invoked.
274        if let Some(target) = target {
275            if let ty::Closure(did, _) = self.body.local_decls[target].ty.kind() {
276                let did = did.expect_local();
277                if let Some((span, hir_place)) = self.infcx.tcx.closure_kind_origin(did) {
278                    diag.subdiagnostic(OnClosureNote::MovedTwice {
279                        place_name: &ty::place_to_string_for_capture(self.infcx.tcx, hir_place),
280                        span: *span,
281                    });
282                    return true;
283                }
284            }
285        }
286        false
287    }
288
289    /// End-user visible description of `place` if one can be found.
290    /// If the place is a temporary for instance, `"value"` will be returned.
291    pub(super) fn describe_any_place(&self, place_ref: PlaceRef<'tcx>) -> String {
292        match self.describe_place(place_ref) {
293            Some(mut descr) => {
294                // Surround descr with `backticks`.
295                descr.reserve(2);
296                descr.insert(0, '`');
297                descr.push('`');
298                descr
299            }
300            None => "value".to_string(),
301        }
302    }
303
304    /// End-user visible description of `place` if one can be found.
305    /// If the place is a temporary for instance, `None` will be returned.
306    pub(super) fn describe_place(&self, place_ref: PlaceRef<'tcx>) -> Option<String> {
307        self.describe_place_with_options(
308            place_ref,
309            DescribePlaceOpt { including_downcast: false, including_tuple_field: true },
310        )
311    }
312
313    /// End-user visible description of `place` if one can be found. If the place is a temporary
314    /// for instance, `None` will be returned.
315    /// `IncludingDowncast` parameter makes the function return `None` if `ProjectionElem` is
316    /// `Downcast` and `IncludingDowncast` is true
317    pub(super) fn describe_place_with_options(
318        &self,
319        place: PlaceRef<'tcx>,
320        opt: DescribePlaceOpt,
321    ) -> Option<String> {
322        let local = place.local;
323        let mut autoderef_index = None;
324        let mut buf = String::new();
325        let mut ok = self.append_local_to_string(local, &mut buf);
326
327        for (index, elem) in place.projection.into_iter().enumerate() {
328            match elem {
329                ProjectionElem::Deref => {
330                    if index == 0 {
331                        if self.body.local_decls[local].is_ref_for_guard() {
332                            continue;
333                        }
334                        if let LocalInfo::StaticRef { def_id, .. } =
335                            *self.body.local_decls[local].local_info()
336                        {
337                            buf.push_str(self.infcx.tcx.item_name(def_id).as_str());
338                            ok = Ok(());
339                            continue;
340                        }
341                    }
342                    if let Some(field) = self.is_upvar_field_projection(PlaceRef {
343                        local,
344                        projection: place.projection.split_at(index + 1).0,
345                    }) {
346                        let var_index = field.index();
347                        buf = self.upvars[var_index].to_string(self.infcx.tcx);
348                        ok = Ok(());
349                        if !self.upvars[var_index].is_by_ref() {
350                            buf.insert(0, '*');
351                        }
352                    } else {
353                        if autoderef_index.is_none() {
354                            autoderef_index = match place.projection.iter().rposition(|elem| {
355                                !matches!(
356                                    elem,
357                                    ProjectionElem::Deref | ProjectionElem::Downcast(..)
358                                )
359                            }) {
360                                Some(index) => Some(index + 1),
361                                None => Some(0),
362                            };
363                        }
364                        if index >= autoderef_index.unwrap() {
365                            buf.insert(0, '*');
366                        }
367                    }
368                }
369                ProjectionElem::Downcast(..) if opt.including_downcast => return None,
370                ProjectionElem::Downcast(..) => (),
371                ProjectionElem::OpaqueCast(..) => (),
372                ProjectionElem::Subtype(..) => (),
373                ProjectionElem::UnwrapUnsafeBinder(_) => (),
374                ProjectionElem::Field(field, _ty) => {
375                    // FIXME(project-rfc_2229#36): print capture precisely here.
376                    if let Some(field) = self.is_upvar_field_projection(PlaceRef {
377                        local,
378                        projection: place.projection.split_at(index + 1).0,
379                    }) {
380                        buf = self.upvars[field.index()].to_string(self.infcx.tcx);
381                        ok = Ok(());
382                    } else {
383                        let field_name = self.describe_field(
384                            PlaceRef { local, projection: place.projection.split_at(index).0 },
385                            *field,
386                            IncludingTupleField(opt.including_tuple_field),
387                        );
388                        if let Some(field_name_str) = field_name {
389                            buf.push('.');
390                            buf.push_str(&field_name_str);
391                        }
392                    }
393                }
394                ProjectionElem::Index(index) => {
395                    buf.push('[');
396                    if self.append_local_to_string(*index, &mut buf).is_err() {
397                        buf.push('_');
398                    }
399                    buf.push(']');
400                }
401                ProjectionElem::ConstantIndex { .. } | ProjectionElem::Subslice { .. } => {
402                    // Since it isn't possible to borrow an element on a particular index and
403                    // then use another while the borrow is held, don't output indices details
404                    // to avoid confusing the end-user
405                    buf.push_str("[..]");
406                }
407            }
408        }
409        ok.ok().map(|_| buf)
410    }
411
412    fn describe_name(&self, place: PlaceRef<'tcx>) -> Option<Symbol> {
413        for elem in place.projection.into_iter() {
414            match elem {
415                ProjectionElem::Downcast(Some(name), _) => {
416                    return Some(*name);
417                }
418                _ => {}
419            }
420        }
421        None
422    }
423
424    /// Appends end-user visible description of the `local` place to `buf`. If `local` doesn't have
425    /// a name, or its name was generated by the compiler, then `Err` is returned
426    fn append_local_to_string(&self, local: Local, buf: &mut String) -> Result<(), ()> {
427        let decl = &self.body.local_decls[local];
428        match self.local_names[local] {
429            Some(name) if !decl.from_compiler_desugaring() => {
430                buf.push_str(name.as_str());
431                Ok(())
432            }
433            _ => Err(()),
434        }
435    }
436
437    /// End-user visible description of the `field`nth field of `base`
438    fn describe_field(
439        &self,
440        place: PlaceRef<'tcx>,
441        field: FieldIdx,
442        including_tuple_field: IncludingTupleField,
443    ) -> Option<String> {
444        let place_ty = match place {
445            PlaceRef { local, projection: [] } => PlaceTy::from_ty(self.body.local_decls[local].ty),
446            PlaceRef { local, projection: [proj_base @ .., elem] } => match elem {
447                ProjectionElem::Deref
448                | ProjectionElem::Index(..)
449                | ProjectionElem::ConstantIndex { .. }
450                | ProjectionElem::Subslice { .. } => {
451                    PlaceRef { local, projection: proj_base }.ty(self.body, self.infcx.tcx)
452                }
453                ProjectionElem::Downcast(..) => place.ty(self.body, self.infcx.tcx),
454                ProjectionElem::Subtype(ty)
455                | ProjectionElem::OpaqueCast(ty)
456                | ProjectionElem::UnwrapUnsafeBinder(ty) => PlaceTy::from_ty(*ty),
457                ProjectionElem::Field(_, field_type) => PlaceTy::from_ty(*field_type),
458            },
459        };
460        self.describe_field_from_ty(
461            place_ty.ty,
462            field,
463            place_ty.variant_index,
464            including_tuple_field,
465        )
466    }
467
468    /// End-user visible description of the `field_index`nth field of `ty`
469    fn describe_field_from_ty(
470        &self,
471        ty: Ty<'_>,
472        field: FieldIdx,
473        variant_index: Option<VariantIdx>,
474        including_tuple_field: IncludingTupleField,
475    ) -> Option<String> {
476        if let Some(boxed_ty) = ty.boxed_ty() {
477            // If the type is a box, the field is described from the boxed type
478            self.describe_field_from_ty(boxed_ty, field, variant_index, including_tuple_field)
479        } else {
480            match *ty.kind() {
481                ty::Adt(def, _) => {
482                    let variant = if let Some(idx) = variant_index {
483                        assert!(def.is_enum());
484                        def.variant(idx)
485                    } else {
486                        def.non_enum_variant()
487                    };
488                    if !including_tuple_field.0 && variant.ctor_kind() == Some(CtorKind::Fn) {
489                        return None;
490                    }
491                    Some(variant.fields[field].name.to_string())
492                }
493                ty::Tuple(_) => Some(field.index().to_string()),
494                ty::Ref(_, ty, _) | ty::RawPtr(ty, _) => {
495                    self.describe_field_from_ty(ty, field, variant_index, including_tuple_field)
496                }
497                ty::Array(ty, _) | ty::Slice(ty) => {
498                    self.describe_field_from_ty(ty, field, variant_index, including_tuple_field)
499                }
500                ty::Closure(def_id, _) | ty::Coroutine(def_id, _) => {
501                    // We won't be borrowck'ing here if the closure came from another crate,
502                    // so it's safe to call `expect_local`.
503                    //
504                    // We know the field exists so it's safe to call operator[] and `unwrap` here.
505                    let def_id = def_id.expect_local();
506                    let var_id =
507                        self.infcx.tcx.closure_captures(def_id)[field.index()].get_root_variable();
508
509                    Some(self.infcx.tcx.hir().name(var_id).to_string())
510                }
511                _ => {
512                    // Might need a revision when the fields in trait RFC is implemented
513                    // (https://github.com/rust-lang/rfcs/pull/1546)
514                    bug!("End-user description not implemented for field access on `{:?}`", ty);
515                }
516            }
517        }
518    }
519
520    pub(super) fn borrowed_content_source(
521        &self,
522        deref_base: PlaceRef<'tcx>,
523    ) -> BorrowedContentSource<'tcx> {
524        let tcx = self.infcx.tcx;
525
526        // Look up the provided place and work out the move path index for it,
527        // we'll use this to check whether it was originally from an overloaded
528        // operator.
529        match self.move_data.rev_lookup.find(deref_base) {
530            LookupResult::Exact(mpi) | LookupResult::Parent(Some(mpi)) => {
531                debug!("borrowed_content_source: mpi={:?}", mpi);
532
533                for i in &self.move_data.init_path_map[mpi] {
534                    let init = &self.move_data.inits[*i];
535                    debug!("borrowed_content_source: init={:?}", init);
536                    // We're only interested in statements that initialized a value, not the
537                    // initializations from arguments.
538                    let InitLocation::Statement(loc) = init.location else { continue };
539
540                    let bbd = &self.body[loc.block];
541                    let is_terminator = bbd.statements.len() == loc.statement_index;
542                    debug!(
543                        "borrowed_content_source: loc={:?} is_terminator={:?}",
544                        loc, is_terminator,
545                    );
546                    if !is_terminator {
547                        continue;
548                    } else if let Some(Terminator {
549                        kind:
550                            TerminatorKind::Call {
551                                func,
552                                call_source: CallSource::OverloadedOperator,
553                                ..
554                            },
555                        ..
556                    }) = &bbd.terminator
557                    {
558                        if let Some(source) =
559                            BorrowedContentSource::from_call(func.ty(self.body, tcx), tcx)
560                        {
561                            return source;
562                        }
563                    }
564                }
565            }
566            // Base is a `static` so won't be from an overloaded operator
567            _ => (),
568        };
569
570        // If we didn't find an overloaded deref or index, then assume it's a
571        // built in deref and check the type of the base.
572        let base_ty = deref_base.ty(self.body, tcx).ty;
573        if base_ty.is_raw_ptr() {
574            BorrowedContentSource::DerefRawPointer
575        } else if base_ty.is_mutable_ptr() {
576            BorrowedContentSource::DerefMutableRef
577        } else {
578            BorrowedContentSource::DerefSharedRef
579        }
580    }
581
582    /// Return the name of the provided `Ty` (that must be a reference) with a synthesized lifetime
583    /// name where required.
584    pub(super) fn get_name_for_ty(&self, ty: Ty<'tcx>, counter: usize) -> String {
585        let mut printer = ty::print::FmtPrinter::new(self.infcx.tcx, Namespace::TypeNS);
586
587        // We need to add synthesized lifetimes where appropriate. We do
588        // this by hooking into the pretty printer and telling it to label the
589        // lifetimes without names with the value `'0`.
590        if let ty::Ref(region, ..) = ty.kind() {
591            match **region {
592                ty::ReBound(_, ty::BoundRegion { kind: br, .. })
593                | ty::RePlaceholder(ty::PlaceholderRegion {
594                    bound: ty::BoundRegion { kind: br, .. },
595                    ..
596                }) => printer.region_highlight_mode.highlighting_bound_region(br, counter),
597                _ => {}
598            }
599        }
600
601        ty.print(&mut printer).unwrap();
602        printer.into_buffer()
603    }
604
605    /// Returns the name of the provided `Ty` (that must be a reference)'s region with a
606    /// synthesized lifetime name where required.
607    pub(super) fn get_region_name_for_ty(&self, ty: Ty<'tcx>, counter: usize) -> String {
608        let mut printer = ty::print::FmtPrinter::new(self.infcx.tcx, Namespace::TypeNS);
609
610        let region = if let ty::Ref(region, ..) = ty.kind() {
611            match **region {
612                ty::ReBound(_, ty::BoundRegion { kind: br, .. })
613                | ty::RePlaceholder(ty::PlaceholderRegion {
614                    bound: ty::BoundRegion { kind: br, .. },
615                    ..
616                }) => printer.region_highlight_mode.highlighting_bound_region(br, counter),
617                _ => {}
618            }
619            region
620        } else {
621            bug!("ty for annotation of borrow region is not a reference");
622        };
623
624        region.print(&mut printer).unwrap();
625        printer.into_buffer()
626    }
627
628    /// Add a note to region errors and borrow explanations when higher-ranked regions in predicates
629    /// implicitly introduce an "outlives `'static`" constraint.
630    fn add_placeholder_from_predicate_note<G: EmissionGuarantee>(
631        &self,
632        err: &mut Diag<'_, G>,
633        path: &[OutlivesConstraint<'tcx>],
634    ) {
635        let predicate_span = path.iter().find_map(|constraint| {
636            let outlived = constraint.sub;
637            if let Some(origin) = self.regioncx.var_infos.get(outlived)
638                && let RegionVariableOrigin::Nll(NllRegionVariableOrigin::Placeholder(_)) =
639                    origin.origin
640                && let ConstraintCategory::Predicate(span) = constraint.category
641            {
642                Some(span)
643            } else {
644                None
645            }
646        });
647
648        if let Some(span) = predicate_span {
649            err.span_note(span, "due to current limitations in the borrow checker, this implies a `'static` lifetime");
650        }
651    }
652
653    /// Add a label to region errors and borrow explanations when outlives constraints arise from
654    /// proving a type implements `Sized` or `Copy`.
655    fn add_sized_or_copy_bound_info<G: EmissionGuarantee>(
656        &self,
657        err: &mut Diag<'_, G>,
658        blamed_category: ConstraintCategory<'tcx>,
659        path: &[OutlivesConstraint<'tcx>],
660    ) {
661        for sought_category in [ConstraintCategory::SizedBound, ConstraintCategory::CopyBound] {
662            if sought_category != blamed_category
663                && let Some(sought_constraint) = path.iter().find(|c| c.category == sought_category)
664            {
665                let label = format!(
666                    "requirement occurs due to {}",
667                    sought_category.description().trim_end()
668                );
669                err.span_label(sought_constraint.span, label);
670            }
671        }
672    }
673}
674
675/// The span(s) associated to a use of a place.
676#[derive(Copy, Clone, PartialEq, Eq, Debug)]
677pub(super) enum UseSpans<'tcx> {
678    /// The access is caused by capturing a variable for a closure.
679    ClosureUse {
680        /// This is true if the captured variable was from a coroutine.
681        closure_kind: hir::ClosureKind,
682        /// The span of the args of the closure, including the `move` keyword if
683        /// it's present.
684        args_span: Span,
685        /// The span of the use resulting in capture kind
686        /// Check `ty::CaptureInfo` for more details
687        capture_kind_span: Span,
688        /// The span of the use resulting in the captured path
689        /// Check `ty::CaptureInfo` for more details
690        path_span: Span,
691    },
692    /// The access is caused by using a variable as the receiver of a method
693    /// that takes 'self'
694    FnSelfUse {
695        /// The span of the variable being moved
696        var_span: Span,
697        /// The span of the method call on the variable
698        fn_call_span: Span,
699        /// The definition span of the method being called
700        fn_span: Span,
701        kind: CallKind<'tcx>,
702    },
703    /// This access is caused by a `match` or `if let` pattern.
704    PatUse(Span),
705    /// This access has a single span associated to it: common case.
706    OtherUse(Span),
707}
708
709impl UseSpans<'_> {
710    pub(super) fn args_or_use(self) -> Span {
711        match self {
712            UseSpans::ClosureUse { args_span: span, .. }
713            | UseSpans::PatUse(span)
714            | UseSpans::OtherUse(span) => span,
715            UseSpans::FnSelfUse { var_span, .. } => var_span,
716        }
717    }
718
719    /// Returns the span of `self`, in the case of a `ClosureUse` returns the `path_span`
720    pub(super) fn var_or_use_path_span(self) -> Span {
721        match self {
722            UseSpans::ClosureUse { path_span: span, .. }
723            | UseSpans::PatUse(span)
724            | UseSpans::OtherUse(span) => span,
725            UseSpans::FnSelfUse { var_span, .. } => var_span,
726        }
727    }
728
729    /// Returns the span of `self`, in the case of a `ClosureUse` returns the `capture_kind_span`
730    pub(super) fn var_or_use(self) -> Span {
731        match self {
732            UseSpans::ClosureUse { capture_kind_span: span, .. }
733            | UseSpans::PatUse(span)
734            | UseSpans::OtherUse(span) => span,
735            UseSpans::FnSelfUse { var_span, .. } => var_span,
736        }
737    }
738
739    // FIXME(coroutines): Make this just return the `ClosureKind` directly?
740    pub(super) fn coroutine_kind(self) -> Option<CoroutineKind> {
741        match self {
742            UseSpans::ClosureUse {
743                closure_kind: hir::ClosureKind::Coroutine(coroutine_kind),
744                ..
745            } => Some(coroutine_kind),
746            _ => None,
747        }
748    }
749
750    /// Add a span label to the arguments of the closure, if it exists.
751    #[allow(rustc::diagnostic_outside_of_impl)]
752    pub(super) fn args_subdiag(self, err: &mut Diag<'_>, f: impl FnOnce(Span) -> CaptureArgLabel) {
753        if let UseSpans::ClosureUse { args_span, .. } = self {
754            err.subdiagnostic(f(args_span));
755        }
756    }
757
758    /// Add a span label to the use of the captured variable, if it exists.
759    /// only adds label to the `path_span`
760    #[allow(rustc::diagnostic_outside_of_impl)]
761    pub(super) fn var_path_only_subdiag(
762        self,
763        err: &mut Diag<'_>,
764        action: crate::InitializationRequiringAction,
765    ) {
766        use CaptureVarPathUseCause::*;
767
768        use crate::InitializationRequiringAction::*;
769        if let UseSpans::ClosureUse { closure_kind, path_span, .. } = self {
770            match closure_kind {
771                hir::ClosureKind::Coroutine(_) => {
772                    err.subdiagnostic(match action {
773                        Borrow => BorrowInCoroutine { path_span },
774                        MatchOn | Use => UseInCoroutine { path_span },
775                        Assignment => AssignInCoroutine { path_span },
776                        PartialAssignment => AssignPartInCoroutine { path_span },
777                    });
778                }
779                hir::ClosureKind::Closure | hir::ClosureKind::CoroutineClosure(_) => {
780                    err.subdiagnostic(match action {
781                        Borrow => BorrowInClosure { path_span },
782                        MatchOn | Use => UseInClosure { path_span },
783                        Assignment => AssignInClosure { path_span },
784                        PartialAssignment => AssignPartInClosure { path_span },
785                    });
786                }
787            }
788        }
789    }
790
791    /// Add a subdiagnostic to the use of the captured variable, if it exists.
792    #[allow(rustc::diagnostic_outside_of_impl)]
793    pub(super) fn var_subdiag(
794        self,
795        err: &mut Diag<'_>,
796        kind: Option<rustc_middle::mir::BorrowKind>,
797        f: impl FnOnce(hir::ClosureKind, Span) -> CaptureVarCause,
798    ) {
799        if let UseSpans::ClosureUse { closure_kind, capture_kind_span, path_span, .. } = self {
800            if capture_kind_span != path_span {
801                err.subdiagnostic(match kind {
802                    Some(kd) => match kd {
803                        rustc_middle::mir::BorrowKind::Shared
804                        | rustc_middle::mir::BorrowKind::Fake(_) => {
805                            CaptureVarKind::Immut { kind_span: capture_kind_span }
806                        }
807
808                        rustc_middle::mir::BorrowKind::Mut { .. } => {
809                            CaptureVarKind::Mut { kind_span: capture_kind_span }
810                        }
811                    },
812                    None => CaptureVarKind::Move { kind_span: capture_kind_span },
813                });
814            };
815            let diag = f(closure_kind, path_span);
816            err.subdiagnostic(diag);
817        }
818    }
819
820    /// Returns `false` if this place is not used in a closure.
821    pub(super) fn for_closure(&self) -> bool {
822        match *self {
823            UseSpans::ClosureUse { closure_kind, .. } => {
824                matches!(closure_kind, hir::ClosureKind::Closure)
825            }
826            _ => false,
827        }
828    }
829
830    /// Returns `false` if this place is not used in a coroutine.
831    pub(super) fn for_coroutine(&self) -> bool {
832        match *self {
833            // FIXME(coroutines): Do we want this to apply to synthetic coroutines?
834            UseSpans::ClosureUse { closure_kind, .. } => {
835                matches!(closure_kind, hir::ClosureKind::Coroutine(..))
836            }
837            _ => false,
838        }
839    }
840
841    pub(super) fn or_else<F>(self, if_other: F) -> Self
842    where
843        F: FnOnce() -> Self,
844    {
845        match self {
846            closure @ UseSpans::ClosureUse { .. } => closure,
847            UseSpans::PatUse(_) | UseSpans::OtherUse(_) => if_other(),
848            fn_self @ UseSpans::FnSelfUse { .. } => fn_self,
849        }
850    }
851}
852
853pub(super) enum BorrowedContentSource<'tcx> {
854    DerefRawPointer,
855    DerefMutableRef,
856    DerefSharedRef,
857    OverloadedDeref(Ty<'tcx>),
858    OverloadedIndex(Ty<'tcx>),
859}
860
861impl<'tcx> BorrowedContentSource<'tcx> {
862    pub(super) fn describe_for_unnamed_place(&self, tcx: TyCtxt<'_>) -> String {
863        match *self {
864            BorrowedContentSource::DerefRawPointer => "a raw pointer".to_string(),
865            BorrowedContentSource::DerefSharedRef => "a shared reference".to_string(),
866            BorrowedContentSource::DerefMutableRef => "a mutable reference".to_string(),
867            BorrowedContentSource::OverloadedDeref(ty) => ty
868                .ty_adt_def()
869                .and_then(|adt| match tcx.get_diagnostic_name(adt.did())? {
870                    name @ (sym::Rc | sym::Arc) => Some(format!("an `{name}`")),
871                    _ => None,
872                })
873                .unwrap_or_else(|| format!("dereference of `{ty}`")),
874            BorrowedContentSource::OverloadedIndex(ty) => format!("index of `{ty}`"),
875        }
876    }
877
878    pub(super) fn describe_for_named_place(&self) -> Option<&'static str> {
879        match *self {
880            BorrowedContentSource::DerefRawPointer => Some("raw pointer"),
881            BorrowedContentSource::DerefSharedRef => Some("shared reference"),
882            BorrowedContentSource::DerefMutableRef => Some("mutable reference"),
883            // Overloaded deref and index operators should be evaluated into a
884            // temporary. So we don't need a description here.
885            BorrowedContentSource::OverloadedDeref(_)
886            | BorrowedContentSource::OverloadedIndex(_) => None,
887        }
888    }
889
890    pub(super) fn describe_for_immutable_place(&self, tcx: TyCtxt<'_>) -> String {
891        match *self {
892            BorrowedContentSource::DerefRawPointer => "a `*const` pointer".to_string(),
893            BorrowedContentSource::DerefSharedRef => "a `&` reference".to_string(),
894            BorrowedContentSource::DerefMutableRef => {
895                bug!("describe_for_immutable_place: DerefMutableRef isn't immutable")
896            }
897            BorrowedContentSource::OverloadedDeref(ty) => ty
898                .ty_adt_def()
899                .and_then(|adt| match tcx.get_diagnostic_name(adt.did())? {
900                    name @ (sym::Rc | sym::Arc) => Some(format!("an `{name}`")),
901                    _ => None,
902                })
903                .unwrap_or_else(|| format!("dereference of `{ty}`")),
904            BorrowedContentSource::OverloadedIndex(ty) => format!("an index of `{ty}`"),
905        }
906    }
907
908    fn from_call(func: Ty<'tcx>, tcx: TyCtxt<'tcx>) -> Option<Self> {
909        match *func.kind() {
910            ty::FnDef(def_id, args) => {
911                let trait_id = tcx.trait_of_item(def_id)?;
912
913                if tcx.is_lang_item(trait_id, LangItem::Deref)
914                    || tcx.is_lang_item(trait_id, LangItem::DerefMut)
915                {
916                    Some(BorrowedContentSource::OverloadedDeref(args.type_at(0)))
917                } else if tcx.is_lang_item(trait_id, LangItem::Index)
918                    || tcx.is_lang_item(trait_id, LangItem::IndexMut)
919                {
920                    Some(BorrowedContentSource::OverloadedIndex(args.type_at(0)))
921                } else {
922                    None
923                }
924            }
925            _ => None,
926        }
927    }
928}
929
930/// Helper struct for `explain_captures`.
931struct CapturedMessageOpt {
932    is_partial_move: bool,
933    is_loop_message: bool,
934    is_move_msg: bool,
935    is_loop_move: bool,
936    has_suggest_reborrow: bool,
937    maybe_reinitialized_locations_is_empty: bool,
938}
939
940impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
941    /// Finds the spans associated to a move or copy of move_place at location.
942    pub(super) fn move_spans(
943        &self,
944        moved_place: PlaceRef<'tcx>, // Could also be an upvar.
945        location: Location,
946    ) -> UseSpans<'tcx> {
947        use self::UseSpans::*;
948
949        let Some(stmt) = self.body[location.block].statements.get(location.statement_index) else {
950            return OtherUse(self.body.source_info(location).span);
951        };
952
953        debug!("move_spans: moved_place={:?} location={:?} stmt={:?}", moved_place, location, stmt);
954        if let StatementKind::Assign(box (_, Rvalue::Aggregate(kind, places))) = &stmt.kind
955            && let AggregateKind::Closure(def_id, _) | AggregateKind::Coroutine(def_id, _) = **kind
956        {
957            debug!("move_spans: def_id={:?} places={:?}", def_id, places);
958            let def_id = def_id.expect_local();
959            if let Some((args_span, closure_kind, capture_kind_span, path_span)) =
960                self.closure_span(def_id, moved_place, places)
961            {
962                return ClosureUse { closure_kind, args_span, capture_kind_span, path_span };
963            }
964        }
965
966        // StatementKind::FakeRead only contains a def_id if they are introduced as a result
967        // of pattern matching within a closure.
968        if let StatementKind::FakeRead(box (cause, place)) = stmt.kind {
969            match cause {
970                FakeReadCause::ForMatchedPlace(Some(closure_def_id))
971                | FakeReadCause::ForLet(Some(closure_def_id)) => {
972                    debug!("move_spans: def_id={:?} place={:?}", closure_def_id, place);
973                    let places = &[Operand::Move(place)];
974                    if let Some((args_span, closure_kind, capture_kind_span, path_span)) =
975                        self.closure_span(closure_def_id, moved_place, IndexSlice::from_raw(places))
976                    {
977                        return ClosureUse {
978                            closure_kind,
979                            args_span,
980                            capture_kind_span,
981                            path_span,
982                        };
983                    }
984                }
985                _ => {}
986            }
987        }
988
989        let normal_ret =
990            if moved_place.projection.iter().any(|p| matches!(p, ProjectionElem::Downcast(..))) {
991                PatUse(stmt.source_info.span)
992            } else {
993                OtherUse(stmt.source_info.span)
994            };
995
996        // We are trying to find MIR of the form:
997        // ```
998        // _temp = _moved_val;
999        // ...
1000        // FnSelfCall(_temp, ...)
1001        // ```
1002        //
1003        // where `_moved_val` is the place we generated the move error for,
1004        // `_temp` is some other local, and `FnSelfCall` is a function
1005        // that has a `self` parameter.
1006
1007        let target_temp = match stmt.kind {
1008            StatementKind::Assign(box (temp, _)) if temp.as_local().is_some() => {
1009                temp.as_local().unwrap()
1010            }
1011            _ => return normal_ret,
1012        };
1013
1014        debug!("move_spans: target_temp = {:?}", target_temp);
1015
1016        if let Some(Terminator {
1017            kind: TerminatorKind::Call { fn_span, call_source, .. }, ..
1018        }) = &self.body[location.block].terminator
1019        {
1020            let Some((method_did, method_args)) =
1021                find_self_call(self.infcx.tcx, self.body, target_temp, location.block)
1022            else {
1023                return normal_ret;
1024            };
1025
1026            let kind = call_kind(
1027                self.infcx.tcx,
1028                self.infcx.typing_env(self.infcx.param_env),
1029                method_did,
1030                method_args,
1031                *fn_span,
1032                call_source.from_hir_call(),
1033                Some(self.infcx.tcx.fn_arg_names(method_did)[0]),
1034            );
1035
1036            return FnSelfUse {
1037                var_span: stmt.source_info.span,
1038                fn_call_span: *fn_span,
1039                fn_span: self.infcx.tcx.def_span(method_did),
1040                kind,
1041            };
1042        }
1043
1044        normal_ret
1045    }
1046
1047    /// Finds the span of arguments of a closure (within `maybe_closure_span`)
1048    /// and its usage of the local assigned at `location`.
1049    /// This is done by searching in statements succeeding `location`
1050    /// and originating from `maybe_closure_span`.
1051    pub(super) fn borrow_spans(&self, use_span: Span, location: Location) -> UseSpans<'tcx> {
1052        use self::UseSpans::*;
1053        debug!("borrow_spans: use_span={:?} location={:?}", use_span, location);
1054
1055        let target = match self.body[location.block].statements.get(location.statement_index) {
1056            Some(Statement { kind: StatementKind::Assign(box (place, _)), .. }) => {
1057                if let Some(local) = place.as_local() {
1058                    local
1059                } else {
1060                    return OtherUse(use_span);
1061                }
1062            }
1063            _ => return OtherUse(use_span),
1064        };
1065
1066        if self.body.local_kind(target) != LocalKind::Temp {
1067            // operands are always temporaries.
1068            return OtherUse(use_span);
1069        }
1070
1071        // drop and replace might have moved the assignment to the next block
1072        let maybe_additional_statement =
1073            if let TerminatorKind::Drop { target: drop_target, .. } =
1074                self.body[location.block].terminator().kind
1075            {
1076                self.body[drop_target].statements.first()
1077            } else {
1078                None
1079            };
1080
1081        let statements =
1082            self.body[location.block].statements[location.statement_index + 1..].iter();
1083
1084        for stmt in statements.chain(maybe_additional_statement) {
1085            if let StatementKind::Assign(box (_, Rvalue::Aggregate(kind, places))) = &stmt.kind {
1086                let (&def_id, is_coroutine) = match kind {
1087                    box AggregateKind::Closure(def_id, _) => (def_id, false),
1088                    box AggregateKind::Coroutine(def_id, _) => (def_id, true),
1089                    _ => continue,
1090                };
1091                let def_id = def_id.expect_local();
1092
1093                debug!(
1094                    "borrow_spans: def_id={:?} is_coroutine={:?} places={:?}",
1095                    def_id, is_coroutine, places
1096                );
1097                if let Some((args_span, closure_kind, capture_kind_span, path_span)) =
1098                    self.closure_span(def_id, Place::from(target).as_ref(), places)
1099                {
1100                    return ClosureUse { closure_kind, args_span, capture_kind_span, path_span };
1101                } else {
1102                    return OtherUse(use_span);
1103                }
1104            }
1105
1106            if use_span != stmt.source_info.span {
1107                break;
1108            }
1109        }
1110
1111        OtherUse(use_span)
1112    }
1113
1114    /// Finds the spans of a captured place within a closure or coroutine.
1115    /// The first span is the location of the use resulting in the capture kind of the capture
1116    /// The second span is the location the use resulting in the captured path of the capture
1117    fn closure_span(
1118        &self,
1119        def_id: LocalDefId,
1120        target_place: PlaceRef<'tcx>,
1121        places: &IndexSlice<FieldIdx, Operand<'tcx>>,
1122    ) -> Option<(Span, hir::ClosureKind, Span, Span)> {
1123        debug!(
1124            "closure_span: def_id={:?} target_place={:?} places={:?}",
1125            def_id, target_place, places
1126        );
1127        let hir_id = self.infcx.tcx.local_def_id_to_hir_id(def_id);
1128        let expr = &self.infcx.tcx.hir().expect_expr(hir_id).kind;
1129        debug!("closure_span: hir_id={:?} expr={:?}", hir_id, expr);
1130        if let hir::ExprKind::Closure(&hir::Closure { kind, fn_decl_span, .. }) = expr {
1131            for (captured_place, place) in
1132                self.infcx.tcx.closure_captures(def_id).iter().zip(places)
1133            {
1134                match place {
1135                    Operand::Copy(place) | Operand::Move(place)
1136                        if target_place == place.as_ref() =>
1137                    {
1138                        debug!("closure_span: found captured local {:?}", place);
1139                        return Some((
1140                            fn_decl_span,
1141                            kind,
1142                            captured_place.get_capture_kind_span(self.infcx.tcx),
1143                            captured_place.get_path_span(self.infcx.tcx),
1144                        ));
1145                    }
1146                    _ => {}
1147                }
1148            }
1149        }
1150        None
1151    }
1152
1153    /// Helper to retrieve span(s) of given borrow from the current MIR
1154    /// representation
1155    pub(super) fn retrieve_borrow_spans(&self, borrow: &BorrowData<'_>) -> UseSpans<'tcx> {
1156        let span = self.body.source_info(borrow.reserve_location).span;
1157        self.borrow_spans(span, borrow.reserve_location)
1158    }
1159
1160    #[allow(rustc::diagnostic_outside_of_impl)]
1161    #[allow(rustc::untranslatable_diagnostic)] // FIXME: make this translatable
1162    fn explain_captures(
1163        &mut self,
1164        err: &mut Diag<'infcx>,
1165        span: Span,
1166        move_span: Span,
1167        move_spans: UseSpans<'tcx>,
1168        moved_place: Place<'tcx>,
1169        msg_opt: CapturedMessageOpt,
1170    ) {
1171        let CapturedMessageOpt {
1172            is_partial_move: is_partial,
1173            is_loop_message,
1174            is_move_msg,
1175            is_loop_move,
1176            has_suggest_reborrow,
1177            maybe_reinitialized_locations_is_empty,
1178        } = msg_opt;
1179        if let UseSpans::FnSelfUse { var_span, fn_call_span, fn_span, kind } = move_spans {
1180            let place_name = self
1181                .describe_place(moved_place.as_ref())
1182                .map(|n| format!("`{n}`"))
1183                .unwrap_or_else(|| "value".to_owned());
1184            match kind {
1185                CallKind::FnCall { fn_trait_id, self_ty }
1186                    if self.infcx.tcx.is_lang_item(fn_trait_id, LangItem::FnOnce) =>
1187                {
1188                    err.subdiagnostic(CaptureReasonLabel::Call {
1189                        fn_call_span,
1190                        place_name: &place_name,
1191                        is_partial,
1192                        is_loop_message,
1193                    });
1194                    // Check if the move occurs on a value because of a call on a closure that comes
1195                    // from a type parameter `F: FnOnce()`. If so, we provide a targeted `note`:
1196                    // ```
1197                    // error[E0382]: use of moved value: `blk`
1198                    //   --> $DIR/once-cant-call-twice-on-heap.rs:8:5
1199                    //    |
1200                    // LL | fn foo<F:FnOnce()>(blk: F) {
1201                    //    |                    --- move occurs because `blk` has type `F`, which does not implement the `Copy` trait
1202                    // LL | blk();
1203                    //    | ----- `blk` moved due to this call
1204                    // LL | blk();
1205                    //    | ^^^ value used here after move
1206                    //    |
1207                    // note: `FnOnce` closures can only be called once
1208                    //   --> $DIR/once-cant-call-twice-on-heap.rs:6:10
1209                    //    |
1210                    // LL | fn foo<F:FnOnce()>(blk: F) {
1211                    //    |        ^^^^^^^^ `F` is made to be an `FnOnce` closure here
1212                    // LL | blk();
1213                    //    | ----- this value implements `FnOnce`, which causes it to be moved when called
1214                    // ```
1215                    if let ty::Param(param_ty) = *self_ty.kind()
1216                        && let generics = self.infcx.tcx.generics_of(self.mir_def_id())
1217                        && let param = generics.type_param(param_ty, self.infcx.tcx)
1218                        && let Some(hir_generics) = self
1219                            .infcx
1220                            .tcx
1221                            .typeck_root_def_id(self.mir_def_id().to_def_id())
1222                            .as_local()
1223                            .and_then(|def_id| self.infcx.tcx.hir().get_generics(def_id))
1224                        && let spans = hir_generics
1225                            .predicates
1226                            .iter()
1227                            .filter_map(|pred| match pred.kind {
1228                                hir::WherePredicateKind::BoundPredicate(pred) => Some(pred),
1229                                _ => None,
1230                            })
1231                            .filter(|pred| {
1232                                if let Some((id, _)) = pred.bounded_ty.as_generic_param() {
1233                                    id == param.def_id
1234                                } else {
1235                                    false
1236                                }
1237                            })
1238                            .flat_map(|pred| pred.bounds)
1239                            .filter_map(|bound| {
1240                                if let Some(trait_ref) = bound.trait_ref()
1241                                    && let Some(trait_def_id) = trait_ref.trait_def_id()
1242                                    && trait_def_id == fn_trait_id
1243                                {
1244                                    Some(bound.span())
1245                                } else {
1246                                    None
1247                                }
1248                            })
1249                            .collect::<Vec<Span>>()
1250                        && !spans.is_empty()
1251                    {
1252                        let mut span: MultiSpan = spans.clone().into();
1253                        for sp in spans {
1254                            span.push_span_label(sp, fluent::borrowck_moved_a_fn_once_in_call_def);
1255                        }
1256                        span.push_span_label(
1257                            fn_call_span,
1258                            fluent::borrowck_moved_a_fn_once_in_call,
1259                        );
1260                        err.span_note(span, fluent::borrowck_moved_a_fn_once_in_call_call);
1261                    } else {
1262                        err.subdiagnostic(CaptureReasonNote::FnOnceMoveInCall { var_span });
1263                    }
1264                }
1265                CallKind::Operator { self_arg, trait_id, .. } => {
1266                    let self_arg = self_arg.unwrap();
1267                    err.subdiagnostic(CaptureReasonLabel::OperatorUse {
1268                        fn_call_span,
1269                        place_name: &place_name,
1270                        is_partial,
1271                        is_loop_message,
1272                    });
1273                    if self.fn_self_span_reported.insert(fn_span) {
1274                        let lang = self.infcx.tcx.lang_items();
1275                        err.subdiagnostic(
1276                            if [lang.not_trait(), lang.deref_trait(), lang.neg_trait()]
1277                                .contains(&Some(trait_id))
1278                            {
1279                                CaptureReasonNote::UnOpMoveByOperator { span: self_arg.span }
1280                            } else {
1281                                CaptureReasonNote::LhsMoveByOperator { span: self_arg.span }
1282                            },
1283                        );
1284                    }
1285                }
1286                CallKind::Normal { self_arg, desugaring, method_did, method_args } => {
1287                    let self_arg = self_arg.unwrap();
1288                    let mut has_sugg = false;
1289                    let tcx = self.infcx.tcx;
1290                    // Avoid pointing to the same function in multiple different
1291                    // error messages.
1292                    if span != DUMMY_SP && self.fn_self_span_reported.insert(self_arg.span) {
1293                        self.explain_iterator_advancement_in_for_loop_if_applicable(
1294                            err,
1295                            span,
1296                            &move_spans,
1297                        );
1298
1299                        let func = tcx.def_path_str(method_did);
1300                        err.subdiagnostic(CaptureReasonNote::FuncTakeSelf {
1301                            func,
1302                            place_name: place_name.clone(),
1303                            span: self_arg.span,
1304                        });
1305                    }
1306                    let parent_did = tcx.parent(method_did);
1307                    let parent_self_ty =
1308                        matches!(tcx.def_kind(parent_did), rustc_hir::def::DefKind::Impl { .. })
1309                            .then_some(parent_did)
1310                            .and_then(|did| match tcx.type_of(did).instantiate_identity().kind() {
1311                                ty::Adt(def, ..) => Some(def.did()),
1312                                _ => None,
1313                            });
1314                    let is_option_or_result = parent_self_ty.is_some_and(|def_id| {
1315                        matches!(tcx.get_diagnostic_name(def_id), Some(sym::Option | sym::Result))
1316                    });
1317                    if is_option_or_result && maybe_reinitialized_locations_is_empty {
1318                        err.subdiagnostic(CaptureReasonLabel::BorrowContent { var_span });
1319                    }
1320                    if let Some((CallDesugaringKind::ForLoopIntoIter, _)) = desugaring {
1321                        let ty = moved_place.ty(self.body, tcx).ty;
1322                        let suggest = match tcx.get_diagnostic_item(sym::IntoIterator) {
1323                            Some(def_id) => type_known_to_meet_bound_modulo_regions(
1324                                self.infcx,
1325                                self.infcx.param_env,
1326                                Ty::new_imm_ref(tcx, tcx.lifetimes.re_erased, ty),
1327                                def_id,
1328                            ),
1329                            _ => false,
1330                        };
1331                        if suggest {
1332                            err.subdiagnostic(CaptureReasonSuggest::IterateSlice {
1333                                ty,
1334                                span: move_span.shrink_to_lo(),
1335                            });
1336                        }
1337
1338                        err.subdiagnostic(CaptureReasonLabel::ImplicitCall {
1339                            fn_call_span,
1340                            place_name: &place_name,
1341                            is_partial,
1342                            is_loop_message,
1343                        });
1344                        // If the moved place was a `&mut` ref, then we can
1345                        // suggest to reborrow it where it was moved, so it
1346                        // will still be valid by the time we get to the usage.
1347                        if let ty::Ref(_, _, hir::Mutability::Mut) =
1348                            moved_place.ty(self.body, self.infcx.tcx).ty.kind()
1349                        {
1350                            // Suggest `reborrow` in other place for following situations:
1351                            // 1. If we are in a loop this will be suggested later.
1352                            // 2. If the moved value is a mut reference, it is used in a
1353                            // generic function and the corresponding arg's type is generic param.
1354                            if !is_loop_move && !has_suggest_reborrow {
1355                                self.suggest_reborrow(
1356                                    err,
1357                                    move_span.shrink_to_lo(),
1358                                    moved_place.as_ref(),
1359                                );
1360                            }
1361                        }
1362                    } else {
1363                        if let Some((CallDesugaringKind::Await, _)) = desugaring {
1364                            err.subdiagnostic(CaptureReasonLabel::Await {
1365                                fn_call_span,
1366                                place_name: &place_name,
1367                                is_partial,
1368                                is_loop_message,
1369                            });
1370                        } else {
1371                            err.subdiagnostic(CaptureReasonLabel::MethodCall {
1372                                fn_call_span,
1373                                place_name: &place_name,
1374                                is_partial,
1375                                is_loop_message,
1376                            });
1377                        }
1378                        // Erase and shadow everything that could be passed to the new infcx.
1379                        let ty = moved_place.ty(self.body, tcx).ty;
1380
1381                        if let ty::Adt(def, args) = ty.peel_refs().kind()
1382                            && tcx.is_lang_item(def.did(), LangItem::Pin)
1383                            && let ty::Ref(_, _, hir::Mutability::Mut) = args.type_at(0).kind()
1384                            && let self_ty = self.infcx.instantiate_binder_with_fresh_vars(
1385                                fn_call_span,
1386                                BoundRegionConversionTime::FnCall,
1387                                tcx.fn_sig(method_did).instantiate(tcx, method_args).input(0),
1388                            )
1389                            && self.infcx.can_eq(self.infcx.param_env, ty, self_ty)
1390                        {
1391                            err.subdiagnostic(CaptureReasonSuggest::FreshReborrow {
1392                                span: move_span.shrink_to_hi(),
1393                            });
1394                            has_sugg = true;
1395                        }
1396                        if let Some(clone_trait) = tcx.lang_items().clone_trait() {
1397                            let sugg = if moved_place
1398                                .iter_projections()
1399                                .any(|(_, elem)| matches!(elem, ProjectionElem::Deref))
1400                            {
1401                                let (start, end) = if let Some(expr) = self.find_expr(move_span)
1402                                    && let Some(_) = self.clone_on_reference(expr)
1403                                    && let hir::ExprKind::MethodCall(_, rcvr, _, _) = expr.kind
1404                                {
1405                                    (move_span.shrink_to_lo(), move_span.with_lo(rcvr.span.hi()))
1406                                } else {
1407                                    (move_span.shrink_to_lo(), move_span.shrink_to_hi())
1408                                };
1409                                vec![
1410                                    // We use the fully-qualified path because `.clone()` can
1411                                    // sometimes choose `<&T as Clone>` instead of `<T as Clone>`
1412                                    // when going through auto-deref, so this ensures that doesn't
1413                                    // happen, causing suggestions for `.clone().clone()`.
1414                                    (start, format!("<{ty} as Clone>::clone(&")),
1415                                    (end, ")".to_string()),
1416                                ]
1417                            } else {
1418                                vec![(move_span.shrink_to_hi(), ".clone()".to_string())]
1419                            };
1420                            if let Some(errors) = self.infcx.type_implements_trait_shallow(
1421                                clone_trait,
1422                                ty,
1423                                self.infcx.param_env,
1424                            ) && !has_sugg
1425                            {
1426                                let msg = match &errors[..] {
1427                                    [] => "you can `clone` the value and consume it, but this \
1428                                           might not be your desired behavior"
1429                                        .to_string(),
1430                                    [error] => {
1431                                        format!(
1432                                            "you could `clone` the value and consume it, if the \
1433                                             `{}` trait bound could be satisfied",
1434                                            error.obligation.predicate,
1435                                        )
1436                                    }
1437                                    _ => {
1438                                        format!(
1439                                            "you could `clone` the value and consume it, if the \
1440                                             following trait bounds could be satisfied: {}",
1441                                            listify(&errors, |e: &FulfillmentError<'tcx>| format!(
1442                                                "`{}`",
1443                                                e.obligation.predicate
1444                                            ))
1445                                            .unwrap(),
1446                                        )
1447                                    }
1448                                };
1449                                err.multipart_suggestion_verbose(
1450                                    msg,
1451                                    sugg,
1452                                    Applicability::MaybeIncorrect,
1453                                );
1454                                for error in errors {
1455                                    if let FulfillmentErrorCode::Select(
1456                                        SelectionError::Unimplemented,
1457                                    ) = error.code
1458                                        && let ty::PredicateKind::Clause(ty::ClauseKind::Trait(
1459                                            pred,
1460                                        )) = error.obligation.predicate.kind().skip_binder()
1461                                    {
1462                                        self.infcx.err_ctxt().suggest_derive(
1463                                            &error.obligation,
1464                                            err,
1465                                            error.obligation.predicate.kind().rebind(pred),
1466                                        );
1467                                    }
1468                                }
1469                            }
1470                        }
1471                    }
1472                }
1473                // Other desugarings takes &self, which cannot cause a move
1474                _ => {}
1475            }
1476        } else {
1477            if move_span != span || is_loop_message {
1478                err.subdiagnostic(CaptureReasonLabel::MovedHere {
1479                    move_span,
1480                    is_partial,
1481                    is_move_msg,
1482                    is_loop_message,
1483                });
1484            }
1485            // If the move error occurs due to a loop, don't show
1486            // another message for the same span
1487            if !is_loop_message {
1488                move_spans.var_subdiag(err, None, |kind, var_span| match kind {
1489                    hir::ClosureKind::Coroutine(_) => {
1490                        CaptureVarCause::PartialMoveUseInCoroutine { var_span, is_partial }
1491                    }
1492                    hir::ClosureKind::Closure | hir::ClosureKind::CoroutineClosure(_) => {
1493                        CaptureVarCause::PartialMoveUseInClosure { var_span, is_partial }
1494                    }
1495                })
1496            }
1497        }
1498    }
1499}