(index<- )        ./librustc/middle/borrowck/mod.rs

    git branch:    * master           5200215 auto merge of #14035 : alexcrichton/rust/experimental, r=huonw
    modified:    Fri May  9 13:02:28 2014
   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 doc.rs for a thorough explanation of the borrow checker */
  12  
  13  #![allow(non_camel_case_types)]
  14  
  15  use middle::dataflow::DataFlowContext;
  16  use middle::dataflow::DataFlowOperator;
  17  use euv = middle::expr_use_visitor;
  18  use mc = middle::mem_categorization;
  19  use middle::ty;
  20  use util::ppaux::{note_and_explain_region, Repr, UserString};
  21  
  22  use std::cell::{Cell};
  23  use std::ops::{BitOr, BitAnd};
  24  use std::rc::Rc;
  25  use std::strbuf::StrBuf;
  26  use syntax::ast;
  27  use syntax::ast_map;
  28  use syntax::ast_util;
  29  use syntax::codemap::Span;
  30  use syntax::parse::token;
  31  use syntax::visit;
  32  use syntax::visit::{Visitor, FnKind};
  33  use syntax::ast::{FnDecl, Block, NodeId};
  34  
  35  macro_rules! if_ok(
  36      ($inp: expr) => (
  37          match $inp {
  38              Ok(v) => { v }
  39              Err(e) => { return Err(e); }
  40          }
  41      )
  42  )
  43  
  44  pub mod doc;
  45  
  46  pub mod check_loans;
  47  
  48  pub mod gather_loans;
  49  
  50  pub mod move_data;
  51  
  52  pub struct LoanDataFlowOperator;
  53  
  54  /// FIXME(pcwalton): Should just be #[deriving(Clone)], but that doesn't work
  55  /// yet on unit structs.
  56  impl Clone for LoanDataFlowOperator {
  57      fn clone(&self) -> LoanDataFlowOperator {
  58          LoanDataFlowOperator
  59      }
  60  }
  61  
  62  pub type LoanDataFlow<'a> = DataFlowContext<'a, LoanDataFlowOperator>;
  63  
  64  impl<'a> Visitor<()> for BorrowckCtxt<'a> {
  65      fn visit_fn(&mut self, fk&FnKind, fd&FnDecl,
  66                  b&Block, sSpan, nNodeId, _()) {
  67          borrowck_fn(self, fk, fd, b, s, n);
  68      }
  69  
  70      fn visit_item(&mut self, item&ast::Item, _()) {
  71          borrowck_item(self, item);
  72      }
  73  }
  74  
  75  pub fn check_crate(tcx: &ty::ctxt,
  76                     krate: &ast::Crate) {
  77      let mut bccx = BorrowckCtxt {
  78          tcx: tcx,
  79          stats: @BorrowStats {
  80              loaned_paths_same: Cell::new(0),
  81              loaned_paths_imm: Cell::new(0),
  82              stable_paths: Cell::new(0),
  83              guaranteed_paths: Cell::new(0),
  84          }
  85      };
  86  
  87      visit::walk_crate(&mut bccx, krate, ());
  88  
  89      if tcx.sess.borrowck_stats() {
  90          println!("--- borrowck stats ---");
  91          println!("paths requiring guarantees: {}",
  92                   bccx.stats.guaranteed_paths.get());
  93          println!("paths requiring loans     : {}",
  94                   make_stat(&bccx, bccx.stats.loaned_paths_same.get()));
  95          println!("paths requiring imm loans : {}",
  96                   make_stat(&bccx, bccx.stats.loaned_paths_imm.get()));
  97          println!("stable paths              : {}",
  98                   make_stat(&bccx, bccx.stats.stable_paths.get()));
  99      }
 100  
 101      fn make_stat(bccx&BorrowckCtxt, statuint) -> ~str {
 102          let stat_f = stat as f64;
 103          let total = bccx.stats.guaranteed_paths.get() as f64;
 104          format!("{} ({:.0f}%)", stat  , stat_f * 100.0 / total)
 105      }
 106  }
 107  
 108  fn borrowck_item(this: &mut BorrowckCtxt, item: &ast::Item) {
 109      // Gather loans for items. Note that we don't need
 110      // to check loans for single expressions. The check
 111      // loan step is intended for things that have a data
 112      // flow dependent conditions.
 113      match item.node {
 114          ast::ItemStatic(_, _, ex) => {
 115              gather_loans::gather_loans_in_static_initializer(this, ex);
 116          }
 117          _ => {
 118              visit::walk_item(this, item, ());
 119          }
 120      }
 121  }
 122  
 123  fn borrowck_fn(this: &mut BorrowckCtxt,
 124                 fk: &FnKind,
 125                 decl: &ast::FnDecl,
 126                 body: &ast::Block,
 127                 spSpan,
 128                 idast::NodeId) {
 129      debug!("borrowck_fn(id={})", id);
 130  
 131      // Check the body of fn items.
 132      let id_range = ast_util::compute_id_range_for_fn_body(fk, decl, body, sp, id);
 133      let (all_loans, move_data) =
 134          gather_loans::gather_loans_in_fn(this, decl, body);
 135      let mut loan_dfcx =
 136          DataFlowContext::new(this.tcx,
 137                               LoanDataFlowOperator,
 138                               id_range,
 139                               all_loans.len());
 140      for (loan_idx, loan) in all_loans.iter().enumerate() {
 141          loan_dfcx.add_gen(loan.gen_scope, loan_idx);
 142          loan_dfcx.add_kill(loan.kill_scope, loan_idx);
 143      }
 144      loan_dfcx.propagate(body);
 145  
 146      let flowed_moves = move_data::FlowedMoveData::new(move_data,
 147                                                        this.tcx,
 148                                                        id_range,
 149                                                        body);
 150  
 151      check_loans::check_loans(this, &loan_dfcx, flowed_moves,
 152                               all_loans.as_slice(), body);
 153  
 154      visit::walk_fn(this, fk, decl, body, sp, id, ());
 155  }
 156  
 157  // ----------------------------------------------------------------------
 158  // Type definitions
 159  
 160  pub struct BorrowckCtxt<'a> {
 161      tcx: &'a ty::ctxt,
 162  
 163      // Statistics:
 164      stats: @BorrowStats
 165  }
 166  
 167  pub struct BorrowStats {
 168      loaned_paths_same: Cell<uint>,
 169      loaned_paths_imm: Cell<uint>,
 170      stable_paths: Cell<uint>,
 171      guaranteed_paths: Cell<uint>,
 172  }
 173  
 174  pub type BckResult<T> = Result<T, BckError>;
 175  
 176  #[deriving(Eq)]
 177  pub enum PartialTotal {
 178      Partial,   // Loan affects some portion
 179      Total      // Loan affects entire path
 180  }
 181  
 182  ///////////////////////////////////////////////////////////////////////////
 183  // Loans and loan paths
 184  
 185  /// Record of a loan that was issued.
 186  pub struct Loan {
 187      index: uint,
 188      loan_path: Rc<LoanPath>,
 189      cmt: mc::cmt,
 190      kind: ty::BorrowKind,
 191      restrictions: Vec<Restriction>,
 192      gen_scope: ast::NodeId,
 193      kill_scope: ast::NodeId,
 194      span: Span,
 195      cause: euv::LoanCause,
 196  }
 197  
 198  #[deriving(Eq, TotalEq, Hash)]
 199  pub enum LoanPath {
 200      LpVar(ast::NodeId),               // `x` in doc.rs
 201      LpExtend(Rc<LoanPath>, mc::MutabilityCategory, LoanPathElem)
 202  }
 203  
 204  #[deriving(Eq, TotalEq, Hash)]
 205  pub enum LoanPathElem {
 206      LpDeref(mc::PointerKind),    // `*LV` in doc.rs
 207      LpInterior(mc::InteriorKind) // `LV.f` in doc.rs
 208  }
 209  
 210  impl LoanPath {
 211      pub fn node_id(&self) -> ast::NodeId {
 212          match *self {
 213              LpVar(local_id) => local_id,
 214              LpExtend(ref base, _, _) => base.node_id()
 215          }
 216      }
 217  }
 218  
 219  pub fn opt_loan_path(cmt: &mc::cmt) -> Option<Rc<LoanPath>> {
 220      //! Computes the `LoanPath` (if any) for a `cmt`.
 221      //! Note that this logic is somewhat duplicated in
 222      //! the method `compute()` found in `gather_loans::restrictions`,
 223      //! which allows it to share common loan path pieces as it
 224      //! traverses the CMT.
 225  
 226      match cmt.cat {
 227          mc::cat_rvalue(..) |
 228          mc::cat_static_item |
 229          mc::cat_copied_upvar(mc::CopiedUpvar { onceness: ast::Many, .. }) => {
 230              None
 231          }
 232  
 233          mc::cat_local(id) |
 234          mc::cat_arg(id) |
 235          mc::cat_copied_upvar(mc::CopiedUpvar { upvar_id: id, .. }) |
 236          mc::cat_upvar(ty::UpvarId {var_id: id, ..}, _) => {
 237              Some(Rc::new(LpVar(id)))
 238          }
 239  
 240          mc::cat_deref(ref cmt_base, _, pk) => {
 241              opt_loan_path(cmt_base).map(|lp| {
 242                  Rc::new(LpExtend(lp, cmt.mutbl, LpDeref(pk)))
 243              })
 244          }
 245  
 246          mc::cat_interior(ref cmt_base, ik) => {
 247              opt_loan_path(cmt_base).map(|lp| {
 248                  Rc::new(LpExtend(lp, cmt.mutbl, LpInterior(ik)))
 249              })
 250          }
 251  
 252          mc::cat_downcast(ref cmt_base) |
 253          mc::cat_discr(ref cmt_base, _) => {
 254              opt_loan_path(cmt_base)
 255          }
 256      }
 257  }
 258  
 259  ///////////////////////////////////////////////////////////////////////////
 260  // Restrictions
 261  //
 262  // Borrowing an lvalue often results in *restrictions* that limit what
 263  // can be done with this lvalue during the scope of the loan:
 264  //
 265  // - `RESTR_MUTATE`: The lvalue may not be modified or `&mut` borrowed.
 266  // - `RESTR_FREEZE`: `&` borrows of the lvalue are forbidden.
 267  //
 268  // In addition, no value which is restricted may be moved. Therefore,
 269  // restrictions are meaningful even if the RestrictionSet is empty,
 270  // because the restriction against moves is implied.
 271  
 272  pub struct Restriction {
 273      loan_path: Rc<LoanPath>,
 274      set: RestrictionSet
 275  }
 276  
 277  #[deriving(Eq)]
 278  pub struct RestrictionSet {
 279      bits: u32
 280  }
 281  
 282  #[allow(dead_code)] // potentially useful
 283  pub static RESTR_EMPTY: RestrictionSet  = RestrictionSet {bits: 0b0000};
 284  pub static RESTR_MUTATE: RestrictionSet = RestrictionSet {bits: 0b0001};
 285  pub static RESTR_FREEZE: RestrictionSet = RestrictionSet {bits: 0b0010};
 286  
 287  impl RestrictionSet {
 288      pub fn intersects(&self, restrRestrictionSet) -> bool {
 289          (self.bits & restr.bits) != 0
 290      }
 291  }
 292  
 293  impl BitOr<RestrictionSet,RestrictionSet> for RestrictionSet {
 294      fn bitor(&self, rhs&RestrictionSet) -> RestrictionSet {
 295          RestrictionSet {bits: self.bits | rhs.bits}
 296      }
 297  }
 298  
 299  impl BitAnd<RestrictionSet,RestrictionSet> for RestrictionSet {
 300      fn bitand(&self, rhs&RestrictionSet) -> RestrictionSet {
 301          RestrictionSet {bits: self.bits & rhs.bits}
 302      }
 303  }
 304  
 305  impl Repr for RestrictionSet {
 306      fn repr(&self, _tcx&ty::ctxt) -> ~str {
 307          format!("RestrictionSet(0x{:x})", self.bits as uint)
 308      }
 309  }
 310  
 311  ///////////////////////////////////////////////////////////////////////////
 312  // Errors
 313  
 314  // Errors that can occur
 315  #[deriving(Eq)]
 316  pub enum bckerr_code {
 317      err_mutbl,
 318      err_out_of_scope(ty::Region, ty::Region), // superscope, subscope
 319      err_borrowed_pointer_too_short(
 320          ty::Region, ty::Region, RestrictionSet), // loan, ptr
 321  }
 322  
 323  // Combination of an error code and the categorization of the expression
 324  // that caused it
 325  #[deriving(Eq)]
 326  pub struct BckError {
 327      span: Span,
 328      cause: euv::LoanCause,
 329      cmt: mc::cmt,
 330      code: bckerr_code
 331  }
 332  
 333  pub enum AliasableViolationKind {
 334      MutabilityViolation,
 335      BorrowViolation(euv::LoanCause)
 336  }
 337  
 338  pub enum MovedValueUseKind {
 339      MovedInUse,
 340      MovedInCapture,
 341  }
 342  
 343  ///////////////////////////////////////////////////////////////////////////
 344  // Misc
 345  
 346  impl<'a> BorrowckCtxt<'a> {
 347      pub fn is_subregion_of(&self, r_subty::Region, r_supty::Region)
 348                             -> bool {
 349          self.tcx.region_maps.is_subregion_of(r_sub, r_sup)
 350      }
 351  
 352      pub fn is_subscope_of(&self, r_subast::NodeId, r_supast::NodeId)
 353                            -> bool {
 354          self.tcx.region_maps.is_subscope_of(r_sub, r_sup)
 355      }
 356  
 357      pub fn mc(&self) -> mc::MemCategorizationContext<'a,ty::ctxt> {
 358          mc::MemCategorizationContext::new(self.tcx)
 359      }
 360  
 361      pub fn cat_expr(&self, expr&ast::Expr) -> mc::cmt {
 362          match self.mc().cat_expr(expr) {
 363              Ok(c) => c,
 364              Err(()) => {
 365                  self.tcx.sess.span_bug(expr.span, "error in mem categorization");
 366              }
 367          }
 368      }
 369  
 370      pub fn cat_expr_unadjusted(&self, expr&ast::Expr) -> mc::cmt {
 371          match self.mc().cat_expr_unadjusted(expr) {
 372              Ok(c) => c,
 373              Err(()) => {
 374                  self.tcx.sess.span_bug(expr.span, "error in mem categorization");
 375              }
 376          }
 377      }
 378  
 379      pub fn cat_expr_autoderefd(&self,
 380                                 expr&ast::Expr,
 381                                 adj&ty::AutoAdjustment)
 382                                 -> mc::cmt {
 383          let r = match *adj {
 384              ty::AutoAddEnv(..) | ty::AutoObject(..) => {
 385                  // no autoderefs
 386                  self.mc().cat_expr_unadjusted(expr)
 387              }
 388  
 389              ty::AutoDerefRef(
 390                  ty::AutoDerefRef {
 391                      autoderefs: autoderefs, ..}) => {
 392                  self.mc().cat_expr_autoderefd(expr, autoderefs)
 393              }
 394          };
 395  
 396          match r {
 397              Ok(c) => c,
 398              Err(()) => {
 399                  self.tcx.sess.span_bug(expr.span,
 400                                         "error in mem categorization");
 401              }
 402          }
 403      }
 404  
 405      pub fn cat_def(&self,
 406                     idast::NodeId,
 407                     spanSpan,
 408                     tyty::t,
 409                     defast::Def)
 410                     -> mc::cmt {
 411          match self.mc().cat_def(id, span, ty, def) {
 412              Ok(c) => c,
 413              Err(()) => {
 414                  self.tcx.sess.span_bug(span, "error in mem categorization");
 415              }
 416          }
 417      }
 418  
 419      pub fn cat_captured_var(&self,
 420                              closure_idast::NodeId,
 421                              closure_spanSpan,
 422                              upvar_defast::Def)
 423                              -> mc::cmt {
 424          // Create the cmt for the variable being borrowed, from the
 425          // caller's perspective
 426          let var_id = ast_util::def_id_of_def(upvar_def).node;
 427          let var_ty = ty::node_id_to_type(self.tcx, var_id);
 428          self.cat_def(closure_id, closure_span, var_ty, upvar_def)
 429      }
 430  
 431      pub fn cat_discr(&self, cmtmc::cmt, match_idast::NodeId) -> mc::cmt {
 432          Rc::new(mc::cmt_ {
 433              cat: mc::cat_discr(cmt.clone(), match_id),
 434              mutbl: cmt.mutbl.inherit(),
 435              ..*cmt
 436          })
 437      }
 438  
 439      pub fn cat_pattern(&self,
 440                         cmtmc::cmt,
 441                         pat&ast::Pat,
 442                         op|mc::cmt, &ast::Pat|) {
 443          let r = self.mc().cat_pattern(cmt, pat, |_,x,y| op(x,y));
 444          assert!(r.is_ok());
 445      }
 446  
 447      pub fn report(&self, errBckError) {
 448          self.span_err(
 449              err.span,
 450              self.bckerr_to_str(&err));
 451          self.note_and_explain_bckerr(err);
 452      }
 453  
 454      pub fn report_use_of_moved_value(&self,
 455                                       use_spanSpan,
 456                                       use_kindMovedValueUseKind,
 457                                       lp&LoanPath,
 458                                       move&move_data::Move,
 459                                       moved_lp&LoanPath) {
 460          let verb = match use_kind {
 461              MovedInUse => "use",
 462              MovedInCapture => "capture",
 463          };
 464  
 465          match move.kind {
 466              move_data::Declared => {
 467                  self.tcx.sess.span_err(
 468                      use_span,
 469                      format!("{} of possibly uninitialized variable: `{}`",
 470                           verb,
 471                           self.loan_path_to_str(lp)));
 472              }
 473              _ => {
 474                  let partially = if lp == moved_lp {""} else {"partially "};
 475                  self.tcx.sess.span_err(
 476                      use_span,
 477                      format!("{} of {}moved value: `{}`",
 478                           verb,
 479                           partially,
 480                           self.loan_path_to_str(lp)));
 481              }
 482          }
 483  
 484          match move.kind {
 485              move_data::Declared => {}
 486  
 487              move_data::MoveExpr => {
 488                  let (expr_ty, expr_span) = match self.tcx.map.find(move.id) {
 489                      Some(ast_map::NodeExpr(expr)) => {
 490                          (ty::expr_ty_adjusted(self.tcx, expr), expr.span)
 491                      }
 492                      r => self.tcx.sess.bug(format!("MoveExpr({:?}) maps to {:?}, not Expr",
 493                                                     move.id, r))
 494                  };
 495                  let suggestion = move_suggestion(self.tcx, expr_ty,
 496                          "moved by default (use `copy` to override)");
 497                  self.tcx.sess.span_note(
 498                      expr_span,
 499                      format!("`{}` moved here because it has type `{}`, which is {}",
 500                           self.loan_path_to_str(moved_lp),
 501                           expr_ty.user_string(self.tcx), suggestion));
 502              }
 503  
 504              move_data::MovePat => {
 505                  let pat_ty = ty::node_id_to_type(self.tcx, move.id);
 506                  self.tcx.sess.span_note(self.tcx.map.span(move.id),
 507                      format!("`{}` moved here because it has type `{}`, \
 508                            which is moved by default (use `ref` to override)",
 509                           self.loan_path_to_str(moved_lp),
 510                           pat_ty.user_string(self.tcx)));
 511              }
 512  
 513              move_data::Captured => {
 514                  let (expr_ty, expr_span) = match self.tcx.map.find(move.id) {
 515                      Some(ast_map::NodeExpr(expr)) => {
 516                          (ty::expr_ty_adjusted(self.tcx, expr), expr.span)
 517                      }
 518                      r => self.tcx.sess.bug(format!("Captured({:?}) maps to {:?}, not Expr",
 519                                                     move.id, r))
 520                  };
 521                  let suggestion = move_suggestion(self.tcx, expr_ty,
 522                          "moved by default (make a copy and \
 523                           capture that instead to override)");
 524                  self.tcx.sess.span_note(
 525                      expr_span,
 526                      format!("`{}` moved into closure environment here because it \
 527                            has type `{}`, which is {}",
 528                           self.loan_path_to_str(moved_lp),
 529                           expr_ty.user_string(self.tcx), suggestion));
 530              }
 531          }
 532  
 533          fn move_suggestion(tcx&ty::ctxt, tyty::t, default_msg&'static str)
 534                            -> &'static str {
 535              match ty::get(ty).sty {
 536                  ty::ty_closure(box ty::ClosureTy {
 537                          store: ty::RegionTraitStore(..),
 538                          ..
 539                      }) =>
 540                      "a non-copyable stack closure (capture it in a new closure, \
 541                       e.g. `|x| f(x)`, to override)",
 542                  _ if ty::type_moves_by_default(tcx, ty) =>
 543                      "non-copyable (perhaps you meant to use clone()?)",
 544                  _ => default_msg,
 545              }
 546          }
 547      }
 548  
 549      pub fn report_reassigned_immutable_variable(&self,
 550                                                  spanSpan,
 551                                                  lp&LoanPath,
 552                                                  assign:
 553                                                  &move_data::Assignment) {
 554          self.tcx.sess.span_err(
 555              span,
 556              format!("re-assignment of immutable variable `{}`",
 557                   self.loan_path_to_str(lp)));
 558          self.tcx.sess.span_note(
 559              assign.span,
 560              format!("prior assignment occurs here"));
 561      }
 562  
 563      pub fn span_err(&self, sSpan, m&str) {
 564          self.tcx.sess.span_err(s, m);
 565      }
 566  
 567      pub fn span_note(&self, sSpan, m&str) {
 568          self.tcx.sess.span_note(s, m);
 569      }
 570  
 571      pub fn span_end_note(&self, sSpan, m&str) {
 572          self.tcx.sess.span_end_note(s, m);
 573      }
 574  
 575      pub fn bckerr_to_str(&self, err&BckError) -> ~str {
 576          match err.code {
 577              err_mutbl => {
 578                  let descr = match opt_loan_path(&err.cmt) {
 579                      None => format!("{} {}",
 580                                      err.cmt.mutbl.to_user_str(),
 581                                      self.cmt_to_str(&*err.cmt)),
 582                      Some(lp) => format!("{} {} `{}`",
 583                                          err.cmt.mutbl.to_user_str(),
 584                                          self.cmt_to_str(&*err.cmt),
 585                                          self.loan_path_to_str(&*lp)),
 586                  };
 587  
 588                  match err.cause {
 589                      euv::ClosureCapture(_) => {
 590                          format!("closure cannot assign to {}", descr)
 591                      }
 592                      euv::OverloadedOperator |
 593                      euv::AddrOf |
 594                      euv::RefBinding |
 595                      euv::AutoRef => {
 596                          format!("cannot borrow {} as mutable", descr)
 597                      }
 598                      euv::ClosureInvocation => {
 599                          self.tcx.sess.span_bug(err.span,
 600                              "err_mutbl with a closure invocation");
 601                      }
 602                  }
 603              }
 604              err_out_of_scope(..) => {
 605                  let msg = match opt_loan_path(&err.cmt) {
 606                      None => format!("borrowed value"),
 607                      Some(lp) => format!("`{}`", self.loan_path_to_str(&*lp)),
 608                  };
 609                  format!("{} does not live long enough", msg)
 610              }
 611              err_borrowed_pointer_too_short(..) => {
 612                  let descr = match opt_loan_path(&err.cmt) {
 613                      Some(lp) => format!("`{}`", self.loan_path_to_str(&*lp)),
 614                      None => self.cmt_to_str(&*err.cmt),
 615                  };
 616  
 617                  format!("lifetime of {} is too short to guarantee \
 618                          its contents can be safely reborrowed",
 619                          descr)
 620              }
 621          }
 622      }
 623  
 624      pub fn report_aliasability_violation(&self,
 625                                           spanSpan,
 626                                           kindAliasableViolationKind,
 627                                           causemc::AliasableReason) {
 628          let prefix = match kind {
 629              MutabilityViolation => {
 630                  "cannot assign to data"
 631              }
 632              BorrowViolation(euv::ClosureCapture(_)) => {
 633                  // I don't think we can get aliasability violations
 634                  // with closure captures, so no need to come up with a
 635                  // good error message. The reason this cannot happen
 636                  // is because we only capture local variables in
 637                  // closures, and those are never aliasable.
 638                  self.tcx.sess.span_bug(
 639                      span,
 640                      "aliasability violation with closure");
 641              }
 642              BorrowViolation(euv::OverloadedOperator) |
 643              BorrowViolation(euv::AddrOf) |
 644              BorrowViolation(euv::AutoRef) |
 645              BorrowViolation(euv::RefBinding) => {
 646                  "cannot borrow data mutably"
 647              }
 648  
 649              BorrowViolation(euv::ClosureInvocation) => {
 650                  "closure invocation"
 651              }
 652          };
 653  
 654          match cause {
 655              mc::AliasableOther => {
 656                  self.tcx.sess.span_err(
 657                      span,
 658                      format!("{} in an aliasable location", prefix));
 659              }
 660              mc::AliasableStatic(..) |
 661              mc::AliasableStaticMut(..) => {
 662                  self.tcx.sess.span_err(
 663                      span,
 664                      format!("{} in a static location", prefix));
 665              }
 666              mc::AliasableManaged => {
 667                  self.tcx.sess.span_err(
 668                      span,
 669                      format!("{} in a `@` pointer", prefix));
 670              }
 671              mc::AliasableBorrowed => {
 672                  self.tcx.sess.span_err(
 673                      span,
 674                      format!("{} in a `&` reference", prefix));
 675              }
 676          }
 677      }
 678  
 679      pub fn note_and_explain_bckerr(&self, errBckError) {
 680          let code = err.code;
 681          match code {
 682              err_mutbl(..) => { }
 683  
 684              err_out_of_scope(super_scope, sub_scope) => {
 685                  note_and_explain_region(
 686                      self.tcx,
 687                      "reference must be valid for ",
 688                      sub_scope,
 689                      "...");
 690                  note_and_explain_region(
 691                      self.tcx,
 692                      "...but borrowed value is only valid for ",
 693                      super_scope,
 694                      "");
 695              }
 696  
 697              err_borrowed_pointer_too_short(loan_scope, ptr_scope, _) => {
 698                  let descr = match opt_loan_path(&err.cmt) {
 699                      Some(lp) => format!("`{}`", self.loan_path_to_str(&*lp)),
 700                      None => self.cmt_to_str(&*err.cmt),
 701                  };
 702                  note_and_explain_region(
 703                      self.tcx,
 704                      format!("{} would have to be valid for ", descr),
 705                      loan_scope,
 706                      "...");
 707                  note_and_explain_region(
 708                      self.tcx,
 709                      format!("...but {} is only valid for ", descr),
 710                      ptr_scope,
 711                      "");
 712              }
 713          }
 714      }
 715  
 716      pub fn append_loan_path_to_str(&self,
 717                                     loan_path&LoanPath,
 718                                     out&mut StrBuf) {
 719          match *loan_path {
 720              LpVar(id) => {
 721                  out.push_str(ty::local_var_name_str(self.tcx, id).get());
 722              }
 723  
 724              LpExtend(ref lp_base, _, LpInterior(mc::InteriorField(fname))) => {
 725                  self.append_autoderefd_loan_path_to_str(&**lp_base, out);
 726                  match fname {
 727                      mc::NamedField(fname) => {
 728                          out.push_char('.');
 729                          out.push_str(token::get_name(fname).get());
 730                      }
 731                      mc::PositionalField(idx) => {
 732                          out.push_char('#'); // invent a notation here
 733                          out.push_str(idx.to_str());
 734                      }
 735                  }
 736              }
 737  
 738              LpExtend(ref lp_base, _, LpInterior(mc::InteriorElement(_))) => {
 739                  self.append_autoderefd_loan_path_to_str(&**lp_base, out);
 740                  out.push_str("[..]");
 741              }
 742  
 743              LpExtend(ref lp_base, _, LpDeref(_)) => {
 744                  out.push_char('*');
 745                  self.append_loan_path_to_str(&**lp_base, out);
 746              }
 747          }
 748      }
 749  
 750      pub fn append_autoderefd_loan_path_to_str(&self,
 751                                                loan_path&LoanPath,
 752                                                out&mut StrBuf) {
 753          match *loan_path {
 754              LpExtend(ref lp_base, _, LpDeref(_)) => {
 755                  // For a path like `(*x).f` or `(*x)[3]`, autoderef
 756                  // rules would normally allow users to omit the `*x`.
 757                  // So just serialize such paths to `x.f` or x[3]` respectively.
 758                  self.append_autoderefd_loan_path_to_str(&**lp_base, out)
 759              }
 760  
 761              LpVar(..) | LpExtend(_, _, LpInterior(..)) => {
 762                  self.append_loan_path_to_str(loan_path, out)
 763              }
 764          }
 765      }
 766  
 767      pub fn loan_path_to_str(&self, loan_path&LoanPath) -> ~str {
 768          let mut result = StrBuf::new();
 769          self.append_loan_path_to_str(loan_path, &mut result);
 770          result.into_owned()
 771      }
 772  
 773      pub fn cmt_to_str(&self, cmt&mc::cmt_) -> ~str {
 774          self.mc().cmt_to_str(cmt)
 775      }
 776  }
 777  
 778  impl DataFlowOperator for LoanDataFlowOperator {
 779      #[inline]
 780      fn initial_value(&self) -> bool {
 781          false // no loans in scope by default
 782      }
 783  
 784      #[inline]
 785      fn join(&self, succuint, preduint) -> uint {
 786          succ | pred // loans from both preds are in scope
 787      }
 788  }
 789  
 790  impl Repr for Loan {
 791      fn repr(&self, tcx&ty::ctxt) -> ~str {
 792          format!("Loan_{:?}({}, {:?}, {:?}-{:?}, {})",
 793               self.index,
 794               self.loan_path.repr(tcx),
 795               self.kind,
 796               self.gen_scope,
 797               self.kill_scope,
 798               self.restrictions.repr(tcx))
 799      }
 800  }
 801  
 802  impl Repr for Restriction {
 803      fn repr(&self, tcx&ty::ctxt) -> ~str {
 804          format!("Restriction({}, {:x})",
 805               self.loan_path.repr(tcx),
 806               self.set.bits as uint)
 807      }
 808  }
 809  
 810  impl Repr for LoanPath {
 811      fn repr(&self, tcx&ty::ctxt) -> ~str {
 812          match self {
 813              &LpVar(id) => {
 814                  format!("$({})", tcx.map.node_to_str(id))
 815              }
 816  
 817              &LpExtend(ref lp, _, LpDeref(_)) => {
 818                  format!("{}.*", lp.repr(tcx))
 819              }
 820  
 821              &LpExtend(ref lp, _, LpInterior(ref interior)) => {
 822                  format!("{}.{}", lp.repr(tcx), interior.repr(tcx))
 823              }
 824          }
 825      }
 826  }
 827  


