mod.rs 31.2 KB
Newer Older
1
// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
2 3 4 5 6 7 8 9 10
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

N
Niko Matsakis 已提交
11
/*! See doc.rs for a thorough explanation of the borrow checker */
B
Brian Anderson 已提交
12

13
#[allow(non_camel_case_types)];
P
Patrick Walton 已提交
14

N
Niko Matsakis 已提交
15
use mc = middle::mem_categorization;
16
use middle::ty;
17
use middle::typeck;
18
use middle::moves;
N
Niko Matsakis 已提交
19 20
use middle::dataflow::DataFlowContext;
use middle::dataflow::DataFlowOperator;
21
use util::nodemap::NodeSet;
22
use util::ppaux::{note_and_explain_region, Repr, UserString};
23

24
use std::cell::{Cell, RefCell};
25
use collections::HashMap;
26 27
use std::ops::{BitOr, BitAnd};
use std::result::{Result};
28
use syntax::ast;
N
Niko Matsakis 已提交
29
use syntax::ast_map;
30
use syntax::ast_util;
31
use syntax::codemap::Span;
32
use syntax::parse::token;
33
use syntax::visit;
34 35
use syntax::visit::{Visitor, FnKind};
use syntax::ast::{FnDecl, Block, NodeId};
B
Brian Anderson 已提交
36

N
Niko Matsakis 已提交
37 38 39 40 41 42 43 44 45 46 47
macro_rules! if_ok(
    ($inp: expr) => (
        match $inp {
            Ok(v) => { v }
            Err(e) => { return Err(e); }
        }
    )
)

pub mod doc;

48
pub mod check_loans;
N
Niko Matsakis 已提交
49

50
pub mod gather_loans;
N
Niko Matsakis 已提交
51

52 53
pub mod move_data;

N
Niko Matsakis 已提交
54
pub struct LoanDataFlowOperator;
55

56
/// FIXME(pcwalton): Should just be #[deriving(Clone)], but that doesn't work
57 58 59 60 61 62 63
/// yet on unit structs.
impl Clone for LoanDataFlowOperator {
    fn clone(&self) -> LoanDataFlowOperator {
        LoanDataFlowOperator
    }
}

E
Eduard Burtescu 已提交
64
pub type LoanDataFlow<'a> = DataFlowContext<'a, LoanDataFlowOperator>;
B
Brian Anderson 已提交
65

E
Eduard Burtescu 已提交
66
impl<'a> Visitor<()> for BorrowckCtxt<'a> {
67
    fn visit_fn(&mut self, fk: &FnKind, fd: &FnDecl,
E
Eduard Burtescu 已提交
68
                b: &Block, s: Span, n: NodeId, _: ()) {
69
        borrowck_fn(self, fk, fd, b, s, n);
70
    }
F
Flavio Percoco 已提交
71 72 73 74

    fn visit_item(&mut self, item: &ast::Item, _: ()) {
        borrowck_item(self, item);
    }
75 76
}

E
Eduard Burtescu 已提交
77
pub fn check_crate(tcx: &ty::ctxt,
78
                   method_map: typeck::MethodMap,
79 80 81
                   moves_map: &NodeSet,
                   moved_variables_set: &NodeSet,
                   capture_map: &moves::CaptureMap,
82
                   krate: &ast::Crate)
83
                   -> root_map {
84
    let mut bccx = BorrowckCtxt {
85 86 87
        tcx: tcx,
        method_map: method_map,
        moves_map: moves_map,
N
Niko Matsakis 已提交
88
        moved_variables_set: moved_variables_set,
89 90
        capture_map: capture_map,
        root_map: root_map(),
91
        stats: @BorrowStats {
92 93 94 95
            loaned_paths_same: Cell::new(0),
            loaned_paths_imm: Cell::new(0),
            stable_paths: Cell::new(0),
            guaranteed_paths: Cell::new(0),
96 97
        }
    };
98
    let bccx = &mut bccx;
B
Brian Anderson 已提交
99

100
    visit::walk_crate(bccx, krate, ());
B
Brian Anderson 已提交
101 102

    if tcx.sess.borrowck_stats() {
103
        println!("--- borrowck stats ---");
104
        println!("paths requiring guarantees: {}",
105
                 bccx.stats.guaranteed_paths.get());
106
        println!("paths requiring loans     : {}",
107
                 make_stat(bccx, bccx.stats.loaned_paths_same.get()));
108
        println!("paths requiring imm loans : {}",
109
                 make_stat(bccx, bccx.stats.loaned_paths_imm.get()));
110
        println!("stable paths              : {}",
111
                 make_stat(bccx, bccx.stats.stable_paths.get()));
B
Brian Anderson 已提交
112 113
    }

114
    return bccx.root_map;
B
Brian Anderson 已提交
115

116
    fn make_stat(bccx: &mut BorrowckCtxt, stat: uint) -> ~str {
D
Daniel Micay 已提交
117
        let stat_f = stat as f64;
118
        let total = bccx.stats.guaranteed_paths.get() as f64;
D
Daniel Micay 已提交
119
        format!("{} ({:.0f}%)", stat  , stat_f * 100.0 / total)
B
Brian Anderson 已提交
120 121 122
    }
}

