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