]> git.proxmox.com Git - rustc.git/blobdiff - compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
New upstream version 1.61.0+dfsg1
[rustc.git] / compiler / rustc_borrowck / src / diagnostics / conflict_errors.rs
index fce5ed0ef42390539b10fbdc8d97373ab3269061..883f711b201a97c837faab91470a18378fb08656 100644 (file)
@@ -1,20 +1,23 @@
 use either::Either;
-use rustc_const_eval::util::{CallDesugaringKind, CallKind};
+use rustc_const_eval::util::CallKind;
 use rustc_data_structures::fx::FxHashSet;
-use rustc_errors::{Applicability, DiagnosticBuilder};
+use rustc_errors::{Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed};
 use rustc_hir as hir;
 use rustc_hir::def_id::DefId;
 use rustc_hir::{AsyncGeneratorKind, GeneratorKind};
+use rustc_infer::infer::TyCtxtInferExt;
+use rustc_infer::traits::ObligationCause;
 use rustc_middle::mir::{
     self, AggregateKind, BindingForm, BorrowKind, ClearCrossCrate, ConstraintCategory,
     FakeReadCause, LocalDecl, LocalInfo, LocalKind, Location, Operand, Place, PlaceRef,
     ProjectionElem, Rvalue, Statement, StatementKind, Terminator, TerminatorKind, VarBindingForm,
 };
-use rustc_middle::ty::{self, suggest_constraining_type_param, Ty};
+use rustc_middle::ty::{self, subst::Subst, suggest_constraining_type_params, PredicateKind, Ty};
 use rustc_mir_dataflow::move_paths::{InitKind, MoveOutIndex, MovePathIndex};
 use rustc_span::symbol::sym;
-use rustc_span::{BytePos, MultiSpan, Span, DUMMY_SP};
+use rustc_span::{BytePos, MultiSpan, Span};
 use rustc_trait_selection::infer::InferCtxtExt;
+use rustc_trait_selection::traits::TraitEngineExt as _;
 
 use crate::borrow_set::TwoPhaseActivation;
 use crate::borrowck_errors;
@@ -148,6 +151,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
                         .args_or_use()
                 })
                 .collect::<Vec<Span>>();
+
             let reinits = maybe_reinitialized_locations.len();
             if reinits == 1 {
                 err.span_label(reinit_spans[0], "this reinitialization might get skipped");
@@ -190,144 +194,19 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
                     is_loop_move = true;
                 }
 