librustc/middle/borrowck/mod.rs:204:31-204:31 -enum- definition:
pub enum LoanPathElem {
    LpDeref(mc::PointerKind),    // `*LV` in doc.rs
    LpInterior(mc::InteriorKind) // `LV.f` in doc.rs
references:- 7
205: pub enum LoanPathElem {
librustc/middle/borrowck/gather_loans/restrictions.rs:
174:               mc: mc::MutabilityCategory,
175:               elem: LoanPathElem,
176:               restrictions: RestrictionSet) -> RestrictionResult {
librustc/middle/borrowck/mod.rs:
205: pub enum LoanPathElem {


librustc/middle/borrowck/mod.rs:533:8-533:8 -fn- definition:
        fn move_suggestion(tcx: &ty::ctxt, ty: ty::t, default_msg: &'static str)
                          -> &'static str {
            match ty::get(ty).sty {
references:- 2
520:                 };
521:                 let suggestion = move_suggestion(self.tcx, expr_ty,
522:                         "moved by default (make a copy and \


librustc/middle/borrowck/mod.rs:198:31-198:31 -enum- definition:
pub enum LoanPath {
    LpVar(ast::NodeId),               // `x` in doc.rs
    LpExtend(Rc<LoanPath>, mc::MutabilityCategory, LoanPathElem)
references:- 40
librustc/middle/borrowck/check_loans.rs:
librustc/middle/borrowck/gather_loans/mod.rs:
librustc/middle/borrowck/gather_loans/restrictions.rs:
librustc/middle/borrowck/gather_loans/gather_moves.rs:
librustc/middle/borrowck/move_data.rs:
librustc/middle/borrowck/mod.rs:


librustc/middle/borrowck/mod.rs:101:4-101:4 -fn- definition:
    fn make_stat(bccx: &BorrowckCtxt, stat: uint) -> ~str {
        let stat_f = stat as f64;
        let total = bccx.stats.guaranteed_paths.get() as f64;
references:- 3
95:         println!("paths requiring imm loans : {}",
96:                  make_stat(&bccx, bccx.stats.loaned_paths_imm.get()));
97:         println!("stable paths              : {}",
98:                  make_stat(&bccx, bccx.stats.stable_paths.get()));
99:     }


librustc/middle/borrowck/mod.rs:166:1-166:1 -struct- definition:
pub struct BorrowStats {
    loaned_paths_same: Cell<uint>,
    loaned_paths_imm: Cell<uint>,
references:- 2
163:     // Statistics:
164:     stats: @BorrowStats
165: }


librustc/middle/borrowck/mod.rs:185:38-185:38 -struct- definition:
/// Record of a loan that was issued.
pub struct Loan {
    index: uint,
references:- 16
librustc/middle/borrowck/gather_loans/mod.rs:
308:                 Loan {
309:                     index: self.all_loans.len(),
librustc/middle/borrowck/mod.rs:
790: impl Repr for Loan {
791:     fn repr(&self, tcx: &ty::ctxt) -> ~str {
librustc/middle/borrowck/check_loans.rs:
211:                                                            loan1: &Loan,
212:                                                            loan2: &Loan,
213:                                                            old_loan: &Loan,
214:                                                            new_loan: &Loan)
215:                                                            -> bool {
--
670:                                    loan_path: &LoanPath,
671:                                    loan: &Loan) {
672:         self.bccx.span_err(
librustc/middle/borrowck/gather_loans/mod.rs:
63:     move_error_collector: move_error::MoveErrorCollector,
64:     all_loans: Vec<Loan>,
65:     item_ub: ast::NodeId,
librustc/middle/borrowck/check_loans.rs:
39:     move_data: move_data::FlowedMoveData<'a>,
40:     all_loans: &'a [Loan],
41: }


librustc/middle/borrowck/mod.rs:159:1-159:1 -struct- definition:
pub struct BorrowckCtxt<'a> {
    tcx: &'a ty::ctxt,
    // Statistics:
references:- 28
76:                    krate: &ast::Crate) {
77:     let mut bccx = BorrowckCtxt {
78:         tcx: tcx,
--
123: fn borrowck_fn(this: &mut BorrowckCtxt,
124:                fk: &FnKind,
--
346: impl<'a> BorrowckCtxt<'a> {
347:     pub fn is_subregion_of(&self, r_sub: ty::Region, r_sup: ty::Region)
librustc/middle/borrowck/check_loans.rs:
36: struct CheckLoanCtxt<'a> {
37:     bccx: &'a BorrowckCtxt<'a>,
38:     dfcx_loans: &'a LoanDataFlow<'a>,
--
68: pub fn check_loans(bccx: &BorrowckCtxt,
69:                    dfcx_loans: &LoanDataFlow,
librustc/middle/borrowck/gather_loans/mod.rs:
60: struct GatherLoanCtxt<'a> {
61:     bccx: &'a BorrowckCtxt<'a>,
62:     move_data: move_data::MoveData,
--
355:         fn check_mutability(bccx: &BorrowckCtxt,
356:                             borrow_span: Span,
--
505: pub fn gather_loans_in_static_initializer(bccx: &mut BorrowckCtxt, expr: &ast::Expr) {
librustc/middle/borrowck/gather_loans/lifetime.rs:
49: struct GuaranteeLifetimeContext<'a> {
50:     bccx: &'a BorrowckCtxt<'a>,
librustc/middle/borrowck/gather_loans/restrictions.rs:
29: pub fn compute_restrictions(bccx: &BorrowckCtxt,
30:                             span: Span,
--
49: struct RestrictionsContext<'a> {
50:     bccx: &'a BorrowckCtxt<'a>,
51:     span: Span,
librustc/middle/borrowck/gather_loans/gather_moves.rs:
79: fn gather_move(bccx: &BorrowckCtxt,
80:                move_data: &MoveData,
--
125: fn check_and_get_illegal_move_origin(bccx: &BorrowckCtxt,
126:                                      cmt: &mc::cmt) -> Option<mc::cmt> {
librustc/middle/borrowck/gather_loans/move_error.rs:
36:     pub fn report_potential_errors(&self, bccx: &BorrowckCtxt) {
37:         report_move_errors(bccx, self.errors.borrow().deref())
--
79: fn report_move_errors(bccx: &BorrowckCtxt, errors: &Vec<MoveError>) {
80:     let grouped_errors = group_errors_with_same_origin(errors);
--
155: fn note_move_destination(bccx: &BorrowckCtxt,
156:                          move_to_span: codemap::Span,
librustc/middle/borrowck/gather_loans/gather_moves.rs:
110: pub fn gather_assignment(bccx: &BorrowckCtxt,
111:                          move_data: &MoveData,


librustc/middle/borrowck/mod.rs:51:1-51:1 -struct- definition:
pub struct LoanDataFlowOperator;
/// FIXME(pcwalton): Should just be #[deriving(Clone)], but that doesn't work
/// yet on unit structs.
references:- 4
62: pub type LoanDataFlow<'a> = DataFlowContext<'a, LoanDataFlowOperator>;
--
778: impl DataFlowOperator for LoanDataFlowOperator {
779:     #[inline]


librustc/middle/borrowck/mod.rs:315:16-315:16 -enum- definition:
pub enum bckerr_code {
    err_mutbl,
    err_out_of_scope(ty::Region, ty::Region), // superscope, subscope
references:- 5
314: // Errors that can occur
316: pub enum bckerr_code {
librustc/middle/borrowck/gather_loans/lifetime.rs:
198:     fn report_error(&self, code: bckerr_code) {
199:         self.bccx.report(BckError { cmt: self.cmt_original.clone(),
librustc/middle/borrowck/mod.rs:
329:     cmt: mc::cmt,
330:     code: bckerr_code
331: }


librustc/middle/borrowck/mod.rs:271:1-271:1 -struct- definition:
pub struct Restriction {
    loan_path: Rc<LoanPath>,
    set: RestrictionSet
references:- 6
librustc/middle/borrowck/gather_loans/restrictions.rs:
180:                 let lp = Rc::new(LpExtend(base_lp, mc, elem));
181:                 base_vec.push(Restriction {
182:                     loan_path: lp.clone(),
librustc/middle/borrowck/mod.rs:
802: impl Repr for Restriction {
803:     fn repr(&self, tcx: &ty::ctxt) -> ~str {
librustc/middle/borrowck/check_loans.rs:
127:                                      loan_path: &LoanPath,
128:                                      op: |&Loan, &Restriction| -> bool)
129:                                      -> bool {
librustc/middle/borrowck/gather_loans/restrictions.rs:
25:     Safe,
26:     SafeIf(Rc<LoanPath>, Vec<Restriction>)
27: }
librustc/middle/borrowck/mod.rs:
190:     kind: ty::BorrowKind,
191:     restrictions: Vec<Restriction>,
192:     gen_scope: ast::NodeId,


librustc/middle/borrowck/mod.rs:337:1-337:1 -enum- definition:
pub enum MovedValueUseKind {
    MovedInUse,
    MovedInCapture,
references:- 2
librustc/middle/borrowck/check_loans.rs:
364:                                   span: Span,
365:                                   use_kind: MovedValueUseKind,
366:                                   lp: &Rc<LoanPath>) {
librustc/middle/borrowck/mod.rs:
455:                                      use_span: Span,
456:                                      use_kind: MovedValueUseKind,
457:                                      lp: &LoanPath,


librustc/middle/borrowck/mod.rs:218:1-218:1 -fn- definition:
pub fn opt_loan_path(cmt: &mc::cmt) -> Option<Rc<LoanPath>> {
    //! Computes the `LoanPath` (if any) for a `cmt`.
    //! Note that this logic is somewhat duplicated in
references:- 13
577:             err_mutbl => {
578:                 let descr = match opt_loan_path(&err.cmt) {
579:                     None => format!("{} {}",
--
604:             err_out_of_scope(..) => {
605:                 let msg = match opt_loan_path(&err.cmt) {
606:                     None => format!("borrowed value"),
--
697:             err_borrowed_pointer_too_short(loan_scope, ptr_scope, _) => {
698:                 let descr = match opt_loan_path(&err.cmt) {
699:                     Some(lp) => format!("`{}`", self.loan_path_to_str(&*lp)),
librustc/middle/borrowck/check_loans.rs:
423:         // Otherwise, just a plain error.
424:         match opt_loan_path(&cmt) {
425:             Some(lp) => {
--
544:             let loan_path = match opt_loan_path(&cmt) {
545:                 Some(lp) => lp,
--
824:               debug!("path cmt={}", cmt.repr(this.tcx()));
825:               for lp in opt_loan_path(&cmt).iter() {
826:                   this.check_if_path_is_moved(expr.id, expr.span, MovedInUse, lp);
librustc/middle/borrowck/gather_loans/mod.rs:
136:         match opt_loan_path(&assignee_cmt) {
137:             Some(lp) => {
librustc/middle/borrowck/gather_loans/gather_moves.rs:
99:     match opt_loan_path(&move_info.cmt) {
100:         Some(loan_path) => {
librustc/middle/borrowck/mod.rs:
611:             err_borrowed_pointer_too_short(..) => {
612:                 let descr = match opt_loan_path(&err.cmt) {
613:                     Some(lp) => format!("`{}`", self.loan_path_to_str(&*lp)),


librustc/middle/borrowck/mod.rs:61:1-61:1 -NK_AS_STR_TODO- definition:
pub type LoanDataFlow<'a> = DataFlowContext<'a, LoanDataFlowOperator>;
impl<'a> Visitor<()> for BorrowckCtxt<'a> {
    fn visit_fn(&mut self, fk: &FnKind, fd: &FnDecl,
references:- 2
librustc/middle/borrowck/check_loans.rs:
37:     bccx: &'a BorrowckCtxt<'a>,
38:     dfcx_loans: &'a LoanDataFlow<'a>,
39:     move_data: move_data::FlowedMoveData<'a>,
--
68: pub fn check_loans(bccx: &BorrowckCtxt,
69:                    dfcx_loans: &LoanDataFlow,
70:                    move_data: move_data::FlowedMoveData,


librustc/middle/borrowck/mod.rs:277:16-277:16 -struct- definition:
pub struct RestrictionSet {
    bits: u32
}
references:- 34
librustc/middle/borrowck/gather_loans/mod.rs:
librustc/middle/borrowck/gather_loans/restrictions.rs:
librustc/middle/borrowck/mod.rs:


librustc/middle/borrowck/mod.rs:325:16-325:16 -struct- definition:
pub struct BckError {
    span: Span,
    cause: euv::LoanCause,
references:- 15
librustc/middle/borrowck/gather_loans/mod.rs:
379:                     if !cmt.mutbl.is_mutable() {
380:                         Err(bccx.report(BckError { span: borrow_span,
381:                                                    cause: cause,
librustc/middle/borrowck/gather_loans/lifetime.rs:
198:     fn report_error(&self, code: bckerr_code) {
199:         self.bccx.report(BckError { cmt: self.cmt_original.clone(),
200:                                     span: self.span,
librustc/middle/borrowck/gather_loans/restrictions.rs:
132:                     self.bccx.report(
133:                         BckError {
134:                             span: self.span,
--
147:                     self.bccx.report(
148:                         BckError {
149:                             span: self.span,
librustc/middle/borrowck/mod.rs:
324: // that caused it
326: pub struct BckError {
--
679:     pub fn note_and_explain_bckerr(&self, err: BckError) {
680:         let code = err.code;


librustc/middle/borrowck/mod.rs:176:16-176:16 -enum- definition:
pub enum PartialTotal {
    Partial,   // Loan affects some portion
    Total      // Loan affects entire path
references:- 3
177: pub enum PartialTotal {