F
Flavio Percoco 已提交
123 124 125 126 127 128 129 130 131
fn borrowck_item(this: &mut BorrowckCtxt, item: &ast::Item) {
    // Gather loans for items. Note that we don't need
    // to check loans for single expressions. The check
    // loan step is intended for things that have a data
    // flow dependent conditions.
    match item.node {
        ast::ItemStatic(_, _, ex) => {
            gather_loans::gather_loans_in_static_initializer(this, ex);
        }
132 133 134
        _ => {
            visit::walk_item(this, item, ());
        }
F
Flavio Percoco 已提交
135 136 137
    }
}

138
fn borrowck_fn(this: &mut BorrowckCtxt,
139 140
               fk: &FnKind,
               decl: &ast::FnDecl,
E
Eduard Burtescu 已提交
141
               body: &ast::Block,
142
               sp: Span,
143
               id: ast::NodeId) {
144 145 146 147
    debug!("borrowck_fn(id={})", id);

    // Check the body of fn items.
    let (id_range, all_loans, move_data) =
F
Flavio Percoco 已提交
148
        gather_loans::gather_loans_in_fn(this, decl, body);
149 150 151 152 153
    let mut loan_dfcx =
        DataFlowContext::new(this.tcx,
                             this.method_map,
                             LoanDataFlowOperator,
                             id_range,
E
Eduard Burtescu 已提交
154 155
                             all_loans.len());
    for (loan_idx, loan) in all_loans.iter().enumerate() {
156 157 158 159 160 161 162 163 164 165 166 167
        loan_dfcx.add_gen(loan.gen_scope, loan_idx);
        loan_dfcx.add_kill(loan.kill_scope, loan_idx);
    }
    loan_dfcx.propagate(body);

    let flowed_moves = move_data::FlowedMoveData::new(move_data,
                                                      this.tcx,
                                                      this.method_map,
                                                      id_range,
                                                      body);

    check_loans::check_loans(this, &loan_dfcx, flowed_moves,
E
Eduard Burtescu 已提交
168
                             all_loans.as_slice(), body);
N
Niko Matsakis 已提交
169

170
    visit::walk_fn(this, fk, decl, body, sp, id, ());
N
Niko Matsakis 已提交
171 172
}

B
Brian Anderson 已提交
173 174 175
// ----------------------------------------------------------------------
// Type definitions

E
Eduard Burtescu 已提交
176 177
pub struct BorrowckCtxt<'a> {
    tcx: &'a ty::ctxt,
178
    method_map: typeck::MethodMap,
179 180 181
    moves_map: &'a NodeSet,
    moved_variables_set: &'a NodeSet,
    capture_map: &'a moves::CaptureMap,
182 183 184
    root_map: root_map,

    // Statistics:
185
    stats: @BorrowStats
186 187 188
}

pub struct BorrowStats {
189 190 191 192
    loaned_paths_same: Cell<uint>,
    loaned_paths_imm: Cell<uint>,
    stable_paths: Cell<uint>,
    guaranteed_paths: Cell<uint>,
B
Brian Anderson 已提交
193 194
}

195 196 197 198 199 200 201 202 203 204 205 206 207
// The keys to the root map combine the `id` of the deref expression
// with the number of types that it is *autodereferenced*. So, for
// example, imagine I have a variable `x: @@@T` and an expression
// `(*x).f`.  This will have 3 derefs, one explicit and then two
// autoderefs. These are the relevant `root_map_key` values that could
// appear:
//
//    {id:*x, derefs:0} --> roots `x` (type: @@@T, due to explicit deref)
//    {id:*x, derefs:1} --> roots `*x` (type: @@T, due to autoderef #1)
//    {id:*x, derefs:2} --> roots `**x` (type: @T, due to autoderef #2)
//
// Note that there is no entry with derefs:3---the type of that expression
// is T, which is not a box.
208
#[deriving(Eq, Hash)]
209
pub struct root_map_key {
210
    id: ast::NodeId,
211 212
    derefs: uint
}
B
Brian Anderson 已提交
213

N
Niko Matsakis 已提交
214
pub type BckResult<T> = Result<T, BckError>;
B
Brian Anderson 已提交
215

216
#[deriving(Eq)]
N
Niko Matsakis 已提交
217 218 219
pub enum PartialTotal {
    Partial,   // Loan affects some portion
    Total      // Loan affects entire path
B
Brian Anderson 已提交
220 221
}

N
Niko Matsakis 已提交
222 223 224 225 226 227 228 229
///////////////////////////////////////////////////////////////////////////
// Loans and loan paths

/// Record of a loan that was issued.
pub struct Loan {
    index: uint,
    loan_path: @LoanPath,
    cmt: mc::cmt,
230
    kind: ty::BorrowKind,
231
    restrictions: Vec<Restriction> ,
232 233
    gen_scope: ast::NodeId,
    kill_scope: ast::NodeId,
234
    span: Span,
235 236 237 238 239 240 241 242 243
    cause: LoanCause,
}

#[deriving(Eq)]
pub enum LoanCause {
    ClosureCapture(Span),
    AddrOf,
    AutoRef,
    RefBinding,
244 245
}

246
#[deriving(Eq, Hash)]
N
Niko Matsakis 已提交
247
pub enum LoanPath {
248
    LpVar(ast::NodeId),               // `x` in doc.rs
N
Niko Matsakis 已提交
249 250
    LpExtend(@LoanPath, mc::MutabilityCategory, LoanPathElem)
}
B
Brian Anderson 已提交
251