-                if let UseSpans::FnSelfUse { var_span, fn_call_span, fn_span, kind } = move_spans {
-                    let place_name = self
-                        .describe_place(moved_place.as_ref())
-                        .map(|n| format!("`{}`", n))
-                        .unwrap_or_else(|| "value".to_owned());
-                    match kind {
-                        CallKind::FnCall { fn_trait_id, .. }
-                            if Some(fn_trait_id) == self.infcx.tcx.lang_items().fn_once_trait() =>
-                        {
-                            err.span_label(
-                                fn_call_span,
-                                &format!(
-                                    "{} {}moved due to this call{}",
-                                    place_name, partially_str, loop_message
-                                ),
-                            );
-                            err.span_note(
-                                var_span,
-                                "this value implements `FnOnce`, which causes it to be moved when called",
-                            );
-                        }
-                        CallKind::Operator { self_arg, .. } => {
-                            let self_arg = self_arg.unwrap();
-                            err.span_label(
-                                fn_call_span,
-                                &format!(
-                                    "{} {}moved due to usage in operator{}",
-                                    place_name, partially_str, loop_message
-                                ),
-                            );
-                            if self.fn_self_span_reported.insert(fn_span) {
-                                err.span_note(
-                                    // Check whether the source is accessible
-                                    if self
-                                        .infcx
-                                        .tcx
-                                        .sess
-                                        .source_map()
-                                        .span_to_snippet(self_arg.span)
-                                        .is_ok()
-                                    {
-                                        self_arg.span
-                                    } else {
-                                        fn_call_span
-                                    },
-                                    "calling this operator moves the left-hand side",
-                                );
-                            }
-                        }
-                        CallKind::Normal { self_arg, desugaring, is_option_or_result } => {
-                            let self_arg = self_arg.unwrap();
-                            if let Some((CallDesugaringKind::ForLoopIntoIter, _)) = desugaring {
-                                err.span_label(
-                                    fn_call_span,
-                                    &format!(
-                                        "{} {}moved due to this implicit call to `.into_iter()`{}",
-                                        place_name, partially_str, loop_message
-                                    ),
-                                );
-                                let sess = self.infcx.tcx.sess;
-                                let ty = used_place.ty(self.body, self.infcx.tcx).ty;
-                                // If we have a `&mut` ref, we need to reborrow.
-                                if let ty::Ref(_, _, hir::Mutability::Mut) = ty.kind() {
-                                    // If we are in a loop this will be suggested later.
-                                    if !is_loop_move {
-                                        err.span_suggestion_verbose(
-                                            move_span.shrink_to_lo(),
-                                            &format!(
-                                                "consider creating a fresh reborrow of {} here",
-                                                self.describe_place(moved_place.as_ref())
-                                                    .map(|n| format!("`{}`", n))
-                                                    .unwrap_or_else(
-                                                        || "the mutable reference".to_string()
-                                                    ),
-                                            ),
-                                            "&mut *".to_string(),
-                                            Applicability::MachineApplicable,
-                                        );
-                                    }
-                                } else if let Ok(snippet) =
-                                    sess.source_map().span_to_snippet(move_span)
-                                {
-                                    err.span_suggestion(
-                                        move_span,
-                                        "consider borrowing to avoid moving into the for loop",
-                                        format!("&{}", snippet),
-                                        Applicability::MaybeIncorrect,
-                                    );
-                                }
-                            } else {
-                                err.span_label(
-                                    fn_call_span,
-                                    &format!(
-                                        "{} {}moved due to this method call{}",
-                                        place_name, partially_str, loop_message
-                                    ),
-                                );
-                            }
-                            if is_option_or_result && maybe_reinitialized_locations.is_empty() {
-                                err.span_suggestion_verbose(
-                                    fn_call_span.shrink_to_lo(),
-                                    "consider calling `.as_ref()` to borrow the type's contents",
-                                    "as_ref().".to_string(),
-                                    Applicability::MachineApplicable,
-                                );
-                            }
-                            // Avoid pointing to the same function in multiple different
-                            // error messages.
-                            if span != DUMMY_SP && self.fn_self_span_reported.insert(self_arg.span)
-                            {
-                                err.span_note(
-                                        self_arg.span,
-                                        &format!("this function takes ownership of the receiver `self`, which moves {}", place_name)
-                                    );
-                            }
-                        }
-                        // Other desugarings takes &self, which cannot cause a move
-                        _ => unreachable!(),
-                    }
-                } else {
-                    err.span_label(
-                        move_span,
-                        format!("value {}moved{} here{}", partially_str, move_msg, loop_message),
-                    );
-                    // If the move error occurs due to a loop, don't show
-                    // another message for the same span
-                    if loop_message.is_empty() {
-                        move_spans.var_span_label(
-                            &mut err,
-                            format!(
-                                "variable {}moved due to use{}",
-                                partially_str,
-                                move_spans.describe()
-                            ),
-                            "moved",
-                        );
-                    }
-                }
+                self.explain_captures(
+                    &mut err,
+                    span,
+                    move_span,
+                    move_spans,
+                    *moved_place,
+                    Some(used_place),
+                    partially_str,
+                    loop_message,
+                    move_msg,
+                    is_loop_move,
+                    maybe_reinitialized_locations.is_empty(),
+                );
 
                 if let (UseSpans::PatUse(span), []) =
                     (move_spans, &maybe_reinitialized_locations[..])
@@ -398,35 +277,23 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
                 }
             }
 
