mod.rs 30.8 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.
D
Daniel Micay 已提交
208
#[deriving(Eq, TotalEq, Hash)]
209
pub struct root_map_key {
210 211
    pub id: ast::NodeId,
    pub derefs: uint
212
}
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
}

D
Daniel Micay 已提交
246
#[deriving(Eq, TotalEq, 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

D
Daniel Micay 已提交
252
#[deriving(Eq, TotalEq, 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
#[allow(dead_code)] // potentially useful
330 331
pub static RESTR_EMPTY: RestrictionSet  = RestrictionSet {bits: 0b0000};
pub static RESTR_MUTATE: RestrictionSet = RestrictionSet {bits: 0b0001};
332
pub static RESTR_FREEZE: RestrictionSet = RestrictionSet {bits: 0b0010};
N
Niko Matsakis 已提交
333

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

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

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

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

N
Niko Matsakis 已提交
358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377
///////////////////////////////////////////////////////////////////////////
// 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 {
378
    pub scope: ast::NodeId,
N
Niko Matsakis 已提交
379 380
}

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

383
pub fn root_map() -> root_map {
384
    return @RefCell::new(HashMap::new());
B
Brian Anderson 已提交
385 386
}

N
Niko Matsakis 已提交
387 388 389 390 391 392
///////////////////////////////////////////////////////////////////////////
// Errors

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

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

pub enum AliasableViolationKind {
    MutabilityViolation,
412
    BorrowViolation(LoanCause)
N
Niko Matsakis 已提交
413 414
}

415 416 417 418 419
pub enum MovedValueUseKind {
    MovedInUse,
    MovedInCapture,
}

N
Niko Matsakis 已提交
420
///////////////////////////////////////////////////////////////////////////
B
Brian Anderson 已提交
421 422
// Misc

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

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

434
    pub fn is_move(&self, id: ast::NodeId) -> bool {
435
        self.moves_map.contains(&id)
436 437
    }

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

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

E
Eduard Burtescu 已提交
456
    pub fn cat_expr_unadjusted(&self, expr: &ast::Expr) -> mc::cmt {
457 458 459 460 461 462
        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 已提交
463 464
    }

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

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

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

491
    pub fn cat_def(&self,
492
                   id: ast::NodeId,
493
                   span: Span,
494
                   ty: ty::t,
495
                   def: ast::Def)
496
                   -> mc::cmt {
497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513
        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 已提交
514 515
    }

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

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

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

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

        match move.kind {
            move_data::Declared => {
                self.tcx.sess.span_err(
                    use_span,
552
                    format!("{} of possibly uninitialized variable: `{}`",
553 554 555 556 557 558 559
                         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 已提交
560
                    format!("{} of {}moved value: `{}`",
561 562 563 564 565 566 567 568 569
                         verb,
                         partially,
                         self.loan_path_to_str(lp)));
            }
        }

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

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

E
Eduard Burtescu 已提交
588 589
            move_data::MovePat => {
                let pat_ty = ty::node_id_to_type(self.tcx, move.id);
590
                self.tcx.sess.span_note(self.tcx.map.span(move.id),
A
Alex Crichton 已提交
591
                    format!("`{}` moved here because it has type `{}`, \
592 593 594 595 596
                          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 已提交
597
            move_data::Captured => {
598
                let (expr_ty, expr_span) = match self.tcx.map.find(move.id) {
599
                    Some(ast_map::NodeExpr(expr)) => {
600
                        (ty::expr_ty_adjusted(self.tcx, expr,
601
                                              &*self.method_map.borrow()), expr.span)
E
Eduard Burtescu 已提交
602 603 604 605
                    }
                    r => self.tcx.sess.bug(format!("Captured({:?}) maps to {:?}, not Expr",
                                                   move.id, r))
                };
606 607 608
                let suggestion = move_suggestion(self.tcx, expr_ty,
                        "moved by default (make a copy and \
                         capture that instead to override)");
609
                self.tcx.sess.span_note(
E
Eduard Burtescu 已提交
610
                    expr_span,
A
Alex Crichton 已提交
611 612
                    format!("`{}` moved into closure environment here because it \
                          has type `{}`, which is {}",
613 614 615 616 617
                         self.loan_path_to_str(moved_lp),
                         expr_ty.user_string(self.tcx), suggestion));
            }
        }

E
Eduard Burtescu 已提交
618
        fn move_suggestion(tcx: &ty::ctxt, ty: ty::t, default_msg: &'static str)
619 620 621 622 623
                          -> &'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)",
624
                _ if ty::type_moves_by_default(tcx, ty) =>
625 626
                    "non-copyable (perhaps you meant to use clone()?)",
                _ => default_msg,
627 628 629 630
            }
        }
    }

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

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

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

653 654 655 656
    pub fn span_end_note(&self, s: Span, m: &str) {
        self.tcx.sess.span_end_note(s, m);
    }

657
    pub fn bckerr_to_str(&self, err: BckError) -> ~str {
B
Brian Anderson 已提交
658
        match err.code {
659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677
            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 已提交
678
            }
A
Alex Crichton 已提交
679
            err_out_of_root_scope(..) => {
A
Alex Crichton 已提交
680
                format!("cannot root managed value long enough")
B
Brian Anderson 已提交
681
            }
A
Alex Crichton 已提交
682
            err_out_of_scope(..) => {
683 684 685 686 687
                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 已提交
688
            }
N
Niko Matsakis 已提交
689
            err_borrowed_pointer_too_short(..) => {
690 691
                let descr = match opt_loan_path(err.cmt) {
                    Some(lp) => format!("`{}`", self.loan_path_to_str(lp)),
692
                    None => self.cmt_to_str(err.cmt),
693 694
                };

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

702
    pub fn report_aliasability_violation(&self,
703
                                         span: Span,
704 705
                                         kind: AliasableViolationKind,
                                         cause: mc::AliasableReason) {
N
Niko Matsakis 已提交
706
        let prefix = match kind {
707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724
            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 已提交
725 726 727 728 729 730
        };

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

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

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

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

783
            err_borrowed_pointer_too_short(loan_scope, ptr_scope, _) => {
784 785
                let descr = match opt_loan_path(err.cmt) {
                    Some(lp) => format!("`{}`", self.loan_path_to_str(lp)),
786
                    None => self.cmt_to_str(err.cmt),
787 788 789 790 791 792 793 794 795 796 797 798
                };
                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 已提交
799 800 801
        }
    }

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

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

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

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

836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852
    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)
            }
        }
    }

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