252
#[deriving(Eq, Hash)]
N
Niko Matsakis 已提交
253
pub enum LoanPathElem {
N
Niko Matsakis 已提交
254
    LpDeref(mc::PointerKind),    // `*LV` in doc.rs
255
    LpInterior(mc::InteriorKind) // `LV.f` in doc.rs
256 257
}

258
impl LoanPath {
259
    pub fn node_id(&self) -> ast::NodeId {
N
Niko Matsakis 已提交
260 261 262 263 264
        match *self {
            LpVar(local_id) => local_id,
            LpExtend(base, _, _) => base.node_id()
        }
    }
265
}
B
Brian Anderson 已提交
266

N
Niko Matsakis 已提交
267 268 269 270 271 272 273 274
pub fn opt_loan_path(cmt: mc::cmt) -> Option<@LoanPath> {
    //! Computes the `LoanPath` (if any) for a `cmt`.
    //! Note that this logic is somewhat duplicated in
    //! the method `compute()` found in `gather_loans::restrictions`,
    //! which allows it to share common loan path pieces as it
    //! traverses the CMT.

    match cmt.cat {
A
Alex Crichton 已提交
275
        mc::cat_rvalue(..) |
N
Niko Matsakis 已提交
276
        mc::cat_static_item |
N
Niko Matsakis 已提交
277
        mc::cat_copied_upvar(_) => {
N
Niko Matsakis 已提交
278 279 280
            None
        }

281 282 283
        mc::cat_local(id) |
        mc::cat_arg(id) |
        mc::cat_upvar(ty::UpvarId {var_id: id, ..}, _) => {
N
Niko Matsakis 已提交
284 285 286
            Some(@LpVar(id))
        }

N
Niko Matsakis 已提交
287
        mc::cat_deref(cmt_base, _, pk) => {
288
            opt_loan_path(cmt_base).map(|lp| {
N
Niko Matsakis 已提交
289
                @LpExtend(lp, cmt.mutbl, LpDeref(pk))
290
            })
N
Niko Matsakis 已提交
291 292 293
        }

        mc::cat_interior(cmt_base, ik) => {
294
            opt_loan_path(cmt_base).map(|lp| {
295
                @LpExtend(lp, cmt.mutbl, LpInterior(ik))
296
            })
N
Niko Matsakis 已提交
297 298
        }

299
        mc::cat_downcast(cmt_base) |
N
Niko Matsakis 已提交
300 301 302 303
        mc::cat_discr(cmt_base, _) => {
            opt_loan_path(cmt_base)
        }
    }
304
}
B
Brian Anderson 已提交
305

N
Niko Matsakis 已提交
306 307 308 309 310 311
///////////////////////////////////////////////////////////////////////////
// Restrictions
//
// Borrowing an lvalue often results in *restrictions* that limit what
// can be done with this lvalue during the scope of the loan:
//
312
// - `RESTR_MUTATE`: The lvalue may not be modified or `&mut` borrowed.
313
// - `RESTR_FREEZE`: `&` borrows of the lvalue are forbidden.
N
Niko Matsakis 已提交
314 315 316 317 318 319 320 321
//
// In addition, no value which is restricted may be moved. Therefore,
// restrictions are meaningful even if the RestrictionSet is empty,
// because the restriction against moves is implied.

pub struct Restriction {
    loan_path: @LoanPath,
    set: RestrictionSet
322 323
}

324
#[deriving(Eq)]
N
Niko Matsakis 已提交
325 326
pub struct RestrictionSet {
    bits: u32
B
Brian Anderson 已提交
327 328
}

329 330
pub static RESTR_EMPTY: RestrictionSet  = RestrictionSet {bits: 0b0000};
pub static RESTR_MUTATE: RestrictionSet = RestrictionSet {bits: 0b0001};
331
pub static RESTR_FREEZE: RestrictionSet = RestrictionSet {bits: 0b0010};
N
Niko Matsakis 已提交
332

333 334
impl RestrictionSet {
    pub fn intersects(&self, restr: RestrictionSet) -> bool {
N
Niko Matsakis 已提交
335
        (self.bits & restr.bits) != 0
336 337
    }

338
    pub fn contains_all(&self, restr: RestrictionSet) -> bool {
N
Niko Matsakis 已提交
339
        (self.bits & restr.bits) == restr.bits
340 341 342
    }
}

N
Niko Matsakis 已提交
343 344 345 346 347
impl BitOr<RestrictionSet,RestrictionSet> for RestrictionSet {
    fn bitor(&self, rhs: &RestrictionSet) -> RestrictionSet {
        RestrictionSet {bits: self.bits | rhs.bits}
    }
}
B
Brian Anderson 已提交
348

N
Niko Matsakis 已提交
349 350 351
impl BitAnd<RestrictionSet,RestrictionSet> for RestrictionSet {
    fn bitand(&self, rhs: &RestrictionSet) -> RestrictionSet {
        RestrictionSet {bits: self.bits & rhs.bits}
B
Brian Anderson 已提交
352 353 354
    }
}