+            let opt_name =
+                self.describe_place_with_options(place.as_ref(), IncludingDowncast(true));
+            let note_msg = match opt_name {
+                Some(ref name) => format!("`{}`", name),
+                None => "value".to_owned(),
+            };
+            if self.suggest_borrow_fn_like(&mut err, ty, &move_site_vec, &note_msg) {
+                // Suppress the next suggestion since we don't want to put more bounds onto
+                // something that already has `Fn`-like bounds (or is a closure), so we can't
+                // restrict anyways.
+            } else {
+                self.suggest_adding_copy_bounds(&mut err, ty, span);
+            }
+
             if needs_note {
-                let opt_name =
-                    self.describe_place_with_options(place.as_ref(), IncludingDowncast(true));
-                let note_msg = match opt_name {
-                    Some(ref name) => format!("`{}`", name),
-                    None => "value".to_owned(),
-                };
-                if let ty::Param(param_ty) = ty.kind() {
-                    let tcx = self.infcx.tcx;
-                    let generics = tcx.generics_of(self.mir_def_id());
-                    let param = generics.type_param(&param_ty, tcx);
-                    if let Some(generics) = tcx
-                        .typeck_root_def_id(self.mir_def_id().to_def_id())
-                        .as_local()
-                        .and_then(|def_id| tcx.hir().get_generics(def_id))
-                    {
-                        suggest_constraining_type_param(
-                            tcx,
-                            generics,
-                            &mut err,
-                            param.name.as_str(),
-                            "Copy",
-                            None,
-                        );
-                    }
-                }
                 let span = if let Some(local) = place.as_local() {
-                    let decl = &self.body.local_decls[local];
-                    Some(decl.source_info.span)
+                    Some(self.body.local_decls[local].source_info.span)
                 } else {
                     None
                 };
@@ -454,6 +321,144 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
         }
     }
 