859
    pub fn cmt_to_str(&self, cmt: mc::cmt) -> ~str {
860
        self.mc().cmt_to_str(cmt)
B
Brian Anderson 已提交
861
    }
N
Niko Matsakis 已提交
862 863 864
}

impl DataFlowOperator for LoanDataFlowOperator {
865
    #[inline]
N
Niko Matsakis 已提交
866 867 868 869
    fn initial_value(&self) -> bool {
        false // no loans in scope by default
    }

870
    #[inline]
N
Niko Matsakis 已提交
871 872 873 874
    fn join(&self, succ: uint, pred: uint) -> uint {
        succ | pred // loans from both preds are in scope
    }
}
875

N
Niko Matsakis 已提交
876
impl Repr for Loan {
E
Eduard Burtescu 已提交
877
    fn repr(&self, tcx: &ty::ctxt) -> ~str {
A
Alex Crichton 已提交
878
        format!("Loan_{:?}({}, {:?}, {:?}-{:?}, {})",
N
Niko Matsakis 已提交
879 880
             self.index,
             self.loan_path.repr(tcx),
881
             self.kind,
N
Niko Matsakis 已提交
882 883 884
             self.gen_scope,
             self.kill_scope,
             self.restrictions.repr(tcx))
B
Brian Anderson 已提交
885 886 887
    }
}

N
Niko Matsakis 已提交
888
impl Repr for Restriction {
E
Eduard Burtescu 已提交
889
    fn repr(&self, tcx: &ty::ctxt) -> ~str {
A
Alex Crichton 已提交
890
        format!("Restriction({}, {:x})",
N
Niko Matsakis 已提交
891 892 893 894 895 896
             self.loan_path.repr(tcx),
             self.set.bits as uint)
    }
}

impl Repr for LoanPath {
E
Eduard Burtescu 已提交
897
    fn repr(&self, tcx: &ty::ctxt) -> ~str {
N
Niko Matsakis 已提交
898 899
        match self {
            &LpVar(id) => {
900
                format!("$({})", tcx.map.node_to_str(id))
N
Niko Matsakis 已提交
901 902
            }

N
Niko Matsakis 已提交
903
            &LpExtend(lp, _, LpDeref(_)) => {
A
Alex Crichton 已提交
904
                format!("{}.*", lp.repr(tcx))
N
Niko Matsakis 已提交
905 906 907
            }

            &LpExtend(lp, _, LpInterior(ref interior)) => {
A
Alex Crichton 已提交
908
                format!("{}.{}", lp.repr(tcx), interior.repr(tcx))
N
Niko Matsakis 已提交
909 910
            }
        }
B
Brian Anderson 已提交
911 912
    }
}
913 914 915

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

E
Eduard Burtescu 已提交
916 917
pub struct TcxTyper<'a> {
    tcx: &'a ty::ctxt,
918
    method_map: typeck::MethodMap,
919 920
}

E
Eduard Burtescu 已提交
921 922
impl<'a> mc::Typer for TcxTyper<'a> {
    fn tcx<'a>(&'a self) -> &'a ty::ctxt {
923 924 925 926 927 928 929
        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 已提交
930
    fn node_method_ty(&self, method_call: typeck::MethodCall) -> Option<ty::t> {
931
        self.method_map.borrow().find(&method_call).map(|method| method.ty)
932 933
    }

934
    fn adjustment(&mut self, id: ast::NodeId) -> Option<@ty::AutoAdjustment> {
935
        self.tcx.adjustments.borrow().find_copy(&id)
936 937 938
    }

    fn is_method_call(&mut self, id: ast::NodeId) -> bool {
939
        self.method_map.borrow().contains_key(&typeck::MethodCall::expr(id))
940 941 942 943 944 945 946
    }

    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 {
947
        self.tcx.upvar_borrow_map.borrow().get_copy(&id)
948 949
    }
}