]> git.lizzy.rs Git - rust.git/blob - src/librustc_mir/borrow_check/error_reporting.rs
Auto merge of #47251 - rkruppe:rm-simd-attr, r=eddyb
[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 syntax_pos::Span;
12 use rustc::middle::region::ScopeTree;
13 use rustc::mir::{BorrowKind, Field, Local, Location, Operand};
14 use rustc::mir::{Place, ProjectionElem, Rvalue, Statement, StatementKind};
15 use rustc::ty::{self, RegionKind};
16 use rustc_data_structures::indexed_vec::Idx;
17
18 use std::rc::Rc;
19
20 use super::{MirBorrowckCtxt, Context};
21 use super::{InitializationRequiringAction, PrefixSet};
22 use dataflow::{ActiveBorrows, BorrowData, FlowAtLocation, MovingOutStatements};
23 use dataflow::move_paths::MovePathIndex;
24 use util::borrowck_errors::{BorrowckErrors, Origin};
25
26 impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
27     pub(super) fn report_use_of_moved_or_uninitialized(
28         &mut self,
29         _context: Context,
30         desired_action: InitializationRequiringAction,
31         (place, span): (&Place<'tcx>, Span),
32         mpi: MovePathIndex,
33         curr_move_out: &FlowAtLocation<MovingOutStatements<'_, 'gcx, 'tcx>>,
34     ) {
35         let mois = self.move_data.path_map[mpi]
36             .iter()
37             .filter(|moi| curr_move_out.contains(moi))
38             .collect::<Vec<_>>();
39
40         if mois.is_empty() {
41             let item_msg = match self.describe_place(place) {
42                 Some(name) => format!("`{}`", name),
43                 None => "value".to_owned(),
44             };
45             self.tcx
46                 .cannot_act_on_uninitialized_variable(
47                     span,
48                     desired_action.as_noun(),
49                     &self.describe_place(place).unwrap_or("_".to_owned()),
50                     Origin::Mir,
51                 )
52                 .span_label(span, format!("use of possibly uninitialized {}", item_msg))
53                 .emit();
54         } else {
55             let msg = ""; //FIXME: add "partially " or "collaterally "
56
57             let mut err = self.tcx.cannot_act_on_moved_value(
58                 span,
59                 desired_action.as_noun(),
60                 msg,
61                 &self.describe_place(place).unwrap_or("_".to_owned()),
62                 Origin::Mir,
63             );
64
65             let mut is_loop_move = false;
66             for moi in mois {
67                 let move_msg = ""; //FIXME: add " (into closure)"
68                 let move_span = self.mir.source_info(self.move_data.moves[*moi].source).span;
69                 if span == move_span {
70                     err.span_label(
71                         span,
72                         format!("value moved{} here in previous iteration of loop", move_msg),
73                     );
74                     is_loop_move = true;
75                 } else {
76                     err.span_label(move_span, format!("value moved{} here", move_msg));
77                 };
78             }
79             if !is_loop_move {
80                 err.span_label(
81                     span,
82                     format!(
83                         "value {} here after move",
84                         desired_action.as_verb_in_past_tense()
85                     ),
86                 );
87             }
88
89             if let Some(ty) = self.retrieve_type_for_place(place) {
90                 let needs_note = match ty.sty {
91                     ty::TypeVariants::TyClosure(id, _) => {
92                         let tables = self.tcx.typeck_tables_of(id);
93                         let node_id = self.tcx.hir.as_local_node_id(id).unwrap();
94                         let hir_id = self.tcx.hir.node_to_hir_id(node_id);
95                         if let Some(_) = tables.closure_kind_origins().get(hir_id) {
96                             false
97                         } else {
98                             true
99                         }
100                     },
101                     _ => true,
102                 };
103
104                 if needs_note {
105                     let note_msg = match self.describe_place(place) {
106                         Some(name) => format!("`{}`", name),
107                         None => "value".to_owned(),
108                     };
109
110                     err.note(&format!("move occurs because {} has type `{}`, \
111                                        which does not implement the `Copy` trait",
112                                        note_msg, ty));
113                 }
114             }
115
116             err.emit();
117         }
118     }
119
120     pub(super) fn report_move_out_while_borrowed(
121         &mut self,
122         context: Context,
123         (place, span): (&Place<'tcx>, Span),
124         borrow: &BorrowData<'tcx>,
125     ) {
126         let value_msg = match self.describe_place(place) {
127             Some(name) => format!("`{}`", name),
128             None => "value".to_owned(),
129         };
130         let borrow_msg = match self.describe_place(&borrow.borrowed_place) {
131             Some(name) => format!("`{}`", name),
132             None => "value".to_owned(),
133         };
134         let mut err = self.tcx.cannot_move_when_borrowed(
135             span,
136             &self.describe_place(place).unwrap_or("_".to_owned()),
137             Origin::Mir,
138         );
139         err.span_label(
140             self.retrieve_borrow_span(borrow),
141             format!("borrow of {} occurs here", borrow_msg),
142         );
143         err.span_label(span, format!("move out of {} occurs here", value_msg));
144         self.explain_why_borrow_contains_point(context, borrow, &mut err);
145         err.emit();
146     }
147
148     pub(super) fn report_use_while_mutably_borrowed(
149         &mut self,
150         context: Context,
151         (place, span): (&Place<'tcx>, Span),
152         borrow: &BorrowData<'tcx>,
153     ) {
154         let mut err = self.tcx.cannot_use_when_mutably_borrowed(
155             span,
156             &self.describe_place(place).unwrap_or("_".to_owned()),
157             self.retrieve_borrow_span(borrow),
158             &self.describe_place(&borrow.borrowed_place).unwrap_or("_".to_owned()),
159             Origin::Mir,
160         );
161
162         self.explain_why_borrow_contains_point(context, borrow, &mut err);
163
164         err.emit();
165     }
166
167     /// Finds the span of arguments of a closure (within `maybe_closure_span`) and its usage of
168     /// the local assigned at `location`.
169     /// This is done by searching in statements succeeding `location`
170     /// and originating from `maybe_closure_span`.
171     fn find_closure_span(
172         &self,
173         maybe_closure_span: Span,
174         location: Location,
175     ) -> Option<(Span, Span)> {
176         use rustc::hir::ExprClosure;
177         use rustc::mir::AggregateKind;
178
179         let local = match self.mir[location.block].statements.get(location.statement_index) {
180             Some(&Statement { kind: StatementKind::Assign(Place::Local(local), _), .. }) => local,
181             _ => return None,
182         };
183
184         for stmt in &self.mir[location.block].statements[location.statement_index + 1..] {
185             if maybe_closure_span != stmt.source_info.span {
186                 break;
187             }
188
189             if let StatementKind::Assign(_, Rvalue::Aggregate(ref kind, ref places)) = stmt.kind {
190                 if let AggregateKind::Closure(def_id, _) = **kind {
191                     debug!("find_closure_span: found closure {:?}", places);
192
193                     return if let Some(node_id) = self.tcx.hir.as_local_node_id(def_id) {
194                         let args_span = if let ExprClosure(_, _, _, span, _) =
195                             self.tcx.hir.expect_expr(node_id).node
196                         {
197                             span
198                         } else {
199                             return None;
200                         };
201
202                         self.tcx
203                             .with_freevars(node_id, |freevars| {
204                                 for (v, place) in freevars.iter().zip(places) {
205                                     match *place {
206                                         Operand::Copy(Place::Local(l)) |
207                                         Operand::Move(Place::Local(l)) if local == l =>
208                                         {
209                                             debug!(
210                                                 "find_closure_span: found captured local {:?}",
211                                                 l
212                                             );
213                                             return Some(v.span);
214                                         }
215                                         _ => {}
216                                     }
217                                 }
218                                 None
219                             })
220                             .map(|var_span| (args_span, var_span))
221                     } else {
222                         None
223                     };
224                 }
225             }
226         }
227
228         None
229     }
230
231     pub(super) fn report_conflicting_borrow(
232         &mut self,
233         context: Context,
234         (place, span): (&Place<'tcx>, Span),
235         gen_borrow_kind: BorrowKind,
236         issued_borrow: &BorrowData,
237         end_issued_loan_span: Option<Span>,
238     ) {
239         let issued_span = self.retrieve_borrow_span(issued_borrow);
240
241         let new_closure_span = self.find_closure_span(span, context.loc);
242         let span = new_closure_span.map(|(args, _)| args).unwrap_or(span);
243         let old_closure_span = self.find_closure_span(issued_span, issued_borrow.location);
244         let issued_span = old_closure_span
245             .map(|(args, _)| args)
246             .unwrap_or(issued_span);
247
248         let desc_place = self.describe_place(place).unwrap_or("_".to_owned());
249
250         // FIXME: supply non-"" `opt_via` when appropriate
251         let mut err = match (
252             gen_borrow_kind,
253             "immutable",
254             "mutable",
255             issued_borrow.kind,
256             "immutable",
257             "mutable",
258         ) {
259             (BorrowKind::Shared, lft, _, BorrowKind::Mut, _, rgt) |
260             (BorrowKind::Mut, _, lft, BorrowKind::Shared, rgt, _) => self.tcx
261                 .cannot_reborrow_already_borrowed(
262                     span,
263                     &desc_place,
264                     "",
265                     lft,
266                     issued_span,
267                     "it",
268                     rgt,
269                     "",
270                     end_issued_loan_span,
271                     Origin::Mir,
272                 ),
273
274             (BorrowKind::Mut, _, _, BorrowKind::Mut, _, _) => self.tcx
275                 .cannot_mutably_borrow_multiply(
276                     span,
277                     &desc_place,
278                     "",
279                     issued_span,
280                     "",
281                     end_issued_loan_span,
282                     Origin::Mir,
283                 ),
284
285             (BorrowKind::Unique, _, _, BorrowKind::Unique, _, _) => self.tcx
286                 .cannot_uniquely_borrow_by_two_closures(
287                     span,
288                     &desc_place,
289                     issued_span,
290                     end_issued_loan_span,
291                     Origin::Mir,
292                 ),
293
294             (BorrowKind::Unique, _, _, _, _, _) => self.tcx.cannot_uniquely_borrow_by_one_closure(
295                 span,
296                 &desc_place,
297                 "",
298                 issued_span,
299                 "it",
300                 "",
301                 end_issued_loan_span,
302                 Origin::Mir,
303             ),
304
305             (BorrowKind::Shared, lft, _, BorrowKind::Unique, _, _) => self.tcx
306                 .cannot_reborrow_already_uniquely_borrowed(
307                     span,
308                     &desc_place,
309                     "",
310                     lft,
311                     issued_span,
312                     "",
313                     end_issued_loan_span,
314                     Origin::Mir,
315                 ),
316
317             (BorrowKind::Mut, _, lft, BorrowKind::Unique, _, _) => self.tcx
318                 .cannot_reborrow_already_uniquely_borrowed(
319                     span,
320                     &desc_place,
321                     "",
322                     lft,
323                     issued_span,
324                     "",
325                     end_issued_loan_span,
326                     Origin::Mir,
327                 ),
328
329             (BorrowKind::Shared, _, _, BorrowKind::Shared, _, _) => unreachable!(),
330         };
331
332         if let Some((_, var_span)) = old_closure_span {
333             err.span_label(
334                 var_span,
335                 format!(
336                     "previous borrow occurs due to use of `{}` in closure",
337                     desc_place
338                 ),
339             );
340         }
341
342         if let Some((_, var_span)) = new_closure_span {
343             err.span_label(
344                 var_span,
345                 format!("borrow occurs due to use of `{}` in closure", desc_place),
346             );
347         }
348
349         self.explain_why_borrow_contains_point(context, issued_borrow, &mut err);
350
351         err.emit();
352     }
353
354     pub(super) fn report_borrowed_value_does_not_live_long_enough(
355         &mut self,
356         context: Context,
357         borrow: &BorrowData<'tcx>,
358         drop_span: Span,
359         borrows: &ActiveBorrows<'cx, 'gcx, 'tcx>
360     ) {
361         let end_span = borrows.opt_region_end_span(&borrow.region);
362         let scope_tree = borrows.0.scope_tree();
363         let root_place = self.prefixes(&borrow.borrowed_place, PrefixSet::All).last().unwrap();
364
365         match root_place {
366             &Place::Local(local) => {
367                 if let Some(_) = self.storage_dead_or_drop_error_reported_l.replace(local) {
368                     debug!("report_does_not_live_long_enough({:?}): <suppressed>",
369                            (borrow, drop_span));
370                     return
371                 }
372             }
373             &Place::Static(ref statik) => {
374                 if let Some(_) = self.storage_dead_or_drop_error_reported_s
375                     .replace(statik.def_id)
376                 {
377                     debug!("report_does_not_live_long_enough({:?}): <suppressed>",
378                            (borrow, drop_span));
379                     return
380                 }
381             },
382             &Place::Projection(_) =>
383                 unreachable!("root_place is an unreachable???")
384         };
385
386         let borrow_span = self.mir.source_info(borrow.location).span;
387         let proper_span = match *root_place {
388             Place::Local(local) => self.mir.local_decls[local].source_info.span,
389             _ => drop_span,
390         };
391
392         match (borrow.region, &self.describe_place(&borrow.borrowed_place)) {
393             (RegionKind::ReScope(_), Some(name)) => {
394                 self.report_scoped_local_value_does_not_live_long_enough(
395                     context,
396                     name,
397                     &scope_tree,
398                     &borrow,
399                     drop_span,
400                     borrow_span,
401                     proper_span,
402                     end_span
403                 );
404             },
405             (RegionKind::ReScope(_), None) => {
406                 self.report_scoped_temporary_value_does_not_live_long_enough(
407                     context,
408                     &scope_tree,
409                     &borrow,
410                     drop_span,
411                     borrow_span,
412                     proper_span,
413                     end_span
414                 );
415             },
416             (RegionKind::ReEarlyBound(_), Some(name)) |
417             (RegionKind::ReFree(_), Some(name)) |
418             (RegionKind::ReStatic, Some(name)) |
419             (RegionKind::ReEmpty, Some(name)) |
420             (RegionKind::ReVar(_), Some(name)) => {
421                 self.report_unscoped_local_value_does_not_live_long_enough(
422                     context,
423                     name,
424                     &scope_tree,
425                     &borrow,
426                     drop_span,
427                     borrow_span,
428                     proper_span,
429                     end_span,
430                 );
431             },
432             (RegionKind::ReEarlyBound(_), None) |
433             (RegionKind::ReFree(_), None) |
434             (RegionKind::ReStatic, None) |
435             (RegionKind::ReEmpty, None) |
436             (RegionKind::ReVar(_), None) => {
437                 self.report_unscoped_temporary_value_does_not_live_long_enough(
438                     context,
439                     &scope_tree,
440                     &borrow,
441                     drop_span,
442                     borrow_span,
443                     proper_span,
444                     end_span,
445                 );
446             },
447             (RegionKind::ReLateBound(_, _), _) |
448             (RegionKind::ReSkolemized(_, _), _) |
449             (RegionKind::ReClosureBound(_), _) |
450             (RegionKind::ReErased, _) => {
451                 span_bug!(drop_span, "region does not make sense in this context");
452             },
453         }
454     }
455
456     fn report_scoped_local_value_does_not_live_long_enough(
457         &mut self,
458         context: Context,
459         name: &String,
460         _scope_tree: &Rc<ScopeTree>,
461         borrow: &BorrowData<'tcx>,
462         drop_span: Span,
463         borrow_span: Span,
464         _proper_span: Span,
465         end_span: Option<Span>,
466     ) {
467         let mut err = self.tcx.path_does_not_live_long_enough(borrow_span,
468                                                               &format!("`{}`", name),
469                                                               Origin::Mir);
470         err.span_label(borrow_span, "borrowed value does not live long enough");
471         err.span_label(drop_span, format!("`{}` dropped here while still borrowed", name));
472         if let Some(end) = end_span {
473             err.span_label(end, "borrowed value needs to live until here");
474         }
475         self.explain_why_borrow_contains_point(context, borrow, &mut err);
476         err.emit();
477     }
478
479     fn report_scoped_temporary_value_does_not_live_long_enough(
480         &mut self,
481         context: Context,
482         _scope_tree: &Rc<ScopeTree>,
483         borrow: &BorrowData<'tcx>,
484         drop_span: Span,
485         _borrow_span: Span,
486         proper_span: Span,
487         end_span: Option<Span>,
488     ) {
489         let mut err = self.tcx.path_does_not_live_long_enough(proper_span,
490                                                               "borrowed value",
491                                                               Origin::Mir);
492         err.span_label(proper_span, "temporary value does not live long enough");
493         err.span_label(drop_span, "temporary value dropped here while still borrowed");
494         err.note("consider using a `let` binding to increase its lifetime");
495         if let Some(end) = end_span {
496             err.span_label(end, "temporary value needs to live until here");
497         }
498         self.explain_why_borrow_contains_point(context, borrow, &mut err);
499         err.emit();
500     }
501
502     fn report_unscoped_local_value_does_not_live_long_enough(
503         &mut self,
504         context: Context,
505         name: &String,
506         scope_tree: &Rc<ScopeTree>,
507         borrow: &BorrowData<'tcx>,
508         drop_span: Span,
509         borrow_span: Span,
510         _proper_span: Span,
511         _end_span: Option<Span>,
512     ) {
513         let mut err = self.tcx.path_does_not_live_long_enough(borrow_span,
514                                                               &format!("`{}`", name),
515                                                               Origin::Mir);
516         err.span_label(borrow_span, "borrowed value does not live long enough");
517         err.span_label(drop_span, "borrowed value only lives until here");
518         self.tcx.note_and_explain_region(scope_tree, &mut err,
519                                          "borrowed value must be valid for ",
520                                          borrow.region, "...");
521         self.explain_why_borrow_contains_point(context, borrow, &mut err);
522         err.emit();
523     }
524
525     fn report_unscoped_temporary_value_does_not_live_long_enough(
526         &mut self,
527         context: Context,
528         scope_tree: &Rc<ScopeTree>,
529         borrow: &BorrowData<'tcx>,
530         drop_span: Span,
531         _borrow_span: Span,
532         proper_span: Span,
533         _end_span: Option<Span>
534     ) {
535         let mut err = self.tcx.path_does_not_live_long_enough(proper_span,
536                                                               "borrowed value",
537                                                               Origin::Mir);
538         err.span_label(proper_span, "temporary value does not live long enough");
539         err.span_label(drop_span, "temporary value only lives until here");
540         self.tcx.note_and_explain_region(scope_tree, &mut err,
541                                          "borrowed value must be valid for ",
542                                          borrow.region, "...");
543         self.explain_why_borrow_contains_point(context, borrow, &mut err);
544         err.emit();
545     }
546
547     pub(super) fn report_illegal_mutation_of_borrowed(
548         &mut self,
549         context: Context,
550         (place, span): (&Place<'tcx>, Span),
551         loan: &BorrowData,
552     ) {
553         let mut err = self.tcx.cannot_assign_to_borrowed(
554             span,
555             self.retrieve_borrow_span(loan),
556             &self.describe_place(place).unwrap_or("_".to_owned()),
557             Origin::Mir,
558         );
559
560         self.explain_why_borrow_contains_point(context, loan, &mut err);
561
562         err.emit();
563     }
564
565     pub(super) fn report_illegal_reassignment(
566         &mut self,
567         _context: Context,
568         (place, span): (&Place<'tcx>, Span),
569         assigned_span: Span,
570     ) {
571         let mut err = self.tcx.cannot_reassign_immutable(
572             span,
573             &self.describe_place(place).unwrap_or("_".to_owned()),
574             Origin::Mir,
575         );
576         err.span_label(span, "cannot assign twice to immutable variable");
577         if span != assigned_span {
578             let value_msg = match self.describe_place(place) {
579                 Some(name) => format!("`{}`", name),
580                 None => "value".to_owned(),
581             };
582             err.span_label(assigned_span, format!("first assignment to {}", value_msg));
583         }
584         err.emit();
585     }
586 }
587
588 impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
589     // End-user visible description of `place` if one can be found. If the
590     // place is a temporary for instance, None will be returned.
591     pub(super) fn describe_place(&self, place: &Place<'tcx>) -> Option<String> {
592         let mut buf = String::new();
593         match self.append_place_to_string(place, &mut buf, false) {
594             Ok(()) => Some(buf),
595             Err(()) => None,
596         }
597     }
598
599     // Appends end-user visible description of `place` to `buf`.
600     fn append_place_to_string(
601         &self,
602         place: &Place<'tcx>,
603         buf: &mut String,
604         mut autoderef: bool,
605     ) -> Result<(), ()> {
606         match *place {
607             Place::Local(local) => {
608                 self.append_local_to_string(local, buf)?;
609             }
610             Place::Static(ref static_) => {
611                 buf.push_str(&format!("{}", &self.tcx.item_name(static_.def_id)));
612             }
613             Place::Projection(ref proj) => {
614                 match proj.elem {
615                     ProjectionElem::Deref => {
616                         if let Some(field) = self.is_upvar_field_projection(&proj.base) {
617                             let var_index = field.index();
618                             let name = self.mir.upvar_decls[var_index].debug_name.to_string();
619                             if self.mir.upvar_decls[var_index].by_ref {
620                                 buf.push_str(&name);
621                             } else {
622                                 buf.push_str(&format!("*{}", &name));
623                             }
624                         } else {
625                             if autoderef {
626                                 self.append_place_to_string(&proj.base, buf, autoderef)?;
627                             } else {
628                                 buf.push_str(&"*");
629                                 self.append_place_to_string(&proj.base, buf, autoderef)?;
630                             }
631                         }
632                     }
633                     ProjectionElem::Downcast(..) => {
634                         self.append_place_to_string(&proj.base, buf, autoderef)?;
635                     }
636                     ProjectionElem::Field(field, _ty) => {
637                         autoderef = true;
638
639                         if let Some(field) = self.is_upvar_field_projection(place) {
640                             let var_index = field.index();
641                             let name = self.mir.upvar_decls[var_index].debug_name.to_string();
642                             buf.push_str(&name);
643                         } else {
644                             let field_name = self.describe_field(&proj.base, field);
645                             self.append_place_to_string(&proj.base, buf, autoderef)?;
646                             buf.push_str(&format!(".{}", field_name));
647                         }
648                     }
649                     ProjectionElem::Index(index) => {
650                         autoderef = true;
651
652                         self.append_place_to_string(&proj.base, buf, autoderef)?;
653                         buf.push_str("[");
654                         if let Err(_) = self.append_local_to_string(index, buf) {
655                             buf.push_str("..");
656                         }
657                         buf.push_str("]");
658                     }
659                     ProjectionElem::ConstantIndex { .. } | ProjectionElem::Subslice { .. } => {
660                         autoderef = true;
661                         // Since it isn't possible to borrow an element on a particular index and
662                         // then use another while the borrow is held, don't output indices details
663                         // to avoid confusing the end-user
664                         self.append_place_to_string(&proj.base, buf, autoderef)?;
665                         buf.push_str(&"[..]");
666                     }
667                 };
668             }
669         }
670
671         Ok(())
672     }
673
674     // Appends end-user visible description of the `local` place to `buf`. If `local` doesn't have
675     // a name, then `Err` is returned
676     fn append_local_to_string(&self, local_index: Local, buf: &mut String) -> Result<(), ()> {
677         let local = &self.mir.local_decls[local_index];
678         match local.name {
679             Some(name) => {
680                 buf.push_str(&format!("{}", name));
681                 Ok(())
682             }
683             None => Err(()),
684         }
685     }
686
687     // End-user visible description of the `field`nth field of `base`
688     fn describe_field(&self, base: &Place, field: Field) -> String {
689         match *base {
690             Place::Local(local) => {
691                 let local = &self.mir.local_decls[local];
692                 self.describe_field_from_ty(&local.ty, field)
693             }
694             Place::Static(ref static_) => self.describe_field_from_ty(&static_.ty, field),
695             Place::Projection(ref proj) => match proj.elem {
696                 ProjectionElem::Deref => self.describe_field(&proj.base, field),
697                 ProjectionElem::Downcast(def, variant_index) => {
698                     format!("{}", def.variants[variant_index].fields[field.index()].name)
699                 }
700                 ProjectionElem::Field(_, field_type) => {
701                     self.describe_field_from_ty(&field_type, field)
702                 }
703                 ProjectionElem::Index(..) |
704                 ProjectionElem::ConstantIndex { .. } |
705                 ProjectionElem::Subslice { .. } => {
706                     format!("{}", self.describe_field(&proj.base, field))
707                 }
708             },
709         }
710     }
711
712     // End-user visible description of the `field_index`nth field of `ty`
713     fn describe_field_from_ty(&self, ty: &ty::Ty, field: Field) -> String {
714         if ty.is_box() {
715             // If the type is a box, the field is described from the boxed type
716             self.describe_field_from_ty(&ty.boxed_ty(), field)
717         } else {
718             match ty.sty {
719                 ty::TyAdt(def, _) => if def.is_enum() {
720                     format!("{}", field.index())
721                 } else {
722                     format!("{}", def.non_enum_variant().fields[field.index()].name)
723                 },
724                 ty::TyTuple(_, _) => format!("{}", field.index()),
725                 ty::TyRef(_, tnm) | ty::TyRawPtr(tnm) => {
726                     self.describe_field_from_ty(&tnm.ty, field)
727                 }
728                 ty::TyArray(ty, _) | ty::TySlice(ty) => self.describe_field_from_ty(&ty, field),
729                 ty::TyClosure(closure_def_id, _) => {
730                     // Convert the def-id into a node-id. node-ids are only valid for
731                     // the local code in the current crate, so this returns an `Option` in case
732                     // the closure comes from another crate. But in that case we wouldn't
733                     // be borrowck'ing it, so we can just unwrap:
734                     let node_id = self.tcx.hir.as_local_node_id(closure_def_id).unwrap();
735                     let freevar = self.tcx.with_freevars(node_id, |fv| fv[field.index()]);
736
737                     self.tcx.hir.name(freevar.var_id()).to_string()
738                 }
739                 _ => {
740                     // Might need a revision when the fields in trait RFC is implemented
741                     // (https://github.com/rust-lang/rfcs/pull/1546)
742                     bug!(
743                         "End-user description not implemented for field access on `{:?}`",
744                         ty.sty
745                     );
746                 }
747             }
748         }
749     }
750
751     // Retrieve span of given borrow from the current MIR representation
752     fn retrieve_borrow_span(&self, borrow: &BorrowData) -> Span {
753         self.mir.source_info(borrow.location).span
754     }
755
756     // Retrieve type of a place for the current MIR representation
757     fn retrieve_type_for_place(&self, place: &Place<'tcx>) -> Option<ty::Ty> {
758         match place {
759             Place::Local(local) => {
760                 let local = &self.mir.local_decls[*local];
761                 Some(local.ty)
762             },
763             Place::Static(ref st) => Some(st.ty),
764             Place::Projection(ref proj) => {
765                 match proj.elem {
766                     ProjectionElem::Field(_, ty) => Some(ty),
767                     _ => None,
768                 }
769             },
770         }
771     }
772 }