]> git.lizzy.rs Git - rust.git/blob - compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
Auto merge of #94515 - estebank:tweak-move-error, r=davidtwco
[rust.git] / compiler / rustc_borrowck / src / diagnostics / conflict_errors.rs
1 use either::Either;
2 use rustc_const_eval::util::CallKind;
3 use rustc_data_structures::fx::FxHashSet;
4 use rustc_errors::{Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed};
5 use rustc_hir as hir;
6 use rustc_hir::def_id::DefId;
7 use rustc_hir::{AsyncGeneratorKind, GeneratorKind};
8 use rustc_infer::infer::TyCtxtInferExt;
9 use rustc_infer::traits::ObligationCause;
10 use rustc_middle::mir::{
11     self, AggregateKind, BindingForm, BorrowKind, ClearCrossCrate, ConstraintCategory,
12     FakeReadCause, LocalDecl, LocalInfo, LocalKind, Location, Operand, Place, PlaceRef,
13     ProjectionElem, Rvalue, Statement, StatementKind, Terminator, TerminatorKind, VarBindingForm,
14 };
15 use rustc_middle::ty::{
16     self, suggest_constraining_type_param, suggest_constraining_type_params, PredicateKind, Ty,
17 };
18 use rustc_mir_dataflow::move_paths::{InitKind, MoveOutIndex, MovePathIndex};
19 use rustc_span::symbol::sym;
20 use rustc_span::{BytePos, MultiSpan, Span};
21 use rustc_trait_selection::infer::InferCtxtExt;
22 use rustc_trait_selection::traits::TraitEngineExt as _;
23
24 use crate::borrow_set::TwoPhaseActivation;
25 use crate::borrowck_errors;
26
27 use crate::diagnostics::find_all_local_uses;
28 use crate::{
29     borrow_set::BorrowData, diagnostics::Instance, prefixes::IsPrefixOf,
30     InitializationRequiringAction, MirBorrowckCtxt, PrefixSet, WriteKind,
31 };
32
33 use super::{
34     explain_borrow::{BorrowExplanation, LaterUseKind},
35     IncludingDowncast, RegionName, RegionNameSource, UseSpans,
36 };
37
38 #[derive(Debug)]
39 struct MoveSite {
40     /// Index of the "move out" that we found. The `MoveData` can
41     /// then tell us where the move occurred.
42     moi: MoveOutIndex,
43
44     /// `true` if we traversed a back edge while walking from the point
45     /// of error to the move site.
46     traversed_back_edge: bool,
47 }
48
49 /// Which case a StorageDeadOrDrop is for.
50 #[derive(Copy, Clone, PartialEq, Eq, Debug)]
51 enum StorageDeadOrDrop<'tcx> {
52     LocalStorageDead,
53     BoxedStorageDead,
54     Destructor(Ty<'tcx>),
55 }
56
57 impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
58     pub(crate) fn report_use_of_moved_or_uninitialized(
59         &mut self,
60         location: Location,
61         desired_action: InitializationRequiringAction,
62         (moved_place, used_place, span): (PlaceRef<'tcx>, PlaceRef<'tcx>, Span),
63         mpi: MovePathIndex,
64     ) {
65         debug!(
66             "report_use_of_moved_or_uninitialized: location={:?} desired_action={:?} \
67              moved_place={:?} used_place={:?} span={:?} mpi={:?}",
68             location, desired_action, moved_place, used_place, span, mpi
69         );
70
71         let use_spans =
72             self.move_spans(moved_place, location).or_else(|| self.borrow_spans(span, location));
73         let span = use_spans.args_or_use();
74
75         let (move_site_vec, maybe_reinitialized_locations) = self.get_moved_indexes(location, mpi);
76         debug!(
77             "report_use_of_moved_or_uninitialized: move_site_vec={:?} use_spans={:?}",
78             move_site_vec, use_spans
79         );
80         let move_out_indices: Vec<_> =
81             move_site_vec.iter().map(|move_site| move_site.moi).collect();
82
83         if move_out_indices.is_empty() {
84             let root_place = PlaceRef { projection: &[], ..used_place };
85
86             if !self.uninitialized_error_reported.insert(root_place) {
87                 debug!(
88                     "report_use_of_moved_or_uninitialized place: error about {:?} suppressed",
89                     root_place
90                 );
91                 return;
92             }
93
94             let item_msg =
95                 match self.describe_place_with_options(used_place, IncludingDowncast(true)) {
96                     Some(name) => format!("`{}`", name),
97                     None => "value".to_owned(),
98                 };
99             let mut err = self.cannot_act_on_uninitialized_variable(
100                 span,
101                 desired_action.as_noun(),
102                 &self
103                     .describe_place_with_options(moved_place, IncludingDowncast(true))
104                     .unwrap_or_else(|| "_".to_owned()),
105             );
106             err.span_label(span, format!("use of possibly-uninitialized {}", item_msg));
107
108             use_spans.var_span_label_path_only(
109                 &mut err,
110                 format!("{} occurs due to use{}", desired_action.as_noun(), use_spans.describe()),
111             );
112
113             self.buffer_error(err);
114         } else {
115             if let Some((reported_place, _)) = self.has_move_error(&move_out_indices) {
116                 if self.prefixes(*reported_place, PrefixSet::All).any(|p| p == used_place) {
117                     debug!(
118                         "report_use_of_moved_or_uninitialized place: error suppressed \
119                          mois={:?}",
120                         move_out_indices
121                     );
122                     return;
123                 }
124             }
125
126             let is_partial_move = move_site_vec.iter().any(|move_site| {
127                 let move_out = self.move_data.moves[(*move_site).moi];
128                 let moved_place = &self.move_data.move_paths[move_out.path].place;
129                 // `*(_1)` where `_1` is a `Box` is actually a move out.
130                 let is_box_move = moved_place.as_ref().projection == [ProjectionElem::Deref]
131                     && self.body.local_decls[moved_place.local].ty.is_box();
132
133                 !is_box_move
134                     && used_place != moved_place.as_ref()
135                     && used_place.is_prefix_of(moved_place.as_ref())
136             });
137
138             let partial_str = if is_partial_move { "partial " } else { "" };
139             let partially_str = if is_partial_move { "partially " } else { "" };
140
141             let mut err = self.cannot_act_on_moved_value(
142                 span,
143                 desired_action.as_noun(),
144                 partially_str,
145                 self.describe_place_with_options(moved_place, IncludingDowncast(true)),
146             );
147
148             let reinit_spans = maybe_reinitialized_locations
149                 .iter()
150                 .take(3)
151                 .map(|loc| {
152                     self.move_spans(self.move_data.move_paths[mpi].place.as_ref(), *loc)
153                         .args_or_use()
154                 })
155                 .collect::<Vec<Span>>();
156             let reinits = maybe_reinitialized_locations.len();
157             if reinits == 1 {
158                 err.span_label(reinit_spans[0], "this reinitialization might get skipped");
159             } else if reinits > 1 {
160                 err.span_note(
161                     MultiSpan::from_spans(reinit_spans),
162                     &if reinits <= 3 {
163                         format!("these {} reinitializations might get skipped", reinits)
164                     } else {
165                         format!(
166                             "these 3 reinitializations and {} other{} might get skipped",
167                             reinits - 3,
168                             if reinits == 4 { "" } else { "s" }
169                         )
170                     },
171                 );
172             }
173
174             self.add_moved_or_invoked_closure_note(location, used_place, &mut err);
175
176             let mut is_loop_move = false;
177             let mut in_pattern = false;
178
179             for move_site in &move_site_vec {
180                 let move_out = self.move_data.moves[(*move_site).moi];
181                 let moved_place = &self.move_data.move_paths[move_out.path].place;
182
183                 let move_spans = self.move_spans(moved_place.as_ref(), move_out.source);
184                 let move_span = move_spans.args_or_use();
185
186                 let move_msg = if move_spans.for_closure() { " into closure" } else { "" };
187
188                 let loop_message = if location == move_out.source || move_site.traversed_back_edge {
189                     ", in previous iteration of loop"
190                 } else {
191                     ""
192                 };
193
194                 if location == move_out.source {
195                     is_loop_move = true;
196                 }
197
198                 self.explain_captures(
199                     &mut err,
200                     span,
201                     move_span,
202                     move_spans,
203                     *moved_place,
204                     Some(used_place),
205                     partially_str,
206                     loop_message,
207                     move_msg,
208                     is_loop_move,
209                     maybe_reinitialized_locations.is_empty(),
210                 );
211
212                 if let (UseSpans::PatUse(span), []) =
213                     (move_spans, &maybe_reinitialized_locations[..])
214                 {
215                     if maybe_reinitialized_locations.is_empty() {
216                         err.span_suggestion_verbose(
217                             span.shrink_to_lo(),
218                             &format!(
219                                 "borrow this field in the pattern to avoid moving {}",
220                                 self.describe_place(moved_place.as_ref())
221                                     .map(|n| format!("`{}`", n))
222                                     .unwrap_or_else(|| "the value".to_string())
223                             ),
224                             "ref ".to_string(),
225                             Applicability::MachineApplicable,
226                         );
227                         in_pattern = true;
228                     }
229                 }
230             }
231
232             use_spans.var_span_label_path_only(
233                 &mut err,
234                 format!("{} occurs due to use{}", desired_action.as_noun(), use_spans.describe()),
235             );
236
237             if !is_loop_move {
238                 err.span_label(
239                     span,
240                     format!(
241                         "value {} here after {}move",
242                         desired_action.as_verb_in_past_tense(),
243                         partial_str
244                     ),
245                 );
246             }
247
248             let ty = used_place.ty(self.body, self.infcx.tcx).ty;
249             let needs_note = match ty.kind() {
250                 ty::Closure(id, _) => {
251                     let tables = self.infcx.tcx.typeck(id.expect_local());
252                     let hir_id = self.infcx.tcx.hir().local_def_id_to_hir_id(id.expect_local());
253
254                     tables.closure_kind_origins().get(hir_id).is_none()
255                 }
256                 _ => true,
257             };
258
259             let mpi = self.move_data.moves[move_out_indices[0]].path;
260             let place = &self.move_data.move_paths[mpi].place;
261             let ty = place.ty(self.body, self.infcx.tcx).ty;
262
263             // If we're in pattern, we do nothing in favor of the previous suggestion (#80913).
264             if is_loop_move & !in_pattern {
265                 if let ty::Ref(_, _, hir::Mutability::Mut) = ty.kind() {
266                     // We have a `&mut` ref, we need to reborrow on each iteration (#62112).
267                     err.span_suggestion_verbose(
268                         span.shrink_to_lo(),
269                         &format!(
270                             "consider creating a fresh reborrow of {} here",
271                             self.describe_place(moved_place)
272                                 .map(|n| format!("`{}`", n))
273                                 .unwrap_or_else(|| "the mutable reference".to_string()),
274                         ),
275                         "&mut *".to_string(),
276                         Applicability::MachineApplicable,
277                     );
278                 }
279             }
280
281             if needs_note {
282                 let opt_name =
283                     self.describe_place_with_options(place.as_ref(), IncludingDowncast(true));
284                 let note_msg = match opt_name {
285                     Some(ref name) => format!("`{}`", name),
286                     None => "value".to_owned(),
287                 };
288                 if let ty::Param(param_ty) = ty.kind() {
289                     let tcx = self.infcx.tcx;
290                     let generics = tcx.generics_of(self.mir_def_id());
291                     let param = generics.type_param(&param_ty, tcx);
292                     if let Some(generics) = tcx
293                         .typeck_root_def_id(self.mir_def_id().to_def_id())
294                         .as_local()
295                         .and_then(|def_id| tcx.hir().get_generics(def_id))
296                     {
297                         suggest_constraining_type_param(
298                             tcx,
299                             generics,
300                             &mut err,
301                             param.name.as_str(),
302                             "Copy",
303                             None,
304                         );
305                     }
306                 } else {
307                     // Try to find predicates on *generic params* that would allow copying `ty`
308
309                     let tcx = self.infcx.tcx;
310                     let generics = tcx.generics_of(self.mir_def_id());
311                     if let Some(hir_generics) = tcx
312                         .typeck_root_def_id(self.mir_def_id().to_def_id())
313                         .as_local()
314                         .and_then(|def_id| tcx.hir().get_generics(def_id))
315                     {
316                         let predicates: Result<Vec<_>, _> = tcx.infer_ctxt().enter(|infcx| {
317                             let mut fulfill_cx =
318                                 <dyn rustc_infer::traits::TraitEngine<'_>>::new(infcx.tcx);
319
320                             let copy_did = infcx.tcx.lang_items().copy_trait().unwrap();
321                             let cause = ObligationCause::new(
322                                 span,
323                                 self.mir_hir_id(),
324                                 rustc_infer::traits::ObligationCauseCode::MiscObligation,
325                             );
326                             fulfill_cx.register_bound(
327                                 &infcx,
328                                 self.param_env,
329                                 // Erase any region vids from the type, which may not be resolved
330                                 infcx.tcx.erase_regions(ty),
331                                 copy_did,
332                                 cause,
333                             );
334                             // Select all, including ambiguous predicates
335                             let errors = fulfill_cx.select_all_or_error(&infcx);
336
337                             // Only emit suggestion if all required predicates are on generic
338                             errors
339                                 .into_iter()
340                                 .map(|err| match err.obligation.predicate.kind().skip_binder() {
341                                     PredicateKind::Trait(predicate) => {
342                                         match predicate.self_ty().kind() {
343                                             ty::Param(param_ty) => Ok((
344                                                 generics.type_param(param_ty, tcx),
345                                                 predicate
346                                                     .trait_ref
347                                                     .print_only_trait_path()
348                                                     .to_string(),
349                                             )),
350                                             _ => Err(()),
351                                         }
352                                     }
353                                     _ => Err(()),
354                                 })
355                                 .collect()
356                         });
357
358                         if let Ok(predicates) = predicates {
359                             suggest_constraining_type_params(
360                                 tcx,
361                                 hir_generics,
362                                 &mut err,
363                                 predicates.iter().map(|(param, constraint)| {
364                                     (param.name.as_str(), &**constraint, None)
365                                 }),
366                             );
367                         }
368                     }
369                 }
370
371                 let span = if let Some(local) = place.as_local() {
372                     let decl = &self.body.local_decls[local];
373                     Some(decl.source_info.span)
374                 } else {
375                     None
376                 };
377                 self.note_type_does_not_implement_copy(&mut err, &note_msg, ty, span, partial_str);
378             }
379
380             if let UseSpans::FnSelfUse {
381                 kind: CallKind::DerefCoercion { deref_target, deref_target_ty, .. },
382                 ..
383             } = use_spans
384             {
385                 err.note(&format!(
386                     "{} occurs due to deref coercion to `{}`",
387                     desired_action.as_noun(),
388                     deref_target_ty
389                 ));
390
391                 // Check first whether the source is accessible (issue #87060)
392                 if self.infcx.tcx.sess.source_map().span_to_snippet(deref_target).is_ok() {
393                     err.span_note(deref_target, "deref defined here");
394                 }
395             }
396
397             self.buffer_move_error(move_out_indices, (used_place, err));
398         }
399     }
400
401     pub(crate) fn report_move_out_while_borrowed(
402         &mut self,
403         location: Location,
404         (place, span): (Place<'tcx>, Span),
405         borrow: &BorrowData<'tcx>,
406     ) {
407         debug!(
408             "report_move_out_while_borrowed: location={:?} place={:?} span={:?} borrow={:?}",
409             location, place, span, borrow
410         );
411         let value_msg = self.describe_any_place(place.as_ref());
412         let borrow_msg = self.describe_any_place(borrow.borrowed_place.as_ref());
413
414         let borrow_spans = self.retrieve_borrow_spans(borrow);
415         let borrow_span = borrow_spans.args_or_use();
416
417         let move_spans = self.move_spans(place.as_ref(), location);
418         let span = move_spans.args_or_use();
419
420         let mut err =
421             self.cannot_move_when_borrowed(span, &self.describe_any_place(place.as_ref()));
422         err.span_label(borrow_span, format!("borrow of {} occurs here", borrow_msg));
423         err.span_label(span, format!("move out of {} occurs here", value_msg));
424
425         borrow_spans.var_span_label_path_only(
426             &mut err,
427             format!("borrow occurs due to use{}", borrow_spans.describe()),
428         );
429
430         move_spans.var_span_label(
431             &mut err,
432             format!("move occurs due to use{}", move_spans.describe()),
433             "moved",
434         );
435
436         self.explain_why_borrow_contains_point(location, borrow, None)
437             .add_explanation_to_diagnostic(
438                 self.infcx.tcx,
439                 &self.body,
440                 &self.local_names,
441                 &mut err,
442                 "",
443                 Some(borrow_span),
444                 None,
445             );
446         self.buffer_error(err);
447     }
448
449     pub(crate) fn report_use_while_mutably_borrowed(
450         &mut self,
451         location: Location,
452         (place, _span): (Place<'tcx>, Span),
453         borrow: &BorrowData<'tcx>,
454     ) -> DiagnosticBuilder<'cx, ErrorGuaranteed> {
455         let borrow_spans = self.retrieve_borrow_spans(borrow);
456         let borrow_span = borrow_spans.args_or_use();
457
458         // Conflicting borrows are reported separately, so only check for move
459         // captures.
460         let use_spans = self.move_spans(place.as_ref(), location);
461         let span = use_spans.var_or_use();
462
463         // If the attempted use is in a closure then we do not care about the path span of the place we are currently trying to use
464         // we call `var_span_label` on `borrow_spans` to annotate if the existing borrow was in a closure
465         let mut err = self.cannot_use_when_mutably_borrowed(
466             span,
467             &self.describe_any_place(place.as_ref()),
468             borrow_span,
469             &self.describe_any_place(borrow.borrowed_place.as_ref()),
470         );
471
472         borrow_spans.var_span_label(
473             &mut err,
474             {
475                 let place = &borrow.borrowed_place;
476                 let desc_place = self.describe_any_place(place.as_ref());
477                 format!("borrow occurs due to use of {}{}", desc_place, borrow_spans.describe())
478             },
479             "mutable",
480         );
481
482         self.explain_why_borrow_contains_point(location, borrow, None)
483             .add_explanation_to_diagnostic(
484                 self.infcx.tcx,
485                 &self.body,
486                 &self.local_names,
487                 &mut err,
488                 "",
489                 None,
490                 None,
491             );
492         err
493     }
494
495     pub(crate) fn report_conflicting_borrow(
496         &mut self,
497         location: Location,
498         (place, span): (Place<'tcx>, Span),
499         gen_borrow_kind: BorrowKind,
500         issued_borrow: &BorrowData<'tcx>,
501     ) -> DiagnosticBuilder<'cx, ErrorGuaranteed> {
502         let issued_spans = self.retrieve_borrow_spans(issued_borrow);
503         let issued_span = issued_spans.args_or_use();
504
505         let borrow_spans = self.borrow_spans(span, location);
506         let span = borrow_spans.args_or_use();
507
508         let container_name = if issued_spans.for_generator() || borrow_spans.for_generator() {
509             "generator"
510         } else {
511             "closure"
512         };
513
514         let (desc_place, msg_place, msg_borrow, union_type_name) =
515             self.describe_place_for_conflicting_borrow(place, issued_borrow.borrowed_place);
516
517         let explanation = self.explain_why_borrow_contains_point(location, issued_borrow, None);
518         let second_borrow_desc = if explanation.is_explained() { "second " } else { "" };
519
520         // FIXME: supply non-"" `opt_via` when appropriate
521         let first_borrow_desc;
522         let mut err = match (gen_borrow_kind, issued_borrow.kind) {
523             (BorrowKind::Shared, BorrowKind::Mut { .. }) => {
524                 first_borrow_desc = "mutable ";
525                 self.cannot_reborrow_already_borrowed(
526                     span,
527                     &desc_place,
528                     &msg_place,
529                     "immutable",
530                     issued_span,
531                     "it",
532                     "mutable",
533                     &msg_borrow,
534                     None,
535                 )
536             }
537             (BorrowKind::Mut { .. }, BorrowKind::Shared) => {
538                 first_borrow_desc = "immutable ";
539                 self.cannot_reborrow_already_borrowed(
540                     span,
541                     &desc_place,
542                     &msg_place,
543                     "mutable",
544                     issued_span,
545                     "it",
546                     "immutable",
547                     &msg_borrow,
548                     None,
549                 )
550             }
551
552             (BorrowKind::Mut { .. }, BorrowKind::Mut { .. }) => {
553                 first_borrow_desc = "first ";
554                 let mut err = self.cannot_mutably_borrow_multiply(
555                     span,
556                     &desc_place,
557                     &msg_place,
558                     issued_span,
559                     &msg_borrow,
560                     None,
561                 );
562                 self.suggest_split_at_mut_if_applicable(
563                     &mut err,
564                     place,
565                     issued_borrow.borrowed_place,
566                 );
567                 err
568             }
569
570             (BorrowKind::Unique, BorrowKind::Unique) => {
571                 first_borrow_desc = "first ";
572                 self.cannot_uniquely_borrow_by_two_closures(span, &desc_place, issued_span, None)
573             }
574
575             (BorrowKind::Mut { .. } | BorrowKind::Unique, BorrowKind::Shallow) => {
576                 if let Some(immutable_section_description) =
577                     self.classify_immutable_section(issued_borrow.assigned_place)
578                 {
579                     let mut err = self.cannot_mutate_in_immutable_section(
580                         span,
581                         issued_span,
582                         &desc_place,
583                         immutable_section_description,
584                         "mutably borrow",
585                     );
586                     borrow_spans.var_span_label(
587                         &mut err,
588                         format!(
589                             "borrow occurs due to use of {}{}",
590                             desc_place,
591                             borrow_spans.describe(),
592                         ),
593                         "immutable",
594                     );
595
596                     return err;
597                 } else {
598                     first_borrow_desc = "immutable ";
599                     self.cannot_reborrow_already_borrowed(
600                         span,
601                         &desc_place,
602                         &msg_place,
603                         "mutable",
604                         issued_span,
605                         "it",
606                         "immutable",
607                         &msg_borrow,
608                         None,
609                     )
610                 }
611             }
612
613             (BorrowKind::Unique, _) => {
614                 first_borrow_desc = "first ";
615                 self.cannot_uniquely_borrow_by_one_closure(
616                     span,
617                     container_name,
618                     &desc_place,
619                     "",
620                     issued_span,
621                     "it",
622                     "",
623                     None,
624                 )
625             }
626
627             (BorrowKind::Shared, BorrowKind::Unique) => {
628                 first_borrow_desc = "first ";
629                 self.cannot_reborrow_already_uniquely_borrowed(
630                     span,
631                     container_name,
632                     &desc_place,
633                     "",
634                     "immutable",
635                     issued_span,
636                     "",
637                     None,
638                     second_borrow_desc,
639                 )
640             }
641
642             (BorrowKind::Mut { .. }, BorrowKind::Unique) => {
643                 first_borrow_desc = "first ";
644                 self.cannot_reborrow_already_uniquely_borrowed(
645                     span,
646                     container_name,
647                     &desc_place,
648                     "",
649                     "mutable",
650                     issued_span,
651                     "",
652                     None,
653                     second_borrow_desc,
654                 )
655             }
656
657             (BorrowKind::Shared, BorrowKind::Shared | BorrowKind::Shallow)
658             | (
659                 BorrowKind::Shallow,
660                 BorrowKind::Mut { .. }
661                 | BorrowKind::Unique
662                 | BorrowKind::Shared
663                 | BorrowKind::Shallow,
664             ) => unreachable!(),
665         };
666
667         if issued_spans == borrow_spans {
668             borrow_spans.var_span_label(
669                 &mut err,
670                 format!("borrows occur due to use of {}{}", desc_place, borrow_spans.describe(),),
671                 gen_borrow_kind.describe_mutability(),
672             );
673         } else {
674             let borrow_place = &issued_borrow.borrowed_place;
675             let borrow_place_desc = self.describe_any_place(borrow_place.as_ref());
676             issued_spans.var_span_label(
677                 &mut err,
678                 format!(
679                     "first borrow occurs due to use of {}{}",
680                     borrow_place_desc,
681                     issued_spans.describe(),
682                 ),
683                 issued_borrow.kind.describe_mutability(),
684             );
685
686             borrow_spans.var_span_label(
687                 &mut err,
688                 format!(
689                     "second borrow occurs due to use of {}{}",
690                     desc_place,
691                     borrow_spans.describe(),
692                 ),
693                 gen_borrow_kind.describe_mutability(),
694             );
695         }
696
697         if union_type_name != "" {
698             err.note(&format!(
699                 "{} is a field of the union `{}`, so it overlaps the field {}",
700                 msg_place, union_type_name, msg_borrow,
701             ));
702         }
703
704         explanation.add_explanation_to_diagnostic(
705             self.infcx.tcx,
706             &self.body,
707             &self.local_names,
708             &mut err,
709             first_borrow_desc,
710             None,
711             Some((issued_span, span)),
712         );
713
714         self.suggest_using_local_if_applicable(
715             &mut err,
716             location,
717             (place, span),
718             gen_borrow_kind,
719             issued_borrow,
720             explanation,
721         );
722
723         err
724     }
725
726     #[instrument(level = "debug", skip(self, err))]
727     fn suggest_using_local_if_applicable(
728         &self,
729         err: &mut Diagnostic,
730         location: Location,
731         (place, span): (Place<'tcx>, Span),
732         gen_borrow_kind: BorrowKind,
733         issued_borrow: &BorrowData<'tcx>,
734         explanation: BorrowExplanation,
735     ) {
736         let used_in_call =
737             matches!(explanation, BorrowExplanation::UsedLater(LaterUseKind::Call, _call_span, _));
738         if !used_in_call {
739             debug!("not later used in call");
740             return;
741         }
742
743         let outer_call_loc =
744             if let TwoPhaseActivation::ActivatedAt(loc) = issued_borrow.activation_location {
745                 loc
746             } else {
747                 issued_borrow.reserve_location
748             };
749         let outer_call_stmt = self.body.stmt_at(outer_call_loc);
750
751         let inner_param_location = location;
752         let Some(inner_param_stmt) = self.body.stmt_at(inner_param_location).left() else {
753             debug!("`inner_param_location` {:?} is not for a statement", inner_param_location);
754             return;
755         };
756         let Some(&inner_param) = inner_param_stmt.kind.as_assign().map(|(p, _)| p) else {
757             debug!(
758                 "`inner_param_location` {:?} is not for an assignment: {:?}",
759                 inner_param_location, inner_param_stmt
760             );
761             return;
762         };
763         let inner_param_uses = find_all_local_uses::find(self.body, inner_param.local);
764         let Some((inner_call_loc,inner_call_term)) = inner_param_uses.into_iter().find_map(|loc| {
765             let Either::Right(term) = self.body.stmt_at(loc) else {
766                 debug!("{:?} is a statement, so it can't be a call", loc);
767                 return None;
768             };
769             let TerminatorKind::Call { args, .. } = &term.kind else {
770                 debug!("not a call: {:?}", term);
771                 return None;
772             };
773             debug!("checking call args for uses of inner_param: {:?}", args);
774             if args.contains(&Operand::Move(inner_param)) {
775                 Some((loc,term))
776             } else {
777                 None
778             }
779         }) else {
780             debug!("no uses of inner_param found as a by-move call arg");
781             return;
782         };
783         debug!("===> outer_call_loc = {:?}, inner_call_loc = {:?}", outer_call_loc, inner_call_loc);
784
785         let inner_call_span = inner_call_term.source_info.span;
786         let outer_call_span = outer_call_stmt.either(|s| s.source_info, |t| t.source_info).span;
787         if outer_call_span == inner_call_span || !outer_call_span.contains(inner_call_span) {
788             // FIXME: This stops the suggestion in some cases where it should be emitted.
789             //        Fix the spans for those cases so it's emitted correctly.
790             debug!(
791                 "outer span {:?} does not strictly contain inner span {:?}",
792                 outer_call_span, inner_call_span
793             );
794             return;
795         }
796         err.span_help(inner_call_span, "try adding a local storing this argument...");
797         err.span_help(outer_call_span, "...and then using that local as the argument to this call");
798     }
799
800     fn suggest_split_at_mut_if_applicable(
801         &self,
802         err: &mut Diagnostic,
803         place: Place<'tcx>,
804         borrowed_place: Place<'tcx>,
805     ) {
806         if let ([ProjectionElem::Index(_)], [ProjectionElem::Index(_)]) =
807             (&place.projection[..], &borrowed_place.projection[..])
808         {
809             err.help(
810                 "consider using `.split_at_mut(position)` or similar method to obtain \
811                      two mutable non-overlapping sub-slices",
812             );
813         }
814     }
815
816     /// Returns the description of the root place for a conflicting borrow and the full
817     /// descriptions of the places that caused the conflict.
818     ///
819     /// In the simplest case, where there are no unions involved, if a mutable borrow of `x` is
820     /// attempted while a shared borrow is live, then this function will return:
821     ///
822     ///     ("x", "", "")
823     ///
824     /// In the simple union case, if a mutable borrow of a union field `x.z` is attempted while
825     /// a shared borrow of another field `x.y`, then this function will return:
826     ///
827     ///     ("x", "x.z", "x.y")
828     ///
829     /// In the more complex union case, where the union is a field of a struct, then if a mutable
830     /// borrow of a union field in a struct `x.u.z` is attempted while a shared borrow of
831     /// another field `x.u.y`, then this function will return:
832     ///
833     ///     ("x.u", "x.u.z", "x.u.y")
834     ///
835     /// This is used when creating error messages like below:
836     ///
837     /// ```text
838     /// cannot borrow `a.u` (via `a.u.z.c`) as immutable because it is also borrowed as
839     /// mutable (via `a.u.s.b`) [E0502]
840     /// ```
841     pub(crate) fn describe_place_for_conflicting_borrow(
842         &self,
843         first_borrowed_place: Place<'tcx>,
844         second_borrowed_place: Place<'tcx>,
845     ) -> (String, String, String, String) {
846         // Define a small closure that we can use to check if the type of a place
847         // is a union.
848         let union_ty = |place_base| {
849             // Need to use fn call syntax `PlaceRef::ty` to determine the type of `place_base`;
850             // using a type annotation in the closure argument instead leads to a lifetime error.
851             let ty = PlaceRef::ty(&place_base, self.body, self.infcx.tcx).ty;
852             ty.ty_adt_def().filter(|adt| adt.is_union()).map(|_| ty)
853         };
854
855         // Start with an empty tuple, so we can use the functions on `Option` to reduce some
856         // code duplication (particularly around returning an empty description in the failure
857         // case).
858         Some(())
859             .filter(|_| {
860                 // If we have a conflicting borrow of the same place, then we don't want to add
861                 // an extraneous "via x.y" to our diagnostics, so filter out this case.
862                 first_borrowed_place != second_borrowed_place
863             })
864             .and_then(|_| {
865                 // We're going to want to traverse the first borrowed place to see if we can find
866                 // field access to a union. If we find that, then we will keep the place of the
867                 // union being accessed and the field that was being accessed so we can check the
868                 // second borrowed place for the same union and an access to a different field.
869                 for (place_base, elem) in first_borrowed_place.iter_projections().rev() {
870                     match elem {
871                         ProjectionElem::Field(field, _) if union_ty(place_base).is_some() => {
872                             return Some((place_base, field));
873                         }
874                         _ => {}
875                     }
876                 }
877                 None
878             })
879             .and_then(|(target_base, target_field)| {
880                 // With the place of a union and a field access into it, we traverse the second
881                 // borrowed place and look for an access to a different field of the same union.
882                 for (place_base, elem) in second_borrowed_place.iter_projections().rev() {
883                     if let ProjectionElem::Field(field, _) = elem {
884                         if let Some(union_ty) = union_ty(place_base) {
885                             if field != target_field && place_base == target_base {
886                                 return Some((
887                                     self.describe_any_place(place_base),
888                                     self.describe_any_place(first_borrowed_place.as_ref()),
889                                     self.describe_any_place(second_borrowed_place.as_ref()),
890                                     union_ty.to_string(),
891                                 ));
892                             }
893                         }
894                     }
895                 }
896                 None
897             })
898             .unwrap_or_else(|| {
899                 // If we didn't find a field access into a union, or both places match, then
900                 // only return the description of the first place.
901                 (
902                     self.describe_any_place(first_borrowed_place.as_ref()),
903                     "".to_string(),
904                     "".to_string(),
905                     "".to_string(),
906                 )
907             })
908     }
909
910     /// Reports StorageDeadOrDrop of `place` conflicts with `borrow`.
911     ///
912     /// This means that some data referenced by `borrow` needs to live
913     /// past the point where the StorageDeadOrDrop of `place` occurs.
914     /// This is usually interpreted as meaning that `place` has too
915     /// short a lifetime. (But sometimes it is more useful to report
916     /// it as a more direct conflict between the execution of a
917     /// `Drop::drop` with an aliasing borrow.)
918     pub(crate) fn report_borrowed_value_does_not_live_long_enough(
919         &mut self,
920         location: Location,
921         borrow: &BorrowData<'tcx>,
922         place_span: (Place<'tcx>, Span),
923         kind: Option<WriteKind>,
924     ) {
925         debug!(
926             "report_borrowed_value_does_not_live_long_enough(\
927              {:?}, {:?}, {:?}, {:?}\
928              )",
929             location, borrow, place_span, kind
930         );
931
932         let drop_span = place_span.1;
933         let root_place =
934             self.prefixes(borrow.borrowed_place.as_ref(), PrefixSet::All).last().unwrap();
935
936         let borrow_spans = self.retrieve_borrow_spans(borrow);
937         let borrow_span = borrow_spans.var_or_use_path_span();
938
939         assert!(root_place.projection.is_empty());
940         let proper_span = self.body.local_decls[root_place.local].source_info.span;
941
942         let root_place_projection = self.infcx.tcx.intern_place_elems(root_place.projection);
943
944         if self.access_place_error_reported.contains(&(
945             Place { local: root_place.local, projection: root_place_projection },
946             borrow_span,
947         )) {
948             debug!(
949                 "suppressing access_place error when borrow doesn't live long enough for {:?}",
950                 borrow_span
951             );
952             return;
953         }
954
955         self.access_place_error_reported.insert((
956             Place { local: root_place.local, projection: root_place_projection },
957             borrow_span,
958         ));
959
960         let borrowed_local = borrow.borrowed_place.local;
961         if self.body.local_decls[borrowed_local].is_ref_to_thread_local() {
962             let err =
963                 self.report_thread_local_value_does_not_live_long_enough(drop_span, borrow_span);
964             self.buffer_error(err);
965             return;
966         }
967
968         if let StorageDeadOrDrop::Destructor(dropped_ty) =
969             self.classify_drop_access_kind(borrow.borrowed_place.as_ref())
970         {
971             // If a borrow of path `B` conflicts with drop of `D` (and
972             // we're not in the uninteresting case where `B` is a
973             // prefix of `D`), then report this as a more interesting
974             // destructor conflict.
975             if !borrow.borrowed_place.as_ref().is_prefix_of(place_span.0.as_ref()) {
976                 self.report_borrow_conflicts_with_destructor(
977                     location, borrow, place_span, kind, dropped_ty,
978                 );
979                 return;
980             }
981         }
982
983         let place_desc = self.describe_place(borrow.borrowed_place.as_ref());
984
985         let kind_place = kind.filter(|_| place_desc.is_some()).map(|k| (k, place_span.0));
986         let explanation = self.explain_why_borrow_contains_point(location, &borrow, kind_place);
987
988         debug!(
989             "report_borrowed_value_does_not_live_long_enough(place_desc: {:?}, explanation: {:?})",
990             place_desc, explanation
991         );
992         let err = match (place_desc, explanation) {
993             // If the outlives constraint comes from inside the closure,
994             // for example:
995             //
996             // let x = 0;
997             // let y = &x;
998             // Box::new(|| y) as Box<Fn() -> &'static i32>
999             //
1000             // then just use the normal error. The closure isn't escaping
1001             // and `move` will not help here.
1002             (
1003                 Some(ref name),
1004                 BorrowExplanation::MustBeValidFor {
1005                     category:
1006                         category @ (ConstraintCategory::Return(_)
1007                         | ConstraintCategory::CallArgument
1008                         | ConstraintCategory::OpaqueType),
1009                     from_closure: false,
1010                     ref region_name,
1011                     span,
1012                     ..
1013                 },
1014             ) if borrow_spans.for_generator() | borrow_spans.for_closure() => self
1015                 .report_escaping_closure_capture(
1016                     borrow_spans,
1017                     borrow_span,
1018                     region_name,
1019                     category,
1020                     span,
1021                     &format!("`{}`", name),
1022                 ),
1023             (
1024                 ref name,
1025                 BorrowExplanation::MustBeValidFor {
1026                     category: ConstraintCategory::Assignment,
1027                     from_closure: false,
1028                     region_name:
1029                         RegionName {
1030                             source:
1031                                 RegionNameSource::AnonRegionFromUpvar(upvar_span, ref upvar_name),
1032                             ..
1033                         },
1034                     span,
1035                     ..
1036                 },
1037             ) => self.report_escaping_data(borrow_span, name, upvar_span, upvar_name, span),
1038             (Some(name), explanation) => self.report_local_value_does_not_live_long_enough(
1039                 location,
1040                 &name,
1041                 &borrow,
1042                 drop_span,
1043                 borrow_spans,
1044                 explanation,
1045             ),
1046             (None, explanation) => self.report_temporary_value_does_not_live_long_enough(
1047                 location,
1048                 &borrow,
1049                 drop_span,
1050                 borrow_spans,
1051                 proper_span,
1052                 explanation,
1053             ),
1054         };
1055
1056         self.buffer_error(err);
1057     }
1058
1059     fn report_local_value_does_not_live_long_enough(
1060         &mut self,
1061         location: Location,
1062         name: &str,
1063         borrow: &BorrowData<'tcx>,
1064         drop_span: Span,
1065         borrow_spans: UseSpans<'tcx>,
1066         explanation: BorrowExplanation,
1067     ) -> DiagnosticBuilder<'cx, ErrorGuaranteed> {
1068         debug!(
1069             "report_local_value_does_not_live_long_enough(\
1070              {:?}, {:?}, {:?}, {:?}, {:?}\
1071              )",
1072             location, name, borrow, drop_span, borrow_spans
1073         );
1074
1075         let borrow_span = borrow_spans.var_or_use_path_span();
1076         if let BorrowExplanation::MustBeValidFor {
1077             category,
1078             span,
1079             ref opt_place_desc,
1080             from_closure: false,
1081             ..
1082         } = explanation
1083         {
1084             if let Some(diag) = self.try_report_cannot_return_reference_to_local(
1085                 borrow,
1086                 borrow_span,
1087                 span,
1088                 category,
1089                 opt_place_desc.as_ref(),
1090             ) {
1091                 return diag;
1092             }
1093         }
1094
1095         let mut err = self.path_does_not_live_long_enough(borrow_span, &format!("`{}`", name));
1096
1097         if let Some(annotation) = self.annotate_argument_and_return_for_borrow(borrow) {
1098             let region_name = annotation.emit(self, &mut err);
1099
1100             err.span_label(
1101                 borrow_span,
1102                 format!("`{}` would have to be valid for `{}`...", name, region_name),
1103             );
1104
1105             let fn_hir_id = self.mir_hir_id();
1106             err.span_label(
1107                 drop_span,
1108                 format!(
1109                     "...but `{}` will be dropped here, when the {} returns",
1110                     name,
1111                     self.infcx
1112                         .tcx
1113                         .hir()
1114                         .opt_name(fn_hir_id)
1115                         .map(|name| format!("function `{}`", name))
1116                         .unwrap_or_else(|| {
1117                             match &self
1118                                 .infcx
1119                                 .tcx
1120                                 .typeck(self.mir_def_id())
1121                                 .node_type(fn_hir_id)
1122                                 .kind()
1123                             {
1124                                 ty::Closure(..) => "enclosing closure",
1125                                 ty::Generator(..) => "enclosing generator",
1126                                 kind => bug!("expected closure or generator, found {:?}", kind),
1127                             }
1128                             .to_string()
1129                         })
1130                 ),
1131             );
1132
1133             err.note(
1134                 "functions cannot return a borrow to data owned within the function's scope, \
1135                     functions can only return borrows to data passed as arguments",
1136             );
1137             err.note(
1138                 "to learn more, visit <https://doc.rust-lang.org/book/ch04-02-\
1139                     references-and-borrowing.html#dangling-references>",
1140             );
1141
1142             if let BorrowExplanation::MustBeValidFor { .. } = explanation {
1143             } else {
1144                 explanation.add_explanation_to_diagnostic(
1145                     self.infcx.tcx,
1146                     &self.body,
1147                     &self.local_names,
1148                     &mut err,
1149                     "",
1150                     None,
1151                     None,
1152                 );
1153             }
1154         } else {
1155             err.span_label(borrow_span, "borrowed value does not live long enough");
1156             err.span_label(drop_span, format!("`{}` dropped here while still borrowed", name));
1157
1158             let within = if borrow_spans.for_generator() { " by generator" } else { "" };
1159
1160             borrow_spans.args_span_label(&mut err, format!("value captured here{}", within));
1161
1162             explanation.add_explanation_to_diagnostic(
1163                 self.infcx.tcx,
1164                 &self.body,
1165                 &self.local_names,
1166                 &mut err,
1167                 "",
1168                 None,
1169                 None,
1170             );
1171         }
1172
1173         err
1174     }
1175
1176     fn report_borrow_conflicts_with_destructor(
1177         &mut self,
1178         location: Location,
1179         borrow: &BorrowData<'tcx>,
1180         (place, drop_span): (Place<'tcx>, Span),
1181         kind: Option<WriteKind>,
1182         dropped_ty: Ty<'tcx>,
1183     ) {
1184         debug!(
1185             "report_borrow_conflicts_with_destructor(\
1186              {:?}, {:?}, ({:?}, {:?}), {:?}\
1187              )",
1188             location, borrow, place, drop_span, kind,
1189         );
1190
1191         let borrow_spans = self.retrieve_borrow_spans(borrow);
1192         let borrow_span = borrow_spans.var_or_use();
1193
1194         let mut err = self.cannot_borrow_across_destructor(borrow_span);
1195
1196         let what_was_dropped = match self.describe_place(place.as_ref()) {
1197             Some(name) => format!("`{}`", name),
1198             None => String::from("temporary value"),
1199         };
1200
1201         let label = match self.describe_place(borrow.borrowed_place.as_ref()) {
1202             Some(borrowed) => format!(
1203                 "here, drop of {D} needs exclusive access to `{B}`, \
1204                  because the type `{T}` implements the `Drop` trait",
1205                 D = what_was_dropped,
1206                 T = dropped_ty,
1207                 B = borrowed
1208             ),
1209             None => format!(
1210                 "here is drop of {D}; whose type `{T}` implements the `Drop` trait",
1211                 D = what_was_dropped,
1212                 T = dropped_ty
1213             ),
1214         };
1215         err.span_label(drop_span, label);
1216
1217         // Only give this note and suggestion if they could be relevant.
1218         let explanation =
1219             self.explain_why_borrow_contains_point(location, borrow, kind.map(|k| (k, place)));
1220         match explanation {
1221             BorrowExplanation::UsedLater { .. }
1222             | BorrowExplanation::UsedLaterWhenDropped { .. } => {
1223                 err.note("consider using a `let` binding to create a longer lived value");
1224             }
1225             _ => {}
1226         }
1227
1228         explanation.add_explanation_to_diagnostic(
1229             self.infcx.tcx,
1230             &self.body,
1231             &self.local_names,
1232             &mut err,
1233             "",
1234             None,
1235             None,
1236         );
1237
1238         self.buffer_error(err);
1239     }
1240
1241     fn report_thread_local_value_does_not_live_long_enough(
1242         &mut self,
1243         drop_span: Span,
1244         borrow_span: Span,
1245     ) -> DiagnosticBuilder<'cx, ErrorGuaranteed> {
1246         debug!(
1247             "report_thread_local_value_does_not_live_long_enough(\
1248              {:?}, {:?}\
1249              )",
1250             drop_span, borrow_span
1251         );
1252
1253         let mut err = self.thread_local_value_does_not_live_long_enough(borrow_span);
1254
1255         err.span_label(
1256             borrow_span,
1257             "thread-local variables cannot be borrowed beyond the end of the function",
1258         );
1259         err.span_label(drop_span, "end of enclosing function is here");
1260
1261         err
1262     }
1263
1264     fn report_temporary_value_does_not_live_long_enough(
1265         &mut self,
1266         location: Location,
1267         borrow: &BorrowData<'tcx>,
1268         drop_span: Span,
1269         borrow_spans: UseSpans<'tcx>,
1270         proper_span: Span,
1271         explanation: BorrowExplanation,
1272     ) -> DiagnosticBuilder<'cx, ErrorGuaranteed> {
1273         debug!(
1274             "report_temporary_value_does_not_live_long_enough(\
1275              {:?}, {:?}, {:?}, {:?}\
1276              )",
1277             location, borrow, drop_span, proper_span
1278         );
1279
1280         if let BorrowExplanation::MustBeValidFor { category, span, from_closure: false, .. } =
1281             explanation
1282         {
1283             if let Some(diag) = self.try_report_cannot_return_reference_to_local(
1284                 borrow,
1285                 proper_span,
1286                 span,
1287                 category,
1288                 None,
1289             ) {
1290                 return diag;
1291             }
1292         }
1293
1294         let mut err = self.temporary_value_borrowed_for_too_long(proper_span);
1295         err.span_label(proper_span, "creates a temporary which is freed while still in use");
1296         err.span_label(drop_span, "temporary value is freed at the end of this statement");
1297
1298         match explanation {
1299             BorrowExplanation::UsedLater(..)
1300             | BorrowExplanation::UsedLaterInLoop(..)
1301             | BorrowExplanation::UsedLaterWhenDropped { .. } => {
1302                 // Only give this note and suggestion if it could be relevant.
1303                 err.note("consider using a `let` binding to create a longer lived value");
1304             }
1305             _ => {}
1306         }
1307         explanation.add_explanation_to_diagnostic(
1308             self.infcx.tcx,
1309             &self.body,
1310             &self.local_names,
1311             &mut err,
1312             "",
1313             None,
1314             None,
1315         );
1316
1317         let within = if borrow_spans.for_generator() { " by generator" } else { "" };
1318
1319         borrow_spans.args_span_label(&mut err, format!("value captured here{}", within));
1320
1321         err
1322     }
1323
1324     fn try_report_cannot_return_reference_to_local(
1325         &self,
1326         borrow: &BorrowData<'tcx>,
1327         borrow_span: Span,
1328         return_span: Span,
1329         category: ConstraintCategory,
1330         opt_place_desc: Option<&String>,
1331     ) -> Option<DiagnosticBuilder<'cx, ErrorGuaranteed>> {
1332         let return_kind = match category {
1333             ConstraintCategory::Return(_) => "return",
1334             ConstraintCategory::Yield => "yield",
1335             _ => return None,
1336         };
1337
1338         // FIXME use a better heuristic than Spans
1339         let reference_desc = if return_span == self.body.source_info(borrow.reserve_location).span {
1340             "reference to"
1341         } else {
1342             "value referencing"
1343         };
1344
1345         let (place_desc, note) = if let Some(place_desc) = opt_place_desc {
1346             let local_kind = if let Some(local) = borrow.borrowed_place.as_local() {
1347                 match self.body.local_kind(local) {
1348                     LocalKind::ReturnPointer | LocalKind::Temp => {
1349                         bug!("temporary or return pointer with a name")
1350                     }
1351                     LocalKind::Var => "local variable ",
1352                     LocalKind::Arg
1353                         if !self.upvars.is_empty() && local == ty::CAPTURE_STRUCT_LOCAL =>
1354                     {
1355                         "variable captured by `move` "
1356                     }
1357                     LocalKind::Arg => "function parameter ",
1358                 }
1359             } else {
1360                 "local data "
1361             };
1362             (
1363                 format!("{}`{}`", local_kind, place_desc),
1364                 format!("`{}` is borrowed here", place_desc),
1365             )
1366         } else {
1367             let root_place =
1368                 self.prefixes(borrow.borrowed_place.as_ref(), PrefixSet::All).last().unwrap();
1369             let local = root_place.local;
1370             match self.body.local_kind(local) {
1371                 LocalKind::ReturnPointer | LocalKind::Temp => {
1372                     ("temporary value".to_string(), "temporary value created here".to_string())
1373                 }
1374                 LocalKind::Arg => (
1375                     "function parameter".to_string(),
1376                     "function parameter borrowed here".to_string(),
1377                 ),
1378                 LocalKind::Var => {
1379                     ("local binding".to_string(), "local binding introduced here".to_string())
1380                 }
1381             }
1382         };
1383
1384         let mut err = self.cannot_return_reference_to_local(
1385             return_span,
1386             return_kind,
1387             reference_desc,
1388             &place_desc,
1389         );
1390
1391         if return_span != borrow_span {
1392             err.span_label(borrow_span, note);
1393
1394             let tcx = self.infcx.tcx;
1395             let ty_params = ty::List::empty();
1396
1397             let return_ty = self.regioncx.universal_regions().unnormalized_output_ty;
1398             let return_ty = tcx.erase_regions(return_ty);
1399
1400             // to avoid panics
1401             if let Some(iter_trait) = tcx.get_diagnostic_item(sym::Iterator) {
1402                 if self
1403                     .infcx
1404                     .type_implements_trait(iter_trait, return_ty, ty_params, self.param_env)
1405                     .must_apply_modulo_regions()
1406                 {
1407                     if let Ok(snippet) = tcx.sess.source_map().span_to_snippet(return_span) {
1408                         err.span_suggestion_hidden(
1409                             return_span,
1410                             "use `.collect()` to allocate the iterator",
1411                             format!("{}{}", snippet, ".collect::<Vec<_>>()"),
1412                             Applicability::MaybeIncorrect,
1413                         );
1414                     }
1415                 }
1416             }
1417         }
1418
1419         Some(err)
1420     }
1421
1422     fn report_escaping_closure_capture(
1423         &mut self,
1424         use_span: UseSpans<'tcx>,
1425         var_span: Span,
1426         fr_name: &RegionName,
1427         category: ConstraintCategory,
1428         constraint_span: Span,
1429         captured_var: &str,
1430     ) -> DiagnosticBuilder<'cx, ErrorGuaranteed> {
1431         let tcx = self.infcx.tcx;
1432         let args_span = use_span.args_or_use();
1433
1434         let (sugg_span, suggestion) = match tcx.sess.source_map().span_to_snippet(args_span) {
1435             Ok(string) => {
1436                 if string.starts_with("async ") {
1437                     let pos = args_span.lo() + BytePos(6);
1438                     (args_span.with_lo(pos).with_hi(pos), "move ".to_string())
1439                 } else if string.starts_with("async|") {
1440                     let pos = args_span.lo() + BytePos(5);
1441                     (args_span.with_lo(pos).with_hi(pos), " move".to_string())
1442                 } else {
1443                     (args_span.shrink_to_lo(), "move ".to_string())
1444                 }
1445             }
1446             Err(_) => (args_span, "move |<args>| <body>".to_string()),
1447         };
1448         let kind = match use_span.generator_kind() {
1449             Some(generator_kind) => match generator_kind {
1450                 GeneratorKind::Async(async_kind) => match async_kind {
1451                     AsyncGeneratorKind::Block => "async block",
1452                     AsyncGeneratorKind::Closure => "async closure",
1453                     _ => bug!("async block/closure expected, but async function found."),
1454                 },
1455                 GeneratorKind::Gen => "generator",
1456             },
1457             None => "closure",
1458         };
1459
1460         let mut err =
1461             self.cannot_capture_in_long_lived_closure(args_span, kind, captured_var, var_span);
1462         err.span_suggestion_verbose(
1463             sugg_span,
1464             &format!(
1465                 "to force the {} to take ownership of {} (and any \
1466                  other referenced variables), use the `move` keyword",
1467                 kind, captured_var
1468             ),
1469             suggestion,
1470             Applicability::MachineApplicable,
1471         );
1472
1473         match category {
1474             ConstraintCategory::Return(_) | ConstraintCategory::OpaqueType => {
1475                 let msg = format!("{} is returned here", kind);
1476                 err.span_note(constraint_span, &msg);
1477             }
1478             ConstraintCategory::CallArgument => {
1479                 fr_name.highlight_region_name(&mut err);
1480                 if matches!(use_span.generator_kind(), Some(GeneratorKind::Async(_))) {
1481                     err.note(
1482                         "async blocks are not executed immediately and must either take a \
1483                     reference or ownership of outside variables they use",
1484                     );
1485                 } else {
1486                     let msg = format!("function requires argument type to outlive `{}`", fr_name);
1487                     err.span_note(constraint_span, &msg);
1488                 }
1489             }
1490             _ => bug!(
1491                 "report_escaping_closure_capture called with unexpected constraint \
1492                  category: `{:?}`",
1493                 category
1494             ),
1495         }
1496
1497         err
1498     }
1499
1500     fn report_escaping_data(
1501         &mut self,
1502         borrow_span: Span,
1503         name: &Option<String>,
1504         upvar_span: Span,
1505         upvar_name: &str,
1506         escape_span: Span,
1507     ) -> DiagnosticBuilder<'cx, ErrorGuaranteed> {
1508         let tcx = self.infcx.tcx;
1509
1510         let (_, escapes_from) = tcx.article_and_description(self.mir_def_id().to_def_id());
1511
1512         let mut err =
1513             borrowck_errors::borrowed_data_escapes_closure(tcx, escape_span, escapes_from);
1514
1515         err.span_label(
1516             upvar_span,
1517             format!("`{}` declared here, outside of the {} body", upvar_name, escapes_from),
1518         );
1519
1520         err.span_label(borrow_span, format!("borrow is only valid in the {} body", escapes_from));
1521
1522         if let Some(name) = name {
1523             err.span_label(
1524                 escape_span,
1525                 format!("reference to `{}` escapes the {} body here", name, escapes_from),
1526             );
1527         } else {
1528             err.span_label(
1529                 escape_span,
1530                 format!("reference escapes the {} body here", escapes_from),
1531             );
1532         }
1533
1534         err
1535     }
1536
1537     fn get_moved_indexes(
1538         &mut self,
1539         location: Location,
1540         mpi: MovePathIndex,
1541     ) -> (Vec<MoveSite>, Vec<Location>) {
1542         fn predecessor_locations<'a>(
1543             body: &'a mir::Body<'_>,
1544             location: Location,
1545         ) -> impl Iterator<Item = Location> + 'a {
1546             if location.statement_index == 0 {
1547                 let predecessors = body.predecessors()[location.block].to_vec();
1548                 Either::Left(predecessors.into_iter().map(move |bb| body.terminator_loc(bb)))
1549             } else {
1550                 Either::Right(std::iter::once(Location {
1551                     statement_index: location.statement_index - 1,
1552                     ..location
1553                 }))
1554             }
1555         }
1556
1557         let mut mpis = vec![mpi];
1558         let move_paths = &self.move_data.move_paths;
1559         mpis.extend(move_paths[mpi].parents(move_paths).map(|(mpi, _)| mpi));
1560
1561         let mut stack = Vec::new();
1562         let mut back_edge_stack = Vec::new();
1563
1564         predecessor_locations(self.body, location).for_each(|predecessor| {
1565             if location.dominates(predecessor, &self.dominators) {
1566                 back_edge_stack.push(predecessor)
1567             } else {
1568                 stack.push(predecessor);
1569             }
1570         });
1571
1572         let mut reached_start = false;
1573
1574         /* Check if the mpi is initialized as an argument */
1575         let mut is_argument = false;
1576         for arg in self.body.args_iter() {
1577             let path = self.move_data.rev_lookup.find_local(arg);
1578             if mpis.contains(&path) {
1579                 is_argument = true;
1580             }
1581         }
1582
1583         let mut visited = FxHashSet::default();
1584         let mut move_locations = FxHashSet::default();
1585         let mut reinits = vec![];
1586         let mut result = vec![];
1587
1588         let mut dfs_iter = |result: &mut Vec<MoveSite>, location: Location, is_back_edge: bool| {
1589             debug!(
1590                 "report_use_of_moved_or_uninitialized: (current_location={:?}, back_edge={})",
1591                 location, is_back_edge
1592             );
1593
1594             if !visited.insert(location) {
1595                 return true;
1596             }
1597
1598             // check for moves
1599             let stmt_kind =
1600                 self.body[location.block].statements.get(location.statement_index).map(|s| &s.kind);
1601             if let Some(StatementKind::StorageDead(..)) = stmt_kind {
1602                 // this analysis only tries to find moves explicitly
1603                 // written by the user, so we ignore the move-outs
1604                 // created by `StorageDead` and at the beginning
1605                 // of a function.
1606             } else {
1607                 // If we are found a use of a.b.c which was in error, then we want to look for
1608                 // moves not only of a.b.c but also a.b and a.
1609                 //
1610                 // Note that the moves data already includes "parent" paths, so we don't have to
1611                 // worry about the other case: that is, if there is a move of a.b.c, it is already
1612                 // marked as a move of a.b and a as well, so we will generate the correct errors
1613                 // there.
1614                 for moi in &self.move_data.loc_map[location] {
1615                     debug!("report_use_of_moved_or_uninitialized: moi={:?}", moi);
1616                     let path = self.move_data.moves[*moi].path;
1617                     if mpis.contains(&path) {
1618                         debug!(
1619                             "report_use_of_moved_or_uninitialized: found {:?}",
1620                             move_paths[path].place
1621                         );
1622                         result.push(MoveSite { moi: *moi, traversed_back_edge: is_back_edge });
1623                         move_locations.insert(location);
1624
1625                         // Strictly speaking, we could continue our DFS here. There may be
1626                         // other moves that can reach the point of error. But it is kind of
1627                         // confusing to highlight them.
1628                         //
1629                         // Example:
1630                         //
1631                         // ```
1632                         // let a = vec![];
1633                         // let b = a;
1634                         // let c = a;
1635                         // drop(a); // <-- current point of error
1636                         // ```
1637                         //
1638                         // Because we stop the DFS here, we only highlight `let c = a`,
1639                         // and not `let b = a`. We will of course also report an error at
1640                         // `let c = a` which highlights `let b = a` as the move.
1641                         return true;
1642                     }
1643                 }
1644             }
1645
1646             // check for inits
1647             let mut any_match = false;
1648             for ii in &self.move_data.init_loc_map[location] {
1649                 let init = self.move_data.inits[*ii];
1650                 match init.kind {
1651                     InitKind::Deep | InitKind::NonPanicPathOnly => {
1652                         if mpis.contains(&init.path) {
1653                             any_match = true;
1654                         }
1655                     }
1656                     InitKind::Shallow => {
1657                         if mpi == init.path {
1658                             any_match = true;
1659                         }
1660                     }
1661                 }
1662             }
1663             if any_match {
1664                 reinits.push(location);
1665                 return true;
1666             }
1667             return false;
1668         };
1669
1670         while let Some(location) = stack.pop() {
1671             if dfs_iter(&mut result, location, false) {
1672                 continue;
1673             }
1674
1675             let mut has_predecessor = false;
1676             predecessor_locations(self.body, location).for_each(|predecessor| {
1677                 if location.dominates(predecessor, &self.dominators) {
1678                     back_edge_stack.push(predecessor)
1679                 } else {
1680                     stack.push(predecessor);
1681                 }
1682                 has_predecessor = true;
1683             });
1684
1685             if !has_predecessor {
1686                 reached_start = true;
1687             }
1688         }
1689         if (is_argument || !reached_start) && result.is_empty() {
1690             /* Process back edges (moves in future loop iterations) only if
1691                the move path is definitely initialized upon loop entry,
1692                to avoid spurious "in previous iteration" errors.
1693                During DFS, if there's a path from the error back to the start
1694                of the function with no intervening init or move, then the
1695                move path may be uninitialized at loop entry.
1696             */
1697             while let Some(location) = back_edge_stack.pop() {
1698                 if dfs_iter(&mut result, location, true) {
1699                     continue;
1700                 }
1701
1702                 predecessor_locations(self.body, location)
1703                     .for_each(|predecessor| back_edge_stack.push(predecessor));
1704             }
1705         }
1706
1707         // Check if we can reach these reinits from a move location.
1708         let reinits_reachable = reinits
1709             .into_iter()
1710             .filter(|reinit| {
1711                 let mut visited = FxHashSet::default();
1712                 let mut stack = vec![*reinit];
1713                 while let Some(location) = stack.pop() {
1714                     if !visited.insert(location) {
1715                         continue;
1716                     }
1717                     if move_locations.contains(&location) {
1718                         return true;
1719                     }
1720                     stack.extend(predecessor_locations(self.body, location));
1721                 }
1722                 false
1723             })
1724             .collect::<Vec<Location>>();
1725         (result, reinits_reachable)
1726     }
1727
1728     pub(crate) fn report_illegal_mutation_of_borrowed(
1729         &mut self,
1730         location: Location,
1731         (place, span): (Place<'tcx>, Span),
1732         loan: &BorrowData<'tcx>,
1733     ) {
1734         let loan_spans = self.retrieve_borrow_spans(loan);
1735         let loan_span = loan_spans.args_or_use();
1736
1737         let descr_place = self.describe_any_place(place.as_ref());
1738         if loan.kind == BorrowKind::Shallow {
1739             if let Some(section) = self.classify_immutable_section(loan.assigned_place) {
1740                 let mut err = self.cannot_mutate_in_immutable_section(
1741                     span,
1742                     loan_span,
1743                     &descr_place,
1744                     section,
1745                     "assign",
1746                 );
1747                 loan_spans.var_span_label(
1748                     &mut err,
1749                     format!("borrow occurs due to use{}", loan_spans.describe()),
1750                     loan.kind.describe_mutability(),
1751                 );
1752
1753                 self.buffer_error(err);
1754
1755                 return;
1756             }
1757         }
1758
1759         let mut err = self.cannot_assign_to_borrowed(span, loan_span, &descr_place);
1760
1761         loan_spans.var_span_label(
1762             &mut err,
1763             format!("borrow occurs due to use{}", loan_spans.describe()),
1764             loan.kind.describe_mutability(),
1765         );
1766
1767         self.explain_why_borrow_contains_point(location, loan, None).add_explanation_to_diagnostic(
1768             self.infcx.tcx,
1769             &self.body,
1770             &self.local_names,
1771             &mut err,
1772             "",
1773             None,
1774             None,
1775         );
1776
1777         self.explain_deref_coercion(loan, &mut err);
1778
1779         self.buffer_error(err);
1780     }
1781
1782     fn explain_deref_coercion(&mut self, loan: &BorrowData<'tcx>, err: &mut Diagnostic) {
1783         let tcx = self.infcx.tcx;
1784         if let (
1785             Some(Terminator { kind: TerminatorKind::Call { from_hir_call: false, .. }, .. }),
1786             Some((method_did, method_substs)),
1787         ) = (
1788             &self.body[loan.reserve_location.block].terminator,
1789             rustc_const_eval::util::find_self_call(
1790                 tcx,
1791                 self.body,
1792                 loan.assigned_place.local,
1793                 loan.reserve_location.block,
1794             ),
1795         ) {
1796             if tcx.is_diagnostic_item(sym::deref_method, method_did) {
1797                 let deref_target =
1798                     tcx.get_diagnostic_item(sym::deref_target).and_then(|deref_target| {
1799                         Instance::resolve(tcx, self.param_env, deref_target, method_substs)
1800                             .transpose()
1801                     });
1802                 if let Some(Ok(instance)) = deref_target {
1803                     let deref_target_ty = instance.ty(tcx, self.param_env);
1804                     err.note(&format!(
1805                         "borrow occurs due to deref coercion to `{}`",
1806                         deref_target_ty
1807                     ));
1808                     err.span_note(tcx.def_span(instance.def_id()), "deref defined here");
1809                 }
1810             }
1811         }
1812     }
1813
1814     /// Reports an illegal reassignment; for example, an assignment to
1815     /// (part of) a non-`mut` local that occurs potentially after that
1816     /// local has already been initialized. `place` is the path being
1817     /// assigned; `err_place` is a place providing a reason why
1818     /// `place` is not mutable (e.g., the non-`mut` local `x` in an
1819     /// assignment to `x.f`).
1820     pub(crate) fn report_illegal_reassignment(
1821         &mut self,
1822         _location: Location,
1823         (place, span): (Place<'tcx>, Span),
1824         assigned_span: Span,
1825         err_place: Place<'tcx>,
1826     ) {
1827         let (from_arg, local_decl, local_name) = match err_place.as_local() {
1828             Some(local) => (
1829                 self.body.local_kind(local) == LocalKind::Arg,
1830                 Some(&self.body.local_decls[local]),
1831                 self.local_names[local],
1832             ),
1833             None => (false, None, None),
1834         };
1835
1836         // If root local is initialized immediately (everything apart from let
1837         // PATTERN;) then make the error refer to that local, rather than the
1838         // place being assigned later.
1839         let (place_description, assigned_span) = match local_decl {
1840             Some(LocalDecl {
1841                 local_info:
1842                     Some(box LocalInfo::User(
1843                         ClearCrossCrate::Clear
1844                         | ClearCrossCrate::Set(BindingForm::Var(VarBindingForm {
1845                             opt_match_place: None,
1846                             ..
1847                         })),
1848                     ))
1849                     | Some(box LocalInfo::StaticRef { .. })
1850                     | None,
1851                 ..
1852             })
1853             | None => (self.describe_any_place(place.as_ref()), assigned_span),
1854             Some(decl) => (self.describe_any_place(err_place.as_ref()), decl.source_info.span),
1855         };
1856
1857         let mut err = self.cannot_reassign_immutable(span, &place_description, from_arg);
1858         let msg = if from_arg {
1859             "cannot assign to immutable argument"
1860         } else {
1861             "cannot assign twice to immutable variable"
1862         };
1863         if span != assigned_span {
1864             if !from_arg {
1865                 err.span_label(assigned_span, format!("first assignment to {}", place_description));
1866             }
1867         }
1868         if let Some(decl) = local_decl
1869             && let Some(name) = local_name
1870             && decl.can_be_made_mutable()
1871         {
1872             err.span_suggestion(
1873                 decl.source_info.span,
1874                 "consider making this binding mutable",
1875                 format!("mut {}", name),
1876                 Applicability::MachineApplicable,
1877             );
1878         }
1879         err.span_label(span, msg);
1880         self.buffer_error(err);
1881     }
1882
1883     fn classify_drop_access_kind(&self, place: PlaceRef<'tcx>) -> StorageDeadOrDrop<'tcx> {
1884         let tcx = self.infcx.tcx;
1885         match place.last_projection() {
1886             None => StorageDeadOrDrop::LocalStorageDead,
1887             Some((place_base, elem)) => {
1888                 // FIXME(spastorino) make this iterate
1889                 let base_access = self.classify_drop_access_kind(place_base);
1890                 match elem {
1891                     ProjectionElem::Deref => match base_access {
1892                         StorageDeadOrDrop::LocalStorageDead
1893                         | StorageDeadOrDrop::BoxedStorageDead => {
1894                             assert!(
1895                                 place_base.ty(self.body, tcx).ty.is_box(),
1896                                 "Drop of value behind a reference or raw pointer"
1897                             );
1898                             StorageDeadOrDrop::BoxedStorageDead
1899                         }
1900                         StorageDeadOrDrop::Destructor(_) => base_access,
1901                     },
1902                     ProjectionElem::Field(..) | ProjectionElem::Downcast(..) => {
1903                         let base_ty = place_base.ty(self.body, tcx).ty;
1904                         match base_ty.kind() {
1905                             ty::Adt(def, _) if def.has_dtor(tcx) => {
1906                                 // Report the outermost adt with a destructor
1907                                 match base_access {
1908                                     StorageDeadOrDrop::Destructor(_) => base_access,
1909                                     StorageDeadOrDrop::LocalStorageDead
1910                                     | StorageDeadOrDrop::BoxedStorageDead => {
1911                                         StorageDeadOrDrop::Destructor(base_ty)
1912                                     }
1913                                 }
1914                             }
1915                             _ => base_access,
1916                         }
1917                     }
1918                     ProjectionElem::ConstantIndex { .. }
1919                     | ProjectionElem::Subslice { .. }
1920                     | ProjectionElem::Index(_) => base_access,
1921                 }
1922             }
1923         }
1924     }
1925
1926     /// Describe the reason for the fake borrow that was assigned to `place`.
1927     fn classify_immutable_section(&self, place: Place<'tcx>) -> Option<&'static str> {
1928         use rustc_middle::mir::visit::Visitor;
1929         struct FakeReadCauseFinder<'tcx> {
1930             place: Place<'tcx>,
1931             cause: Option<FakeReadCause>,
1932         }
1933         impl<'tcx> Visitor<'tcx> for FakeReadCauseFinder<'tcx> {
1934             fn visit_statement(&mut self, statement: &Statement<'tcx>, _: Location) {
1935                 match statement {
1936                     Statement { kind: StatementKind::FakeRead(box (cause, place)), .. }
1937                         if *place == self.place =>
1938                     {
1939                         self.cause = Some(*cause);
1940                     }
1941                     _ => (),
1942                 }
1943             }
1944         }
1945         let mut visitor = FakeReadCauseFinder { place, cause: None };
1946         visitor.visit_body(&self.body);
1947         match visitor.cause {
1948             Some(FakeReadCause::ForMatchGuard) => Some("match guard"),
1949             Some(FakeReadCause::ForIndex) => Some("indexing expression"),
1950             _ => None,
1951         }
1952     }
1953
1954     /// Annotate argument and return type of function and closure with (synthesized) lifetime for
1955     /// borrow of local value that does not live long enough.
1956     fn annotate_argument_and_return_for_borrow(
1957         &self,
1958         borrow: &BorrowData<'tcx>,
1959     ) -> Option<AnnotatedBorrowFnSignature<'tcx>> {
1960         // Define a fallback for when we can't match a closure.
1961         let fallback = || {
1962             let is_closure = self.infcx.tcx.is_closure(self.mir_def_id().to_def_id());
1963             if is_closure {
1964                 None
1965             } else {
1966                 let ty = self.infcx.tcx.type_of(self.mir_def_id());
1967                 match ty.kind() {
1968                     ty::FnDef(_, _) | ty::FnPtr(_) => self.annotate_fn_sig(
1969                         self.mir_def_id().to_def_id(),
1970                         self.infcx.tcx.fn_sig(self.mir_def_id()),
1971                     ),
1972                     _ => None,
1973                 }
1974             }
1975         };
1976
1977         // In order to determine whether we need to annotate, we need to check whether the reserve
1978         // place was an assignment into a temporary.
1979         //
1980         // If it was, we check whether or not that temporary is eventually assigned into the return
1981         // place. If it was, we can add annotations about the function's return type and arguments
1982         // and it'll make sense.
1983         let location = borrow.reserve_location;
1984         debug!("annotate_argument_and_return_for_borrow: location={:?}", location);
1985         if let Some(&Statement { kind: StatementKind::Assign(box (ref reservation, _)), .. }) =
1986             &self.body[location.block].statements.get(location.statement_index)
1987         {
1988             debug!("annotate_argument_and_return_for_borrow: reservation={:?}", reservation);
1989             // Check that the initial assignment of the reserve location is into a temporary.
1990             let mut target = match reservation.as_local() {
1991                 Some(local) if self.body.local_kind(local) == LocalKind::Temp => local,
1992                 _ => return None,
1993             };
1994
1995             // Next, look through the rest of the block, checking if we are assigning the
1996             // `target` (that is, the place that contains our borrow) to anything.
1997             let mut annotated_closure = None;
1998             for stmt in &self.body[location.block].statements[location.statement_index + 1..] {
1999                 debug!(
2000                     "annotate_argument_and_return_for_borrow: target={:?} stmt={:?}",
2001                     target, stmt
2002                 );
2003                 if let StatementKind::Assign(box (place, rvalue)) = &stmt.kind {
2004                     if let Some(assigned_to) = place.as_local() {
2005                         debug!(
2006                             "annotate_argument_and_return_for_borrow: assigned_to={:?} \
2007                              rvalue={:?}",
2008                             assigned_to, rvalue
2009                         );
2010                         // Check if our `target` was captured by a closure.
2011                         if let Rvalue::Aggregate(
2012                             box AggregateKind::Closure(def_id, substs),
2013                             operands,
2014                         ) = rvalue
2015                         {
2016                             for operand in operands {
2017                                 let (Operand::Copy(assigned_from) | Operand::Move(assigned_from)) = operand else {
2018                                     continue;
2019                                 };
2020                                 debug!(
2021                                     "annotate_argument_and_return_for_borrow: assigned_from={:?}",
2022                                     assigned_from
2023                                 );
2024
2025                                 // Find the local from the operand.
2026                                 let Some(assigned_from_local) = assigned_from.local_or_deref_local() else {
2027                                     continue;
2028                                 };
2029
2030                                 if assigned_from_local != target {
2031                                     continue;
2032                                 }
2033
2034                                 // If a closure captured our `target` and then assigned
2035                                 // into a place then we should annotate the closure in
2036                                 // case it ends up being assigned into the return place.
2037                                 annotated_closure =
2038                                     self.annotate_fn_sig(*def_id, substs.as_closure().sig());
2039                                 debug!(
2040                                     "annotate_argument_and_return_for_borrow: \
2041                                      annotated_closure={:?} assigned_from_local={:?} \
2042                                      assigned_to={:?}",
2043                                     annotated_closure, assigned_from_local, assigned_to
2044                                 );
2045
2046                                 if assigned_to == mir::RETURN_PLACE {
2047                                     // If it was assigned directly into the return place, then
2048                                     // return now.
2049                                     return annotated_closure;
2050                                 } else {
2051                                     // Otherwise, update the target.
2052                                     target = assigned_to;
2053                                 }
2054                             }
2055
2056                             // If none of our closure's operands matched, then skip to the next
2057                             // statement.
2058                             continue;
2059                         }
2060
2061                         // Otherwise, look at other types of assignment.
2062                         let assigned_from = match rvalue {
2063                             Rvalue::Ref(_, _, assigned_from) => assigned_from,
2064                             Rvalue::Use(operand) => match operand {
2065                                 Operand::Copy(assigned_from) | Operand::Move(assigned_from) => {
2066                                     assigned_from
2067                                 }
2068                                 _ => continue,
2069                             },
2070                             _ => continue,
2071                         };
2072                         debug!(
2073                             "annotate_argument_and_return_for_borrow: \
2074                              assigned_from={:?}",
2075                             assigned_from,
2076                         );
2077
2078                         // Find the local from the rvalue.
2079                         let Some(assigned_from_local) = assigned_from.local_or_deref_local() else { continue };
2080                         debug!(
2081                             "annotate_argument_and_return_for_borrow: \
2082                              assigned_from_local={:?}",
2083                             assigned_from_local,
2084                         );
2085
2086                         // Check if our local matches the target - if so, we've assigned our
2087                         // borrow to a new place.
2088                         if assigned_from_local != target {
2089                             continue;
2090                         }
2091
2092                         // If we assigned our `target` into a new place, then we should
2093                         // check if it was the return place.
2094                         debug!(
2095                             "annotate_argument_and_return_for_borrow: \
2096                              assigned_from_local={:?} assigned_to={:?}",
2097                             assigned_from_local, assigned_to
2098                         );
2099                         if assigned_to == mir::RETURN_PLACE {
2100                             // If it was then return the annotated closure if there was one,
2101                             // else, annotate this function.
2102                             return annotated_closure.or_else(fallback);
2103                         }
2104
2105                         // If we didn't assign into the return place, then we just update
2106                         // the target.
2107                         target = assigned_to;
2108                     }
2109                 }
2110             }
2111
2112             // Check the terminator if we didn't find anything in the statements.
2113             let terminator = &self.body[location.block].terminator();
2114             debug!(
2115                 "annotate_argument_and_return_for_borrow: target={:?} terminator={:?}",
2116                 target, terminator
2117             );
2118             if let TerminatorKind::Call { destination: Some((place, _)), args, .. } =
2119                 &terminator.kind
2120             {
2121                 if let Some(assigned_to) = place.as_local() {
2122                     debug!(
2123                         "annotate_argument_and_return_for_borrow: assigned_to={:?} args={:?}",
2124                         assigned_to, args
2125                     );
2126                     for operand in args {
2127                         let (Operand::Copy(assigned_from) | Operand::Move(assigned_from)) = operand else {
2128                             continue;
2129                         };
2130                         debug!(
2131                             "annotate_argument_and_return_for_borrow: assigned_from={:?}",
2132                             assigned_from,
2133                         );
2134
2135                         if let Some(assigned_from_local) = assigned_from.local_or_deref_local() {
2136                             debug!(
2137                                 "annotate_argument_and_return_for_borrow: assigned_from_local={:?}",
2138                                 assigned_from_local,
2139                             );
2140
2141                             if assigned_to == mir::RETURN_PLACE && assigned_from_local == target {
2142                                 return annotated_closure.or_else(fallback);
2143                             }
2144                         }
2145                     }
2146                 }
2147             }
2148         }
2149
2150         // If we haven't found an assignment into the return place, then we need not add
2151         // any annotations.
2152         debug!("annotate_argument_and_return_for_borrow: none found");
2153         None
2154     }
2155
2156     /// Annotate the first argument and return type of a function signature if they are
2157     /// references.
2158     fn annotate_fn_sig(
2159         &self,
2160         did: DefId,
2161         sig: ty::PolyFnSig<'tcx>,
2162     ) -> Option<AnnotatedBorrowFnSignature<'tcx>> {
2163         debug!("annotate_fn_sig: did={:?} sig={:?}", did, sig);
2164         let is_closure = self.infcx.tcx.is_closure(did);
2165         let fn_hir_id = self.infcx.tcx.hir().local_def_id_to_hir_id(did.as_local()?);
2166         let fn_decl = self.infcx.tcx.hir().fn_decl_by_hir_id(fn_hir_id)?;
2167
2168         // We need to work out which arguments to highlight. We do this by looking
2169         // at the return type, where there are three cases:
2170         //
2171         // 1. If there are named arguments, then we should highlight the return type and
2172         //    highlight any of the arguments that are also references with that lifetime.
2173         //    If there are no arguments that have the same lifetime as the return type,
2174         //    then don't highlight anything.
2175         // 2. The return type is a reference with an anonymous lifetime. If this is
2176         //    the case, then we can take advantage of (and teach) the lifetime elision
2177         //    rules.
2178         //
2179         //    We know that an error is being reported. So the arguments and return type
2180         //    must satisfy the elision rules. Therefore, if there is a single argument
2181         //    then that means the return type and first (and only) argument have the same
2182         //    lifetime and the borrow isn't meeting that, we can highlight the argument
2183         //    and return type.
2184         //
2185         //    If there are multiple arguments then the first argument must be self (else
2186         //    it would not satisfy the elision rules), so we can highlight self and the
2187         //    return type.
2188         // 3. The return type is not a reference. In this case, we don't highlight
2189         //    anything.
2190         let return_ty = sig.output();
2191         match return_ty.skip_binder().kind() {
2192             ty::Ref(return_region, _, _) if return_region.has_name() && !is_closure => {
2193                 // This is case 1 from above, return type is a named reference so we need to
2194                 // search for relevant arguments.
2195                 let mut arguments = Vec::new();
2196                 for (index, argument) in sig.inputs().skip_binder().iter().enumerate() {
2197                     if let ty::Ref(argument_region, _, _) = argument.kind() {
2198                         if argument_region == return_region {
2199                             // Need to use the `rustc_middle::ty` types to compare against the
2200                             // `return_region`. Then use the `rustc_hir` type to get only
2201                             // the lifetime span.
2202                             if let hir::TyKind::Rptr(lifetime, _) = &fn_decl.inputs[index].kind {
2203                                 // With access to the lifetime, we can get
2204                                 // the span of it.
2205                                 arguments.push((*argument, lifetime.span));
2206                             } else {
2207                                 bug!("ty type is a ref but hir type is not");
2208                             }
2209                         }
2210                     }
2211                 }
2212
2213                 // We need to have arguments. This shouldn't happen, but it's worth checking.
2214                 if arguments.is_empty() {
2215                     return None;
2216                 }
2217
2218                 // We use a mix of the HIR and the Ty types to get information
2219                 // as the HIR doesn't have full types for closure arguments.
2220                 let return_ty = sig.output().skip_binder();
2221                 let mut return_span = fn_decl.output.span();
2222                 if let hir::FnRetTy::Return(ty) = &fn_decl.output {
2223                     if let hir::TyKind::Rptr(lifetime, _) = ty.kind {
2224                         return_span = lifetime.span;
2225                     }
2226                 }
2227
2228                 Some(AnnotatedBorrowFnSignature::NamedFunction {
2229                     arguments,
2230                     return_ty,
2231                     return_span,
2232                 })
2233             }
2234             ty::Ref(_, _, _) if is_closure => {
2235                 // This is case 2 from above but only for closures, return type is anonymous
2236                 // reference so we select
2237                 // the first argument.
2238                 let argument_span = fn_decl.inputs.first()?.span;
2239                 let argument_ty = sig.inputs().skip_binder().first()?;
2240
2241                 // Closure arguments are wrapped in a tuple, so we need to get the first
2242                 // from that.
2243                 if let ty::Tuple(elems) = argument_ty.kind() {
2244                     let &argument_ty = elems.first()?;
2245                     if let ty::Ref(_, _, _) = argument_ty.kind() {
2246                         return Some(AnnotatedBorrowFnSignature::Closure {
2247                             argument_ty,
2248                             argument_span,
2249                         });
2250                     }
2251                 }
2252
2253                 None
2254             }
2255             ty::Ref(_, _, _) => {
2256                 // This is also case 2 from above but for functions, return type is still an
2257                 // anonymous reference so we select the first argument.
2258                 let argument_span = fn_decl.inputs.first()?.span;
2259                 let argument_ty = *sig.inputs().skip_binder().first()?;
2260
2261                 let return_span = fn_decl.output.span();
2262                 let return_ty = sig.output().skip_binder();
2263
2264                 // We expect the first argument to be a reference.
2265                 match argument_ty.kind() {
2266                     ty::Ref(_, _, _) => {}
2267                     _ => return None,
2268                 }
2269
2270                 Some(AnnotatedBorrowFnSignature::AnonymousFunction {
2271                     argument_ty,
2272                     argument_span,
2273                     return_ty,
2274                     return_span,
2275                 })
2276             }
2277             _ => {
2278                 // This is case 3 from above, return type is not a reference so don't highlight
2279                 // anything.
2280                 None
2281             }
2282         }
2283     }
2284 }
2285
2286 #[derive(Debug)]
2287 enum AnnotatedBorrowFnSignature<'tcx> {
2288     NamedFunction {
2289         arguments: Vec<(Ty<'tcx>, Span)>,
2290         return_ty: Ty<'tcx>,
2291         return_span: Span,
2292     },
2293     AnonymousFunction {
2294         argument_ty: Ty<'tcx>,
2295         argument_span: Span,
2296         return_ty: Ty<'tcx>,
2297         return_span: Span,
2298     },
2299     Closure {
2300         argument_ty: Ty<'tcx>,
2301         argument_span: Span,
2302     },
2303 }
2304
2305 impl<'tcx> AnnotatedBorrowFnSignature<'tcx> {
2306     /// Annotate the provided diagnostic with information about borrow from the fn signature that
2307     /// helps explain.
2308     pub(crate) fn emit(&self, cx: &mut MirBorrowckCtxt<'_, 'tcx>, diag: &mut Diagnostic) -> String {
2309         match self {
2310             &AnnotatedBorrowFnSignature::Closure { argument_ty, argument_span } => {
2311                 diag.span_label(
2312                     argument_span,
2313                     format!("has type `{}`", cx.get_name_for_ty(argument_ty, 0)),
2314                 );
2315
2316                 cx.get_region_name_for_ty(argument_ty, 0)
2317             }
2318             &AnnotatedBorrowFnSignature::AnonymousFunction {
2319                 argument_ty,
2320                 argument_span,
2321                 return_ty,
2322                 return_span,
2323             } => {
2324                 let argument_ty_name = cx.get_name_for_ty(argument_ty, 0);
2325                 diag.span_label(argument_span, format!("has type `{}`", argument_ty_name));
2326
2327                 let return_ty_name = cx.get_name_for_ty(return_ty, 0);
2328                 let types_equal = return_ty_name == argument_ty_name;
2329                 diag.span_label(
2330                     return_span,
2331                     format!(
2332                         "{}has type `{}`",
2333                         if types_equal { "also " } else { "" },
2334                         return_ty_name,
2335                     ),
2336                 );
2337
2338                 diag.note(
2339                     "argument and return type have the same lifetime due to lifetime elision rules",
2340                 );
2341                 diag.note(
2342                     "to learn more, visit <https://doc.rust-lang.org/book/ch10-03-\
2343                      lifetime-syntax.html#lifetime-elision>",
2344                 );
2345
2346                 cx.get_region_name_for_ty(return_ty, 0)
2347             }
2348             AnnotatedBorrowFnSignature::NamedFunction { arguments, return_ty, return_span } => {
2349                 // Region of return type and arguments checked to be the same earlier.
2350                 let region_name = cx.get_region_name_for_ty(*return_ty, 0);
2351                 for (_, argument_span) in arguments {
2352                     diag.span_label(*argument_span, format!("has lifetime `{}`", region_name));
2353                 }
2354
2355                 diag.span_label(*return_span, format!("also has lifetime `{}`", region_name,));
2356
2357                 diag.help(&format!(
2358                     "use data from the highlighted arguments which match the `{}` lifetime of \
2359                      the return type",
2360                     region_name,
2361                 ));
2362
2363                 region_name
2364             }
2365         }
2366     }
2367 }