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