+    fn suggest_borrow_fn_like(
+        &self,
+        err: &mut DiagnosticBuilder<'tcx, ErrorGuaranteed>,
+        ty: Ty<'tcx>,
+        move_sites: &[MoveSite],
+        value_name: &str,
+    ) -> bool {
+        let tcx = self.infcx.tcx;
+
+        // Find out if the predicates show that the type is a Fn or FnMut
+        let find_fn_kind_from_did = |predicates: &[(ty::Predicate<'tcx>, Span)], substs| {
+            predicates.iter().find_map(|(pred, _)| {
+                let pred = if let Some(substs) = substs {
+                    pred.subst(tcx, substs).kind().skip_binder()
+                } else {
+                    pred.kind().skip_binder()
+                };
+                if let ty::PredicateKind::Trait(pred) = pred && pred.self_ty() == ty {
+                    if Some(pred.def_id()) == tcx.lang_items().fn_trait() {
+                        return Some(hir::Mutability::Not);
+                    } else if Some(pred.def_id()) == tcx.lang_items().fn_mut_trait() {
+                        return Some(hir::Mutability::Mut);
+                    }
+                }
+                None
+            })
+        };
+
+        // If the type is opaque/param/closure, and it is Fn or FnMut, let's suggest (mutably)
+        // borrowing the type, since `&mut F: FnMut` iff `F: FnMut` and similarly for `Fn`.
+        // These types seem reasonably opaque enough that they could be substituted with their
+        // borrowed variants in a function body when we see a move error.
+        let borrow_level = match ty.kind() {
+            ty::Param(_) => find_fn_kind_from_did(
+                tcx.explicit_predicates_of(self.mir_def_id().to_def_id()).predicates,
+                None,
+            ),
+            ty::Opaque(did, substs) => {
+                find_fn_kind_from_did(tcx.explicit_item_bounds(*did), Some(*substs))
+            }
+            ty::Closure(_, substs) => match substs.as_closure().kind() {
+                ty::ClosureKind::Fn => Some(hir::Mutability::Not),
+                ty::ClosureKind::FnMut => Some(hir::Mutability::Mut),
+                _ => None,
+            },
+            _ => None,
+        };
+
+        let Some(borrow_level) = borrow_level else { return false; };
+        let sugg = move_sites
+            .iter()
+            .map(|move_site| {
+                let move_out = self.move_data.moves[(*move_site).moi];
+                let moved_place = &self.move_data.move_paths[move_out.path].place;
+                let move_spans = self.move_spans(moved_place.as_ref(), move_out.source);
+                let move_span = move_spans.args_or_use();
+                let suggestion = if borrow_level == hir::Mutability::Mut {
+                    "&mut ".to_string()
+                } else {
+                    "&".to_string()
+                };
+                (move_span.shrink_to_lo(), suggestion)
+            })
+            .collect();
+        err.multipart_suggestion_verbose(
+            &format!(
+                "consider {}borrowing {value_name}",
+                if borrow_level == hir::Mutability::Mut { "mutably " } else { "" }
+            ),
+            sugg,
+            Applicability::MaybeIncorrect,
+        );
+        true
+    }
+
+    fn suggest_adding_copy_bounds(
+        &self,
+        err: &mut DiagnosticBuilder<'tcx, ErrorGuaranteed>,
+        ty: Ty<'tcx>,
+        span: Span,
+    ) {
+        let tcx = self.infcx.tcx;
+        let generics = tcx.generics_of(self.mir_def_id());
+
+        let Some(hir_generics) = tcx
+            .typeck_root_def_id(self.mir_def_id().to_def_id())
+            .as_local()
+            .and_then(|def_id| tcx.hir().get_generics(def_id))
+        else { return; };
+        // Try to find predicates on *generic params* that would allow copying `ty`
+        let predicates: Result<Vec<_>, _> = tcx.infer_ctxt().enter(|infcx| {
+            let mut fulfill_cx = <dyn rustc_infer::traits::TraitEngine<'_>>::new(infcx.tcx);
+
+            let copy_did = infcx.tcx.lang_items().copy_trait().unwrap();
+            let cause = ObligationCause::new(
+                span,
+                self.mir_hir_id(),
+                rustc_infer::traits::ObligationCauseCode::MiscObligation,
+            );
+            fulfill_cx.register_bound(
+                &infcx,
+                self.param_env,
+                // Erase any region vids from the type, which may not be resolved
+                infcx.tcx.erase_regions(ty),
+                copy_did,
+                cause,
+            );
+            // Select all, including ambiguous predicates
+            let errors = fulfill_cx.select_all_or_error(&infcx);
+
+            // Only emit suggestion if all required predicates are on generic
+            errors
+                .into_iter()
+                .map(|err| match err.obligation.predicate.kind().skip_binder() {
+                    PredicateKind::Trait(predicate) => match predicate.self_ty().kind() {
+                        ty::Param(param_ty) => Ok((
+                            generics.type_param(param_ty, tcx),
+                            predicate.trait_ref.print_only_trait_path().to_string(),
+                        )),
+                        _ => Err(()),
+                    },
+                    _ => Err(()),
+                })
+                .collect()
+        });
+
+        if let Ok(predicates) = predicates {
+            suggest_constraining_type_params(
+                tcx,
+                hir_generics,
+                err,
+                predicates
+                    .iter()
+                    .map(|(param, constraint)| (param.name.as_str(), &**constraint, None)),
+            );
+        }
+    }
+
     pub(crate) fn report_move_out_while_borrowed(
         &mut self,
         location: Location,
@@ -507,7 +512,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
         location: Location,
         (place, _span): (Place<'tcx>, Span),
         borrow: &BorrowData<'tcx>,
-    ) -> DiagnosticBuilder<'cx> {
+    ) -> DiagnosticBuilder<'cx, ErrorGuaranteed> {
         let borrow_spans = self.retrieve_borrow_spans(borrow);
         let borrow_span = borrow_spans.args_or_use();
 
@@ -554,7 +559,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
         (place, span): (Place<'tcx>, Span),
         gen_borrow_kind: BorrowKind,
         issued_borrow: &BorrowData<'tcx>,
-    ) -> DiagnosticBuilder<'cx> {
+    ) -> DiagnosticBuilder<'cx, ErrorGuaranteed> {
         let issued_spans = self.retrieve_borrow_spans(issued_borrow);
         let issued_span = issued_spans.args_or_use();
 