355
impl Repr for RestrictionSet {
E
Eduard Burtescu 已提交
356
    fn repr(&self, _tcx: &ty::ctxt) -> ~str {
357 358 359 360
        format!("RestrictionSet(0x{:x})", self.bits as uint)
    }
}

N
Niko Matsakis 已提交
361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380
///////////////////////////////////////////////////////////////////////////
// Rooting of managed boxes
//
// When we borrow the interior of a managed box, it is sometimes
// necessary to *root* the box, meaning to stash a copy of the box
// somewhere that the garbage collector will find it. This ensures
// that the box is not collected for the lifetime of the borrow.
//
// As part of this rooting, we sometimes also freeze the box at
// runtime, meaning that we dynamically detect when the box is
// borrowed in incompatible ways.
//
// Both of these actions are driven through the `root_map`, which maps
// from a node to the dynamic rooting action that should be taken when
// that node executes. The node is identified through a
// `root_map_key`, which pairs a node-id and a deref count---the
// problem is that sometimes the box that needs to be rooted is only
// uncovered after a certain number of auto-derefs.

pub struct RootInfo {
381
    scope: ast::NodeId,
N
Niko Matsakis 已提交
382 383
}

384
pub type root_map = @RefCell<HashMap<root_map_key, RootInfo>>;
N
Niko Matsakis 已提交
385

386
pub fn root_map() -> root_map {
387
    return @RefCell::new(HashMap::new());
B
Brian Anderson 已提交
388 389
}

N
Niko Matsakis 已提交
390 391 392 393 394 395
///////////////////////////////////////////////////////////////////////////
// Errors

// Errors that can occur
#[deriving(Eq)]
pub enum bckerr_code {
396
    err_mutbl,
N
Niko Matsakis 已提交
397 398
    err_out_of_root_scope(ty::Region, ty::Region), // superscope, subscope
    err_out_of_scope(ty::Region, ty::Region), // superscope, subscope
399 400
    err_borrowed_pointer_too_short(
        ty::Region, ty::Region, RestrictionSet), // loan, ptr
N
Niko Matsakis 已提交
401 402 403 404 405 406
}

// Combination of an error code and the categorization of the expression
// that caused it
#[deriving(Eq)]
pub struct BckError {
407
    span: Span,
408
    cause: LoanCause,
N
Niko Matsakis 已提交
409 410 411 412 413 414
    cmt: mc::cmt,
    code: bckerr_code
}

pub enum AliasableViolationKind {
    MutabilityViolation,
415
    BorrowViolation(LoanCause)
N
Niko Matsakis 已提交
416 417
}

418 419 420 421 422
pub enum MovedValueUseKind {
    MovedInUse,
    MovedInCapture,
}

N
Niko Matsakis 已提交
423
///////////////////////////////////////////////////////////////////////////
B
Brian Anderson 已提交
424 425
// Misc

E
Eduard Burtescu 已提交
426
impl<'a> BorrowckCtxt<'a> {
427 428
    pub fn is_subregion_of(&self, r_sub: ty::Region, r_sup: ty::Region)
                           -> bool {
429
        self.tcx.region_maps.is_subregion_of(r_sub, r_sup)
B
Brian Anderson 已提交
430 431
    }

432
    pub fn is_subscope_of(&self, r_sub: ast::NodeId, r_sup: ast::NodeId)
433
                          -> bool {
N
Niko Matsakis 已提交
434 435 436
        self.tcx.region_maps.is_subscope_of(r_sub, r_sup)
    }

437
    pub fn is_move(&self, id: ast::NodeId) -> bool {
438
        self.moves_map.contains(&id)
439 440
    }

E
Eduard Burtescu 已提交
441
    pub fn mc(&self) -> mc::MemCategorizationContext<TcxTyper<'a>> {
442 443 444 445 446 447 448 449
        mc::MemCategorizationContext {
            typer: TcxTyper {
                tcx: self.tcx,
                method_map: self.method_map
            }
        }
    }

E
Eduard Burtescu 已提交
450
    pub fn cat_expr(&self, expr: &ast::Expr) -> mc::cmt {
451 452 453 454 455 456
        match self.mc().cat_expr(expr) {
            Ok(c) => c,
            Err(()) => {
                self.tcx.sess.span_bug(expr.span, "error in mem categorization");
            }
        }
B
Brian Anderson 已提交
457 458
    }

E
Eduard Burtescu 已提交
459
    pub fn cat_expr_unadjusted(&self, expr: &ast::Expr) -> mc::cmt {
460 461 462 463 464 465
        match self.mc().cat_expr_unadjusted(expr) {
            Ok(c) => c,
            Err(()) => {
                self.tcx.sess.span_bug(expr.span, "error in mem categorization");
            }
        }
B
Brian Anderson 已提交
466 467
    }

468
    pub fn cat_expr_autoderefd(&self,
E
Eduard Burtescu 已提交
469 470
                               expr: &ast::Expr,
                               adj: &ty::AutoAdjustment)
471
                               -> mc::cmt {
472
        let r = match *adj {
473
            ty::AutoAddEnv(..) | ty::AutoObject(..) => {
474
                // no autoderefs
475
                self.mc().cat_expr_unadjusted(expr)
476 477 478 479
            }

            ty::AutoDerefRef(
                ty::AutoDerefRef {
A
Alex Crichton 已提交
480
                    autoderefs: autoderefs, ..}) => {
481 482 483 484 485 486 487 488 489
                self.mc().cat_expr_autoderefd(expr, autoderefs)
            }
        };

        match r {
            Ok(c) => c,
            Err(()) => {
                self.tcx.sess.span_bug(expr.span,
                                       "error in mem categorization");
490 491
            }
        }
B
Brian Anderson 已提交
492 493
    }

