]> git.lizzy.rs Git - rust.git/blob - compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
Rollup merge of #105172 - alexs-sh:issue-98861-fix-next, r=scottmcm
[rust.git] / compiler / rustc_borrowck / src / diagnostics / conflict_errors.rs
1 use either::Either;
2 use rustc_const_eval::util::CallKind;
3 use rustc_data_structures::captures::Captures;
4 use rustc_data_structures::fx::FxHashSet;
5 use rustc_errors::{
6     struct_span_err, Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed, MultiSpan,
7 };
8 use rustc_hir as hir;
9 use rustc_hir::def::Res;
10 use rustc_hir::intravisit::{walk_block, walk_expr, Visitor};
11 use rustc_hir::{AsyncGeneratorKind, GeneratorKind, LangItem};
12 use rustc_infer::infer::TyCtxtInferExt;
13 use rustc_infer::traits::ObligationCause;
14 use rustc_middle::mir::tcx::PlaceTy;
15 use rustc_middle::mir::{
16     self, AggregateKind, BindingForm, BorrowKind, ClearCrossCrate, ConstraintCategory,
17     FakeReadCause, LocalDecl, LocalInfo, LocalKind, Location, Operand, Place, PlaceRef,
18     ProjectionElem, Rvalue, Statement, StatementKind, Terminator, TerminatorKind, VarBindingForm,
19 };
20 use rustc_middle::ty::{self, suggest_constraining_type_params, PredicateKind, Ty};
21 use rustc_mir_dataflow::move_paths::{InitKind, MoveOutIndex, MovePathIndex};
22 use rustc_span::def_id::LocalDefId;
23 use rustc_span::hygiene::DesugaringKind;
24 use rustc_span::symbol::{kw, sym};
25 use rustc_span::{BytePos, Span, Symbol};
26 use rustc_trait_selection::infer::InferCtxtExt;
27
28 use crate::borrow_set::TwoPhaseActivation;
29 use crate::borrowck_errors;
30
31 use crate::diagnostics::conflict_errors::StorageDeadOrDrop::LocalStorageDead;
32 use crate::diagnostics::find_all_local_uses;
33 use crate::diagnostics::mutability_errors::mut_borrow_of_mutable_ref;
34 use crate::{
35     borrow_set::BorrowData, diagnostics::Instance, prefixes::IsPrefixOf,
36     InitializationRequiringAction, MirBorrowckCtxt, PrefixSet, WriteKind,
37 };
38
39 use super::{
40     explain_borrow::{BorrowExplanation, LaterUseKind},
41     DescribePlaceOpt, RegionName, RegionNameSource, UseSpans,
42 };
43
44 #[derive(Debug)]
45 struct MoveSite {
46     /// Index of the "move out" that we found. The `MoveData` can
47     /// then tell us where the move occurred.
48     moi: MoveOutIndex,
49
50     /// `true` if we traversed a back edge while walking from the point
51     /// of error to the move site.
52     traversed_back_edge: bool,
53 }
54
55 /// Which case a StorageDeadOrDrop is for.
56 #[derive(Copy, Clone, PartialEq, Eq, Debug)]
57 enum StorageDeadOrDrop<'tcx> {
58     LocalStorageDead,
59     BoxedStorageDead,
60     Destructor(Ty<'tcx>),
61 }
62
63 impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
64     pub(crate) fn report_use_of_moved_or_uninitialized(
65         &mut self,
66         location: Location,
67         desired_action: InitializationRequiringAction,
68         (moved_place, used_place, span): (PlaceRef<'tcx>, PlaceRef<'tcx>, Span),
69         mpi: MovePathIndex,
70     ) {
71         debug!(
72             "report_use_of_moved_or_uninitialized: location={:?} desired_action={:?} \
73              moved_place={:?} used_place={:?} span={:?} mpi={:?}",
74             location, desired_action, moved_place, used_place, span, mpi
75         );
76
77         let use_spans =
78             self.move_spans(moved_place, location).or_else(|| self.borrow_spans(span, location));
79         let span = use_spans.args_or_use();
80
81         let (move_site_vec, maybe_reinitialized_locations) = self.get_moved_indexes(location, mpi);
82         debug!(
83             "report_use_of_moved_or_uninitialized: move_site_vec={:?} use_spans={:?}",
84             move_site_vec, use_spans
85         );
86         let move_out_indices: Vec<_> =
87             move_site_vec.iter().map(|move_site| move_site.moi).collect();
88
89         if move_out_indices.is_empty() {
90             let root_place = PlaceRef { projection: &[], ..used_place };
91
92             if !self.uninitialized_error_reported.insert(root_place) {
93                 debug!(
94                     "report_use_of_moved_or_uninitialized place: error about {:?} suppressed",
95                     root_place
96                 );
97                 return;
98             }
99
100             let err = self.report_use_of_uninitialized(
101                 mpi,
102                 used_place,
103                 moved_place,
104                 desired_action,
105                 span,
106                 use_spans,
107             );
108             self.buffer_error(err);
109         } else {
110             if let Some((reported_place, _)) = self.has_move_error(&move_out_indices) {
111                 if self.prefixes(*reported_place, PrefixSet::All).any(|p| p == used_place) {
112                     debug!(
113                         "report_use_of_moved_or_uninitialized place: error suppressed mois={:?}",
114                         move_out_indices
115                     );
116                     return;
117                 }
118             }
119
120             let is_partial_move = move_site_vec.iter().any(|move_site| {
121                 let move_out = self.move_data.moves[(*move_site).moi];
122                 let moved_place = &self.move_data.move_paths[move_out.path].place;
123                 // `*(_1)` where `_1` is a `Box` is actually a move out.
124                 let is_box_move = moved_place.as_ref().projection == [ProjectionElem::Deref]
125                     && self.body.local_decls[moved_place.local].ty.is_box();
126
127                 !is_box_move
128                     && used_place != moved_place.as_ref()
129                     && used_place.is_prefix_of(moved_place.as_ref())
130             });
131
132             let partial_str = if is_partial_move { "partial " } else { "" };
133             let partially_str = if is_partial_move { "partially " } else { "" };
134
135             let mut err = self.cannot_act_on_moved_value(
136                 span,
137                 desired_action.as_noun(),
138                 partially_str,
139                 self.describe_place_with_options(
140                     moved_place,
141                     DescribePlaceOpt { including_downcast: true, including_tuple_field: true },
142                 ),
143             );
144
145             let reinit_spans = maybe_reinitialized_locations
146                 .iter()
147                 .take(3)
148                 .map(|loc| {
149                     self.move_spans(self.move_data.move_paths[mpi].place.as_ref(), *loc)
150                         .args_or_use()
151                 })
152                 .collect::<Vec<Span>>();
153
154             let reinits = maybe_reinitialized_locations.len();
155             if reinits == 1 {
156                 err.span_label(reinit_spans[0], "this reinitialization might get skipped");
157             } else if reinits > 1 {
158                 err.span_note(
159                     MultiSpan::from_spans(reinit_spans),
160                     &if reinits <= 3 {
161                         format!("these {reinits} reinitializations might get skipped")
162                     } else {
163                         format!(
164                             "these 3 reinitializations and {} other{} might get skipped",
165                             reinits - 3,
166                             if reinits == 4 { "" } else { "s" }
167                         )
168                     },
169                 );
170             }
171
172             let closure = self.add_moved_or_invoked_closure_note(location, used_place, &mut err);
173
174             let mut is_loop_move = false;
175             let mut in_pattern = false;
176             let mut seen_spans = FxHashSet::default();
177
178             for move_site in &move_site_vec {
179                 let move_out = self.move_data.moves[(*move_site).moi];
180                 let moved_place = &self.move_data.move_paths[move_out.path].place;
181
182                 let move_spans = self.move_spans(moved_place.as_ref(), move_out.source);
183                 let move_span = move_spans.args_or_use();
184
185                 let move_msg = if move_spans.for_closure() { " into closure" } else { "" };
186
187                 let loop_message = if location == move_out.source || move_site.traversed_back_edge {
188                     ", in previous iteration of loop"
189                 } else {
190                     ""
191                 };
192
193                 if location == move_out.source {
194                     is_loop_move = true;
195                 }
196
197                 if !seen_spans.contains(&move_span) {
198                     if !closure {
199                         self.suggest_ref_or_clone(
200                             mpi,
201                             move_span,
202                             &mut err,
203                             &mut in_pattern,
204                             move_spans,
205                         );
206                     }
207
208                     self.explain_captures(
209                         &mut err,
210                         span,
211                         move_span,
212                         move_spans,
213                         *moved_place,
214                         partially_str,
215                         loop_message,
216                         move_msg,
217                         is_loop_move,
218                         maybe_reinitialized_locations.is_empty(),
219                     );
220                 }
221                 seen_spans.insert(move_span);
222             }
223
224             use_spans.var_path_only_subdiag(&mut err, desired_action);
225
226             if !is_loop_move {
227                 err.span_label(
228                     span,
229                     format!(
230                         "value {} here after {partial_str}move",
231                         desired_action.as_verb_in_past_tense(),
232                     ),
233                 );
234             }
235
236             let ty = used_place.ty(self.body, self.infcx.tcx).ty;
237             let needs_note = match ty.kind() {
238                 ty::Closure(id, _) => {
239                     let tables = self.infcx.tcx.typeck(id.expect_local());
240                     let hir_id = self.infcx.tcx.hir().local_def_id_to_hir_id(id.expect_local());
241
242                     tables.closure_kind_origins().get(hir_id).is_none()
243                 }
244                 _ => true,
245             };
246
247             let mpi = self.move_data.moves[move_out_indices[0]].path;
248             let place = &self.move_data.move_paths[mpi].place;
249             let ty = place.ty(self.body, self.infcx.tcx).ty;
250
251             // If we're in pattern, we do nothing in favor of the previous suggestion (#80913).
252             // Same for if we're in a loop, see #101119.
253             if is_loop_move & !in_pattern && !matches!(use_spans, UseSpans::ClosureUse { .. }) {
254                 if let ty::Ref(_, _, hir::Mutability::Mut) = ty.kind() {
255                     // We have a `&mut` ref, we need to reborrow on each iteration (#62112).
256                     err.span_suggestion_verbose(
257                         span.shrink_to_lo(),
258                         &format!(
259                             "consider creating a fresh reborrow of {} here",
260                             self.describe_place(moved_place)
261                                 .map(|n| format!("`{n}`"))
262                                 .unwrap_or_else(|| "the mutable reference".to_string()),
263                         ),
264                         "&mut *",
265                         Applicability::MachineApplicable,
266                     );
267                 }
268             }
269
270             let opt_name = self.describe_place_with_options(
271                 place.as_ref(),
272                 DescribePlaceOpt { including_downcast: true, including_tuple_field: true },
273             );
274             let note_msg = match opt_name {
275                 Some(name) => format!("`{name}`"),
276                 None => "value".to_owned(),
277             };
278             if self.suggest_borrow_fn_like(&mut err, ty, &move_site_vec, &note_msg) {
279                 // Suppress the next suggestion since we don't want to put more bounds onto
280                 // something that already has `Fn`-like bounds (or is a closure), so we can't
281                 // restrict anyways.
282             } else {
283                 self.suggest_adding_copy_bounds(&mut err, ty, span);
284             }
285
286             if needs_note {
287                 let span = if let Some(local) = place.as_local() {
288                     Some(self.body.local_decls[local].source_info.span)
289                 } else {
290                     None
291                 };
292                 self.note_type_does_not_implement_copy(&mut err, &note_msg, ty, span, partial_str);
293             }
294
295             if let UseSpans::FnSelfUse {
296                 kind: CallKind::DerefCoercion { deref_target, deref_target_ty, .. },
297                 ..
298             } = use_spans
299             {
300                 err.note(&format!(
301                     "{} occurs due to deref coercion to `{deref_target_ty}`",
302                     desired_action.as_noun(),
303                 ));
304
305                 // Check first whether the source is accessible (issue #87060)
306                 if self.infcx.tcx.sess.source_map().is_span_accessible(deref_target) {
307                     err.span_note(deref_target, "deref defined here");
308                 }
309             }
310
311             self.buffer_move_error(move_out_indices, (used_place, err));
312         }
313     }
314
315     fn suggest_ref_or_clone(
316         &mut self,
317         mpi: MovePathIndex,
318         move_span: Span,
319         err: &mut DiagnosticBuilder<'_, ErrorGuaranteed>,
320         in_pattern: &mut bool,
321         move_spans: UseSpans<'_>,
322     ) {
323         struct ExpressionFinder<'hir> {
324             expr_span: Span,
325             expr: Option<&'hir hir::Expr<'hir>>,
326             pat: Option<&'hir hir::Pat<'hir>>,
327             parent_pat: Option<&'hir hir::Pat<'hir>>,
328         }
329         impl<'hir> Visitor<'hir> for ExpressionFinder<'hir> {
330             fn visit_expr(&mut self, e: &'hir hir::Expr<'hir>) {
331                 if e.span == self.expr_span {
332                     self.expr = Some(e);
333                 }
334                 hir::intravisit::walk_expr(self, e);
335             }
336             fn visit_pat(&mut self, p: &'hir hir::Pat<'hir>) {
337                 if p.span == self.expr_span {
338                     self.pat = Some(p);
339                 }
340                 if let hir::PatKind::Binding(hir::BindingAnnotation::NONE, _, i, sub) = p.kind {
341                     if i.span == self.expr_span || p.span == self.expr_span {
342                         self.pat = Some(p);
343                     }
344                     // Check if we are in a situation of `ident @ ident` where we want to suggest
345                     // `ref ident @ ref ident` or `ref ident @ Struct { ref ident }`.
346                     if let Some(subpat) = sub && self.pat.is_none() {
347                         self.visit_pat(subpat);
348                         if self.pat.is_some() {
349                             self.parent_pat = Some(p);
350                         }
351                         return;
352                     }
353                 }
354                 hir::intravisit::walk_pat(self, p);
355             }
356         }
357         let hir = self.infcx.tcx.hir();
358         if let Some(hir::Node::Item(hir::Item {
359             kind: hir::ItemKind::Fn(_, _, body_id),
360             ..
361         })) = hir.find(self.mir_hir_id())
362             && let Some(hir::Node::Expr(expr)) = hir.find(body_id.hir_id)
363         {
364             let place = &self.move_data.move_paths[mpi].place;
365             let span = place.as_local()
366                 .map(|local| self.body.local_decls[local].source_info.span);
367             let mut finder = ExpressionFinder {
368                 expr_span: move_span,
369                 expr: None,
370                 pat: None,
371                 parent_pat: None,
372             };
373             finder.visit_expr(expr);
374             if let Some(span) = span && let Some(expr) = finder.expr {
375                 for (_, expr) in hir.parent_iter(expr.hir_id) {
376                     if let hir::Node::Expr(expr) = expr {
377                         if expr.span.contains(span) {
378                             // If the let binding occurs within the same loop, then that
379                             // loop isn't relevant, like in the following, the outermost `loop`
380                             // doesn't play into `x` being moved.
381                             // ```
382                             // loop {
383                             //     let x = String::new();
384                             //     loop {
385                             //         foo(x);
386                             //     }
387                             // }
388                             // ```
389                             break;
390                         }
391                         if let hir::ExprKind::Loop(.., loop_span) = expr.kind {
392                             err.span_label(loop_span, "inside of this loop");
393                         }
394                     }
395                 }
396                 let typeck = self.infcx.tcx.typeck(self.mir_def_id());
397                 let hir_id = hir.parent_id(expr.hir_id);
398                 if let Some(parent) = hir.find(hir_id) {
399                     let (def_id, args, offset) = if let hir::Node::Expr(parent_expr) = parent
400                         && let hir::ExprKind::MethodCall(_, _, args, _) = parent_expr.kind
401                         && let Some(def_id) = typeck.type_dependent_def_id(parent_expr.hir_id)
402                     {
403                         (def_id.as_local(), args, 1)
404                     } else if let hir::Node::Expr(parent_expr) = parent
405                         && let hir::ExprKind::Call(call, args) = parent_expr.kind
406                         && let ty::FnDef(def_id, _) = typeck.node_type(call.hir_id).kind()
407                     {
408                         (def_id.as_local(), args, 0)
409                     } else {
410                         (None, &[][..], 0)
411                     };
412                     if let Some(def_id) = def_id
413                         && let Some(node) = hir.find(hir.local_def_id_to_hir_id(def_id))
414                         && let Some(fn_sig) = node.fn_sig()
415                         && let Some(ident) = node.ident()
416                         && let Some(pos) = args.iter().position(|arg| arg.hir_id == expr.hir_id)
417                         && let Some(arg) = fn_sig.decl.inputs.get(pos + offset)
418                     {
419                         let mut span: MultiSpan = arg.span.into();
420                         span.push_span_label(
421                             arg.span,
422                             "this parameter takes ownership of the value".to_string(),
423                         );
424                         let descr = match node.fn_kind() {
425                             Some(hir::intravisit::FnKind::ItemFn(..)) | None => "function",
426                             Some(hir::intravisit::FnKind::Method(..)) => "method",
427                             Some(hir::intravisit::FnKind::Closure) => "closure",
428                         };
429                         span.push_span_label(
430                             ident.span,
431                             format!("in this {descr}"),
432                         );
433                         err.span_note(
434                             span,
435                             format!(
436                                 "consider changing this parameter type in {descr} `{ident}` to \
437                                  borrow instead if owning the value isn't necessary",
438                             ),
439                         );
440                     }
441                     let place = &self.move_data.move_paths[mpi].place;
442                     let ty = place.ty(self.body, self.infcx.tcx).ty;
443                     if let hir::Node::Expr(parent_expr) = parent
444                         && let hir::ExprKind::Call(call_expr, _) = parent_expr.kind
445                         && let hir::ExprKind::Path(
446                             hir::QPath::LangItem(LangItem::IntoIterIntoIter, _, _)
447                         ) = call_expr.kind
448                     {
449                         // Do not suggest `.clone()` in a `for` loop, we already suggest borrowing.
450                     } else if let UseSpans::FnSelfUse {
451                         kind: CallKind::Normal { .. },
452                         ..
453                     } = move_spans {
454                         // We already suggest cloning for these cases in `explain_captures`.
455                     } else {
456                         self.suggest_cloning(err, ty, move_span);
457                     }
458                 }
459             }
460             if let Some(pat) = finder.pat {
461                 *in_pattern = true;
462                 let mut sugg = vec![(pat.span.shrink_to_lo(), "ref ".to_string())];
463                 if let Some(pat) = finder.parent_pat {
464                     sugg.insert(0, (pat.span.shrink_to_lo(), "ref ".to_string()));
465                 }
466                 err.multipart_suggestion_verbose(
467                     "borrow this binding in the pattern to avoid moving the value",
468                     sugg,
469                     Applicability::MachineApplicable,
470                 );
471             }
472         }
473     }
474
475     fn report_use_of_uninitialized(
476         &self,
477         mpi: MovePathIndex,
478         used_place: PlaceRef<'tcx>,
479         moved_place: PlaceRef<'tcx>,
480         desired_action: InitializationRequiringAction,
481         span: Span,
482         use_spans: UseSpans<'tcx>,
483     ) -> DiagnosticBuilder<'cx, ErrorGuaranteed> {
484         // We need all statements in the body where the binding was assigned to to later find all
485         // the branching code paths where the binding *wasn't* assigned to.
486         let inits = &self.move_data.init_path_map[mpi];
487         let move_path = &self.move_data.move_paths[mpi];
488         let decl_span = self.body.local_decls[move_path.place.local].source_info.span;
489         let mut spans = vec![];
490         for init_idx in inits {
491             let init = &self.move_data.inits[*init_idx];
492             let span = init.span(&self.body);
493             if !span.is_dummy() {
494                 spans.push(span);
495             }
496         }
497
498         let (name, desc) = match self.describe_place_with_options(
499             moved_place,
500             DescribePlaceOpt { including_downcast: true, including_tuple_field: true },
501         ) {
502             Some(name) => (format!("`{name}`"), format!("`{name}` ")),
503             None => ("the variable".to_string(), String::new()),
504         };
505         let path = match self.describe_place_with_options(
506             used_place,
507             DescribePlaceOpt { including_downcast: true, including_tuple_field: true },
508         ) {
509             Some(name) => format!("`{name}`"),
510             None => "value".to_string(),
511         };
512
513         // We use the statements were the binding was initialized, and inspect the HIR to look
514         // for the branching codepaths that aren't covered, to point at them.
515         let map = self.infcx.tcx.hir();
516         let body_id = map.body_owned_by(self.mir_def_id());
517         let body = map.body(body_id);
518
519         let mut visitor = ConditionVisitor { spans: &spans, name: &name, errors: vec![] };
520         visitor.visit_body(&body);
521
522         let mut show_assign_sugg = false;
523         let isnt_initialized = if let InitializationRequiringAction::PartialAssignment
524         | InitializationRequiringAction::Assignment = desired_action
525         {
526             // The same error is emitted for bindings that are *sometimes* initialized and the ones
527             // that are *partially* initialized by assigning to a field of an uninitialized
528             // binding. We differentiate between them for more accurate wording here.
529             "isn't fully initialized"
530         } else if !spans.iter().any(|i| {
531             // We filter these to avoid misleading wording in cases like the following,
532             // where `x` has an `init`, but it is in the same place we're looking at:
533             // ```
534             // let x;
535             // x += 1;
536             // ```
537             !i.contains(span)
538             // We filter these to avoid incorrect main message on `match-cfg-fake-edges.rs`
539             && !visitor
540                 .errors
541                 .iter()
542                 .map(|(sp, _)| *sp)
543                 .any(|sp| span < sp && !sp.contains(span))
544         }) {
545             show_assign_sugg = true;
546             "isn't initialized"
547         } else {
548             "is possibly-uninitialized"
549         };
550
551         let used = desired_action.as_general_verb_in_past_tense();
552         let mut err =
553             struct_span_err!(self, span, E0381, "{used} binding {desc}{isnt_initialized}");
554         use_spans.var_path_only_subdiag(&mut err, desired_action);
555
556         if let InitializationRequiringAction::PartialAssignment
557         | InitializationRequiringAction::Assignment = desired_action
558         {
559             err.help(
560                 "partial initialization isn't supported, fully initialize the binding with a \
561                  default value and mutate it, or use `std::mem::MaybeUninit`",
562             );
563         }
564         err.span_label(span, format!("{path} {used} here but it {isnt_initialized}"));
565
566         let mut shown = false;
567         for (sp, label) in visitor.errors {
568             if sp < span && !sp.overlaps(span) {
569                 // When we have a case like `match-cfg-fake-edges.rs`, we don't want to mention
570                 // match arms coming after the primary span because they aren't relevant:
571                 // ```
572                 // let x;
573                 // match y {
574                 //     _ if { x = 2; true } => {}
575                 //     _ if {
576                 //         x; //~ ERROR
577                 //         false
578                 //     } => {}
579                 //     _ => {} // We don't want to point to this.
580                 // };
581                 // ```
582                 err.span_label(sp, &label);
583                 shown = true;
584             }
585         }
586         if !shown {
587             for sp in &spans {
588                 if *sp < span && !sp.overlaps(span) {
589                     err.span_label(*sp, "binding initialized here in some conditions");
590                 }
591             }
592         }
593
594         err.span_label(decl_span, "binding declared here but left uninitialized");
595         if show_assign_sugg {
596             struct LetVisitor {
597                 decl_span: Span,
598                 sugg_span: Option<Span>,
599             }
600
601             impl<'v> Visitor<'v> for LetVisitor {
602                 fn visit_stmt(&mut self, ex: &'v hir::Stmt<'v>) {
603                     if self.sugg_span.is_some() {
604                         return;
605                     }
606                     if let hir::StmtKind::Local(hir::Local {
607                             span, ty, init: None, ..
608                         }) = &ex.kind && span.contains(self.decl_span) {
609                             self.sugg_span = ty.map_or(Some(self.decl_span), |ty| Some(ty.span));
610                     }
611                     hir::intravisit::walk_stmt(self, ex);
612                 }
613             }
614
615             let mut visitor = LetVisitor { decl_span, sugg_span: None };
616             visitor.visit_body(&body);
617             if let Some(span) = visitor.sugg_span {
618                 self.suggest_assign_value(&mut err, moved_place, span);
619             }
620         }
621         err
622     }
623
624     fn suggest_assign_value(
625         &self,
626         err: &mut Diagnostic,
627         moved_place: PlaceRef<'tcx>,
628         sugg_span: Span,
629     ) {
630         let ty = moved_place.ty(self.body, self.infcx.tcx).ty;
631         debug!("ty: {:?}, kind: {:?}", ty, ty.kind());
632
633         let tcx = self.infcx.tcx;
634         let implements_default = |ty, param_env| {
635             let Some(default_trait) = tcx.get_diagnostic_item(sym::Default) else {
636                 return false;
637             };
638             // Regions are already solved, so we must use a fresh InferCtxt,
639             // but the type has region variables, so erase those.
640             tcx.infer_ctxt()
641                 .build()
642                 .type_implements_trait(default_trait, [tcx.erase_regions(ty)], param_env)
643                 .must_apply_modulo_regions()
644         };
645
646         let assign_value = match ty.kind() {
647             ty::Bool => "false",
648             ty::Float(_) => "0.0",
649             ty::Int(_) | ty::Uint(_) => "0",
650             ty::Never | ty::Error(_) => "",
651             ty::Adt(def, _) if Some(def.did()) == tcx.get_diagnostic_item(sym::Vec) => "vec![]",
652             ty::Adt(_, _) if implements_default(ty, self.param_env) => "Default::default()",
653             _ => "todo!()",
654         };
655
656         if !assign_value.is_empty() {
657             err.span_suggestion_verbose(
658                 sugg_span.shrink_to_hi(),
659                 "consider assigning a value",
660                 format!(" = {}", assign_value),
661                 Applicability::MaybeIncorrect,
662             );
663         }
664     }
665
666     fn suggest_borrow_fn_like(
667         &self,
668         err: &mut Diagnostic,
669         ty: Ty<'tcx>,
670         move_sites: &[MoveSite],
671         value_name: &str,
672     ) -> bool {
673         let tcx = self.infcx.tcx;
674
675         // Find out if the predicates show that the type is a Fn or FnMut
676         let find_fn_kind_from_did = |predicates: ty::EarlyBinder<
677             &[(ty::Predicate<'tcx>, Span)],
678         >,
679                                      substs| {
680             predicates.0.iter().find_map(|(pred, _)| {
681                     let pred = if let Some(substs) = substs {
682                         predicates.rebind(*pred).subst(tcx, substs).kind().skip_binder()
683                     } else {
684                         pred.kind().skip_binder()
685                     };
686                     if let ty::PredicateKind::Clause(ty::Clause::Trait(pred)) = pred && pred.self_ty() == ty {
687                     if Some(pred.def_id()) == tcx.lang_items().fn_trait() {
688                         return Some(hir::Mutability::Not);
689                     } else if Some(pred.def_id()) == tcx.lang_items().fn_mut_trait() {
690                         return Some(hir::Mutability::Mut);
691                     }
692                 }
693                     None
694                 })
695         };
696
697         // If the type is opaque/param/closure, and it is Fn or FnMut, let's suggest (mutably)
698         // borrowing the type, since `&mut F: FnMut` iff `F: FnMut` and similarly for `Fn`.
699         // These types seem reasonably opaque enough that they could be substituted with their
700         // borrowed variants in a function body when we see a move error.
701         let borrow_level = match ty.kind() {
702             ty::Param(_) => find_fn_kind_from_did(
703                 tcx.bound_explicit_predicates_of(self.mir_def_id().to_def_id())
704                     .map_bound(|p| p.predicates),
705                 None,
706             ),
707             ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs, .. }) => {
708                 find_fn_kind_from_did(tcx.bound_explicit_item_bounds(*def_id), Some(*substs))
709             }
710             ty::Closure(_, substs) => match substs.as_closure().kind() {
711                 ty::ClosureKind::Fn => Some(hir::Mutability::Not),
712                 ty::ClosureKind::FnMut => Some(hir::Mutability::Mut),
713                 _ => None,
714             },
715             _ => None,
716         };
717
718         let Some(borrow_level) = borrow_level else { return false; };
719         let sugg = move_sites
720             .iter()
721             .map(|move_site| {
722                 let move_out = self.move_data.moves[(*move_site).moi];
723                 let moved_place = &self.move_data.move_paths[move_out.path].place;
724                 let move_spans = self.move_spans(moved_place.as_ref(), move_out.source);
725                 let move_span = move_spans.args_or_use();
726                 let suggestion = borrow_level.ref_prefix_str().to_owned();
727                 (move_span.shrink_to_lo(), suggestion)
728             })
729             .collect();
730         err.multipart_suggestion_verbose(
731             format!("consider {}borrowing {value_name}", borrow_level.mutably_str()),
732             sugg,
733             Applicability::MaybeIncorrect,
734         );
735         true
736     }
737
738     fn suggest_cloning(&self, err: &mut Diagnostic, ty: Ty<'tcx>, span: Span) {
739         let tcx = self.infcx.tcx;
740         // Try to find predicates on *generic params* that would allow copying `ty`
741         let infcx = tcx.infer_ctxt().build();
742
743         if let Some(clone_trait_def) = tcx.lang_items().clone_trait()
744             && infcx
745                 .type_implements_trait(
746                     clone_trait_def,
747                     [tcx.erase_regions(ty)],
748                     self.param_env,
749                 )
750                 .must_apply_modulo_regions()
751         {
752             err.span_suggestion_verbose(
753                 span.shrink_to_hi(),
754                 "consider cloning the value if the performance cost is acceptable",
755                 ".clone()",
756                 Applicability::MachineApplicable,
757             );
758         }
759     }
760
761     fn suggest_adding_copy_bounds(&self, err: &mut Diagnostic, ty: Ty<'tcx>, span: Span) {
762         let tcx = self.infcx.tcx;
763         let generics = tcx.generics_of(self.mir_def_id());
764
765         let Some(hir_generics) = tcx
766             .typeck_root_def_id(self.mir_def_id().to_def_id())
767             .as_local()
768             .and_then(|def_id| tcx.hir().get_generics(def_id))
769         else { return; };
770         // Try to find predicates on *generic params* that would allow copying `ty`
771         let infcx = tcx.infer_ctxt().build();
772         let copy_did = infcx.tcx.require_lang_item(LangItem::Copy, Some(span));
773         let cause = ObligationCause::new(
774             span,
775             self.mir_hir_id(),
776             rustc_infer::traits::ObligationCauseCode::MiscObligation,
777         );
778         let errors = rustc_trait_selection::traits::fully_solve_bound(
779             &infcx,
780             cause,
781             self.param_env,
782             // Erase any region vids from the type, which may not be resolved
783             infcx.tcx.erase_regions(ty),
784             copy_did,
785         );
786
787         // Only emit suggestion if all required predicates are on generic
788         let predicates: Result<Vec<_>, _> = errors
789             .into_iter()
790             .map(|err| match err.obligation.predicate.kind().skip_binder() {
791                 PredicateKind::Clause(ty::Clause::Trait(predicate)) => {
792                     match predicate.self_ty().kind() {
793                         ty::Param(param_ty) => Ok((
794                             generics.type_param(param_ty, tcx),
795                             predicate.trait_ref.print_only_trait_path().to_string(),
796                         )),
797                         _ => Err(()),
798                     }
799                 }
800                 _ => Err(()),
801             })
802             .collect();
803
804         if let Ok(predicates) = predicates {
805             suggest_constraining_type_params(
806                 tcx,
807                 hir_generics,
808                 err,
809                 predicates
810                     .iter()
811                     .map(|(param, constraint)| (param.name.as_str(), &**constraint, None)),
812             );
813         }
814     }
815
816     pub(crate) fn report_move_out_while_borrowed(
817         &mut self,
818         location: Location,
819         (place, span): (Place<'tcx>, Span),
820         borrow: &BorrowData<'tcx>,
821     ) {
822         debug!(
823             "report_move_out_while_borrowed: location={:?} place={:?} span={:?} borrow={:?}",
824             location, place, span, borrow
825         );
826         let value_msg = self.describe_any_place(place.as_ref());
827         let borrow_msg = self.describe_any_place(borrow.borrowed_place.as_ref());
828
829         let borrow_spans = self.retrieve_borrow_spans(borrow);
830         let borrow_span = borrow_spans.args_or_use();
831
832         let move_spans = self.move_spans(place.as_ref(), location);
833         let span = move_spans.args_or_use();
834
835         let mut err = self.cannot_move_when_borrowed(
836             span,
837             borrow_span,
838             &self.describe_any_place(place.as_ref()),
839             &borrow_msg,
840             &value_msg,
841         );
842
843         borrow_spans.var_path_only_subdiag(&mut err, crate::InitializationRequiringAction::Borrow);
844
845         move_spans.var_span_label(
846             &mut err,
847             format!("move occurs due to use{}", move_spans.describe()),
848             "moved",
849         );
850
851         self.explain_why_borrow_contains_point(location, borrow, None)
852             .add_explanation_to_diagnostic(
853                 self.infcx.tcx,
854                 &self.body,
855                 &self.local_names,
856                 &mut err,
857                 "",
858                 Some(borrow_span),
859                 None,
860             );
861         self.buffer_error(err);
862     }
863
864     pub(crate) fn report_use_while_mutably_borrowed(
865         &mut self,
866         location: Location,
867         (place, _span): (Place<'tcx>, Span),
868         borrow: &BorrowData<'tcx>,
869     ) -> DiagnosticBuilder<'cx, ErrorGuaranteed> {
870         let borrow_spans = self.retrieve_borrow_spans(borrow);
871         let borrow_span = borrow_spans.args_or_use();
872
873         // Conflicting borrows are reported separately, so only check for move
874         // captures.
875         let use_spans = self.move_spans(place.as_ref(), location);
876         let span = use_spans.var_or_use();
877
878         // 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
879         // we call `var_span_label` on `borrow_spans` to annotate if the existing borrow was in a closure
880         let mut err = self.cannot_use_when_mutably_borrowed(
881             span,
882             &self.describe_any_place(place.as_ref()),
883             borrow_span,
884             &self.describe_any_place(borrow.borrowed_place.as_ref()),
885         );
886         borrow_spans.var_subdiag(&mut err, Some(borrow.kind), |kind, var_span| {
887             use crate::session_diagnostics::CaptureVarCause::*;
888             let place = &borrow.borrowed_place;
889             let desc_place = self.describe_any_place(place.as_ref());
890             match kind {
891                 Some(_) => BorrowUsePlaceGenerator { place: desc_place, var_span },
892                 None => BorrowUsePlaceClosure { place: desc_place, var_span },
893             }
894         });
895
896         self.explain_why_borrow_contains_point(location, borrow, None)
897             .add_explanation_to_diagnostic(
898                 self.infcx.tcx,
899                 &self.body,
900                 &self.local_names,
901                 &mut err,
902                 "",
903                 None,
904                 None,
905             );
906         err
907     }
908
909     pub(crate) fn report_conflicting_borrow(
910         &mut self,
911         location: Location,
912         (place, span): (Place<'tcx>, Span),
913         gen_borrow_kind: BorrowKind,
914         issued_borrow: &BorrowData<'tcx>,
915     ) -> DiagnosticBuilder<'cx, ErrorGuaranteed> {
916         let issued_spans = self.retrieve_borrow_spans(issued_borrow);
917         let issued_span = issued_spans.args_or_use();
918
919         let borrow_spans = self.borrow_spans(span, location);
920         let span = borrow_spans.args_or_use();
921
922         let container_name = if issued_spans.for_generator() || borrow_spans.for_generator() {
923             "generator"
924         } else {
925             "closure"
926         };
927
928         let (desc_place, msg_place, msg_borrow, union_type_name) =
929             self.describe_place_for_conflicting_borrow(place, issued_borrow.borrowed_place);
930
931         let explanation = self.explain_why_borrow_contains_point(location, issued_borrow, None);
932         let second_borrow_desc = if explanation.is_explained() { "second " } else { "" };
933
934         // FIXME: supply non-"" `opt_via` when appropriate
935         let first_borrow_desc;
936         let mut err = match (gen_borrow_kind, issued_borrow.kind) {
937             (BorrowKind::Shared, BorrowKind::Mut { .. }) => {
938                 first_borrow_desc = "mutable ";
939                 self.cannot_reborrow_already_borrowed(
940                     span,
941                     &desc_place,
942                     &msg_place,
943                     "immutable",
944                     issued_span,
945                     "it",
946                     "mutable",
947                     &msg_borrow,
948                     None,
949                 )
950             }
951             (BorrowKind::Mut { .. }, BorrowKind::Shared) => {
952                 first_borrow_desc = "immutable ";
953                 let mut err = self.cannot_reborrow_already_borrowed(
954                     span,
955                     &desc_place,
956                     &msg_place,
957                     "mutable",
958                     issued_span,
959                     "it",
960                     "immutable",
961                     &msg_borrow,
962                     None,
963                 );
964                 self.suggest_binding_for_closure_capture_self(
965                     &mut err,
966                     issued_borrow.borrowed_place,
967                     &issued_spans,
968                 );
969                 err
970             }
971
972             (BorrowKind::Mut { .. }, BorrowKind::Mut { .. }) => {
973                 first_borrow_desc = "first ";
974                 let mut err = self.cannot_mutably_borrow_multiply(
975                     span,
976                     &desc_place,
977                     &msg_place,
978                     issued_span,
979                     &msg_borrow,
980                     None,
981                 );
982                 self.suggest_split_at_mut_if_applicable(
983                     &mut err,
984                     place,
985                     issued_borrow.borrowed_place,
986                 );
987                 err
988             }
989
990             (BorrowKind::Unique, BorrowKind::Unique) => {
991                 first_borrow_desc = "first ";
992                 self.cannot_uniquely_borrow_by_two_closures(span, &desc_place, issued_span, None)
993             }
994
995             (BorrowKind::Mut { .. } | BorrowKind::Unique, BorrowKind::Shallow) => {
996                 if let Some(immutable_section_description) =
997                     self.classify_immutable_section(issued_borrow.assigned_place)
998                 {
999                     let mut err = self.cannot_mutate_in_immutable_section(
1000                         span,
1001                         issued_span,
1002                         &desc_place,
1003                         immutable_section_description,
1004                         "mutably borrow",
1005                     );
1006                     borrow_spans.var_span_label(
1007                         &mut err,
1008                         format!(
1009                             "borrow occurs due to use of {}{}",
1010                             desc_place,
1011                             borrow_spans.describe(),
1012                         ),
1013                         "immutable",
1014                     );
1015
1016                     return err;
1017                 } else {
1018                     first_borrow_desc = "immutable ";
1019                     self.cannot_reborrow_already_borrowed(
1020                         span,
1021                         &desc_place,
1022                         &msg_place,
1023                         "mutable",
1024                         issued_span,
1025                         "it",
1026                         "immutable",
1027                         &msg_borrow,
1028                         None,
1029                     )
1030                 }
1031             }
1032
1033             (BorrowKind::Unique, _) => {
1034                 first_borrow_desc = "first ";
1035                 self.cannot_uniquely_borrow_by_one_closure(
1036                     span,
1037                     container_name,
1038                     &desc_place,
1039                     "",
1040                     issued_span,
1041                     "it",
1042                     "",
1043                     None,
1044                 )
1045             }
1046
1047             (BorrowKind::Shared, BorrowKind::Unique) => {
1048                 first_borrow_desc = "first ";
1049                 self.cannot_reborrow_already_uniquely_borrowed(
1050                     span,
1051                     container_name,
1052                     &desc_place,
1053                     "",
1054                     "immutable",
1055                     issued_span,
1056                     "",
1057                     None,
1058                     second_borrow_desc,
1059                 )
1060             }
1061
1062             (BorrowKind::Mut { .. }, BorrowKind::Unique) => {
1063                 first_borrow_desc = "first ";
1064                 self.cannot_reborrow_already_uniquely_borrowed(
1065                     span,
1066                     container_name,
1067                     &desc_place,
1068                     "",
1069                     "mutable",
1070                     issued_span,
1071                     "",
1072                     None,
1073                     second_borrow_desc,
1074                 )
1075             }
1076
1077             (BorrowKind::Shared, BorrowKind::Shared | BorrowKind::Shallow)
1078             | (
1079                 BorrowKind::Shallow,
1080                 BorrowKind::Mut { .. }
1081                 | BorrowKind::Unique
1082                 | BorrowKind::Shared
1083                 | BorrowKind::Shallow,
1084             ) => unreachable!(),
1085         };
1086
1087         if issued_spans == borrow_spans {
1088             borrow_spans.var_span_label(
1089                 &mut err,
1090                 format!("borrows occur due to use of {}{}", desc_place, borrow_spans.describe(),),
1091                 gen_borrow_kind.describe_mutability(),
1092             );
1093         } else {
1094             let borrow_place = &issued_borrow.borrowed_place;
1095             let borrow_place_desc = self.describe_any_place(borrow_place.as_ref());
1096             issued_spans.var_span_label(
1097                 &mut err,
1098                 format!(
1099                     "first borrow occurs due to use of {}{}",
1100                     borrow_place_desc,
1101                     issued_spans.describe(),
1102                 ),
1103                 issued_borrow.kind.describe_mutability(),
1104             );
1105
1106             borrow_spans.var_span_label(
1107                 &mut err,
1108                 format!(
1109                     "second borrow occurs due to use of {}{}",
1110                     desc_place,
1111                     borrow_spans.describe(),
1112                 ),
1113                 gen_borrow_kind.describe_mutability(),
1114             );
1115         }
1116
1117         if union_type_name != "" {
1118             err.note(&format!(
1119                 "{} is a field of the union `{}`, so it overlaps the field {}",
1120                 msg_place, union_type_name, msg_borrow,
1121             ));
1122         }
1123
1124         explanation.add_explanation_to_diagnostic(
1125             self.infcx.tcx,
1126             &self.body,
1127             &self.local_names,
1128             &mut err,
1129             first_borrow_desc,
1130             None,
1131             Some((issued_span, span)),
1132         );
1133
1134         self.suggest_using_local_if_applicable(&mut err, location, issued_borrow, explanation);
1135
1136         err
1137     }
1138
1139     #[instrument(level = "debug", skip(self, err))]
1140     fn suggest_using_local_if_applicable(
1141         &self,
1142         err: &mut Diagnostic,
1143         location: Location,
1144         issued_borrow: &BorrowData<'tcx>,
1145         explanation: BorrowExplanation<'tcx>,
1146     ) {
1147         let used_in_call = matches!(
1148             explanation,
1149             BorrowExplanation::UsedLater(LaterUseKind::Call | LaterUseKind::Other, _call_span, _)
1150         );
1151         if !used_in_call {
1152             debug!("not later used in call");
1153             return;
1154         }
1155
1156         let use_span =
1157             if let BorrowExplanation::UsedLater(LaterUseKind::Other, use_span, _) = explanation {
1158                 Some(use_span)
1159             } else {
1160                 None
1161             };
1162
1163         let outer_call_loc =
1164             if let TwoPhaseActivation::ActivatedAt(loc) = issued_borrow.activation_location {
1165                 loc
1166             } else {
1167                 issued_borrow.reserve_location
1168             };
1169         let outer_call_stmt = self.body.stmt_at(outer_call_loc);
1170
1171         let inner_param_location = location;
1172         let Some(inner_param_stmt) = self.body.stmt_at(inner_param_location).left() else {
1173             debug!("`inner_param_location` {:?} is not for a statement", inner_param_location);
1174             return;
1175         };
1176         let Some(&inner_param) = inner_param_stmt.kind.as_assign().map(|(p, _)| p) else {
1177             debug!(
1178                 "`inner_param_location` {:?} is not for an assignment: {:?}",
1179                 inner_param_location, inner_param_stmt
1180             );
1181             return;
1182         };
1183         let inner_param_uses = find_all_local_uses::find(self.body, inner_param.local);
1184         let Some((inner_call_loc, inner_call_term)) = inner_param_uses.into_iter().find_map(|loc| {
1185             let Either::Right(term) = self.body.stmt_at(loc) else {
1186                 debug!("{:?} is a statement, so it can't be a call", loc);
1187                 return None;
1188             };
1189             let TerminatorKind::Call { args, .. } = &term.kind else {
1190                 debug!("not a call: {:?}", term);
1191                 return None;
1192             };
1193             debug!("checking call args for uses of inner_param: {:?}", args);
1194             if args.contains(&Operand::Move(inner_param)) {
1195                 Some((loc, term))
1196             } else {
1197                 None
1198             }
1199         }) else {
1200             debug!("no uses of inner_param found as a by-move call arg");
1201             return;
1202         };
1203         debug!("===> outer_call_loc = {:?}, inner_call_loc = {:?}", outer_call_loc, inner_call_loc);
1204
1205         let inner_call_span = inner_call_term.source_info.span;
1206         let outer_call_span = match use_span {
1207             Some(span) => span,
1208             None => outer_call_stmt.either(|s| s.source_info, |t| t.source_info).span,
1209         };
1210         if outer_call_span == inner_call_span || !outer_call_span.contains(inner_call_span) {
1211             // FIXME: This stops the suggestion in some cases where it should be emitted.
1212             //        Fix the spans for those cases so it's emitted correctly.
1213             debug!(
1214                 "outer span {:?} does not strictly contain inner span {:?}",
1215                 outer_call_span, inner_call_span
1216             );
1217             return;
1218         }
1219         err.span_help(
1220             inner_call_span,
1221             &format!(
1222                 "try adding a local storing this{}...",
1223                 if use_span.is_some() { "" } else { " argument" }
1224             ),
1225         );
1226         err.span_help(
1227             outer_call_span,
1228             &format!(
1229                 "...and then using that local {}",
1230                 if use_span.is_some() { "here" } else { "as the argument to this call" }
1231             ),
1232         );
1233     }
1234
1235     fn suggest_split_at_mut_if_applicable(
1236         &self,
1237         err: &mut Diagnostic,
1238         place: Place<'tcx>,
1239         borrowed_place: Place<'tcx>,
1240     ) {
1241         if let ([ProjectionElem::Index(_)], [ProjectionElem::Index(_)]) =
1242             (&place.projection[..], &borrowed_place.projection[..])
1243         {
1244             err.help(
1245                 "consider using `.split_at_mut(position)` or similar method to obtain \
1246                      two mutable non-overlapping sub-slices",
1247             );
1248         }
1249     }
1250
1251     fn suggest_binding_for_closure_capture_self(
1252         &self,
1253         err: &mut Diagnostic,
1254         borrowed_place: Place<'tcx>,
1255         issued_spans: &UseSpans<'tcx>,
1256     ) {
1257         let UseSpans::ClosureUse { capture_kind_span, .. } = issued_spans else { return };
1258         let hir = self.infcx.tcx.hir();
1259
1260         // check whether the borrowed place is capturing `self` by mut reference
1261         let local = borrowed_place.local;
1262         let Some(_) = self
1263             .body
1264             .local_decls
1265             .get(local)
1266             .map(|l| mut_borrow_of_mutable_ref(l, self.local_names[local])) else { return };
1267
1268         struct ExpressionFinder<'hir> {
1269             capture_span: Span,
1270             closure_change_spans: Vec<Span>,
1271             closure_arg_span: Option<Span>,
1272             in_closure: bool,
1273             suggest_arg: String,
1274             hir: rustc_middle::hir::map::Map<'hir>,
1275             closure_local_id: Option<hir::HirId>,
1276             closure_call_changes: Vec<(Span, String)>,
1277         }
1278         impl<'hir> Visitor<'hir> for ExpressionFinder<'hir> {
1279             fn visit_expr(&mut self, e: &'hir hir::Expr<'hir>) {
1280                 if e.span.contains(self.capture_span) {
1281                     if let hir::ExprKind::Closure(&hir::Closure {
1282                             movability: None,
1283                             body,
1284                             fn_arg_span,
1285                             fn_decl: hir::FnDecl{ inputs, .. },
1286                             ..
1287                         }) = e.kind &&
1288                         let Some(hir::Node::Expr(body )) = self.hir.find(body.hir_id) {
1289                             self.suggest_arg = "this: &Self".to_string();
1290                             if inputs.len() > 0 {
1291                                 self.suggest_arg.push_str(", ");
1292                             }
1293                             self.in_closure = true;
1294                             self.closure_arg_span = fn_arg_span;
1295                             self.visit_expr(body);
1296                             self.in_closure = false;
1297                     }
1298                 }
1299                 if let hir::Expr { kind: hir::ExprKind::Path(path), .. } = e {
1300                     if let hir::QPath::Resolved(_, hir::Path { segments: [seg], ..}) = path &&
1301                         seg.ident.name == kw::SelfLower && self.in_closure {
1302                             self.closure_change_spans.push(e.span);
1303                     }
1304                 }
1305                 hir::intravisit::walk_expr(self, e);
1306             }
1307
1308             fn visit_local(&mut self, local: &'hir hir::Local<'hir>) {
1309                 if let hir::Pat { kind: hir::PatKind::Binding(_, hir_id, _ident, _), .. } = local.pat &&
1310                     let Some(init) = local.init
1311                 {
1312                     if let hir::Expr { kind: hir::ExprKind::Closure(&hir::Closure {
1313                             movability: None,
1314                             ..
1315                         }), .. } = init &&
1316                         init.span.contains(self.capture_span) {
1317                             self.closure_local_id = Some(*hir_id);
1318                     }
1319                 }
1320                 hir::intravisit::walk_local(self, local);
1321             }
1322
1323             fn visit_stmt(&mut self, s: &'hir hir::Stmt<'hir>) {
1324                 if let hir::StmtKind::Semi(e) = s.kind &&
1325                     let hir::ExprKind::Call(hir::Expr { kind: hir::ExprKind::Path(path), ..}, args) = e.kind &&
1326                     let hir::QPath::Resolved(_, hir::Path { segments: [seg], ..}) = path &&
1327                     let Res::Local(hir_id) = seg.res &&
1328                         Some(hir_id) == self.closure_local_id {
1329                         let (span, arg_str) = if args.len() > 0 {
1330                             (args[0].span.shrink_to_lo(), "self, ".to_string())
1331                         } else {
1332                             let span = e.span.trim_start(seg.ident.span).unwrap_or(e.span);
1333                             (span, "(self)".to_string())
1334                         };
1335                         self.closure_call_changes.push((span, arg_str));
1336                 }
1337                 hir::intravisit::walk_stmt(self, s);
1338             }
1339         }
1340
1341         if let Some(hir::Node::ImplItem(
1342                     hir::ImplItem { kind: hir::ImplItemKind::Fn(_fn_sig, body_id), .. }
1343                 )) = hir.find(self.mir_hir_id()) &&
1344             let Some(hir::Node::Expr(expr)) = hir.find(body_id.hir_id) {
1345             let mut finder = ExpressionFinder {
1346                 capture_span: *capture_kind_span,
1347                 closure_change_spans: vec![],
1348                 closure_arg_span: None,
1349                 in_closure: false,
1350                 suggest_arg: String::new(),
1351                 closure_local_id: None,
1352                 closure_call_changes: vec![],
1353                 hir,
1354             };
1355             finder.visit_expr(expr);
1356
1357             if finder.closure_change_spans.is_empty() || finder.closure_call_changes.is_empty() {
1358                 return;
1359             }
1360
1361             let mut sugg = vec![];
1362             let sm = self.infcx.tcx.sess.source_map();
1363
1364             if let Some(span) = finder.closure_arg_span {
1365                 sugg.push((sm.next_point(span.shrink_to_lo()).shrink_to_hi(), finder.suggest_arg));
1366             }
1367             for span in finder.closure_change_spans {
1368                 sugg.push((span, "this".to_string()));
1369             }
1370
1371             for (span, suggest) in finder.closure_call_changes {
1372                 sugg.push((span, suggest));
1373             }
1374
1375             err.multipart_suggestion_verbose(
1376                 "try explicitly pass `&Self` into the Closure as an argument",
1377                 sugg,
1378                 Applicability::MachineApplicable,
1379             );
1380         }
1381     }
1382
1383     /// Returns the description of the root place for a conflicting borrow and the full
1384     /// descriptions of the places that caused the conflict.
1385     ///
1386     /// In the simplest case, where there are no unions involved, if a mutable borrow of `x` is
1387     /// attempted while a shared borrow is live, then this function will return:
1388     /// ```
1389     /// ("x", "", "")
1390     /// # ;
1391     /// ```
1392     /// In the simple union case, if a mutable borrow of a union field `x.z` is attempted while
1393     /// a shared borrow of another field `x.y`, then this function will return:
1394     /// ```
1395     /// ("x", "x.z", "x.y")
1396     /// # ;
1397     /// ```
1398     /// In the more complex union case, where the union is a field of a struct, then if a mutable
1399     /// borrow of a union field in a struct `x.u.z` is attempted while a shared borrow of
1400     /// another field `x.u.y`, then this function will return:
1401     /// ```
1402     /// ("x.u", "x.u.z", "x.u.y")
1403     /// # ;
1404     /// ```
1405     /// This is used when creating error messages like below:
1406     ///
1407     /// ```text
1408     /// cannot borrow `a.u` (via `a.u.z.c`) as immutable because it is also borrowed as
1409     /// mutable (via `a.u.s.b`) [E0502]
1410     /// ```
1411     pub(crate) fn describe_place_for_conflicting_borrow(
1412         &self,
1413         first_borrowed_place: Place<'tcx>,
1414         second_borrowed_place: Place<'tcx>,
1415     ) -> (String, String, String, String) {
1416         // Define a small closure that we can use to check if the type of a place
1417         // is a union.
1418         let union_ty = |place_base| {
1419             // Need to use fn call syntax `PlaceRef::ty` to determine the type of `place_base`;
1420             // using a type annotation in the closure argument instead leads to a lifetime error.
1421             let ty = PlaceRef::ty(&place_base, self.body, self.infcx.tcx).ty;
1422             ty.ty_adt_def().filter(|adt| adt.is_union()).map(|_| ty)
1423         };
1424
1425         // Start with an empty tuple, so we can use the functions on `Option` to reduce some
1426         // code duplication (particularly around returning an empty description in the failure
1427         // case).
1428         Some(())
1429             .filter(|_| {
1430                 // If we have a conflicting borrow of the same place, then we don't want to add
1431                 // an extraneous "via x.y" to our diagnostics, so filter out this case.
1432                 first_borrowed_place != second_borrowed_place
1433             })
1434             .and_then(|_| {
1435                 // We're going to want to traverse the first borrowed place to see if we can find
1436                 // field access to a union. If we find that, then we will keep the place of the
1437                 // union being accessed and the field that was being accessed so we can check the
1438                 // second borrowed place for the same union and an access to a different field.
1439                 for (place_base, elem) in first_borrowed_place.iter_projections().rev() {
1440                     match elem {
1441                         ProjectionElem::Field(field, _) if union_ty(place_base).is_some() => {
1442                             return Some((place_base, field));
1443                         }
1444                         _ => {}
1445                     }
1446                 }
1447                 None
1448             })
1449             .and_then(|(target_base, target_field)| {
1450                 // With the place of a union and a field access into it, we traverse the second
1451                 // borrowed place and look for an access to a different field of the same union.
1452                 for (place_base, elem) in second_borrowed_place.iter_projections().rev() {
1453                     if let ProjectionElem::Field(field, _) = elem {
1454                         if let Some(union_ty) = union_ty(place_base) {
1455                             if field != target_field && place_base == target_base {
1456                                 return Some((
1457                                     self.describe_any_place(place_base),
1458                                     self.describe_any_place(first_borrowed_place.as_ref()),
1459                                     self.describe_any_place(second_borrowed_place.as_ref()),
1460                                     union_ty.to_string(),
1461                                 ));
1462                             }
1463                         }
1464                     }
1465                 }
1466                 None
1467             })
1468             .unwrap_or_else(|| {
1469                 // If we didn't find a field access into a union, or both places match, then
1470                 // only return the description of the first place.
1471                 (
1472                     self.describe_any_place(first_borrowed_place.as_ref()),
1473                     "".to_string(),
1474                     "".to_string(),
1475                     "".to_string(),
1476                 )
1477             })
1478     }
1479
1480     /// Reports StorageDeadOrDrop of `place` conflicts with `borrow`.
1481     ///
1482     /// This means that some data referenced by `borrow` needs to live
1483     /// past the point where the StorageDeadOrDrop of `place` occurs.
1484     /// This is usually interpreted as meaning that `place` has too
1485     /// short a lifetime. (But sometimes it is more useful to report
1486     /// it as a more direct conflict between the execution of a
1487     /// `Drop::drop` with an aliasing borrow.)
1488     #[instrument(level = "debug", skip(self))]
1489     pub(crate) fn report_borrowed_value_does_not_live_long_enough(
1490         &mut self,
1491         location: Location,
1492         borrow: &BorrowData<'tcx>,
1493         place_span: (Place<'tcx>, Span),
1494         kind: Option<WriteKind>,
1495     ) {
1496         let drop_span = place_span.1;
1497         let root_place =
1498             self.prefixes(borrow.borrowed_place.as_ref(), PrefixSet::All).last().unwrap();
1499
1500         let borrow_spans = self.retrieve_borrow_spans(borrow);
1501         let borrow_span = borrow_spans.var_or_use_path_span();
1502
1503         assert!(root_place.projection.is_empty());
1504         let proper_span = self.body.local_decls[root_place.local].source_info.span;
1505
1506         let root_place_projection = self.infcx.tcx.intern_place_elems(root_place.projection);
1507
1508         if self.access_place_error_reported.contains(&(
1509             Place { local: root_place.local, projection: root_place_projection },
1510             borrow_span,
1511         )) {
1512             debug!(
1513                 "suppressing access_place error when borrow doesn't live long enough for {:?}",
1514                 borrow_span
1515             );
1516             return;
1517         }
1518
1519         self.access_place_error_reported.insert((
1520             Place { local: root_place.local, projection: root_place_projection },
1521             borrow_span,
1522         ));
1523
1524         let borrowed_local = borrow.borrowed_place.local;
1525         if self.body.local_decls[borrowed_local].is_ref_to_thread_local() {
1526             let err =
1527                 self.report_thread_local_value_does_not_live_long_enough(drop_span, borrow_span);
1528             self.buffer_error(err);
1529             return;
1530         }
1531
1532         if let StorageDeadOrDrop::Destructor(dropped_ty) =
1533             self.classify_drop_access_kind(borrow.borrowed_place.as_ref())
1534         {
1535             // If a borrow of path `B` conflicts with drop of `D` (and
1536             // we're not in the uninteresting case where `B` is a
1537             // prefix of `D`), then report this as a more interesting
1538             // destructor conflict.
1539             if !borrow.borrowed_place.as_ref().is_prefix_of(place_span.0.as_ref()) {
1540                 self.report_borrow_conflicts_with_destructor(
1541                     location, borrow, place_span, kind, dropped_ty,
1542                 );
1543                 return;
1544             }
1545         }
1546
1547         let place_desc = self.describe_place(borrow.borrowed_place.as_ref());
1548
1549         let kind_place = kind.filter(|_| place_desc.is_some()).map(|k| (k, place_span.0));
1550         let explanation = self.explain_why_borrow_contains_point(location, &borrow, kind_place);
1551
1552         debug!(?place_desc, ?explanation);
1553
1554         let err = match (place_desc, explanation) {
1555             // If the outlives constraint comes from inside the closure,
1556             // for example:
1557             //
1558             // let x = 0;
1559             // let y = &x;
1560             // Box::new(|| y) as Box<Fn() -> &'static i32>
1561             //
1562             // then just use the normal error. The closure isn't escaping
1563             // and `move` will not help here.
1564             (
1565                 Some(name),
1566                 BorrowExplanation::UsedLater(LaterUseKind::ClosureCapture, var_or_use_span, _),
1567             ) => self.report_escaping_closure_capture(
1568                 borrow_spans,
1569                 borrow_span,
1570                 &RegionName {
1571                     name: self.synthesize_region_name(),
1572                     source: RegionNameSource::Static,
1573                 },
1574                 ConstraintCategory::CallArgument(None),
1575                 var_or_use_span,
1576                 &format!("`{}`", name),
1577                 "block",
1578             ),
1579             (
1580                 Some(name),
1581                 BorrowExplanation::MustBeValidFor {
1582                     category:
1583                         category @ (ConstraintCategory::Return(_)
1584                         | ConstraintCategory::CallArgument(_)
1585                         | ConstraintCategory::OpaqueType),
1586                     from_closure: false,
1587                     ref region_name,
1588                     span,
1589                     ..
1590                 },
1591             ) if borrow_spans.for_generator() | borrow_spans.for_closure() => self
1592                 .report_escaping_closure_capture(
1593                     borrow_spans,
1594                     borrow_span,
1595                     region_name,
1596                     category,
1597                     span,
1598                     &format!("`{}`", name),
1599                     "function",
1600                 ),
1601             (
1602                 name,
1603                 BorrowExplanation::MustBeValidFor {
1604                     category: ConstraintCategory::Assignment,
1605                     from_closure: false,
1606                     region_name:
1607                         RegionName {
1608                             source: RegionNameSource::AnonRegionFromUpvar(upvar_span, upvar_name),
1609                             ..
1610                         },
1611                     span,
1612                     ..
1613                 },
1614             ) => self.report_escaping_data(borrow_span, &name, upvar_span, upvar_name, span),
1615             (Some(name), explanation) => self.report_local_value_does_not_live_long_enough(
1616                 location,
1617                 &name,
1618                 &borrow,
1619                 drop_span,
1620                 borrow_spans,
1621                 explanation,
1622             ),
1623             (None, explanation) => self.report_temporary_value_does_not_live_long_enough(
1624                 location,
1625                 &borrow,
1626                 drop_span,
1627                 borrow_spans,
1628                 proper_span,
1629                 explanation,
1630             ),
1631         };
1632
1633         self.buffer_error(err);
1634     }
1635
1636     fn report_local_value_does_not_live_long_enough(
1637         &mut self,
1638         location: Location,
1639         name: &str,
1640         borrow: &BorrowData<'tcx>,
1641         drop_span: Span,
1642         borrow_spans: UseSpans<'tcx>,
1643         explanation: BorrowExplanation<'tcx>,
1644     ) -> DiagnosticBuilder<'cx, ErrorGuaranteed> {
1645         debug!(
1646             "report_local_value_does_not_live_long_enough(\
1647              {:?}, {:?}, {:?}, {:?}, {:?}\
1648              )",
1649             location, name, borrow, drop_span, borrow_spans
1650         );
1651
1652         let borrow_span = borrow_spans.var_or_use_path_span();
1653         if let BorrowExplanation::MustBeValidFor {
1654             category,
1655             span,
1656             ref opt_place_desc,
1657             from_closure: false,
1658             ..
1659         } = explanation
1660         {
1661             if let Some(diag) = self.try_report_cannot_return_reference_to_local(
1662                 borrow,
1663                 borrow_span,
1664                 span,
1665                 category,
1666                 opt_place_desc.as_ref(),
1667             ) {
1668                 return diag;
1669             }
1670         }
1671
1672         let mut err = self.path_does_not_live_long_enough(borrow_span, &format!("`{}`", name));
1673
1674         if let Some(annotation) = self.annotate_argument_and_return_for_borrow(borrow) {
1675             let region_name = annotation.emit(self, &mut err);
1676
1677             err.span_label(
1678                 borrow_span,
1679                 format!("`{}` would have to be valid for `{}`...", name, region_name),
1680             );
1681
1682             let fn_hir_id = self.mir_hir_id();
1683             err.span_label(
1684                 drop_span,
1685                 format!(
1686                     "...but `{}` will be dropped here, when the {} returns",
1687                     name,
1688                     self.infcx
1689                         .tcx
1690                         .hir()
1691                         .opt_name(fn_hir_id)
1692                         .map(|name| format!("function `{}`", name))
1693                         .unwrap_or_else(|| {
1694                             match &self
1695                                 .infcx
1696                                 .tcx
1697                                 .typeck(self.mir_def_id())
1698                                 .node_type(fn_hir_id)
1699                                 .kind()
1700                             {
1701                                 ty::Closure(..) => "enclosing closure",
1702                                 ty::Generator(..) => "enclosing generator",
1703                                 kind => bug!("expected closure or generator, found {:?}", kind),
1704                             }
1705                             .to_string()
1706                         })
1707                 ),
1708             );
1709
1710             err.note(
1711                 "functions cannot return a borrow to data owned within the function's scope, \
1712                     functions can only return borrows to data passed as arguments",
1713             );
1714             err.note(
1715                 "to learn more, visit <https://doc.rust-lang.org/book/ch04-02-\
1716                     references-and-borrowing.html#dangling-references>",
1717             );
1718
1719             if let BorrowExplanation::MustBeValidFor { .. } = explanation {
1720             } else {
1721                 explanation.add_explanation_to_diagnostic(
1722                     self.infcx.tcx,
1723                     &self.body,
1724                     &self.local_names,
1725                     &mut err,
1726                     "",
1727                     None,
1728                     None,
1729                 );
1730             }
1731         } else {
1732             err.span_label(borrow_span, "borrowed value does not live long enough");
1733             err.span_label(drop_span, format!("`{}` dropped here while still borrowed", name));
1734
1735             let within = if borrow_spans.for_generator() { " by generator" } else { "" };
1736
1737             borrow_spans.args_span_label(&mut err, format!("value captured here{}", within));
1738
1739             explanation.add_explanation_to_diagnostic(
1740                 self.infcx.tcx,
1741                 &self.body,
1742                 &self.local_names,
1743                 &mut err,
1744                 "",
1745                 None,
1746                 None,
1747             );
1748         }
1749
1750         err
1751     }
1752
1753     fn report_borrow_conflicts_with_destructor(
1754         &mut self,
1755         location: Location,
1756         borrow: &BorrowData<'tcx>,
1757         (place, drop_span): (Place<'tcx>, Span),
1758         kind: Option<WriteKind>,
1759         dropped_ty: Ty<'tcx>,
1760     ) {
1761         debug!(
1762             "report_borrow_conflicts_with_destructor(\
1763              {:?}, {:?}, ({:?}, {:?}), {:?}\
1764              )",
1765             location, borrow, place, drop_span, kind,
1766         );
1767
1768         let borrow_spans = self.retrieve_borrow_spans(borrow);
1769         let borrow_span = borrow_spans.var_or_use();
1770
1771         let mut err = self.cannot_borrow_across_destructor(borrow_span);
1772
1773         let what_was_dropped = match self.describe_place(place.as_ref()) {
1774             Some(name) => format!("`{}`", name),
1775             None => String::from("temporary value"),
1776         };
1777
1778         let label = match self.describe_place(borrow.borrowed_place.as_ref()) {
1779             Some(borrowed) => format!(
1780                 "here, drop of {D} needs exclusive access to `{B}`, \
1781                  because the type `{T}` implements the `Drop` trait",
1782                 D = what_was_dropped,
1783                 T = dropped_ty,
1784                 B = borrowed
1785             ),
1786             None => format!(
1787                 "here is drop of {D}; whose type `{T}` implements the `Drop` trait",
1788                 D = what_was_dropped,
1789                 T = dropped_ty
1790             ),
1791         };
1792         err.span_label(drop_span, label);
1793
1794         // Only give this note and suggestion if they could be relevant.
1795         let explanation =
1796             self.explain_why_borrow_contains_point(location, borrow, kind.map(|k| (k, place)));
1797         match explanation {
1798             BorrowExplanation::UsedLater { .. }
1799             | BorrowExplanation::UsedLaterWhenDropped { .. } => {
1800                 err.note("consider using a `let` binding to create a longer lived value");
1801             }
1802             _ => {}
1803         }
1804
1805         explanation.add_explanation_to_diagnostic(
1806             self.infcx.tcx,
1807             &self.body,
1808             &self.local_names,
1809             &mut err,
1810             "",
1811             None,
1812             None,
1813         );
1814
1815         self.buffer_error(err);
1816     }
1817
1818     fn report_thread_local_value_does_not_live_long_enough(
1819         &mut self,
1820         drop_span: Span,
1821         borrow_span: Span,
1822     ) -> DiagnosticBuilder<'cx, ErrorGuaranteed> {
1823         debug!(
1824             "report_thread_local_value_does_not_live_long_enough(\
1825              {:?}, {:?}\
1826              )",
1827             drop_span, borrow_span
1828         );
1829
1830         let mut err = self.thread_local_value_does_not_live_long_enough(borrow_span);
1831
1832         err.span_label(
1833             borrow_span,
1834             "thread-local variables cannot be borrowed beyond the end of the function",
1835         );
1836         err.span_label(drop_span, "end of enclosing function is here");
1837
1838         err
1839     }
1840
1841     #[instrument(level = "debug", skip(self))]
1842     fn report_temporary_value_does_not_live_long_enough(
1843         &mut self,
1844         location: Location,
1845         borrow: &BorrowData<'tcx>,
1846         drop_span: Span,
1847         borrow_spans: UseSpans<'tcx>,
1848         proper_span: Span,
1849         explanation: BorrowExplanation<'tcx>,
1850     ) -> DiagnosticBuilder<'cx, ErrorGuaranteed> {
1851         if let BorrowExplanation::MustBeValidFor { category, span, from_closure: false, .. } =
1852             explanation
1853         {
1854             if let Some(diag) = self.try_report_cannot_return_reference_to_local(
1855                 borrow,
1856                 proper_span,
1857                 span,
1858                 category,
1859                 None,
1860             ) {
1861                 return diag;
1862             }
1863         }
1864
1865         let mut err = self.temporary_value_borrowed_for_too_long(proper_span);
1866         err.span_label(proper_span, "creates a temporary value which is freed while still in use");
1867         err.span_label(drop_span, "temporary value is freed at the end of this statement");
1868
1869         match explanation {
1870             BorrowExplanation::UsedLater(..)
1871             | BorrowExplanation::UsedLaterInLoop(..)
1872             | BorrowExplanation::UsedLaterWhenDropped { .. } => {
1873                 // Only give this note and suggestion if it could be relevant.
1874                 let sm = self.infcx.tcx.sess.source_map();
1875                 let mut suggested = false;
1876                 let msg = "consider using a `let` binding to create a longer lived value";
1877
1878                 /// We check that there's a single level of block nesting to ensure always correct
1879                 /// suggestions. If we don't, then we only provide a free-form message to avoid
1880                 /// misleading users in cases like `tests/ui/nll/borrowed-temporary-error.rs`.
1881                 /// We could expand the analysis to suggest hoising all of the relevant parts of
1882                 /// the users' code to make the code compile, but that could be too much.
1883                 struct NestedStatementVisitor {
1884                     span: Span,
1885                     current: usize,
1886                     found: usize,
1887                 }
1888
1889                 impl<'tcx> Visitor<'tcx> for NestedStatementVisitor {
1890                     fn visit_block(&mut self, block: &hir::Block<'tcx>) {
1891                         self.current += 1;
1892                         walk_block(self, block);
1893                         self.current -= 1;
1894                     }
1895                     fn visit_expr(&mut self, expr: &hir::Expr<'tcx>) {
1896                         if self.span == expr.span {
1897                             self.found = self.current;
1898                         }
1899                         walk_expr(self, expr);
1900                     }
1901                 }
1902                 let source_info = self.body.source_info(location);
1903                 if let Some(scope) = self.body.source_scopes.get(source_info.scope)
1904                     && let ClearCrossCrate::Set(scope_data) = &scope.local_data
1905                     && let Some(node) = self.infcx.tcx.hir().find(scope_data.lint_root)
1906                     && let Some(id) = node.body_id()
1907                     && let hir::ExprKind::Block(block, _) = self.infcx.tcx.hir().body(id).value.kind
1908                 {
1909                     for stmt in block.stmts {
1910                         let mut visitor = NestedStatementVisitor {
1911                             span: proper_span,
1912                             current: 0,
1913                             found: 0,
1914                         };
1915                         visitor.visit_stmt(stmt);
1916                         if visitor.found == 0
1917                             && stmt.span.contains(proper_span)
1918                             && let Some(p) = sm.span_to_margin(stmt.span)
1919                             && let Ok(s) = sm.span_to_snippet(proper_span)
1920                         {
1921                             let addition = format!("let binding = {};\n{}", s, " ".repeat(p));
1922                             err.multipart_suggestion_verbose(
1923                                 msg,
1924                                 vec![
1925                                     (stmt.span.shrink_to_lo(), addition),
1926                                     (proper_span, "binding".to_string()),
1927                                 ],
1928                                 Applicability::MaybeIncorrect,
1929                             );
1930                             suggested = true;
1931                             break;
1932                         }
1933                     }
1934                 }
1935                 if !suggested {
1936                     err.note(msg);
1937                 }
1938             }
1939             _ => {}
1940         }
1941         explanation.add_explanation_to_diagnostic(
1942             self.infcx.tcx,
1943             &self.body,
1944             &self.local_names,
1945             &mut err,
1946             "",
1947             None,
1948             None,
1949         );
1950
1951         let within = if borrow_spans.for_generator() { " by generator" } else { "" };
1952
1953         borrow_spans.args_span_label(&mut err, format!("value captured here{}", within));
1954
1955         err
1956     }
1957
1958     fn try_report_cannot_return_reference_to_local(
1959         &self,
1960         borrow: &BorrowData<'tcx>,
1961         borrow_span: Span,
1962         return_span: Span,
1963         category: ConstraintCategory<'tcx>,
1964         opt_place_desc: Option<&String>,
1965     ) -> Option<DiagnosticBuilder<'cx, ErrorGuaranteed>> {
1966         let return_kind = match category {
1967             ConstraintCategory::Return(_) => "return",
1968             ConstraintCategory::Yield => "yield",
1969             _ => return None,
1970         };
1971
1972         // FIXME use a better heuristic than Spans
1973         let reference_desc = if return_span == self.body.source_info(borrow.reserve_location).span {
1974             "reference to"
1975         } else {
1976             "value referencing"
1977         };
1978
1979         let (place_desc, note) = if let Some(place_desc) = opt_place_desc {
1980             let local_kind = if let Some(local) = borrow.borrowed_place.as_local() {
1981                 match self.body.local_kind(local) {
1982                     LocalKind::ReturnPointer | LocalKind::Temp => {
1983                         bug!("temporary or return pointer with a name")
1984                     }
1985                     LocalKind::Var => "local variable ",
1986                     LocalKind::Arg
1987                         if !self.upvars.is_empty() && local == ty::CAPTURE_STRUCT_LOCAL =>
1988                     {
1989                         "variable captured by `move` "
1990                     }
1991                     LocalKind::Arg => "function parameter ",
1992                 }
1993             } else {
1994                 "local data "
1995             };
1996             (
1997                 format!("{}`{}`", local_kind, place_desc),
1998                 format!("`{}` is borrowed here", place_desc),
1999             )
2000         } else {
2001             let root_place =
2002                 self.prefixes(borrow.borrowed_place.as_ref(), PrefixSet::All).last().unwrap();
2003             let local = root_place.local;
2004             match self.body.local_kind(local) {
2005                 LocalKind::ReturnPointer | LocalKind::Temp => {
2006                     ("temporary value".to_string(), "temporary value created here".to_string())
2007                 }
2008                 LocalKind::Arg => (
2009                     "function parameter".to_string(),
2010                     "function parameter borrowed here".to_string(),
2011                 ),
2012                 LocalKind::Var => {
2013                     ("local binding".to_string(), "local binding introduced here".to_string())
2014                 }
2015             }
2016         };
2017
2018         let mut err = self.cannot_return_reference_to_local(
2019             return_span,
2020             return_kind,
2021             reference_desc,
2022             &place_desc,
2023         );
2024
2025         if return_span != borrow_span {
2026             err.span_label(borrow_span, note);
2027
2028             let tcx = self.infcx.tcx;
2029
2030             let return_ty = self.regioncx.universal_regions().unnormalized_output_ty;
2031             let return_ty = tcx.erase_regions(return_ty);
2032
2033             // to avoid panics
2034             if let Some(iter_trait) = tcx.get_diagnostic_item(sym::Iterator)
2035                 && self
2036                     .infcx
2037                     .type_implements_trait(iter_trait, [return_ty], self.param_env)
2038                     .must_apply_modulo_regions()
2039             {
2040                 err.span_suggestion_hidden(
2041                     return_span.shrink_to_hi(),
2042                     "use `.collect()` to allocate the iterator",
2043                     ".collect::<Vec<_>>()",
2044                     Applicability::MaybeIncorrect,
2045                 );
2046             }
2047         }
2048
2049         Some(err)
2050     }
2051
2052     #[instrument(level = "debug", skip(self))]
2053     fn report_escaping_closure_capture(
2054         &mut self,
2055         use_span: UseSpans<'tcx>,
2056         var_span: Span,
2057         fr_name: &RegionName,
2058         category: ConstraintCategory<'tcx>,
2059         constraint_span: Span,
2060         captured_var: &str,
2061         scope: &str,
2062     ) -> DiagnosticBuilder<'cx, ErrorGuaranteed> {
2063         let tcx = self.infcx.tcx;
2064         let args_span = use_span.args_or_use();
2065
2066         let (sugg_span, suggestion) = match tcx.sess.source_map().span_to_snippet(args_span) {
2067             Ok(string) => {
2068                 if string.starts_with("async ") {
2069                     let pos = args_span.lo() + BytePos(6);
2070                     (args_span.with_lo(pos).with_hi(pos), "move ")
2071                 } else if string.starts_with("async|") {
2072                     let pos = args_span.lo() + BytePos(5);
2073                     (args_span.with_lo(pos).with_hi(pos), " move")
2074                 } else {
2075                     (args_span.shrink_to_lo(), "move ")
2076                 }
2077             }
2078             Err(_) => (args_span, "move |<args>| <body>"),
2079         };
2080         let kind = match use_span.generator_kind() {
2081             Some(generator_kind) => match generator_kind {
2082                 GeneratorKind::Async(async_kind) => match async_kind {
2083                     AsyncGeneratorKind::Block => "async block",
2084                     AsyncGeneratorKind::Closure => "async closure",
2085                     _ => bug!("async block/closure expected, but async function found."),
2086                 },
2087                 GeneratorKind::Gen => "generator",
2088             },
2089             None => "closure",
2090         };
2091
2092         let mut err = self.cannot_capture_in_long_lived_closure(
2093             args_span,
2094             kind,
2095             captured_var,
2096             var_span,
2097             scope,
2098         );
2099         err.span_suggestion_verbose(
2100             sugg_span,
2101             &format!(
2102                 "to force the {} to take ownership of {} (and any \
2103                  other referenced variables), use the `move` keyword",
2104                 kind, captured_var
2105             ),
2106             suggestion,
2107             Applicability::MachineApplicable,
2108         );
2109
2110         match category {
2111             ConstraintCategory::Return(_) | ConstraintCategory::OpaqueType => {
2112                 let msg = format!("{} is returned here", kind);
2113                 err.span_note(constraint_span, &msg);
2114             }
2115             ConstraintCategory::CallArgument(_) => {
2116                 fr_name.highlight_region_name(&mut err);
2117                 if matches!(use_span.generator_kind(), Some(GeneratorKind::Async(_))) {
2118                     err.note(
2119                         "async blocks are not executed immediately and must either take a \
2120                          reference or ownership of outside variables they use",
2121                     );
2122                 } else {
2123                     let msg = format!("{scope} requires argument type to outlive `{fr_name}`");
2124                     err.span_note(constraint_span, &msg);
2125                 }
2126             }
2127             _ => bug!(
2128                 "report_escaping_closure_capture called with unexpected constraint \
2129                  category: `{:?}`",
2130                 category
2131             ),
2132         }
2133
2134         err
2135     }
2136
2137     fn report_escaping_data(
2138         &mut self,
2139         borrow_span: Span,
2140         name: &Option<String>,
2141         upvar_span: Span,
2142         upvar_name: Symbol,
2143         escape_span: Span,
2144     ) -> DiagnosticBuilder<'cx, ErrorGuaranteed> {
2145         let tcx = self.infcx.tcx;
2146
2147         let (_, escapes_from) = tcx.article_and_description(self.mir_def_id().to_def_id());
2148
2149         let mut err =
2150             borrowck_errors::borrowed_data_escapes_closure(tcx, escape_span, escapes_from);
2151
2152         err.span_label(
2153             upvar_span,
2154             format!("`{}` declared here, outside of the {} body", upvar_name, escapes_from),
2155         );
2156
2157         err.span_label(borrow_span, format!("borrow is only valid in the {} body", escapes_from));
2158
2159         if let Some(name) = name {
2160             err.span_label(
2161                 escape_span,
2162                 format!("reference to `{}` escapes the {} body here", name, escapes_from),
2163             );
2164         } else {
2165             err.span_label(
2166                 escape_span,
2167                 format!("reference escapes the {} body here", escapes_from),
2168             );
2169         }
2170
2171         err
2172     }
2173
2174     fn get_moved_indexes(
2175         &mut self,
2176         location: Location,
2177         mpi: MovePathIndex,
2178     ) -> (Vec<MoveSite>, Vec<Location>) {
2179         fn predecessor_locations<'tcx, 'a>(
2180             body: &'a mir::Body<'tcx>,
2181             location: Location,
2182         ) -> impl Iterator<Item = Location> + Captures<'tcx> + 'a {
2183             if location.statement_index == 0 {
2184                 let predecessors = body.basic_blocks.predecessors()[location.block].to_vec();
2185                 Either::Left(predecessors.into_iter().map(move |bb| body.terminator_loc(bb)))
2186             } else {
2187                 Either::Right(std::iter::once(Location {
2188                     statement_index: location.statement_index - 1,
2189                     ..location
2190                 }))
2191             }
2192         }
2193
2194         let mut mpis = vec![mpi];
2195         let move_paths = &self.move_data.move_paths;
2196         mpis.extend(move_paths[mpi].parents(move_paths).map(|(mpi, _)| mpi));
2197
2198         let mut stack = Vec::new();
2199         let mut back_edge_stack = Vec::new();
2200
2201         predecessor_locations(self.body, location).for_each(|predecessor| {
2202             if location.dominates(predecessor, &self.dominators) {
2203                 back_edge_stack.push(predecessor)
2204             } else {
2205                 stack.push(predecessor);
2206             }
2207         });
2208
2209         let mut reached_start = false;
2210
2211         /* Check if the mpi is initialized as an argument */
2212         let mut is_argument = false;
2213         for arg in self.body.args_iter() {
2214             let path = self.move_data.rev_lookup.find_local(arg);
2215             if mpis.contains(&path) {
2216                 is_argument = true;
2217             }
2218         }
2219
2220         let mut visited = FxHashSet::default();
2221         let mut move_locations = FxHashSet::default();
2222         let mut reinits = vec![];
2223         let mut result = vec![];
2224
2225         let mut dfs_iter = |result: &mut Vec<MoveSite>, location: Location, is_back_edge: bool| {
2226             debug!(
2227                 "report_use_of_moved_or_uninitialized: (current_location={:?}, back_edge={})",
2228                 location, is_back_edge
2229             );
2230
2231             if !visited.insert(location) {
2232                 return true;
2233             }
2234
2235             // check for moves
2236             let stmt_kind =
2237                 self.body[location.block].statements.get(location.statement_index).map(|s| &s.kind);
2238             if let Some(StatementKind::StorageDead(..)) = stmt_kind {
2239                 // this analysis only tries to find moves explicitly
2240                 // written by the user, so we ignore the move-outs
2241                 // created by `StorageDead` and at the beginning
2242                 // of a function.
2243             } else {
2244                 // If we are found a use of a.b.c which was in error, then we want to look for
2245                 // moves not only of a.b.c but also a.b and a.
2246                 //
2247                 // Note that the moves data already includes "parent" paths, so we don't have to
2248                 // worry about the other case: that is, if there is a move of a.b.c, it is already
2249                 // marked as a move of a.b and a as well, so we will generate the correct errors
2250                 // there.
2251                 for moi in &self.move_data.loc_map[location] {
2252                     debug!("report_use_of_moved_or_uninitialized: moi={:?}", moi);
2253                     let path = self.move_data.moves[*moi].path;
2254                     if mpis.contains(&path) {
2255                         debug!(
2256                             "report_use_of_moved_or_uninitialized: found {:?}",
2257                             move_paths[path].place
2258                         );
2259                         result.push(MoveSite { moi: *moi, traversed_back_edge: is_back_edge });
2260                         move_locations.insert(location);
2261
2262                         // Strictly speaking, we could continue our DFS here. There may be
2263                         // other moves that can reach the point of error. But it is kind of
2264                         // confusing to highlight them.
2265                         //
2266                         // Example:
2267                         //
2268                         // ```
2269                         // let a = vec![];
2270                         // let b = a;
2271                         // let c = a;
2272                         // drop(a); // <-- current point of error
2273                         // ```
2274                         //
2275                         // Because we stop the DFS here, we only highlight `let c = a`,
2276                         // and not `let b = a`. We will of course also report an error at
2277                         // `let c = a` which highlights `let b = a` as the move.
2278                         return true;
2279                     }
2280                 }
2281             }
2282
2283             // check for inits
2284             let mut any_match = false;
2285             for ii in &self.move_data.init_loc_map[location] {
2286                 let init = self.move_data.inits[*ii];
2287                 match init.kind {
2288                     InitKind::Deep | InitKind::NonPanicPathOnly => {
2289                         if mpis.contains(&init.path) {
2290                             any_match = true;
2291                         }
2292                     }
2293                     InitKind::Shallow => {
2294                         if mpi == init.path {
2295                             any_match = true;
2296                         }
2297                     }
2298                 }
2299             }
2300             if any_match {
2301                 reinits.push(location);
2302                 return true;
2303             }
2304             return false;
2305         };
2306
2307         while let Some(location) = stack.pop() {
2308             if dfs_iter(&mut result, location, false) {
2309                 continue;
2310             }
2311
2312             let mut has_predecessor = false;
2313             predecessor_locations(self.body, location).for_each(|predecessor| {
2314                 if location.dominates(predecessor, &self.dominators) {
2315                     back_edge_stack.push(predecessor)
2316                 } else {
2317                     stack.push(predecessor);
2318                 }
2319                 has_predecessor = true;
2320             });
2321
2322             if !has_predecessor {
2323                 reached_start = true;
2324             }
2325         }
2326         if (is_argument || !reached_start) && result.is_empty() {
2327             /* Process back edges (moves in future loop iterations) only if
2328                the move path is definitely initialized upon loop entry,
2329                to avoid spurious "in previous iteration" errors.
2330                During DFS, if there's a path from the error back to the start
2331                of the function with no intervening init or move, then the
2332                move path may be uninitialized at loop entry.
2333             */
2334             while let Some(location) = back_edge_stack.pop() {
2335                 if dfs_iter(&mut result, location, true) {
2336                     continue;
2337                 }
2338
2339                 predecessor_locations(self.body, location)
2340                     .for_each(|predecessor| back_edge_stack.push(predecessor));
2341             }
2342         }
2343
2344         // Check if we can reach these reinits from a move location.
2345         let reinits_reachable = reinits
2346             .into_iter()
2347             .filter(|reinit| {
2348                 let mut visited = FxHashSet::default();
2349                 let mut stack = vec![*reinit];
2350                 while let Some(location) = stack.pop() {
2351                     if !visited.insert(location) {
2352                         continue;
2353                     }
2354                     if move_locations.contains(&location) {
2355                         return true;
2356                     }
2357                     stack.extend(predecessor_locations(self.body, location));
2358                 }
2359                 false
2360             })
2361             .collect::<Vec<Location>>();
2362         (result, reinits_reachable)
2363     }
2364
2365     pub(crate) fn report_illegal_mutation_of_borrowed(
2366         &mut self,
2367         location: Location,
2368         (place, span): (Place<'tcx>, Span),
2369         loan: &BorrowData<'tcx>,
2370     ) {
2371         let loan_spans = self.retrieve_borrow_spans(loan);
2372         let loan_span = loan_spans.args_or_use();
2373
2374         let descr_place = self.describe_any_place(place.as_ref());
2375         if loan.kind == BorrowKind::Shallow {
2376             if let Some(section) = self.classify_immutable_section(loan.assigned_place) {
2377                 let mut err = self.cannot_mutate_in_immutable_section(
2378                     span,
2379                     loan_span,
2380                     &descr_place,
2381                     section,
2382                     "assign",
2383                 );
2384                 loan_spans.var_span_label(
2385                     &mut err,
2386                     format!("borrow occurs due to use{}", loan_spans.describe()),
2387                     loan.kind.describe_mutability(),
2388                 );
2389
2390                 self.buffer_error(err);
2391
2392                 return;
2393             }
2394         }
2395
2396         let mut err = self.cannot_assign_to_borrowed(span, loan_span, &descr_place);
2397
2398         loan_spans.var_span_label(
2399             &mut err,
2400             format!("borrow occurs due to use{}", loan_spans.describe()),
2401             loan.kind.describe_mutability(),
2402         );
2403
2404         self.explain_why_borrow_contains_point(location, loan, None).add_explanation_to_diagnostic(
2405             self.infcx.tcx,
2406             &self.body,
2407             &self.local_names,
2408             &mut err,
2409             "",
2410             None,
2411             None,
2412         );
2413
2414         self.explain_deref_coercion(loan, &mut err);
2415
2416         self.buffer_error(err);
2417     }
2418
2419     fn explain_deref_coercion(&mut self, loan: &BorrowData<'tcx>, err: &mut Diagnostic) {
2420         let tcx = self.infcx.tcx;
2421         if let (
2422             Some(Terminator { kind: TerminatorKind::Call { from_hir_call: false, .. }, .. }),
2423             Some((method_did, method_substs)),
2424         ) = (
2425             &self.body[loan.reserve_location.block].terminator,
2426             rustc_const_eval::util::find_self_call(
2427                 tcx,
2428                 self.body,
2429                 loan.assigned_place.local,
2430                 loan.reserve_location.block,
2431             ),
2432         ) {
2433             if tcx.is_diagnostic_item(sym::deref_method, method_did) {
2434                 let deref_target =
2435                     tcx.get_diagnostic_item(sym::deref_target).and_then(|deref_target| {
2436                         Instance::resolve(tcx, self.param_env, deref_target, method_substs)
2437                             .transpose()
2438                     });
2439                 if let Some(Ok(instance)) = deref_target {
2440                     let deref_target_ty = instance.ty(tcx, self.param_env);
2441                     err.note(&format!(
2442                         "borrow occurs due to deref coercion to `{}`",
2443                         deref_target_ty
2444                     ));
2445                     err.span_note(tcx.def_span(instance.def_id()), "deref defined here");
2446                 }
2447             }
2448         }
2449     }
2450
2451     /// Reports an illegal reassignment; for example, an assignment to
2452     /// (part of) a non-`mut` local that occurs potentially after that
2453     /// local has already been initialized. `place` is the path being
2454     /// assigned; `err_place` is a place providing a reason why
2455     /// `place` is not mutable (e.g., the non-`mut` local `x` in an
2456     /// assignment to `x.f`).
2457     pub(crate) fn report_illegal_reassignment(
2458         &mut self,
2459         _location: Location,
2460         (place, span): (Place<'tcx>, Span),
2461         assigned_span: Span,
2462         err_place: Place<'tcx>,
2463     ) {
2464         let (from_arg, local_decl, local_name) = match err_place.as_local() {
2465             Some(local) => (
2466                 self.body.local_kind(local) == LocalKind::Arg,
2467                 Some(&self.body.local_decls[local]),
2468                 self.local_names[local],
2469             ),
2470             None => (false, None, None),
2471         };
2472
2473         // If root local is initialized immediately (everything apart from let
2474         // PATTERN;) then make the error refer to that local, rather than the
2475         // place being assigned later.
2476         let (place_description, assigned_span) = match local_decl {
2477             Some(LocalDecl {
2478                 local_info:
2479                     Some(box LocalInfo::User(
2480                         ClearCrossCrate::Clear
2481                         | ClearCrossCrate::Set(BindingForm::Var(VarBindingForm {
2482                             opt_match_place: None,
2483                             ..
2484                         })),
2485                     ))
2486                     | Some(box LocalInfo::StaticRef { .. })
2487                     | None,
2488                 ..
2489             })
2490             | None => (self.describe_any_place(place.as_ref()), assigned_span),
2491             Some(decl) => (self.describe_any_place(err_place.as_ref()), decl.source_info.span),
2492         };
2493
2494         let mut err = self.cannot_reassign_immutable(span, &place_description, from_arg);
2495         let msg = if from_arg {
2496             "cannot assign to immutable argument"
2497         } else {
2498             "cannot assign twice to immutable variable"
2499         };
2500         if span != assigned_span && !from_arg {
2501             err.span_label(assigned_span, format!("first assignment to {}", place_description));
2502         }
2503         if let Some(decl) = local_decl
2504             && let Some(name) = local_name
2505             && decl.can_be_made_mutable()
2506         {
2507             err.span_suggestion(
2508                 decl.source_info.span,
2509                 "consider making this binding mutable",
2510                 format!("mut {}", name),
2511                 Applicability::MachineApplicable,
2512             );
2513         }
2514         err.span_label(span, msg);
2515         self.buffer_error(err);
2516     }
2517
2518     fn classify_drop_access_kind(&self, place: PlaceRef<'tcx>) -> StorageDeadOrDrop<'tcx> {
2519         let tcx = self.infcx.tcx;
2520         let (kind, _place_ty) = place.projection.iter().fold(
2521             (LocalStorageDead, PlaceTy::from_ty(self.body.local_decls[place.local].ty)),
2522             |(kind, place_ty), &elem| {
2523                 (
2524                     match elem {
2525                         ProjectionElem::Deref => match kind {
2526                             StorageDeadOrDrop::LocalStorageDead
2527                             | StorageDeadOrDrop::BoxedStorageDead => {
2528                                 assert!(
2529                                     place_ty.ty.is_box(),
2530                                     "Drop of value behind a reference or raw pointer"
2531                                 );
2532                                 StorageDeadOrDrop::BoxedStorageDead
2533                             }
2534                             StorageDeadOrDrop::Destructor(_) => kind,
2535                         },
2536                         ProjectionElem::OpaqueCast { .. }
2537                         | ProjectionElem::Field(..)
2538                         | ProjectionElem::Downcast(..) => {
2539                             match place_ty.ty.kind() {
2540                                 ty::Adt(def, _) if def.has_dtor(tcx) => {
2541                                     // Report the outermost adt with a destructor
2542                                     match kind {
2543                                         StorageDeadOrDrop::Destructor(_) => kind,
2544                                         StorageDeadOrDrop::LocalStorageDead
2545                                         | StorageDeadOrDrop::BoxedStorageDead => {
2546                                             StorageDeadOrDrop::Destructor(place_ty.ty)
2547                                         }
2548                                     }
2549                                 }
2550                                 _ => kind,
2551                             }
2552                         }
2553                         ProjectionElem::ConstantIndex { .. }
2554                         | ProjectionElem::Subslice { .. }
2555                         | ProjectionElem::Index(_) => kind,
2556                     },
2557                     place_ty.projection_ty(tcx, elem),
2558                 )
2559             },
2560         );
2561         kind
2562     }
2563
2564     /// Describe the reason for the fake borrow that was assigned to `place`.
2565     fn classify_immutable_section(&self, place: Place<'tcx>) -> Option<&'static str> {
2566         use rustc_middle::mir::visit::Visitor;
2567         struct FakeReadCauseFinder<'tcx> {
2568             place: Place<'tcx>,
2569             cause: Option<FakeReadCause>,
2570         }
2571         impl<'tcx> Visitor<'tcx> for FakeReadCauseFinder<'tcx> {
2572             fn visit_statement(&mut self, statement: &Statement<'tcx>, _: Location) {
2573                 match statement {
2574                     Statement { kind: StatementKind::FakeRead(box (cause, place)), .. }
2575                         if *place == self.place =>
2576                     {
2577                         self.cause = Some(*cause);
2578                     }
2579                     _ => (),
2580                 }
2581             }
2582         }
2583         let mut visitor = FakeReadCauseFinder { place, cause: None };
2584         visitor.visit_body(&self.body);
2585         match visitor.cause {
2586             Some(FakeReadCause::ForMatchGuard) => Some("match guard"),
2587             Some(FakeReadCause::ForIndex) => Some("indexing expression"),
2588             _ => None,
2589         }
2590     }
2591
2592     /// Annotate argument and return type of function and closure with (synthesized) lifetime for
2593     /// borrow of local value that does not live long enough.
2594     fn annotate_argument_and_return_for_borrow(
2595         &self,
2596         borrow: &BorrowData<'tcx>,
2597     ) -> Option<AnnotatedBorrowFnSignature<'tcx>> {
2598         // Define a fallback for when we can't match a closure.
2599         let fallback = || {
2600             let is_closure = self.infcx.tcx.is_closure(self.mir_def_id().to_def_id());
2601             if is_closure {
2602                 None
2603             } else {
2604                 let ty = self.infcx.tcx.type_of(self.mir_def_id());
2605                 match ty.kind() {
2606                     ty::FnDef(_, _) | ty::FnPtr(_) => self.annotate_fn_sig(
2607                         self.mir_def_id(),
2608                         self.infcx.tcx.fn_sig(self.mir_def_id()),
2609                     ),
2610                     _ => None,
2611                 }
2612             }
2613         };
2614
2615         // In order to determine whether we need to annotate, we need to check whether the reserve
2616         // place was an assignment into a temporary.
2617         //
2618         // If it was, we check whether or not that temporary is eventually assigned into the return
2619         // place. If it was, we can add annotations about the function's return type and arguments
2620         // and it'll make sense.
2621         let location = borrow.reserve_location;
2622         debug!("annotate_argument_and_return_for_borrow: location={:?}", location);
2623         if let Some(Statement { kind: StatementKind::Assign(box (reservation, _)), .. }) =
2624             &self.body[location.block].statements.get(location.statement_index)
2625         {
2626             debug!("annotate_argument_and_return_for_borrow: reservation={:?}", reservation);
2627             // Check that the initial assignment of the reserve location is into a temporary.
2628             let mut target = match reservation.as_local() {
2629                 Some(local) if self.body.local_kind(local) == LocalKind::Temp => local,
2630                 _ => return None,
2631             };
2632
2633             // Next, look through the rest of the block, checking if we are assigning the
2634             // `target` (that is, the place that contains our borrow) to anything.
2635             let mut annotated_closure = None;
2636             for stmt in &self.body[location.block].statements[location.statement_index + 1..] {
2637                 debug!(
2638                     "annotate_argument_and_return_for_borrow: target={:?} stmt={:?}",
2639                     target, stmt
2640                 );
2641                 if let StatementKind::Assign(box (place, rvalue)) = &stmt.kind {
2642                     if let Some(assigned_to) = place.as_local() {
2643                         debug!(
2644                             "annotate_argument_and_return_for_borrow: assigned_to={:?} \
2645                              rvalue={:?}",
2646                             assigned_to, rvalue
2647                         );
2648                         // Check if our `target` was captured by a closure.
2649                         if let Rvalue::Aggregate(
2650                             box AggregateKind::Closure(def_id, substs),
2651                             operands,
2652                         ) = rvalue
2653                         {
2654                             for operand in operands {
2655                                 let (Operand::Copy(assigned_from) | Operand::Move(assigned_from)) = operand else {
2656                                     continue;
2657                                 };
2658                                 debug!(
2659                                     "annotate_argument_and_return_for_borrow: assigned_from={:?}",
2660                                     assigned_from
2661                                 );
2662
2663                                 // Find the local from the operand.
2664                                 let Some(assigned_from_local) = assigned_from.local_or_deref_local() else {
2665                                     continue;
2666                                 };
2667
2668                                 if assigned_from_local != target {
2669                                     continue;
2670                                 }
2671
2672                                 // If a closure captured our `target` and then assigned
2673                                 // into a place then we should annotate the closure in
2674                                 // case it ends up being assigned into the return place.
2675                                 annotated_closure =
2676                                     self.annotate_fn_sig(*def_id, substs.as_closure().sig());
2677                                 debug!(
2678                                     "annotate_argument_and_return_for_borrow: \
2679                                      annotated_closure={:?} assigned_from_local={:?} \
2680                                      assigned_to={:?}",
2681                                     annotated_closure, assigned_from_local, assigned_to
2682                                 );
2683
2684                                 if assigned_to == mir::RETURN_PLACE {
2685                                     // If it was assigned directly into the return place, then
2686                                     // return now.
2687                                     return annotated_closure;
2688                                 } else {
2689                                     // Otherwise, update the target.
2690                                     target = assigned_to;
2691                                 }
2692                             }
2693
2694                             // If none of our closure's operands matched, then skip to the next
2695                             // statement.
2696                             continue;
2697                         }
2698
2699                         // Otherwise, look at other types of assignment.
2700                         let assigned_from = match rvalue {
2701                             Rvalue::Ref(_, _, assigned_from) => assigned_from,
2702                             Rvalue::Use(operand) => match operand {
2703                                 Operand::Copy(assigned_from) | Operand::Move(assigned_from) => {
2704                                     assigned_from
2705                                 }
2706                                 _ => continue,
2707                             },
2708                             _ => continue,
2709                         };
2710                         debug!(
2711                             "annotate_argument_and_return_for_borrow: \
2712                              assigned_from={:?}",
2713                             assigned_from,
2714                         );
2715
2716                         // Find the local from the rvalue.
2717                         let Some(assigned_from_local) = assigned_from.local_or_deref_local() else { continue };
2718                         debug!(
2719                             "annotate_argument_and_return_for_borrow: \
2720                              assigned_from_local={:?}",
2721                             assigned_from_local,
2722                         );
2723
2724                         // Check if our local matches the target - if so, we've assigned our
2725                         // borrow to a new place.
2726                         if assigned_from_local != target {
2727                             continue;
2728                         }
2729
2730                         // If we assigned our `target` into a new place, then we should
2731                         // check if it was the return place.
2732                         debug!(
2733                             "annotate_argument_and_return_for_borrow: \
2734                              assigned_from_local={:?} assigned_to={:?}",
2735                             assigned_from_local, assigned_to
2736                         );
2737                         if assigned_to == mir::RETURN_PLACE {
2738                             // If it was then return the annotated closure if there was one,
2739                             // else, annotate this function.
2740                             return annotated_closure.or_else(fallback);
2741                         }
2742
2743                         // If we didn't assign into the return place, then we just update
2744                         // the target.
2745                         target = assigned_to;
2746                     }
2747                 }
2748             }
2749
2750             // Check the terminator if we didn't find anything in the statements.
2751             let terminator = &self.body[location.block].terminator();
2752             debug!(
2753                 "annotate_argument_and_return_for_borrow: target={:?} terminator={:?}",
2754                 target, terminator
2755             );
2756             if let TerminatorKind::Call { destination, target: Some(_), args, .. } =
2757                 &terminator.kind
2758             {
2759                 if let Some(assigned_to) = destination.as_local() {
2760                     debug!(
2761                         "annotate_argument_and_return_for_borrow: assigned_to={:?} args={:?}",
2762                         assigned_to, args
2763                     );
2764                     for operand in args {
2765                         let (Operand::Copy(assigned_from) | Operand::Move(assigned_from)) = operand else {
2766                             continue;
2767                         };
2768                         debug!(
2769                             "annotate_argument_and_return_for_borrow: assigned_from={:?}",
2770                             assigned_from,
2771                         );
2772
2773                         if let Some(assigned_from_local) = assigned_from.local_or_deref_local() {
2774                             debug!(
2775                                 "annotate_argument_and_return_for_borrow: assigned_from_local={:?}",
2776                                 assigned_from_local,
2777                             );
2778
2779                             if assigned_to == mir::RETURN_PLACE && assigned_from_local == target {
2780                                 return annotated_closure.or_else(fallback);
2781                             }
2782                         }
2783                     }
2784                 }
2785             }
2786         }
2787
2788         // If we haven't found an assignment into the return place, then we need not add
2789         // any annotations.
2790         debug!("annotate_argument_and_return_for_borrow: none found");
2791         None
2792     }
2793
2794     /// Annotate the first argument and return type of a function signature if they are
2795     /// references.
2796     fn annotate_fn_sig(
2797         &self,
2798         did: LocalDefId,
2799         sig: ty::PolyFnSig<'tcx>,
2800     ) -> Option<AnnotatedBorrowFnSignature<'tcx>> {
2801         debug!("annotate_fn_sig: did={:?} sig={:?}", did, sig);
2802         let is_closure = self.infcx.tcx.is_closure(did.to_def_id());
2803         let fn_hir_id = self.infcx.tcx.hir().local_def_id_to_hir_id(did);
2804         let fn_decl = self.infcx.tcx.hir().fn_decl_by_hir_id(fn_hir_id)?;
2805
2806         // We need to work out which arguments to highlight. We do this by looking
2807         // at the return type, where there are three cases:
2808         //
2809         // 1. If there are named arguments, then we should highlight the return type and
2810         //    highlight any of the arguments that are also references with that lifetime.
2811         //    If there are no arguments that have the same lifetime as the return type,
2812         //    then don't highlight anything.
2813         // 2. The return type is a reference with an anonymous lifetime. If this is
2814         //    the case, then we can take advantage of (and teach) the lifetime elision
2815         //    rules.
2816         //
2817         //    We know that an error is being reported. So the arguments and return type
2818         //    must satisfy the elision rules. Therefore, if there is a single argument
2819         //    then that means the return type and first (and only) argument have the same
2820         //    lifetime and the borrow isn't meeting that, we can highlight the argument
2821         //    and return type.
2822         //
2823         //    If there are multiple arguments then the first argument must be self (else
2824         //    it would not satisfy the elision rules), so we can highlight self and the
2825         //    return type.
2826         // 3. The return type is not a reference. In this case, we don't highlight
2827         //    anything.
2828         let return_ty = sig.output();
2829         match return_ty.skip_binder().kind() {
2830             ty::Ref(return_region, _, _) if return_region.has_name() && !is_closure => {
2831                 // This is case 1 from above, return type is a named reference so we need to
2832                 // search for relevant arguments.
2833                 let mut arguments = Vec::new();
2834                 for (index, argument) in sig.inputs().skip_binder().iter().enumerate() {
2835                     if let ty::Ref(argument_region, _, _) = argument.kind() {
2836                         if argument_region == return_region {
2837                             // Need to use the `rustc_middle::ty` types to compare against the
2838                             // `return_region`. Then use the `rustc_hir` type to get only
2839                             // the lifetime span.
2840                             if let hir::TyKind::Ref(lifetime, _) = &fn_decl.inputs[index].kind {
2841                                 // With access to the lifetime, we can get
2842                                 // the span of it.
2843                                 arguments.push((*argument, lifetime.ident.span));
2844                             } else {
2845                                 bug!("ty type is a ref but hir type is not");
2846                             }
2847                         }
2848                     }
2849                 }
2850
2851                 // We need to have arguments. This shouldn't happen, but it's worth checking.
2852                 if arguments.is_empty() {
2853                     return None;
2854                 }
2855
2856                 // We use a mix of the HIR and the Ty types to get information
2857                 // as the HIR doesn't have full types for closure arguments.
2858                 let return_ty = sig.output().skip_binder();
2859                 let mut return_span = fn_decl.output.span();
2860                 if let hir::FnRetTy::Return(ty) = &fn_decl.output {
2861                     if let hir::TyKind::Ref(lifetime, _) = ty.kind {
2862                         return_span = lifetime.ident.span;
2863                     }
2864                 }
2865
2866                 Some(AnnotatedBorrowFnSignature::NamedFunction {
2867                     arguments,
2868                     return_ty,
2869                     return_span,
2870                 })
2871             }
2872             ty::Ref(_, _, _) if is_closure => {
2873                 // This is case 2 from above but only for closures, return type is anonymous
2874                 // reference so we select
2875                 // the first argument.
2876                 let argument_span = fn_decl.inputs.first()?.span;
2877                 let argument_ty = sig.inputs().skip_binder().first()?;
2878
2879                 // Closure arguments are wrapped in a tuple, so we need to get the first
2880                 // from that.
2881                 if let ty::Tuple(elems) = argument_ty.kind() {
2882                     let &argument_ty = elems.first()?;
2883                     if let ty::Ref(_, _, _) = argument_ty.kind() {
2884                         return Some(AnnotatedBorrowFnSignature::Closure {
2885                             argument_ty,
2886                             argument_span,
2887                         });
2888                     }
2889                 }
2890
2891                 None
2892             }
2893             ty::Ref(_, _, _) => {
2894                 // This is also case 2 from above but for functions, return type is still an
2895                 // anonymous reference so we select the first argument.
2896                 let argument_span = fn_decl.inputs.first()?.span;
2897                 let argument_ty = *sig.inputs().skip_binder().first()?;
2898
2899                 let return_span = fn_decl.output.span();
2900                 let return_ty = sig.output().skip_binder();
2901
2902                 // We expect the first argument to be a reference.
2903                 match argument_ty.kind() {
2904                     ty::Ref(_, _, _) => {}
2905                     _ => return None,
2906                 }
2907
2908                 Some(AnnotatedBorrowFnSignature::AnonymousFunction {
2909                     argument_ty,
2910                     argument_span,
2911                     return_ty,
2912                     return_span,
2913                 })
2914             }
2915             _ => {
2916                 // This is case 3 from above, return type is not a reference so don't highlight
2917                 // anything.
2918                 None
2919             }
2920         }
2921     }
2922 }
2923
2924 #[derive(Debug)]
2925 enum AnnotatedBorrowFnSignature<'tcx> {
2926     NamedFunction {
2927         arguments: Vec<(Ty<'tcx>, Span)>,
2928         return_ty: Ty<'tcx>,
2929         return_span: Span,
2930     },
2931     AnonymousFunction {
2932         argument_ty: Ty<'tcx>,
2933         argument_span: Span,
2934         return_ty: Ty<'tcx>,
2935         return_span: Span,
2936     },
2937     Closure {
2938         argument_ty: Ty<'tcx>,
2939         argument_span: Span,
2940     },
2941 }
2942
2943 impl<'tcx> AnnotatedBorrowFnSignature<'tcx> {
2944     /// Annotate the provided diagnostic with information about borrow from the fn signature that
2945     /// helps explain.
2946     pub(crate) fn emit(&self, cx: &mut MirBorrowckCtxt<'_, 'tcx>, diag: &mut Diagnostic) -> String {
2947         match self {
2948             &AnnotatedBorrowFnSignature::Closure { argument_ty, argument_span } => {
2949                 diag.span_label(
2950                     argument_span,
2951                     format!("has type `{}`", cx.get_name_for_ty(argument_ty, 0)),
2952                 );
2953
2954                 cx.get_region_name_for_ty(argument_ty, 0)
2955             }
2956             &AnnotatedBorrowFnSignature::AnonymousFunction {
2957                 argument_ty,
2958                 argument_span,
2959                 return_ty,
2960                 return_span,
2961             } => {
2962                 let argument_ty_name = cx.get_name_for_ty(argument_ty, 0);
2963                 diag.span_label(argument_span, format!("has type `{}`", argument_ty_name));
2964
2965                 let return_ty_name = cx.get_name_for_ty(return_ty, 0);
2966                 let types_equal = return_ty_name == argument_ty_name;
2967                 diag.span_label(
2968                     return_span,
2969                     format!(
2970                         "{}has type `{}`",
2971                         if types_equal { "also " } else { "" },
2972                         return_ty_name,
2973                     ),
2974                 );
2975
2976                 diag.note(
2977                     "argument and return type have the same lifetime due to lifetime elision rules",
2978                 );
2979                 diag.note(
2980                     "to learn more, visit <https://doc.rust-lang.org/book/ch10-03-\
2981                      lifetime-syntax.html#lifetime-elision>",
2982                 );
2983
2984                 cx.get_region_name_for_ty(return_ty, 0)
2985             }
2986             AnnotatedBorrowFnSignature::NamedFunction { arguments, return_ty, return_span } => {
2987                 // Region of return type and arguments checked to be the same earlier.
2988                 let region_name = cx.get_region_name_for_ty(*return_ty, 0);
2989                 for (_, argument_span) in arguments {
2990                     diag.span_label(*argument_span, format!("has lifetime `{}`", region_name));
2991                 }
2992
2993                 diag.span_label(*return_span, format!("also has lifetime `{}`", region_name,));
2994
2995                 diag.help(&format!(
2996                     "use data from the highlighted arguments which match the `{}` lifetime of \
2997                      the return type",
2998                     region_name,
2999                 ));
3000
3001                 region_name
3002             }
3003         }
3004     }
3005 }
3006
3007 /// Detect whether one of the provided spans is a statement nested within the top-most visited expr
3008 struct ReferencedStatementsVisitor<'a>(&'a [Span], bool);
3009
3010 impl<'a, 'v> Visitor<'v> for ReferencedStatementsVisitor<'a> {
3011     fn visit_stmt(&mut self, s: &'v hir::Stmt<'v>) {
3012         match s.kind {
3013             hir::StmtKind::Semi(expr) if self.0.contains(&expr.span) => {
3014                 self.1 = true;
3015             }
3016             _ => {}
3017         }
3018     }
3019 }
3020
3021 /// Given a set of spans representing statements initializing the relevant binding, visit all the
3022 /// function expressions looking for branching code paths that *do not* initialize the binding.
3023 struct ConditionVisitor<'b> {
3024     spans: &'b [Span],
3025     name: &'b str,
3026     errors: Vec<(Span, String)>,
3027 }
3028
3029 impl<'b, 'v> Visitor<'v> for ConditionVisitor<'b> {
3030     fn visit_expr(&mut self, ex: &'v hir::Expr<'v>) {
3031         match ex.kind {
3032             hir::ExprKind::If(cond, body, None) => {
3033                 // `if` expressions with no `else` that initialize the binding might be missing an
3034                 // `else` arm.
3035                 let mut v = ReferencedStatementsVisitor(self.spans, false);
3036                 v.visit_expr(body);
3037                 if v.1 {
3038                     self.errors.push((
3039                         cond.span,
3040                         format!(
3041                             "if this `if` condition is `false`, {} is not initialized",
3042                             self.name,
3043                         ),
3044                     ));
3045                     self.errors.push((
3046                         ex.span.shrink_to_hi(),
3047                         format!("an `else` arm might be missing here, initializing {}", self.name),
3048                     ));
3049                 }
3050             }
3051             hir::ExprKind::If(cond, body, Some(other)) => {
3052                 // `if` expressions where the binding is only initialized in one of the two arms
3053                 // might be missing a binding initialization.
3054                 let mut a = ReferencedStatementsVisitor(self.spans, false);
3055                 a.visit_expr(body);
3056                 let mut b = ReferencedStatementsVisitor(self.spans, false);
3057                 b.visit_expr(other);
3058                 match (a.1, b.1) {
3059                     (true, true) | (false, false) => {}
3060                     (true, false) => {
3061                         if other.span.is_desugaring(DesugaringKind::WhileLoop) {
3062                             self.errors.push((
3063                                 cond.span,
3064                                 format!(
3065                                     "if this condition isn't met and the `while` loop runs 0 \
3066                                      times, {} is not initialized",
3067                                     self.name
3068                                 ),
3069                             ));
3070                         } else {
3071                             self.errors.push((
3072                                 body.span.shrink_to_hi().until(other.span),
3073                                 format!(
3074                                     "if the `if` condition is `false` and this `else` arm is \
3075                                      executed, {} is not initialized",
3076                                     self.name
3077                                 ),
3078                             ));
3079                         }
3080                     }
3081                     (false, true) => {
3082                         self.errors.push((
3083                             cond.span,
3084                             format!(
3085                                 "if this condition is `true`, {} is not initialized",
3086                                 self.name
3087                             ),
3088                         ));
3089                     }
3090                 }
3091             }
3092             hir::ExprKind::Match(e, arms, loop_desugar) => {
3093                 // If the binding is initialized in one of the match arms, then the other match
3094                 // arms might be missing an initialization.
3095                 let results: Vec<bool> = arms
3096                     .iter()
3097                     .map(|arm| {
3098                         let mut v = ReferencedStatementsVisitor(self.spans, false);
3099                         v.visit_arm(arm);
3100                         v.1
3101                     })
3102                     .collect();
3103                 if results.iter().any(|x| *x) && !results.iter().all(|x| *x) {
3104                     for (arm, seen) in arms.iter().zip(results) {
3105                         if !seen {
3106                             if loop_desugar == hir::MatchSource::ForLoopDesugar {
3107                                 self.errors.push((
3108                                     e.span,
3109                                     format!(
3110                                         "if the `for` loop runs 0 times, {} is not initialized",
3111                                         self.name
3112                                     ),
3113                                 ));
3114                             } else if let Some(guard) = &arm.guard {
3115                                 self.errors.push((
3116                                     arm.pat.span.to(guard.body().span),
3117                                     format!(
3118                                         "if this pattern and condition are matched, {} is not \
3119                                          initialized",
3120                                         self.name
3121                                     ),
3122                                 ));
3123                             } else {
3124                                 self.errors.push((
3125                                     arm.pat.span,
3126                                     format!(
3127                                         "if this pattern is matched, {} is not initialized",
3128                                         self.name
3129                                     ),
3130                                 ));
3131                             }
3132                         }
3133                     }
3134                 }
3135             }
3136             // FIXME: should we also account for binops, particularly `&&` and `||`? `try` should
3137             // also be accounted for. For now it is fine, as if we don't find *any* relevant
3138             // branching code paths, we point at the places where the binding *is* initialized for
3139             // *some* context.
3140             _ => {}
3141         }
3142         walk_expr(self, ex);
3143     }
3144 }