@@ -782,7 +787,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
     #[instrument(level = "debug", skip(self, err))]
     fn suggest_using_local_if_applicable(
         &self,
-        err: &mut DiagnosticBuilder<'_>,
+        err: &mut Diagnostic,
         location: Location,
         (place, span): (Place<'tcx>, Span),
         gen_borrow_kind: BorrowKind,
@@ -855,7 +860,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
 
     fn suggest_split_at_mut_if_applicable(
         &self,
-        err: &mut DiagnosticBuilder<'_>,
+        err: &mut Diagnostic,
         place: Place<'tcx>,
         borrowed_place: Place<'tcx>,
     ) {
@@ -1120,7 +1125,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
         drop_span: Span,
         borrow_spans: UseSpans<'tcx>,
         explanation: BorrowExplanation,
-    ) -> DiagnosticBuilder<'cx> {
+    ) -> DiagnosticBuilder<'cx, ErrorGuaranteed> {
         debug!(
             "report_local_value_does_not_live_long_enough(\
              {:?}, {:?}, {:?}, {:?}, {:?}\
@@ -1298,7 +1303,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
         &mut self,
         drop_span: Span,
         borrow_span: Span,
-    ) -> DiagnosticBuilder<'cx> {
+    ) -> DiagnosticBuilder<'cx, ErrorGuaranteed> {
         debug!(
             "report_thread_local_value_does_not_live_long_enough(\
              {:?}, {:?}\
@@ -1325,7 +1330,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
         borrow_spans: UseSpans<'tcx>,
         proper_span: Span,
         explanation: BorrowExplanation,
-    ) -> DiagnosticBuilder<'cx> {
+    ) -> DiagnosticBuilder<'cx, ErrorGuaranteed> {
         debug!(
             "report_temporary_value_does_not_live_long_enough(\
              {:?}, {:?}, {:?}, {:?}\
@@ -1384,7 +1389,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
         return_span: Span,
         category: ConstraintCategory,
         opt_place_desc: Option<&String>,
-    ) -> Option<DiagnosticBuilder<'cx>> {
+    ) -> Option<DiagnosticBuilder<'cx, ErrorGuaranteed>> {
         let return_kind = match category {
             ConstraintCategory::Return(_) => "return",
             ConstraintCategory::Yield => "yield",
@@ -1483,7 +1488,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
         category: ConstraintCategory,
         constraint_span: Span,
         captured_var: &str,
-    ) -> DiagnosticBuilder<'cx> {
+    ) -> DiagnosticBuilder<'cx, ErrorGuaranteed> {
         let tcx = self.infcx.tcx;
         let args_span = use_span.args_or_use();
 
@@ -1560,7 +1565,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
         upvar_span: Span,
         upvar_name: &str,
         escape_span: Span,
-    ) -> DiagnosticBuilder<'cx> {
+    ) -> DiagnosticBuilder<'cx, ErrorGuaranteed> {
         let tcx = self.infcx.tcx;
 
         let (_, escapes_from) = tcx.article_and_description(self.mir_def_id().to_def_id());
@@ -1835,7 +1840,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
         self.buffer_error(err);
     }
 
