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