]> git.lizzy.rs Git - rust.git/blob - src/librustc_borrowck/borrowck/mod.rs
Merge remote-tracking branch 'origin/master' into gen
[rust.git] / src / librustc_borrowck / borrowck / mod.rs
1 // Copyright 2012-2014 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 //! See The Book chapter on the borrow checker for more details.
12
13 #![allow(non_camel_case_types)]
14
15 pub use self::LoanPathKind::*;
16 pub use self::LoanPathElem::*;
17 pub use self::bckerr_code::*;
18 pub use self::AliasableViolationKind::*;
19 pub use self::MovedValueUseKind::*;
20
21 use self::InteriorKind::*;
22
23 use rustc::hir::map as hir_map;
24 use rustc::hir::map::blocks::FnLikeNode;
25 use rustc::cfg;
26 use rustc::middle::dataflow::DataFlowContext;
27 use rustc::middle::dataflow::BitwiseOperator;
28 use rustc::middle::dataflow::DataFlowOperator;
29 use rustc::middle::dataflow::KillFrom;
30 use rustc::hir::def_id::{DefId, DefIndex};
31 use rustc::middle::expr_use_visitor as euv;
32 use rustc::middle::mem_categorization as mc;
33 use rustc::middle::mem_categorization::Categorization;
34 use rustc::middle::mem_categorization::ImmutabilityBlame;
35 use rustc::middle::region::{self, RegionMaps};
36 use rustc::middle::free_region::RegionRelations;
37 use rustc::ty::{self, TyCtxt};
38 use rustc::ty::maps::Providers;
39 use rustc::util::nodemap::FxHashMap;
40 use rustc_mir::util::borrowck_errors::{BorrowckErrors, Origin};
41
42 use std::fmt;
43 use std::rc::Rc;
44 use std::hash::{Hash, Hasher};
45 use syntax::ast;
46 use syntax_pos::{MultiSpan, Span};
47 use errors::DiagnosticBuilder;
48
49 use rustc::hir;
50 use rustc::hir::intravisit::{self, Visitor};
51
52 pub mod check_loans;
53
54 pub mod gather_loans;
55
56 pub mod move_data;
57
58 #[derive(Clone, Copy)]
59 pub struct LoanDataFlowOperator;
60
61 pub type LoanDataFlow<'a, 'tcx> = DataFlowContext<'a, 'tcx, LoanDataFlowOperator>;
62
63 pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
64     for body_owner_def_id in tcx.body_owners() {
65         tcx.borrowck(body_owner_def_id);
66     }
67 }
68
69 pub fn provide(providers: &mut Providers) {
70     *providers = Providers {
71         borrowck,
72         ..*providers
73     };
74 }
75
76 /// Collection of conclusions determined via borrow checker analyses.
77 pub struct AnalysisData<'a, 'tcx: 'a> {
78     pub all_loans: Vec<Loan<'tcx>>,
79     pub loans: DataFlowContext<'a, 'tcx, LoanDataFlowOperator>,
80     pub move_data: move_data::FlowedMoveData<'a, 'tcx>,
81 }
82
83 fn borrowck<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, owner_def_id: DefId) {
84     debug!("borrowck(body_owner_def_id={:?})", owner_def_id);
85
86     let owner_id = tcx.hir.as_local_node_id(owner_def_id).unwrap();
87
88     match tcx.hir.get(owner_id) {
89         hir_map::NodeStructCtor(_) |
90         hir_map::NodeVariant(_) => {
91             // We get invoked with anything that has MIR, but some of
92             // those things (notably the synthesized constructors from
93             // tuple structs/variants) do not have an associated body
94             // and do not need borrowchecking.
95             return;
96         }
97         _ => { }
98     }
99
100     let body_id = tcx.hir.body_owned_by(owner_id);
101     let tables = tcx.typeck_tables_of(owner_def_id);
102     let region_maps = tcx.region_maps(owner_def_id);
103     let body = tcx.hir.body(body_id);
104     let bccx = &mut BorrowckCtxt { tcx, tables, region_maps, owner_def_id, body };
105
106     // Eventually, borrowck will always read the MIR, but at the
107     // moment we do not. So, for now, we always force MIR to be
108     // constructed for a given fn, since this may result in errors
109     // being reported and we want that to happen.
110     //
111     // Note that `mir_validated` is a "stealable" result; the
112     // thief, `optimized_mir()`, forces borrowck, so we know that
113     // is not yet stolen.
114     tcx.mir_validated(owner_def_id).borrow();
115
116     // option dance because you can't capture an uninitialized variable
117     // by mut-ref.
118     let mut cfg = None;
119     if let Some(AnalysisData { all_loans,
120                                loans: loan_dfcx,
121                                move_data: flowed_moves }) =
122         build_borrowck_dataflow_data(bccx, false, body_id,
123                                      |bccx| {
124                                          cfg = Some(cfg::CFG::new(bccx.tcx, &body));
125                                          cfg.as_mut().unwrap()
126                                      })
127     {
128         check_loans::check_loans(bccx, &loan_dfcx, &flowed_moves, &all_loans, body);
129     }
130 }
131
132 fn build_borrowck_dataflow_data<'a, 'c, 'tcx, F>(this: &mut BorrowckCtxt<'a, 'tcx>,
133                                                  force_analysis: bool,
134                                                  body_id: hir::BodyId,
135                                                  get_cfg: F)
136                                                  -> Option<AnalysisData<'a, 'tcx>>
137     where F: FnOnce(&mut BorrowckCtxt<'a, 'tcx>) -> &'c cfg::CFG
138 {
139     // Check the body of fn items.
140     let tcx = this.tcx;
141     let id_range = {
142         let mut visitor = intravisit::IdRangeComputingVisitor::new(&tcx.hir);
143         visitor.visit_body(this.body);
144         visitor.result()
145     };
146     let (all_loans, move_data) =
147         gather_loans::gather_loans_in_fn(this, body_id);
148
149     if !force_analysis && move_data.is_empty() && all_loans.is_empty() {
150         // large arrays of data inserted as constants can take a lot of
151         // time and memory to borrow-check - see issue #36799. However,
152         // they don't have lvalues, so no borrow-check is actually needed.
153         // Recognize that case and skip borrow-checking.
154         debug!("skipping loan propagation for {:?} because of no loans", body_id);
155         return None;
156     } else {
157         debug!("propagating loans in {:?}", body_id);
158     }
159
160     let cfg = get_cfg(this);
161     let mut loan_dfcx =
162         DataFlowContext::new(this.tcx,
163                              "borrowck",
164                              Some(this.body),
165                              cfg,
166                              LoanDataFlowOperator,
167                              id_range,
168                              all_loans.len());
169     for (loan_idx, loan) in all_loans.iter().enumerate() {
170         loan_dfcx.add_gen(loan.gen_scope.node_id(), loan_idx);
171         loan_dfcx.add_kill(KillFrom::ScopeEnd,
172                            loan.kill_scope.node_id(), loan_idx);
173     }
174     loan_dfcx.add_kills_from_flow_exits(cfg);
175     loan_dfcx.propagate(cfg, this.body);
176
177     let flowed_moves = move_data::FlowedMoveData::new(move_data,
178                                                       this,
179                                                       cfg,
180                                                       id_range,
181                                                       this.body);
182
183     Some(AnalysisData { all_loans,
184                         loans: loan_dfcx,
185                         move_data:flowed_moves })
186 }
187
188 /// Accessor for introspective clients inspecting `AnalysisData` and
189 /// the `BorrowckCtxt` itself , e.g. the flowgraph visualizer.
190 pub fn build_borrowck_dataflow_data_for_fn<'a, 'tcx>(
191     tcx: TyCtxt<'a, 'tcx, 'tcx>,
192     body_id: hir::BodyId,
193     cfg: &cfg::CFG)
194     -> (BorrowckCtxt<'a, 'tcx>, AnalysisData<'a, 'tcx>)
195 {
196     let owner_id = tcx.hir.body_owner(body_id);
197     let owner_def_id = tcx.hir.local_def_id(owner_id);
198     let tables = tcx.typeck_tables_of(owner_def_id);
199     let region_maps = tcx.region_maps(owner_def_id);
200     let body = tcx.hir.body(body_id);
201     let mut bccx = BorrowckCtxt { tcx, tables, region_maps, owner_def_id, body };
202
203     let dataflow_data = build_borrowck_dataflow_data(&mut bccx, true, body_id, |_| cfg);
204     (bccx, dataflow_data.unwrap())
205 }
206
207 // ----------------------------------------------------------------------
208 // Type definitions
209
210 pub struct BorrowckCtxt<'a, 'tcx: 'a> {
211     tcx: TyCtxt<'a, 'tcx, 'tcx>,
212
213     // tables for the current thing we are checking; set to
214     // Some in `borrowck_fn` and cleared later
215     tables: &'a ty::TypeckTables<'tcx>,
216
217     region_maps: Rc<RegionMaps>,
218
219     owner_def_id: DefId,
220
221     body: &'tcx hir::Body,
222 }
223
224 impl<'b, 'tcx: 'b> BorrowckErrors for BorrowckCtxt<'b, 'tcx> {
225     fn struct_span_err_with_code<'a, S: Into<MultiSpan>>(&'a self,
226                                                          sp: S,
227                                                          msg: &str,
228                                                          code: &str)
229                                                          -> DiagnosticBuilder<'a>
230     {
231         self.tcx.sess.struct_span_err_with_code(sp, msg, code)
232     }
233
234     fn struct_span_err<'a, S: Into<MultiSpan>>(&'a self,
235                                                sp: S,
236                                                msg: &str)
237                                                -> DiagnosticBuilder<'a>
238     {
239         self.tcx.sess.struct_span_err(sp, msg)
240     }
241 }
242
243 ///////////////////////////////////////////////////////////////////////////
244 // Loans and loan paths
245
246 /// Record of a loan that was issued.
247 pub struct Loan<'tcx> {
248     index: usize,
249     loan_path: Rc<LoanPath<'tcx>>,
250     kind: ty::BorrowKind,
251     restricted_paths: Vec<Rc<LoanPath<'tcx>>>,
252
253     /// gen_scope indicates where loan is introduced. Typically the
254     /// loan is introduced at the point of the borrow, but in some
255     /// cases, notably method arguments, the loan may be introduced
256     /// only later, once it comes into scope.  See also
257     /// `GatherLoanCtxt::compute_gen_scope`.
258     gen_scope: region::CodeExtent,
259
260     /// kill_scope indicates when the loan goes out of scope.  This is
261     /// either when the lifetime expires or when the local variable
262     /// which roots the loan-path goes out of scope, whichever happens
263     /// faster. See also `GatherLoanCtxt::compute_kill_scope`.
264     kill_scope: region::CodeExtent,
265     span: Span,
266     cause: euv::LoanCause,
267 }
268
269 impl<'tcx> Loan<'tcx> {
270     pub fn loan_path(&self) -> Rc<LoanPath<'tcx>> {
271         self.loan_path.clone()
272     }
273 }
274
275 #[derive(Eq)]
276 pub struct LoanPath<'tcx> {
277     kind: LoanPathKind<'tcx>,
278     ty: ty::Ty<'tcx>,
279 }
280
281 impl<'tcx> PartialEq for LoanPath<'tcx> {
282     fn eq(&self, that: &LoanPath<'tcx>) -> bool {
283         self.kind == that.kind
284     }
285 }
286
287 impl<'tcx> Hash for LoanPath<'tcx> {
288     fn hash<H: Hasher>(&self, state: &mut H) {
289         self.kind.hash(state);
290     }
291 }
292
293 #[derive(PartialEq, Eq, Hash, Debug)]
294 pub enum LoanPathKind<'tcx> {
295     LpVar(ast::NodeId),                         // `x` in README.md
296     LpUpvar(ty::UpvarId),                       // `x` captured by-value into closure
297     LpDowncast(Rc<LoanPath<'tcx>>, DefId), // `x` downcast to particular enum variant
298     LpExtend(Rc<LoanPath<'tcx>>, mc::MutabilityCategory, LoanPathElem<'tcx>)
299 }
300
301 impl<'tcx> LoanPath<'tcx> {
302     fn new(kind: LoanPathKind<'tcx>, ty: ty::Ty<'tcx>) -> LoanPath<'tcx> {
303         LoanPath { kind: kind, ty: ty }
304     }
305
306     fn to_type(&self) -> ty::Ty<'tcx> { self.ty }
307 }
308
309 // FIXME (pnkfelix): See discussion here
310 // https://github.com/pnkfelix/rust/commit/
311 //     b2b39e8700e37ad32b486b9a8409b50a8a53aa51#commitcomment-7892003
312 const DOWNCAST_PRINTED_OPERATOR: &'static str = " as ";
313
314 // A local, "cleaned" version of `mc::InteriorKind` that drops
315 // information that is not relevant to loan-path analysis. (In
316 // particular, the distinction between how precisely an array-element
317 // is tracked is irrelevant here.)
318 #[derive(Clone, Copy, PartialEq, Eq, Hash)]
319 pub enum InteriorKind {
320     InteriorField(mc::FieldName),
321     InteriorElement,
322 }
323
324 trait ToInteriorKind { fn cleaned(self) -> InteriorKind; }
325 impl ToInteriorKind for mc::InteriorKind {
326     fn cleaned(self) -> InteriorKind {
327         match self {
328             mc::InteriorField(name) => InteriorField(name),
329             mc::InteriorElement(_) => InteriorElement,
330         }
331     }
332 }
333
334 // This can be:
335 // - a pointer dereference (`*LV` in README.md)
336 // - a field reference, with an optional definition of the containing
337 //   enum variant (`LV.f` in README.md)
338 // `DefId` is present when the field is part of struct that is in
339 // a variant of an enum. For instance in:
340 // `enum E { X { foo: u32 }, Y { foo: u32 }}`
341 // each `foo` is qualified by the definitition id of the variant (`X` or `Y`).
342 #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
343 pub enum LoanPathElem<'tcx> {
344     LpDeref(mc::PointerKind<'tcx>),
345     LpInterior(Option<DefId>, InteriorKind),
346 }
347
348 fn closure_to_block(closure_id: DefIndex,
349                     tcx: TyCtxt) -> ast::NodeId {
350     let closure_id = tcx.hir.def_index_to_node_id(closure_id);
351     match tcx.hir.get(closure_id) {
352         hir_map::NodeExpr(expr) => match expr.node {
353             hir::ExprClosure(.., body_id, _, _) => {
354                 body_id.node_id
355             }
356             _ => {
357                 bug!("encountered non-closure id: {}", closure_id)
358             }
359         },
360         _ => bug!("encountered non-expr id: {}", closure_id)
361     }
362 }
363
364 impl<'a, 'tcx> LoanPath<'tcx> {
365     pub fn kill_scope(&self, bccx: &BorrowckCtxt<'a, 'tcx>) -> region::CodeExtent {
366         match self.kind {
367             LpVar(local_id) => bccx.region_maps.var_scope(local_id),
368             LpUpvar(upvar_id) => {
369                 let block_id = closure_to_block(upvar_id.closure_expr_id, bccx.tcx);
370                 region::CodeExtent::Misc(block_id)
371             }
372             LpDowncast(ref base, _) |
373             LpExtend(ref base, ..) => base.kill_scope(bccx),
374         }
375     }
376
377     fn has_fork(&self, other: &LoanPath<'tcx>) -> bool {
378         match (&self.kind, &other.kind) {
379             (&LpExtend(ref base, _, LpInterior(opt_variant_id, id)),
380              &LpExtend(ref base2, _, LpInterior(opt_variant_id2, id2))) =>
381                 if id == id2 && opt_variant_id == opt_variant_id2 {
382                     base.has_fork(&base2)
383                 } else {
384                     true
385                 },
386             (&LpExtend(ref base, _, LpDeref(_)), _) => base.has_fork(other),
387             (_, &LpExtend(ref base, _, LpDeref(_))) => self.has_fork(&base),
388             _ => false,
389         }
390     }
391
392     fn depth(&self) -> usize {
393         match self.kind {
394             LpExtend(ref base, _, LpDeref(_)) => base.depth(),
395             LpExtend(ref base, _, LpInterior(..)) => base.depth() + 1,
396             _ => 0,
397         }
398     }
399
400     fn common(&self, other: &LoanPath<'tcx>) -> Option<LoanPath<'tcx>> {
401         match (&self.kind, &other.kind) {
402             (&LpExtend(ref base, a, LpInterior(opt_variant_id, id)),
403              &LpExtend(ref base2, _, LpInterior(opt_variant_id2, id2))) => {
404                 if id == id2 && opt_variant_id == opt_variant_id2 {
405                     base.common(&base2).map(|x| {
406                         let xd = x.depth();
407                         if base.depth() == xd && base2.depth() == xd {
408                             LoanPath {
409                                 kind: LpExtend(Rc::new(x), a, LpInterior(opt_variant_id, id)),
410                                 ty: self.ty,
411                             }
412                         } else {
413                             x
414                         }
415                     })
416                 } else {
417                     base.common(&base2)
418                 }
419             }
420             (&LpExtend(ref base, _, LpDeref(_)), _) => base.common(other),
421             (_, &LpExtend(ref other, _, LpDeref(_))) => self.common(&other),
422             (&LpVar(id), &LpVar(id2)) => {
423                 if id == id2 {
424                     Some(LoanPath { kind: LpVar(id), ty: self.ty })
425                 } else {
426                     None
427                 }
428             }
429             (&LpUpvar(id), &LpUpvar(id2)) => {
430                 if id == id2 {
431                     Some(LoanPath { kind: LpUpvar(id), ty: self.ty })
432                 } else {
433                     None
434                 }
435             }
436             _ => None,
437         }
438     }
439 }
440
441 pub fn opt_loan_path<'tcx>(cmt: &mc::cmt<'tcx>) -> Option<Rc<LoanPath<'tcx>>> {
442     //! Computes the `LoanPath` (if any) for a `cmt`.
443     //! Note that this logic is somewhat duplicated in
444     //! the method `compute()` found in `gather_loans::restrictions`,
445     //! which allows it to share common loan path pieces as it
446     //! traverses the CMT.
447
448     let new_lp = |v: LoanPathKind<'tcx>| Rc::new(LoanPath::new(v, cmt.ty));
449
450     match cmt.cat {
451         Categorization::Rvalue(..) |
452         Categorization::StaticItem => {
453             None
454         }
455
456         Categorization::Local(id) => {
457             Some(new_lp(LpVar(id)))
458         }
459
460         Categorization::Upvar(mc::Upvar { id, .. }) => {
461             Some(new_lp(LpUpvar(id)))
462         }
463
464         Categorization::Deref(ref cmt_base, pk) => {
465             opt_loan_path(cmt_base).map(|lp| {
466                 new_lp(LpExtend(lp, cmt.mutbl, LpDeref(pk)))
467             })
468         }
469
470         Categorization::Interior(ref cmt_base, ik) => {
471             opt_loan_path(cmt_base).map(|lp| {
472                 let opt_variant_id = match cmt_base.cat {
473                     Categorization::Downcast(_, did) =>  Some(did),
474                     _ => None
475                 };
476                 new_lp(LpExtend(lp, cmt.mutbl, LpInterior(opt_variant_id, ik.cleaned())))
477             })
478         }
479
480         Categorization::Downcast(ref cmt_base, variant_def_id) =>
481             opt_loan_path(cmt_base)
482             .map(|lp| {
483                 new_lp(LpDowncast(lp, variant_def_id))
484             }),
485
486     }
487 }
488
489 ///////////////////////////////////////////////////////////////////////////
490 // Errors
491
492 // Errors that can occur
493 #[derive(Debug, PartialEq)]
494 pub enum bckerr_code<'tcx> {
495     err_mutbl,
496     /// superscope, subscope, loan cause
497     err_out_of_scope(ty::Region<'tcx>, ty::Region<'tcx>, euv::LoanCause),
498     err_borrowed_pointer_too_short(ty::Region<'tcx>, ty::Region<'tcx>), // loan, ptr
499 }
500
501 // Combination of an error code and the categorization of the expression
502 // that caused it
503 #[derive(Debug, PartialEq)]
504 pub struct BckError<'tcx> {
505     span: Span,
506     cause: AliasableViolationKind,
507     cmt: mc::cmt<'tcx>,
508     code: bckerr_code<'tcx>
509 }
510
511 #[derive(Copy, Clone, Debug, PartialEq)]
512 pub enum AliasableViolationKind {
513     MutabilityViolation,
514     BorrowViolation(euv::LoanCause)
515 }
516
517 #[derive(Copy, Clone, Debug)]
518 pub enum MovedValueUseKind {
519     MovedInUse,
520     MovedInCapture,
521 }
522
523 ///////////////////////////////////////////////////////////////////////////
524 // Misc
525
526 impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> {
527     pub fn is_subregion_of(&self,
528                            r_sub: ty::Region<'tcx>,
529                            r_sup: ty::Region<'tcx>)
530                            -> bool
531     {
532         let region_rels = RegionRelations::new(self.tcx,
533                                                self.owner_def_id,
534                                                &self.region_maps,
535                                                &self.tables.free_region_map);
536         region_rels.is_subregion_of(r_sub, r_sup)
537     }
538
539     pub fn report(&self, err: BckError<'tcx>) {
540         // Catch and handle some particular cases.
541         match (&err.code, &err.cause) {
542             (&err_out_of_scope(&ty::ReScope(_), &ty::ReStatic, _),
543              &BorrowViolation(euv::ClosureCapture(span))) |
544             (&err_out_of_scope(&ty::ReScope(_), &ty::ReEarlyBound(..), _),
545              &BorrowViolation(euv::ClosureCapture(span))) |
546             (&err_out_of_scope(&ty::ReScope(_), &ty::ReFree(..), _),
547              &BorrowViolation(euv::ClosureCapture(span))) => {
548                 return self.report_out_of_scope_escaping_closure_capture(&err, span);
549             }
550             _ => { }
551         }
552
553         self.report_bckerr(&err);
554     }
555
556     pub fn report_use_of_moved_value(&self,
557                                      use_span: Span,
558                                      use_kind: MovedValueUseKind,
559                                      lp: &LoanPath<'tcx>,
560                                      the_move: &move_data::Move,
561                                      moved_lp: &LoanPath<'tcx>,
562                                      _param_env: ty::ParamEnv<'tcx>) {
563         let (verb, verb_participle) = match use_kind {
564             MovedInUse => ("use", "used"),
565             MovedInCapture => ("capture", "captured"),
566         };
567
568         let (_ol, _moved_lp_msg, mut err, need_note) = match the_move.kind {
569             move_data::Declared => {
570                 // If this is an uninitialized variable, just emit a simple warning
571                 // and return.
572                 self.cannot_act_on_uninitialized_variable(use_span,
573                                                           verb,
574                                                           &self.loan_path_to_string(lp),
575                                                           Origin::Ast)
576                     .span_label(use_span, format!("use of possibly uninitialized `{}`",
577                                                   self.loan_path_to_string(lp)))
578                     .emit();
579                 return;
580             }
581             _ => {
582                 // If moved_lp is something like `x.a`, and lp is something like `x.b`, we would
583                 // normally generate a rather confusing message:
584                 //
585                 //     error: use of moved value: `x.b`
586                 //     note: `x.a` moved here...
587                 //
588                 // What we want to do instead is get the 'common ancestor' of the two moves and
589                 // use that for most of the message instead, giving is something like this:
590                 //
591                 //     error: use of moved value: `x`
592                 //     note: `x` moved here (through moving `x.a`)...
593
594                 let common = moved_lp.common(lp);
595                 let has_common = common.is_some();
596                 let has_fork = moved_lp.has_fork(lp);
597                 let (nl, ol, moved_lp_msg) =
598                     if has_fork && has_common {
599                         let nl = self.loan_path_to_string(&common.unwrap());
600                         let ol = nl.clone();
601                         let moved_lp_msg = format!(" (through moving `{}`)",
602                                                    self.loan_path_to_string(moved_lp));
603                         (nl, ol, moved_lp_msg)
604                     } else {
605                         (self.loan_path_to_string(lp),
606                          self.loan_path_to_string(moved_lp),
607                          String::new())
608                     };
609
610                 let partial = moved_lp.depth() > lp.depth();
611                 let msg = if !has_fork && partial { "partially " }
612                           else if has_fork && !has_common { "collaterally "}
613                           else { "" };
614                 let mut err = struct_span_err!(
615                     self.tcx.sess, use_span, E0382,
616                     "{} of {}moved value: `{}`",
617                     verb, msg, nl);
618                 let need_note = match lp.ty.sty {
619                     ty::TypeVariants::TyClosure(id, _) => {
620                         let node_id = self.tcx.hir.as_local_node_id(id).unwrap();
621                         let hir_id = self.tcx.hir.node_to_hir_id(node_id);
622                         if let Some(&(ty::ClosureKind::FnOnce, Some((span, name)))) =
623                             self.tables.closure_kinds().get(hir_id)
624                         {
625                             err.span_note(span, &format!(
626                                 "closure cannot be invoked more than once because \
627                                 it moves the variable `{}` out of its environment",
628                                 name
629                             ));
630                             false
631                         } else {
632                             true
633                         }
634                     }
635                     _ => true,
636                 };
637                 (ol, moved_lp_msg, err, need_note)
638             }
639         };
640
641         // Get type of value and span where it was previously
642         // moved.
643         let (move_span, move_note) = match the_move.kind {
644             move_data::Declared => {
645                 unreachable!();
646             }
647
648             move_data::MoveExpr |
649             move_data::MovePat =>
650                 (self.tcx.hir.span(the_move.id), ""),
651
652             move_data::Captured =>
653                 (match self.tcx.hir.expect_expr(the_move.id).node {
654                     hir::ExprClosure(.., fn_decl_span, _) => fn_decl_span,
655                     ref r => bug!("Captured({}) maps to non-closure: {:?}",
656                                   the_move.id, r),
657                 }, " (into closure)"),
658         };
659
660         // Annotate the use and the move in the span. Watch out for
661         // the case where the use and the move are the same. This
662         // means the use is in a loop.
663         err = if use_span == move_span {
664             err.span_label(
665                 use_span,
666                 format!("value moved{} here in previous iteration of loop",
667                          move_note));
668             err
669         } else {
670             err.span_label(use_span, format!("value {} here after move", verb_participle))
671                .span_label(move_span, format!("value moved{} here", move_note));
672             err
673         };
674
675         if need_note {
676             err.note(&format!("move occurs because `{}` has type `{}`, \
677                                which does not implement the `Copy` trait",
678                               self.loan_path_to_string(moved_lp),
679                               moved_lp.ty));
680         }
681
682         // Note: we used to suggest adding a `ref binding` or calling
683         // `clone` but those suggestions have been removed because
684         // they are often not what you actually want to do, and were
685         // not considered particularly helpful.
686
687         err.emit();
688     }
689
690     pub fn report_partial_reinitialization_of_uninitialized_structure(
691             &self,
692             span: Span,
693             lp: &LoanPath<'tcx>) {
694         span_err!(
695             self.tcx.sess, span, E0383,
696             "partial reinitialization of uninitialized structure `{}`",
697             self.loan_path_to_string(lp));
698     }
699
700     pub fn report_reassigned_immutable_variable(&self,
701                                                 span: Span,
702                                                 lp: &LoanPath<'tcx>,
703                                                 assign:
704                                                 &move_data::Assignment) {
705         let mut err = self.cannot_reassign_immutable(span,
706                                                      &self.loan_path_to_string(lp),
707                                                      Origin::Ast);
708         err.span_label(span, "re-assignment of immutable variable");
709         if span != assign.span {
710             err.span_label(assign.span, format!("first assignment to `{}`",
711                                               self.loan_path_to_string(lp)));
712         }
713         err.emit();
714     }
715
716     pub fn span_err(&self, s: Span, m: &str) {
717         self.tcx.sess.span_err(s, m);
718     }
719
720     pub fn struct_span_err<S: Into<MultiSpan>>(&self, s: S, m: &str)
721                                               -> DiagnosticBuilder<'a> {
722         self.tcx.sess.struct_span_err(s, m)
723     }
724
725     pub fn struct_span_err_with_code<S: Into<MultiSpan>>(&self,
726                                                          s: S,
727                                                          msg: &str,
728                                                          code: &str)
729                                                          -> DiagnosticBuilder<'a> {
730         self.tcx.sess.struct_span_err_with_code(s, msg, code)
731     }
732
733     pub fn span_err_with_code<S: Into<MultiSpan>>(&self, s: S, msg: &str, code: &str) {
734         self.tcx.sess.span_err_with_code(s, msg, code);
735     }
736
737     fn report_bckerr(&self, err: &BckError<'tcx>) {
738         let error_span = err.span.clone();
739
740         match err.code {
741             err_mutbl => {
742                 let descr = match err.cmt.note {
743                     mc::NoteClosureEnv(_) | mc::NoteUpvarRef(_) => {
744                         self.cmt_to_string(&err.cmt)
745                     }
746                     _ => match opt_loan_path(&err.cmt) {
747                         None => {
748                             format!("{} {}",
749                                     err.cmt.mutbl.to_user_str(),
750                                     self.cmt_to_string(&err.cmt))
751
752                         }
753                         Some(lp) => {
754                             format!("{} {} `{}`",
755                                     err.cmt.mutbl.to_user_str(),
756                                     self.cmt_to_string(&err.cmt),
757                                     self.loan_path_to_string(&lp))
758                         }
759                     }
760                 };
761
762                 let mut db = match err.cause {
763                     MutabilityViolation => {
764                         struct_span_err!(self.tcx.sess,
765                                          error_span,
766                                          E0594,
767                                          "cannot assign to {}",
768                                          descr)
769                     }
770                     BorrowViolation(euv::ClosureCapture(_)) => {
771                         struct_span_err!(self.tcx.sess, error_span, E0595,
772                                          "closure cannot assign to {}", descr)
773                     }
774                     BorrowViolation(euv::OverloadedOperator) |
775                     BorrowViolation(euv::AddrOf) |
776                     BorrowViolation(euv::RefBinding) |
777                     BorrowViolation(euv::AutoRef) |
778                     BorrowViolation(euv::AutoUnsafe) |
779                     BorrowViolation(euv::ForLoop) |
780                     BorrowViolation(euv::MatchDiscriminant) => {
781                         struct_span_err!(self.tcx.sess, error_span, E0596,
782                                          "cannot borrow {} as mutable", descr)
783                     }
784                     BorrowViolation(euv::ClosureInvocation) => {
785                         span_bug!(err.span,
786                             "err_mutbl with a closure invocation");
787                     }
788                 };
789
790                 self.note_and_explain_mutbl_error(&mut db, &err, &error_span);
791                 self.note_immutability_blame(&mut db, err.cmt.immutability_blame());
792                 db.emit();
793             }
794             err_out_of_scope(super_scope, sub_scope, cause) => {
795                 let msg = match opt_loan_path(&err.cmt) {
796                     None => "borrowed value".to_string(),
797                     Some(lp) => {
798                         format!("`{}`", self.loan_path_to_string(&lp))
799                     }
800                 };
801
802                 // When you have a borrow that lives across a yield,
803                 // that reference winds up captured in the generator
804                 // type. Regionck then constraints it to live as long
805                 // as the generator itself. If that borrow is borrowing
806                 // data owned by the generator, this winds up resulting in
807                 // an `err_out_of_scope` error:
808                 //
809                 // ```
810                 // {
811                 //     let g = || {
812                 //         let a = &3; // this borrow is forced to ... -+
813                 //         yield ();          //                        |
814                 //         println!("{}", a); //                        |
815                 //     };                     //                        |
816                 // } <----------------------... live until here --------+
817                 // ```
818                 //
819                 // To detect this case, we look for cases where the
820                 // `super_scope` (lifetime of the value) is within the
821                 // body, but the `sub_scope` is not.
822                 debug!("err_out_of_scope: self.body.is_generator = {:?}",
823                        self.body.is_generator);
824                 let maybe_borrow_across_yield = if self.body.is_generator {
825                     let body_extent = region::CodeExtent::Misc(self.body.id().node_id);
826                     debug!("err_out_of_scope: body_extent = {:?}", body_extent);
827                     debug!("err_out_of_scope: super_scope = {:?}", super_scope);
828                     debug!("err_out_of_scope: sub_scope = {:?}", sub_scope);
829                     match (super_scope, sub_scope) {
830                         (&ty::RegionKind::ReScope(value_extent),
831                          &ty::RegionKind::ReScope(loan_extent)) => {
832                             if {
833                                 // value_extent <= body_extent &&
834                                 self.region_maps.is_subscope_of(value_extent, body_extent) &&
835                                     // body_extent <= loan_extent
836                                     self.region_maps.is_subscope_of(body_extent, loan_extent)
837                             } {
838                                 // We now know that this is a case
839                                 // that fits the bill described above:
840                                 // a borrow of something whose scope
841                                 // is within the generator, but the
842                                 // borrow is for a scope outside the
843                                 // generator.
844                                 //
845                                 // Now look within the scope of the of
846                                 // the value being borrowed (in the
847                                 // example above, that would be the
848                                 // block remainder that starts with
849                                 // `let a`) for a yield. We can cite
850                                 // that for the user.
851                                 self.tcx.yield_in_extent(value_extent, &mut FxHashMap())
852                             } else {
853                                 None
854                             }
855                         }
856                         _ => None,
857                     }
858                 } else {
859                     None
860                 };
861
862                 if let Some(yield_span) = maybe_borrow_across_yield {
863                     debug!("err_out_of_scope: opt_yield_span = {:?}", yield_span);
864                     struct_span_err!(self.tcx.sess,
865                                      error_span,
866                                      E0626,
867                                      "borrow may still be in use when generator yields")
868                         .span_label(yield_span, "possible yield occurs here")
869                         .emit();
870                     return;
871                 }
872
873                 let mut db = struct_span_err!(self.tcx.sess,
874                                               error_span,
875                                               E0597,
876                                               "{} does not live long enough",
877                                               msg);
878
879                 let (value_kind, value_msg) = match err.cmt.cat {
880                     mc::Categorization::Rvalue(..) =>
881                         ("temporary value", "temporary value created here"),
882                     _ =>
883                         ("borrowed value", "borrow occurs here")
884                 };
885
886                 let is_closure = match cause {
887                     euv::ClosureCapture(s) => {
888                         // The primary span starts out as the closure creation point.
889                         // Change the primary span here to highlight the use of the variable
890                         // in the closure, because it seems more natural. Highlight
891                         // closure creation point as a secondary span.
892                         match db.span.primary_span() {
893                             Some(primary) => {
894                                 db.span = MultiSpan::from_span(s);
895                                 db.span_label(primary, "capture occurs here");
896                                 db.span_label(s, "does not live long enough");
897                                 true
898                             }
899                             None => false
900                         }
901                     }
902                     _ => {
903                         db.span_label(error_span, "does not live long enough");
904                         false
905                     }
906                 };
907
908                 let sub_span = self.region_end_span(sub_scope);
909                 let super_span = self.region_end_span(super_scope);
910
911                 match (sub_span, super_span) {
912                     (Some(s1), Some(s2)) if s1 == s2 => {
913                         if !is_closure {
914                             db.span = MultiSpan::from_span(s1);
915                             db.span_label(error_span, value_msg);
916                             let msg = match opt_loan_path(&err.cmt) {
917                                 None => value_kind.to_string(),
918                                 Some(lp) => {
919                                     format!("`{}`", self.loan_path_to_string(&lp))
920                                 }
921                             };
922                             db.span_label(s1,
923                                           format!("{} dropped here while still borrowed", msg));
924                         } else {
925                             db.span_label(s1, format!("{} dropped before borrower", value_kind));
926                         }
927                         db.note("values in a scope are dropped in the opposite order \
928                                 they are created");
929                     }
930                     (Some(s1), Some(s2)) if !is_closure => {
931                         db.span = MultiSpan::from_span(s2);
932                         db.span_label(error_span, value_msg);
933                         let msg = match opt_loan_path(&err.cmt) {
934                             None => value_kind.to_string(),
935                             Some(lp) => {
936                                 format!("`{}`", self.loan_path_to_string(&lp))
937                             }
938                         };
939                         db.span_label(s2, format!("{} dropped here while still borrowed", msg));
940                         db.span_label(s1, format!("{} needs to live until here", value_kind));
941                     }
942                     _ => {
943                         match sub_span {
944                             Some(s) => {
945                                 db.span_label(s, format!("{} needs to live until here",
946                                                           value_kind));
947                             }
948                             None => {
949                                 self.tcx.note_and_explain_region(
950                                     &mut db,
951                                     "borrowed value must be valid for ",
952                                     sub_scope,
953                                     "...");
954                             }
955                         }
956                         match super_span {
957                             Some(s) => {
958                                 db.span_label(s, format!("{} only lives until here", value_kind));
959                             }
960                             None => {
961                                 self.tcx.note_and_explain_region(
962                                     &mut db,
963                                     "...but borrowed value is only valid for ",
964                                     super_scope,
965                                     "");
966                             }
967                         }
968                     }
969                 }
970
971                 if let Some(_) = statement_scope_span(self.tcx, super_scope) {
972                     db.note("consider using a `let` binding to increase its lifetime");
973                 }
974
975                 db.emit();
976             }
977             err_borrowed_pointer_too_short(loan_scope, ptr_scope) => {
978                 let descr = self.cmt_to_path_or_string(&err.cmt);
979                 let mut db = struct_span_err!(self.tcx.sess, error_span, E0598,
980                                               "lifetime of {} is too short to guarantee \
981                                                its contents can be safely reborrowed",
982                                               descr);
983
984                 let descr = match opt_loan_path(&err.cmt) {
985                     Some(lp) => {
986                         format!("`{}`", self.loan_path_to_string(&lp))
987                     }
988                     None => self.cmt_to_string(&err.cmt),
989                 };
990                 self.tcx.note_and_explain_region(
991                     &mut db,
992                     &format!("{} would have to be valid for ",
993                             descr),
994                     loan_scope,
995                     "...");
996                 self.tcx.note_and_explain_region(
997                     &mut db,
998                     &format!("...but {} is only valid for ", descr),
999                     ptr_scope,
1000                     "");
1001
1002                 db.emit();
1003             }
1004         }
1005     }
1006
1007     pub fn report_aliasability_violation(&self,
1008                                          span: Span,
1009                                          kind: AliasableViolationKind,
1010                                          cause: mc::AliasableReason,
1011                                          cmt: mc::cmt<'tcx>) {
1012         let mut is_closure = false;
1013         let prefix = match kind {
1014             MutabilityViolation => {
1015                 "cannot assign to data"
1016             }
1017             BorrowViolation(euv::ClosureCapture(_)) |
1018             BorrowViolation(euv::OverloadedOperator) |
1019             BorrowViolation(euv::AddrOf) |
1020             BorrowViolation(euv::AutoRef) |
1021             BorrowViolation(euv::AutoUnsafe) |
1022             BorrowViolation(euv::RefBinding) |
1023             BorrowViolation(euv::MatchDiscriminant) => {
1024                 "cannot borrow data mutably"
1025             }
1026
1027             BorrowViolation(euv::ClosureInvocation) => {
1028                 is_closure = true;
1029                 "closure invocation"
1030             }
1031
1032             BorrowViolation(euv::ForLoop) => {
1033                 "`for` loop"
1034             }
1035         };
1036
1037         match cause {
1038             mc::AliasableStatic |
1039             mc::AliasableStaticMut => {
1040                 // This path cannot occur. It happens when we have an
1041                 // `&mut` or assignment to a static. But in the case
1042                 // of `static X`, we get a mutability violation first,
1043                 // and never get here. In the case of `static mut X`,
1044                 // that is unsafe and hence the aliasability error is
1045                 // ignored.
1046                 span_bug!(span, "aliasability violation for static `{}`", prefix)
1047             }
1048             mc::AliasableBorrowed => {}
1049         };
1050         let blame = cmt.immutability_blame();
1051         let mut err = match blame {
1052             Some(ImmutabilityBlame::ClosureEnv(id)) => {
1053                 let mut err = struct_span_err!(
1054                     self.tcx.sess, span, E0387,
1055                     "{} in a captured outer variable in an `Fn` closure", prefix);
1056
1057                 // FIXME: the distinction between these 2 messages looks wrong.
1058                 let help = if let BorrowViolation(euv::ClosureCapture(_)) = kind {
1059                     // The aliasability violation with closure captures can
1060                     // happen for nested closures, so we know the enclosing
1061                     // closure incorrectly accepts an `Fn` while it needs to
1062                     // be `FnMut`.
1063                     "consider changing this to accept closures that implement `FnMut`"
1064
1065                 } else {
1066                     "consider changing this closure to take self by mutable reference"
1067                 };
1068                 let node_id = self.tcx.hir.def_index_to_node_id(id);
1069                 err.span_help(self.tcx.hir.span(node_id), help);
1070                 err
1071             }
1072             _ =>  {
1073                 let mut err = struct_span_err!(
1074                     self.tcx.sess, span, E0389,
1075                     "{} in a `&` reference", prefix);
1076                 err.span_label(span, "assignment into an immutable reference");
1077                 err
1078             }
1079         };
1080         self.note_immutability_blame(&mut err, blame);
1081
1082         if is_closure {
1083             err.help("closures behind references must be called via `&mut`");
1084         }
1085         err.emit();
1086     }
1087
1088     /// Given a type, if it is an immutable reference, return a suggestion to make it mutable
1089     fn suggest_mut_for_immutable(&self, pty: &hir::Ty, is_implicit_self: bool) -> Option<String> {
1090         // Check wether the argument is an immutable reference
1091         debug!("suggest_mut_for_immutable({:?}, {:?})", pty, is_implicit_self);
1092         if let hir::TyRptr(lifetime, hir::MutTy {
1093             mutbl: hir::Mutability::MutImmutable,
1094             ref ty
1095         }) = pty.node {
1096             // Account for existing lifetimes when generating the message
1097             let pointee_snippet = match self.tcx.sess.codemap().span_to_snippet(ty.span) {
1098                 Ok(snippet) => snippet,
1099                 _ => return None
1100             };
1101
1102             let lifetime_snippet = if !lifetime.is_elided() {
1103                 format!("{} ", match self.tcx.sess.codemap().span_to_snippet(lifetime.span) {
1104                     Ok(lifetime_snippet) => lifetime_snippet,
1105                     _ => return None
1106                 })
1107             } else {
1108                 String::new()
1109             };
1110             Some(format!("use `&{}mut {}` here to make mutable",
1111                          lifetime_snippet,
1112                          if is_implicit_self { "self" } else { &*pointee_snippet }))
1113         } else {
1114             None
1115         }
1116     }
1117
1118     fn local_binding_mode(&self, node_id: ast::NodeId) -> ty::BindingMode {
1119         let pat = match self.tcx.hir.get(node_id) {
1120             hir_map::Node::NodeLocal(pat) => pat,
1121             node => bug!("bad node for local: {:?}", node)
1122         };
1123
1124         match pat.node {
1125             hir::PatKind::Binding(..) => {
1126                 *self.tables
1127                      .pat_binding_modes()
1128                      .get(pat.hir_id)
1129                      .expect("missing binding mode")
1130             }
1131             _ => bug!("local is not a binding: {:?}", pat)
1132         }
1133     }
1134
1135     fn local_ty(&self, node_id: ast::NodeId) -> (Option<&hir::Ty>, bool) {
1136         let parent = self.tcx.hir.get_parent_node(node_id);
1137         let parent_node = self.tcx.hir.get(parent);
1138
1139         // The parent node is like a fn
1140         if let Some(fn_like) = FnLikeNode::from_node(parent_node) {
1141             // `nid`'s parent's `Body`
1142             let fn_body = self.tcx.hir.body(fn_like.body());
1143             // Get the position of `node_id` in the arguments list
1144             let arg_pos = fn_body.arguments.iter().position(|arg| arg.pat.id == node_id);
1145             if let Some(i) = arg_pos {
1146                 // The argument's `Ty`
1147                 (Some(&fn_like.decl().inputs[i]),
1148                  i == 0 && fn_like.decl().has_implicit_self)
1149             } else {
1150                 (None, false)
1151             }
1152         } else {
1153             (None, false)
1154         }
1155     }
1156
1157     fn note_immutability_blame(&self,
1158                                db: &mut DiagnosticBuilder,
1159                                blame: Option<ImmutabilityBlame>) {
1160         match blame {
1161             None => {}
1162             Some(ImmutabilityBlame::ClosureEnv(_)) => {}
1163             Some(ImmutabilityBlame::ImmLocal(node_id)) => {
1164                 let let_span = self.tcx.hir.span(node_id);
1165                 if let ty::BindByValue(..) = self.local_binding_mode(node_id) {
1166                     if let Ok(snippet) = self.tcx.sess.codemap().span_to_snippet(let_span) {
1167                         let (_, is_implicit_self) = self.local_ty(node_id);
1168                         if is_implicit_self && snippet != "self" {
1169                             // avoid suggesting `mut &self`.
1170                             return
1171                         }
1172                         db.span_label(
1173                             let_span,
1174                             format!("consider changing this to `mut {}`", snippet)
1175                         );
1176                     }
1177                 }
1178             }
1179             Some(ImmutabilityBlame::LocalDeref(node_id)) => {
1180                 let let_span = self.tcx.hir.span(node_id);
1181                 match self.local_binding_mode(node_id) {
1182                     ty::BindByReference(..) => {
1183                         let snippet = self.tcx.sess.codemap().span_to_snippet(let_span);
1184                         if let Ok(snippet) = snippet {
1185                             db.span_label(
1186                                 let_span,
1187                                 format!("consider changing this to `{}`",
1188                                          snippet.replace("ref ", "ref mut "))
1189                             );
1190                         }
1191                     }
1192                     ty::BindByValue(..) => {
1193                         if let (Some(local_ty), is_implicit_self) = self.local_ty(node_id) {
1194                             if let Some(msg) =
1195                                  self.suggest_mut_for_immutable(local_ty, is_implicit_self) {
1196                                 db.span_label(local_ty.span, msg);
1197                             }
1198                         }
1199                     }
1200                 }
1201             }
1202             Some(ImmutabilityBlame::AdtFieldDeref(_, field)) => {
1203                 let node_id = match self.tcx.hir.as_local_node_id(field.did) {
1204                     Some(node_id) => node_id,
1205                     None => return
1206                 };
1207
1208                 if let hir_map::Node::NodeField(ref field) = self.tcx.hir.get(node_id) {
1209                     if let Some(msg) = self.suggest_mut_for_immutable(&field.ty, false) {
1210                         db.span_label(field.ty.span, msg);
1211                     }
1212                 }
1213             }
1214         }
1215     }
1216
1217     fn report_out_of_scope_escaping_closure_capture(&self,
1218                                                     err: &BckError<'tcx>,
1219                                                     capture_span: Span)
1220     {
1221         let cmt_path_or_string = self.cmt_to_path_or_string(&err.cmt);
1222
1223         let suggestion =
1224             match self.tcx.sess.codemap().span_to_snippet(err.span) {
1225                 Ok(string) => format!("move {}", string),
1226                 Err(_) => format!("move |<args>| <body>")
1227             };
1228
1229         struct_span_err!(self.tcx.sess, err.span, E0373,
1230                          "closure may outlive the current function, \
1231                           but it borrows {}, \
1232                           which is owned by the current function",
1233                          cmt_path_or_string)
1234             .span_label(capture_span,
1235                        format!("{} is borrowed here",
1236                                 cmt_path_or_string))
1237             .span_label(err.span,
1238                        format!("may outlive borrowed value {}",
1239                                 cmt_path_or_string))
1240             .span_suggestion(err.span,
1241                              &format!("to force the closure to take ownership of {} \
1242                                        (and any other referenced variables), \
1243                                        use the `move` keyword",
1244                                        cmt_path_or_string),
1245                              suggestion)
1246             .emit();
1247     }
1248
1249     fn region_end_span(&self, region: ty::Region<'tcx>) -> Option<Span> {
1250         match *region {
1251             ty::ReScope(scope) => {
1252                 match scope.span(&self.tcx.hir) {
1253                     Some(s) => {
1254                         Some(s.end_point())
1255                     }
1256                     None => {
1257                         None
1258                     }
1259                 }
1260             }
1261             _ => None
1262         }
1263     }
1264
1265     fn note_and_explain_mutbl_error(&self, db: &mut DiagnosticBuilder, err: &BckError<'tcx>,
1266                                     error_span: &Span) {
1267         match err.cmt.note {
1268             mc::NoteClosureEnv(upvar_id) | mc::NoteUpvarRef(upvar_id) => {
1269                 // If this is an `Fn` closure, it simply can't mutate upvars.
1270                 // If it's an `FnMut` closure, the original variable was declared immutable.
1271                 // We need to determine which is the case here.
1272                 let kind = match err.cmt.upvar().unwrap().cat {
1273                     Categorization::Upvar(mc::Upvar { kind, .. }) => kind,
1274                     _ => bug!()
1275                 };
1276                 if kind == ty::ClosureKind::Fn {
1277                     let closure_node_id =
1278                         self.tcx.hir.def_index_to_node_id(upvar_id.closure_expr_id);
1279                     db.span_help(self.tcx.hir.span(closure_node_id),
1280                                  "consider changing this closure to take \
1281                                   self by mutable reference");
1282                 }
1283             }
1284             _ => {
1285                 if let Categorization::Deref(..) = err.cmt.cat {
1286                     db.span_label(*error_span, "cannot borrow as mutable");
1287                 } else if let Categorization::Local(local_id) = err.cmt.cat {
1288                     let span = self.tcx.hir.span(local_id);
1289                     if let Ok(snippet) = self.tcx.sess.codemap().span_to_snippet(span) {
1290                         if snippet.starts_with("ref mut ") || snippet.starts_with("&mut ") {
1291                             db.span_label(*error_span, "cannot reborrow mutably");
1292                             db.span_label(*error_span, "try removing `&mut` here");
1293                         } else {
1294                             db.span_label(*error_span, "cannot borrow mutably");
1295                         }
1296                     } else {
1297                         db.span_label(*error_span, "cannot borrow mutably");
1298                     }
1299                 } else if let Categorization::Interior(ref cmt, _) = err.cmt.cat {
1300                     if let mc::MutabilityCategory::McImmutable = cmt.mutbl {
1301                         db.span_label(*error_span,
1302                                       "cannot mutably borrow immutable field");
1303                     }
1304                 }
1305             }
1306         }
1307     }
1308     pub fn append_loan_path_to_string(&self,
1309                                       loan_path: &LoanPath<'tcx>,
1310                                       out: &mut String) {
1311         match loan_path.kind {
1312             LpUpvar(ty::UpvarId { var_id: id, closure_expr_id: _ }) => {
1313                 out.push_str(&self.tcx.local_var_name_str_def_index(id));
1314             }
1315             LpVar(id) => {
1316                 out.push_str(&self.tcx.local_var_name_str(id));
1317             }
1318
1319             LpDowncast(ref lp_base, variant_def_id) => {
1320                 out.push('(');
1321                 self.append_loan_path_to_string(&lp_base, out);
1322                 out.push_str(DOWNCAST_PRINTED_OPERATOR);
1323                 out.push_str(&self.tcx.item_path_str(variant_def_id));
1324                 out.push(')');
1325             }
1326
1327             LpExtend(ref lp_base, _, LpInterior(_, InteriorField(fname))) => {
1328                 self.append_autoderefd_loan_path_to_string(&lp_base, out);
1329                 match fname {
1330                     mc::NamedField(fname) => {
1331                         out.push('.');
1332                         out.push_str(&fname.as_str());
1333                     }
1334                     mc::PositionalField(idx) => {
1335                         out.push('.');
1336                         out.push_str(&idx.to_string());
1337                     }
1338                 }
1339             }
1340
1341             LpExtend(ref lp_base, _, LpInterior(_, InteriorElement)) => {
1342                 self.append_autoderefd_loan_path_to_string(&lp_base, out);
1343                 out.push_str("[..]");
1344             }
1345
1346             LpExtend(ref lp_base, _, LpDeref(_)) => {
1347                 out.push('*');
1348                 self.append_loan_path_to_string(&lp_base, out);
1349             }
1350         }
1351     }
1352
1353     pub fn append_autoderefd_loan_path_to_string(&self,
1354                                                  loan_path: &LoanPath<'tcx>,
1355                                                  out: &mut String) {
1356         match loan_path.kind {
1357             LpExtend(ref lp_base, _, LpDeref(_)) => {
1358                 // For a path like `(*x).f` or `(*x)[3]`, autoderef
1359                 // rules would normally allow users to omit the `*x`.
1360                 // So just serialize such paths to `x.f` or x[3]` respectively.
1361                 self.append_autoderefd_loan_path_to_string(&lp_base, out)
1362             }
1363
1364             LpDowncast(ref lp_base, variant_def_id) => {
1365                 out.push('(');
1366                 self.append_autoderefd_loan_path_to_string(&lp_base, out);
1367                 out.push(':');
1368                 out.push_str(&self.tcx.item_path_str(variant_def_id));
1369                 out.push(')');
1370             }
1371
1372             LpVar(..) | LpUpvar(..) | LpExtend(.., LpInterior(..)) => {
1373                 self.append_loan_path_to_string(loan_path, out)
1374             }
1375         }
1376     }
1377
1378     pub fn loan_path_to_string(&self, loan_path: &LoanPath<'tcx>) -> String {
1379         let mut result = String::new();
1380         self.append_loan_path_to_string(loan_path, &mut result);
1381         result
1382     }
1383
1384     pub fn cmt_to_string(&self, cmt: &mc::cmt_<'tcx>) -> String {
1385         cmt.descriptive_string(self.tcx)
1386     }
1387
1388     pub fn cmt_to_path_or_string(&self, cmt: &mc::cmt<'tcx>) -> String {
1389         match opt_loan_path(cmt) {
1390             Some(lp) => format!("`{}`", self.loan_path_to_string(&lp)),
1391             None => self.cmt_to_string(cmt),
1392         }
1393     }
1394 }
1395
1396 fn statement_scope_span(tcx: TyCtxt, region: ty::Region) -> Option<Span> {
1397     match *region {
1398         ty::ReScope(scope) => {
1399             match tcx.hir.find(scope.node_id()) {
1400                 Some(hir_map::NodeStmt(stmt)) => Some(stmt.span),
1401                 _ => None
1402             }
1403         }
1404         _ => None
1405     }
1406 }
1407
1408 impl BitwiseOperator for LoanDataFlowOperator {
1409     #[inline]
1410     fn join(&self, succ: usize, pred: usize) -> usize {
1411         succ | pred // loans from both preds are in scope
1412     }
1413 }
1414
1415 impl DataFlowOperator for LoanDataFlowOperator {
1416     #[inline]
1417     fn initial_value(&self) -> bool {
1418         false // no loans in scope by default
1419     }
1420 }
1421
1422 impl<'tcx> fmt::Debug for InteriorKind {
1423     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1424         match *self {
1425             InteriorField(mc::NamedField(fld)) => write!(f, "{}", fld),
1426             InteriorField(mc::PositionalField(i)) => write!(f, "#{}", i),
1427             InteriorElement => write!(f, "[]"),
1428         }
1429     }
1430 }
1431
1432 impl<'tcx> fmt::Debug for Loan<'tcx> {
1433     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1434         write!(f, "Loan_{}({:?}, {:?}, {:?}-{:?}, {:?})",
1435                self.index,
1436                self.loan_path,
1437                self.kind,
1438                self.gen_scope,
1439                self.kill_scope,
1440                self.restricted_paths)
1441     }
1442 }
1443
1444 impl<'tcx> fmt::Debug for LoanPath<'tcx> {
1445     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1446         match self.kind {
1447             LpVar(id) => {
1448                 write!(f, "$({})", ty::tls::with(|tcx| tcx.hir.node_to_string(id)))
1449             }
1450
1451             LpUpvar(ty::UpvarId{ var_id, closure_expr_id }) => {
1452                 let s = ty::tls::with(|tcx| {
1453                     let var_node_id = tcx.hir.def_index_to_node_id(var_id);
1454                     tcx.hir.node_to_string(var_node_id)
1455                 });
1456                 write!(f, "$({} captured by id={:?})", s, closure_expr_id)
1457             }
1458
1459             LpDowncast(ref lp, variant_def_id) => {
1460                 let variant_str = if variant_def_id.is_local() {
1461                     ty::tls::with(|tcx| tcx.item_path_str(variant_def_id))
1462                 } else {
1463                     format!("{:?}", variant_def_id)
1464                 };
1465                 write!(f, "({:?}{}{})", lp, DOWNCAST_PRINTED_OPERATOR, variant_str)
1466             }
1467
1468             LpExtend(ref lp, _, LpDeref(_)) => {
1469                 write!(f, "{:?}.*", lp)
1470             }
1471
1472             LpExtend(ref lp, _, LpInterior(_, ref interior)) => {
1473                 write!(f, "{:?}.{:?}", lp, interior)
1474             }
1475         }
1476     }
1477 }
1478
1479 impl<'tcx> fmt::Display for LoanPath<'tcx> {
1480     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1481         match self.kind {
1482             LpVar(id) => {
1483                 write!(f, "$({})", ty::tls::with(|tcx| tcx.hir.node_to_user_string(id)))
1484             }
1485
1486             LpUpvar(ty::UpvarId{ var_id, closure_expr_id: _ }) => {
1487                 let s = ty::tls::with(|tcx| {
1488                     let var_node_id = tcx.hir.def_index_to_node_id(var_id);
1489                     tcx.hir.node_to_string(var_node_id)
1490                 });
1491                 write!(f, "$({} captured by closure)", s)
1492             }
1493
1494             LpDowncast(ref lp, variant_def_id) => {
1495                 let variant_str = if variant_def_id.is_local() {
1496                     ty::tls::with(|tcx| tcx.item_path_str(variant_def_id))
1497                 } else {
1498                     format!("{:?}", variant_def_id)
1499                 };
1500                 write!(f, "({}{}{})", lp, DOWNCAST_PRINTED_OPERATOR, variant_str)
1501             }
1502
1503             LpExtend(ref lp, _, LpDeref(_)) => {
1504                 write!(f, "{}.*", lp)
1505             }
1506
1507             LpExtend(ref lp, _, LpInterior(_, ref interior)) => {
1508                 write!(f, "{}.{:?}", lp, interior)
1509             }
1510         }
1511     }
1512 }