-    fn explain_deref_coercion(&mut self, loan: &BorrowData<'tcx>, err: &mut DiagnosticBuilder<'_>) {
+    fn explain_deref_coercion(&mut self, loan: &BorrowData<'tcx>, err: &mut Diagnostic) {
         let tcx = self.infcx.tcx;
         if let (
             Some(Terminator { kind: TerminatorKind::Call { from_hir_call: false, .. }, .. }),
@@ -1921,17 +1926,16 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
                 err.span_label(assigned_span, format!("first assignment to {}", place_description));
             }
         }
-        if let Some(decl) = local_decl {
-            if let Some(name) = local_name {
-                if decl.can_be_made_mutable() {
-                    err.span_suggestion(
-                        decl.source_info.span,
-                        "consider making this binding mutable",
-                        format!("mut {}", name),
-                        Applicability::MachineApplicable,
-                    );
-                }
-            }
+        if let Some(decl) = local_decl
+            && let Some(name) = local_name
+            && decl.can_be_made_mutable()
+        {
+            err.span_suggestion(
+                decl.source_info.span,
+                "consider making this binding mutable",
+                format!("mut {}", name),
+                Applicability::MachineApplicable,
+            );
         }
         err.span_label(span, msg);
         self.buffer_error(err);
@@ -2071,11 +2075,8 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
                         ) = rvalue
                         {
                             for operand in operands {
-                                let assigned_from = match operand {
-                                    Operand::Copy(assigned_from) | Operand::Move(assigned_from) => {
-                                        assigned_from
-                                    }
-                                    _ => continue,
+                                let (Operand::Copy(assigned_from) | Operand::Move(assigned_from)) = operand else {
+                                    continue;
                                 };
                                 debug!(
                                     "annotate_argument_and_return_for_borrow: assigned_from={:?}",
@@ -2083,10 +2084,8 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
                                 );
 
                                 // Find the local from the operand.
-                                let assigned_from_local = match assigned_from.local_or_deref_local()
-                                {
-                                    Some(local) => local,
-                                    None => continue,
+                                let Some(assigned_from_local) = assigned_from.local_or_deref_local() else {
+                                    continue;
                                 };
 
                                 if assigned_from_local != target {
@@ -2138,10 +2137,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
                         );
 
                         // Find the local from the rvalue.
-                        let assigned_from_local = match assigned_from.local_or_deref_local() {
-                            Some(local) => local,
-                            None => continue,
-                        };
+                        let Some(assigned_from_local) = assigned_from.local_or_deref_local() else { continue };
                         debug!(
                             "annotate_argument_and_return_for_borrow: \
                              assigned_from_local={:?}",
@@ -2189,11 +2185,8 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
                         assigned_to, args
                     );
                     for operand in args {
-                        let assigned_from = match operand {
-                            Operand::Copy(assigned_from) | Operand::Move(assigned_from) => {
-                                assigned_from
-                            }
-                            _ => continue,
+                        let (Operand::Copy(assigned_from) | Operand::Move(assigned_from)) = operand else {
+                            continue;
                         };
                         debug!(
                             "annotate_argument_and_return_for_borrow: assigned_from={:?}",
@@ -2309,7 +2302,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
                 // Closure arguments are wrapped in a tuple, so we need to get the first
                 // from that.
                 if let ty::Tuple(elems) = argument_ty.kind() {
-                    let argument_ty = elems.first()?.expect_ty();
+                    let &argument_ty = elems.first()?;
                     if let ty::Ref(_, _, _) = argument_ty.kind() {
                         return Some(AnnotatedBorrowFnSignature::Closure {
                             argument_ty,
@@ -2373,11 +2366,7 @@ enum AnnotatedBorrowFnSignature<'tcx> {
 impl<'tcx> AnnotatedBorrowFnSignature<'tcx> {
     /// Annotate the provided diagnostic with information about borrow from the fn signature that
     /// helps explain.
-    pub(crate) fn emit(
-        &self,
-        cx: &mut MirBorrowckCtxt<'_, 'tcx>,
-        diag: &mut DiagnosticBuilder<'_>,
-    ) -> String {
+    pub(crate) fn emit(&self, cx: &mut MirBorrowckCtxt<'_, 'tcx>, diag: &mut Diagnostic) -> String {
         match self {
             &AnnotatedBorrowFnSignature::Closure { argument_ty, argument_span } => {
                 diag.span_label(