494
    pub fn cat_def(&self,
495
                   id: ast::NodeId,
496
                   span: Span,
497
                   ty: ty::t,
498
                   def: ast::Def)
499
                   -> mc::cmt {
500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516
        match self.mc().cat_def(id, span, ty, def) {
            Ok(c) => c,
            Err(()) => {
                self.tcx.sess.span_bug(span, "error in mem categorization");
            }
        }
    }

    pub fn cat_captured_var(&self,
                            id: ast::NodeId,
                            span: Span,
                            captured_var: &moves::CaptureVar) -> mc::cmt {
        // Create the cmt for the variable being borrowed, from the
        // caller's perspective
        let var_id = ast_util::def_id_of_def(captured_var.def).node;
        let var_ty = ty::node_id_to_type(self.tcx, var_id);
        self.cat_def(id, span, var_ty, captured_var.def)
B
Brian Anderson 已提交
517 518
    }

519
    pub fn cat_discr(&self, cmt: mc::cmt, match_id: ast::NodeId) -> mc::cmt {
N
Niko Matsakis 已提交
520 521 522
        @mc::cmt_ {cat:mc::cat_discr(cmt, match_id),
                   mutbl:cmt.mutbl.inherit(),
                   ..*cmt}
B
Brian Anderson 已提交
523 524
    }

525 526
    pub fn cat_pattern(&self,
                       cmt: mc::cmt,
527
                       pat: @ast::Pat,
E
Eduard Burtescu 已提交
528
                       op: |mc::cmt, &ast::Pat|) {
529 530
        let r = self.mc().cat_pattern(cmt, pat, |_,x,y| op(x,y));
        assert!(r.is_ok());
B
Brian Anderson 已提交
531 532
    }

533
    pub fn report(&self, err: BckError) {
B
Brian Anderson 已提交
534
        self.span_err(
N
Niko Matsakis 已提交
535 536
            err.span,
            self.bckerr_to_str(err));
B
Brian Anderson 已提交
537 538 539
        self.note_and_explain_bckerr(err);
    }

540
    pub fn report_use_of_moved_value(&self,
541
                                     use_span: Span,
542
                                     use_kind: MovedValueUseKind,
543
                                     lp: &LoanPath,
544 545
                                     move: &move_data::Move,
                                     moved_lp: @LoanPath) {
546 547 548 549 550 551 552 553 554
        let verb = match use_kind {
            MovedInUse => "use",
            MovedInCapture => "capture",
        };

        match move.kind {
            move_data::Declared => {
                self.tcx.sess.span_err(
                    use_span,
555
                    format!("{} of possibly uninitialized variable: `{}`",
556 557 558 559 560 561 562
                         verb,
                         self.loan_path_to_str(lp)));
            }
            _ => {
                let partially = if lp == moved_lp {""} else {"partially "};
                self.tcx.sess.span_err(
                    use_span,
A
Alex Crichton 已提交
563
                    format!("{} of {}moved value: `{}`",
564 565 566 567 568 569 570 571 572
                         verb,
                         partially,
                         self.loan_path_to_str(lp)));
            }
        }

        match move.kind {
            move_data::Declared => {}

E
Eduard Burtescu 已提交
573
            move_data::MoveExpr => {
574
                let (expr_ty, expr_span) = match self.tcx.map.find(move.id) {
575
                    Some(ast_map::NodeExpr(expr)) => {
576 577
                        (ty::expr_ty_adjusted(self.tcx, expr,
                                              self.method_map.borrow().get()), expr.span)
E
Eduard Burtescu 已提交
578 579 580 581
                    }
                    r => self.tcx.sess.bug(format!("MoveExpr({:?}) maps to {:?}, not Expr",
                                                   move.id, r))
                };
582 583
                let suggestion = move_suggestion(self.tcx, expr_ty,
                        "moved by default (use `copy` to override)");
584
                self.tcx.sess.span_note(
E
Eduard Burtescu 已提交
585
                    expr_span,
A
Alex Crichton 已提交
586
                    format!("`{}` moved here because it has type `{}`, which is {}",
587
                         self.loan_path_to_str(moved_lp),
588
                         expr_ty.user_string(self.tcx), suggestion));
589 590
            }

E
Eduard Burtescu 已提交
591 592
            move_data::MovePat => {
                let pat_ty = ty::node_id_to_type(self.tcx, move.id);
593
                self.tcx.sess.span_note(self.tcx.map.span(move.id),
A
Alex Crichton 已提交
594
                    format!("`{}` moved here because it has type `{}`, \
595 596 597 598 599
                          which is moved by default (use `ref` to override)",
                         self.loan_path_to_str(moved_lp),
                         pat_ty.user_string(self.tcx)));
            }

E
Eduard Burtescu 已提交
600
            move_data::Captured => {
601
                let (expr_ty, expr_span) = match self.tcx.map.find(move.id) {
602
                    Some(ast_map::NodeExpr(expr)) => {
603 604
                        (ty::expr_ty_adjusted(self.tcx, expr,
                                              self.method_map.borrow().get()), expr.span)
E
Eduard Burtescu 已提交
605 606 607 608
                    }
                    r => self.tcx.sess.bug(format!("Captured({:?}) maps to {:?}, not Expr",
                                                   move.id, r))
                };
609 610 611
                let suggestion = move_suggestion(self.tcx, expr_ty,
                        "moved by default (make a copy and \
                         capture that instead to override)");
612
                self.tcx.sess.span_note(
E
Eduard Burtescu 已提交
613
                    expr_span,
A
Alex Crichton 已提交
614 615
                    format!("`{}` moved into closure environment here because it \
                          has type `{}`, which is {}",
616 617 618 619 620
                         self.loan_path_to_str(moved_lp),
                         expr_ty.user_string(self.tcx), suggestion));
            }
        }

E
Eduard Burtescu 已提交
621
        fn move_suggestion(tcx: &ty::ctxt, ty: ty::t, default_msg: &'static str)
622 623 624 625 626
                          -> &'static str {
            match ty::get(ty).sty {
                ty::ty_closure(ref cty) if cty.sigil == ast::BorrowedSigil =>
                    "a non-copyable stack closure (capture it in a new closure, \
                     e.g. `|x| f(x)`, to override)",
627
                _ if ty::type_moves_by_default(tcx, ty) =>
628 629
                    "non-copyable (perhaps you meant to use clone()?)",
                _ => default_msg,
630 631 632 633
            }
        }
    }

634
    pub fn report_reassigned_immutable_variable(&self,
635
                                                span: Span,
636
                                                lp: &LoanPath,
637 638
                                                assign:
                                                &move_data::Assignment) {
639 640
        self.tcx.sess.span_err(
            span,
A
Alex Crichton 已提交
641
            format!("re-assignment of immutable variable `{}`",
642 643 644
                 self.loan_path_to_str(lp)));
        self.tcx.sess.span_note(
            assign.span,
A
Alex Crichton 已提交
645
            format!("prior assignment occurs here"));
646 647
    }

648
    pub fn span_err(&self, s: Span, m: &str) {
B
Brian Anderson 已提交
649 650 651
        self.tcx.sess.span_err(s, m);
    }

652
    pub fn span_note(&self, s: Span, m: &str) {
B
Brian Anderson 已提交
653 654 655
        self.tcx.sess.span_note(s, m);
    }

656 657 658 659
    pub fn span_end_note(&self, s: Span, m: &str) {
        self.tcx.sess.span_end_note(s, m);
    }

660
    pub fn bckerr_to_str(&self, err: BckError) -> ~str {
B
Brian Anderson 已提交
661
        match err.code {
662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680
            err_mutbl => {
                let descr = match opt_loan_path(err.cmt) {
                    None => format!("{} {}",
                                    err.cmt.mutbl.to_user_str(),
                                    self.cmt_to_str(err.cmt)),
                    Some(lp) => format!("{} {} `{}`",
                                        err.cmt.mutbl.to_user_str(),
                                        self.cmt_to_str(err.cmt),
                                        self.loan_path_to_str(lp)),
                };

                match err.cause {
                    ClosureCapture(_) => {
                        format!("closure cannot assign to {}", descr)
                    }
                    AddrOf | RefBinding | AutoRef => {
                        format!("cannot borrow {} as mutable", descr)
                    }
                }
B
Brian Anderson 已提交
681
            }
A
Alex Crichton 已提交
682
            err_out_of_root_scope(..) => {
A
Alex Crichton 已提交
683
                format!("cannot root managed value long enough")
B
Brian Anderson 已提交
684
            }
A
Alex Crichton 已提交
685
            err_out_of_scope(..) => {
686 687 688 689 690
                let msg = match opt_loan_path(err.cmt) {
                    None => format!("borrowed value"),
                    Some(lp) => format!("`{}`", self.loan_path_to_str(lp)),
                };
                format!("{} does not live long enough", msg)
B
Brian Anderson 已提交
691
            }
N
Niko Matsakis 已提交
692
            err_borrowed_pointer_too_short(..) => {
693 694
                let descr = match opt_loan_path(err.cmt) {
                    Some(lp) => format!("`{}`", self.loan_path_to_str(lp)),
695
                    None => self.cmt_to_str(err.cmt),
696 697
                };

698 699 700
                format!("lifetime of {} is too short to guarantee \
                        its contents can be safely reborrowed",
                        descr)
701
            }
N
Niko Matsakis 已提交
702 703 704
        }
    }

705
    pub fn report_aliasability_violation(&self,
706
                                         span: Span,
707 708
                                         kind: AliasableViolationKind,
                                         cause: mc::AliasableReason) {
N
Niko Matsakis 已提交
709
        let prefix = match kind {
710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727
            MutabilityViolation => {
                "cannot assign to data"
            }
            BorrowViolation(ClosureCapture(_)) => {
                // I don't think we can get aliasability violations
                // with closure captures, so no need to come up with a
                // good error message. The reason this cannot happen
                // is because we only capture local variables in
                // closures, and those are never aliasable.
                self.tcx.sess.span_bug(
                    span,
                    "aliasability violation with closure");
            }
            BorrowViolation(AddrOf) |
            BorrowViolation(AutoRef) |
            BorrowViolation(RefBinding) => {
                "cannot borrow data mutably"
            }
N
Niko Matsakis 已提交
728 729 730 731 732 733
        };

        match cause {
            mc::AliasableOther => {
                self.tcx.sess.span_err(
                    span,
A
Alex Crichton 已提交
734
                    format!("{} in an aliasable location", prefix));
B
Brian Anderson 已提交
735
            }
736 737
            mc::AliasableStatic(..) |
            mc::AliasableStaticMut(..) => {
738 739 740 741
                self.tcx.sess.span_err(
                    span,
                    format!("{} in a static location", prefix));
            }
742
            mc::AliasableManaged => {
743 744 745
                self.tcx.sess.span_err(
                    span,
                    format!("{} in a `@` pointer", prefix));
N
Niko Matsakis 已提交
746
            }
747
            mc::AliasableBorrowed => {
N
Niko Matsakis 已提交
748 749
                self.tcx.sess.span_err(
                    span,
750
                    format!("{} in a `&` reference", prefix));
B
Brian Anderson 已提交
751 752 753 754
            }
        }
    }

755
    pub fn note_and_explain_bckerr(&self, err: BckError) {
B
Brian Anderson 已提交
756 757
        let code = err.code;
        match code {
758
            err_mutbl(..) => { }
B
Brian Anderson 已提交
759 760 761 762

            err_out_of_root_scope(super_scope, sub_scope) => {
                note_and_explain_region(
                    self.tcx,
763
                    "managed value would have to be rooted for ",
B
Brian Anderson 已提交
764
                    sub_scope,
765
                    "...");
B
Brian Anderson 已提交
766 767
                note_and_explain_region(
                    self.tcx,
768
                    "...but can only be rooted for ",
B
Brian Anderson 已提交
769
                    super_scope,
770
                    "");
B
Brian Anderson 已提交
771 772 773 774 775
            }

            err_out_of_scope(super_scope, sub_scope) => {
                note_and_explain_region(
                    self.tcx,
776
                    "reference must be valid for ",
B
Brian Anderson 已提交
777
                    sub_scope,
778
                    "...");
B
Brian Anderson 已提交
779 780
                note_and_explain_region(
                    self.tcx,
781
                    "...but borrowed value is only valid for ",
B
Brian Anderson 已提交
782
                    super_scope,
783
                    "");
784 785
            }

786
            err_borrowed_pointer_too_short(loan_scope, ptr_scope, _) => {
787 788
                let descr = match opt_loan_path(err.cmt) {
                    Some(lp) => format!("`{}`", self.loan_path_to_str(lp)),
789
                    None => self.cmt_to_str(err.cmt),
790 791 792 793 794 795 796 797 798 799 800 801
                };
                note_and_explain_region(
                    self.tcx,
                    format!("{} would have to be valid for ", descr),
                    loan_scope,
                    "...");
                note_and_explain_region(
                    self.tcx,
                    format!("...but {} is only valid for ", descr),
                    ptr_scope,
                    "");
            }
B
Brian Anderson 已提交
802 803 804
        }
    }

805 806 807
    pub fn append_loan_path_to_str(&self,
                                   loan_path: &LoanPath,
                                   out: &mut ~str) {
N
Niko Matsakis 已提交
808 809
        match *loan_path {
            LpVar(id) => {
810
                out.push_str(ty::local_var_name_str(self.tcx, id).get());
N
Niko Matsakis 已提交
811
            }
B
Brian Anderson 已提交
812

813
            LpExtend(lp_base, _, LpInterior(mc::InteriorField(fname))) => {
814
                self.append_autoderefd_loan_path_to_str(lp_base, out);
815
                match fname {
816
                    mc::NamedField(fname) => {
817
                        out.push_char('.');
818
                        out.push_str(token::get_name(fname).get());
819 820
                    }
                    mc::PositionalField(idx) => {
821 822
                        out.push_char('#'); // invent a notation here
                        out.push_str(idx.to_str());
823 824
                    }
                }
N
Niko Matsakis 已提交
825 826
            }

827
            LpExtend(lp_base, _, LpInterior(mc::InteriorElement(_))) => {
828 829
                self.append_autoderefd_loan_path_to_str(lp_base, out);
                out.push_str("[..]");
N
Niko Matsakis 已提交
830 831
            }

N
Niko Matsakis 已提交
832
            LpExtend(lp_base, _, LpDeref(_)) => {
833
                out.push_char('*');
N
Niko Matsakis 已提交
834 835 836 837 838
                self.append_loan_path_to_str(lp_base, out);
            }
        }
    }

839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855
    pub fn append_autoderefd_loan_path_to_str(&self,
                                              loan_path: &LoanPath,
                                              out: &mut ~str) {
        match *loan_path {
            LpExtend(lp_base, _, LpDeref(_)) => {
                // For a path like `(*x).f` or `(*x)[3]`, autoderef
                // rules would normally allow users to omit the `*x`.
                // So just serialize such paths to `x.f` or x[3]` respectively.
                self.append_autoderefd_loan_path_to_str(lp_base, out)
            }

            LpVar(..) | LpExtend(_, _, LpInterior(..)) => {
                self.append_loan_path_to_str(loan_path, out)
            }
        }
    }

856
    pub fn loan_path_to_str(&self, loan_path: &LoanPath) -> ~str {
N
Niko Matsakis 已提交
857 858 859
        let mut result = ~"";
        self.append_loan_path_to_str(loan_path, &mut result);
        result
B
Brian Anderson 已提交
860 861
    }

862
    pub fn cmt_to_str(&self, cmt: mc::cmt) -> ~str {
863
        self.mc().cmt_to_str(cmt)
B
Brian Anderson 已提交
864 865
    }

866 867
    pub fn mut_to_str(&self, mutbl: ast::Mutability) -> ~str {
        self.mc().mut_to_str(mutbl)
B
Brian Anderson 已提交
868 869
    }

870
    pub fn mut_to_keyword(&self, mutbl: ast::Mutability) -> &'static str {
N
Niko Matsakis 已提交
871
        match mutbl {
872 873
            ast::MutImmutable => "",
            ast::MutMutable => "mut",
874 875
        }
    }
N
Niko Matsakis 已提交
876 877 878
}

impl DataFlowOperator for LoanDataFlowOperator {
879
    #[inline]
N
Niko Matsakis 已提交
880 881 882 883
    fn initial_value(&self) -> bool {
        false // no loans in scope by default
    }

884
    #[inline]
N
Niko Matsakis 已提交
885 886 887 888
    fn join(&self, succ: uint, pred: uint) -> uint {
        succ | pred // loans from both preds are in scope
    }
}
889

N
Niko Matsakis 已提交
890
impl Repr for Loan {
E
Eduard Burtescu 已提交
891
    fn repr(&self, tcx: &ty::ctxt) -> ~str {
A
Alex Crichton 已提交
892
        format!("Loan_{:?}({}, {:?}, {:?}-{:?}, {})",
N
Niko Matsakis 已提交
893 894
             self.index,
             self.loan_path.repr(tcx),
895
             self.kind,
N
Niko Matsakis 已提交
896 897 898
             self.gen_scope,
             self.kill_scope,
             self.restrictions.repr(tcx))
B
Brian Anderson 已提交
899 900 901
    }
}

N
Niko Matsakis 已提交
902
impl Repr for Restriction {
E
Eduard Burtescu 已提交
903
    fn repr(&self, tcx: &ty::ctxt) -> ~str {
A
Alex Crichton 已提交
904
        format!("Restriction({}, {:x})",
N
Niko Matsakis 已提交
905 906 907 908 909 910
             self.loan_path.repr(tcx),
             self.set.bits as uint)
    }
}

impl Repr for LoanPath {
E
Eduard Burtescu 已提交
911
    fn repr(&self, tcx: &ty::ctxt) -> ~str {
N
Niko Matsakis 已提交
912 913
        match self {
            &LpVar(id) => {
914
                format!("$({})", tcx.map.node_to_str(id))
N
Niko Matsakis 已提交
915 916
            }

N
Niko Matsakis 已提交
917
            &LpExtend(lp, _, LpDeref(_)) => {
A
Alex Crichton 已提交
918
                format!("{}.*", lp.repr(tcx))
N
Niko Matsakis 已提交
919 920 921
            }

            &LpExtend(lp, _, LpInterior(ref interior)) => {
A
Alex Crichton 已提交
922
                format!("{}.{}", lp.repr(tcx), interior.repr(tcx))
N
Niko Matsakis 已提交
923 924
            }
        }
B
Brian Anderson 已提交
925 926
    }
}
927 928 929

///////////////////////////////////////////////////////////////////////////

E
Eduard Burtescu 已提交
930 931
pub struct TcxTyper<'a> {
    tcx: &'a ty::ctxt,
932
    method_map: typeck::MethodMap,
933 934
}

E
Eduard Burtescu 已提交
935 936
impl<'a> mc::Typer for TcxTyper<'a> {
    fn tcx<'a>(&'a self) -> &'a ty::ctxt {
937 938 939 940 941 942 943
        self.tcx
    }

    fn node_ty(&mut self, id: ast::NodeId) -> mc::McResult<ty::t> {
        Ok(ty::node_id_to_type(self.tcx, id))
    }

E
Eduard Burtescu 已提交
944
    fn node_method_ty(&self, method_call: typeck::MethodCall) -> Option<ty::t> {
945
        self.method_map.borrow().get().find(&method_call).map(|method| method.ty)
946 947
    }

948 949 950 951 952 953
    fn adjustment(&mut self, id: ast::NodeId) -> Option<@ty::AutoAdjustment> {
        let adjustments = self.tcx.adjustments.borrow();
        adjustments.get().find_copy(&id)
    }

    fn is_method_call(&mut self, id: ast::NodeId) -> bool {
954
        self.method_map.borrow().get().contains_key(&typeck::MethodCall::expr(id))
955 956 957 958 959 960 961 962 963 964 965
    }

    fn temporary_scope(&mut self, id: ast::NodeId) -> Option<ast::NodeId> {
        self.tcx.region_maps.temporary_scope(id)
    }

    fn upvar_borrow(&mut self, id: ty::UpvarId) -> ty::UpvarBorrow {
        let upvar_borrow_map = self.tcx.upvar_borrow_map.borrow();
        upvar_borrow_map.get().get_copy(&id)
    }
}