2012-12-03 16:48:01 -08:00
|
|
|
// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
|
|
|
|
// 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.
|
|
|
|
|
2013-03-15 15:24:24 -04:00
|
|
|
/*! See doc.rs for a thorough explanation of the borrow checker */
|
2012-11-28 16:20:41 -08:00
|
|
|
|
2013-05-21 18:24:42 -07:00
|
|
|
|
2013-03-15 15:24:24 -04:00
|
|
|
use mc = middle::mem_categorization;
|
2012-12-23 17:41:37 -05:00
|
|
|
use middle::ty;
|
2013-02-25 14:11:21 -05:00
|
|
|
use middle::typeck;
|
2013-01-10 10:59:58 -08:00
|
|
|
use middle::moves;
|
2013-03-15 15:24:24 -04:00
|
|
|
use middle::dataflow::DataFlowContext;
|
|
|
|
use middle::dataflow::DataFlowOperator;
|
2013-05-22 06:54:35 -04:00
|
|
|
use util::ppaux::{note_and_explain_region, Repr, UserString};
|
2012-12-13 13:05:22 -08:00
|
|
|
|
2013-12-21 18:13:17 -08:00
|
|
|
use std::cell::{Cell, RefCell};
|
2013-12-30 18:57:48 -08:00
|
|
|
use std::hashmap::HashMap;
|
2013-06-28 18:32:26 -04:00
|
|
|
use std::ops::{BitOr, BitAnd};
|
|
|
|
use std::result::{Result};
|
2012-12-13 13:05:22 -08:00
|
|
|
use syntax::ast;
|
2013-03-15 15:24:24 -04:00
|
|
|
use syntax::ast_map;
|
2014-01-27 14:18:36 +02:00
|
|
|
use syntax::ast_util;
|
2013-08-31 18:13:04 +02:00
|
|
|
use syntax::codemap::Span;
|
2013-06-04 12:34:25 -07:00
|
|
|
use syntax::parse::token;
|
2013-08-13 00:30:27 +02:00
|
|
|
use syntax::visit;
|
2014-01-09 15:05:33 +02:00
|
|
|
use syntax::visit::{Visitor, FnKind};
|
|
|
|
use syntax::ast::{FnDecl, Block, NodeId};
|
2012-11-28 16:20:41 -08:00
|
|
|
|
2013-03-15 15:24:24 -04:00
|
|
|
macro_rules! if_ok(
|
|
|
|
($inp: expr) => (
|
|
|
|
match $inp {
|
|
|
|
Ok(v) => { v }
|
|
|
|
Err(e) => { return Err(e); }
|
|
|
|
}
|
|
|
|
)
|
|
|
|
)
|
|
|
|
|
|
|
|
pub mod doc;
|
|
|
|
|
2012-12-13 13:05:22 -08:00
|
|
|
pub mod check_loans;
|
2013-03-15 15:24:24 -04:00
|
|
|
|
2012-12-13 13:05:22 -08:00
|
|
|
pub mod gather_loans;
|
2013-03-15 15:24:24 -04:00
|
|
|
|
2013-05-22 06:54:35 -04:00
|
|
|
pub mod move_data;
|
|
|
|
|
2013-03-15 15:24:24 -04:00
|
|
|
pub struct LoanDataFlowOperator;
|
2013-07-02 12:47:32 -07:00
|
|
|
|
2014-01-26 03:43:42 -05:00
|
|
|
/// FIXME(pcwalton): Should just be #[deriving(Clone)], but that doesn't work
|
2013-07-02 12:47:32 -07:00
|
|
|
/// yet on unit structs.
|
|
|
|
impl Clone for LoanDataFlowOperator {
|
|
|
|
fn clone(&self) -> LoanDataFlowOperator {
|
|
|
|
LoanDataFlowOperator
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-03-15 15:24:24 -04:00
|
|
|
pub type LoanDataFlow = DataFlowContext<LoanDataFlowOperator>;
|
2012-11-28 16:20:41 -08:00
|
|
|
|
2013-09-24 01:56:25 +02:00
|
|
|
impl Visitor<()> for BorrowckCtxt {
|
2014-01-09 15:05:33 +02:00
|
|
|
fn visit_fn(&mut self, fk: &FnKind, fd: &FnDecl,
|
2014-01-06 14:00:46 +02:00
|
|
|
b: &Block, s: Span, n: NodeId, _: ()) {
|
2013-09-24 01:56:25 +02:00
|
|
|
borrowck_fn(self, fk, fd, b, s, n);
|
2013-08-13 00:30:27 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-12-30 18:57:48 -08:00
|
|
|
pub fn check_crate(tcx: ty::ctxt,
|
|
|
|
method_map: typeck::method_map,
|
|
|
|
moves_map: moves::MovesMap,
|
|
|
|
moved_variables_set: moves::MovedVariablesSet,
|
|
|
|
capture_map: moves::CaptureMap,
|
2014-02-05 22:15:24 +01:00
|
|
|
krate: &ast::Crate)
|
2013-12-30 18:57:48 -08:00
|
|
|
-> root_map {
|
2013-09-24 01:56:25 +02:00
|
|
|
let mut bccx = BorrowckCtxt {
|
2013-02-04 14:02:01 -08:00
|
|
|
tcx: tcx,
|
|
|
|
method_map: method_map,
|
|
|
|
moves_map: moves_map,
|
2013-03-15 15:24:24 -04:00
|
|
|
moved_variables_set: moved_variables_set,
|
2013-02-04 14:02:01 -08:00
|
|
|
capture_map: capture_map,
|
|
|
|
root_map: root_map(),
|
2013-12-21 18:17:29 -08:00
|
|
|
stats: @BorrowStats {
|
2013-12-21 18:13:17 -08:00
|
|
|
loaned_paths_same: Cell::new(0),
|
|
|
|
loaned_paths_imm: Cell::new(0),
|
|
|
|
stable_paths: Cell::new(0),
|
|
|
|
guaranteed_paths: Cell::new(0),
|
2013-02-04 14:02:01 -08:00
|
|
|
}
|
|
|
|
};
|
2013-09-24 01:56:25 +02:00
|
|
|
let bccx = &mut bccx;
|
2012-11-28 16:20:41 -08:00
|
|
|
|
2014-02-05 22:15:24 +01:00
|
|
|
visit::walk_crate(bccx, krate, ());
|
2012-11-28 16:20:41 -08:00
|
|
|
|
|
|
|
if tcx.sess.borrowck_stats() {
|
2014-01-09 21:06:55 +11:00
|
|
|
println!("--- borrowck stats ---");
|
2013-09-24 22:16:43 -07:00
|
|
|
println!("paths requiring guarantees: {}",
|
2013-12-21 18:13:17 -08:00
|
|
|
bccx.stats.guaranteed_paths.get());
|
2013-09-24 22:16:43 -07:00
|
|
|
println!("paths requiring loans : {}",
|
2013-12-21 18:13:17 -08:00
|
|
|
make_stat(bccx, bccx.stats.loaned_paths_same.get()));
|
2013-09-24 22:16:43 -07:00
|
|
|
println!("paths requiring imm loans : {}",
|
2013-12-21 18:13:17 -08:00
|
|
|
make_stat(bccx, bccx.stats.loaned_paths_imm.get()));
|
2013-09-24 22:16:43 -07:00
|
|
|
println!("stable paths : {}",
|
2013-12-21 18:13:17 -08:00
|
|
|
make_stat(bccx, bccx.stats.stable_paths.get()));
|
2012-11-28 16:20:41 -08:00
|
|
|
}
|
|
|
|
|
2013-12-30 18:57:48 -08:00
|
|
|
return bccx.root_map;
|
2012-11-28 16:20:41 -08:00
|
|
|
|
2013-09-24 01:56:25 +02:00
|
|
|
fn make_stat(bccx: &mut BorrowckCtxt, stat: uint) -> ~str {
|
2013-09-26 02:26:09 -04:00
|
|
|
let stat_f = stat as f64;
|
2013-12-21 18:13:17 -08:00
|
|
|
let total = bccx.stats.guaranteed_paths.get() as f64;
|
2013-09-26 02:26:09 -04:00
|
|
|
format!("{} ({:.0f}%)", stat , stat_f * 100.0 / total)
|
2012-11-28 16:20:41 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-09-24 01:56:25 +02:00
|
|
|
fn borrowck_fn(this: &mut BorrowckCtxt,
|
2014-01-09 15:05:33 +02:00
|
|
|
fk: &FnKind,
|
|
|
|
decl: &ast::FnDecl,
|
2014-01-06 14:00:46 +02:00
|
|
|
body: &ast::Block,
|
2013-08-31 18:13:04 +02:00
|
|
|
sp: Span,
|
2013-09-24 01:56:25 +02:00
|
|
|
id: ast::NodeId) {
|
2014-02-09 14:08:03 -05:00
|
|
|
debug!("borrowck_fn(id={})", id);
|
|
|
|
|
|
|
|
// Check the body of fn items.
|
|
|
|
let (id_range, all_loans, move_data) =
|
|
|
|
gather_loans::gather_loans(this, decl, body);
|
|
|
|
let all_loans = all_loans.borrow();
|
|
|
|
let mut loan_dfcx =
|
|
|
|
DataFlowContext::new(this.tcx,
|
|
|
|
this.method_map,
|
|
|
|
LoanDataFlowOperator,
|
|
|
|
id_range,
|
|
|
|
all_loans.get().len());
|
|
|
|
for (loan_idx, loan) in all_loans.get().iter().enumerate() {
|
|
|
|
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,
|
|
|
|
*all_loans.get(), body);
|
2013-03-15 15:24:24 -04:00
|
|
|
|
2013-09-24 01:56:25 +02:00
|
|
|
visit::walk_fn(this, fk, decl, body, sp, id, ());
|
2013-03-15 15:24:24 -04:00
|
|
|
}
|
|
|
|
|
2012-11-28 16:20:41 -08:00
|
|
|
// ----------------------------------------------------------------------
|
|
|
|
// Type definitions
|
|
|
|
|
2013-01-10 10:59:58 -08:00
|
|
|
pub struct BorrowckCtxt {
|
|
|
|
tcx: ty::ctxt,
|
|
|
|
method_map: typeck::method_map,
|
|
|
|
moves_map: moves::MovesMap,
|
2013-03-15 15:24:24 -04:00
|
|
|
moved_variables_set: moves::MovedVariablesSet,
|
2013-01-10 10:59:58 -08:00
|
|
|
capture_map: moves::CaptureMap,
|
|
|
|
root_map: root_map,
|
|
|
|
|
|
|
|
// Statistics:
|
2013-12-21 18:17:29 -08:00
|
|
|
stats: @BorrowStats
|
2013-02-04 14:02:01 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
pub struct BorrowStats {
|
2013-12-21 18:13:17 -08:00
|
|
|
loaned_paths_same: Cell<uint>,
|
|
|
|
loaned_paths_imm: Cell<uint>,
|
|
|
|
stable_paths: Cell<uint>,
|
|
|
|
guaranteed_paths: Cell<uint>,
|
2012-11-28 16:20:41 -08:00
|
|
|
}
|
|
|
|
|
2013-05-03 12:11:15 -04:00
|
|
|
// 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.
|
2013-03-15 15:24:24 -04:00
|
|
|
#[deriving(Eq, IterBytes)]
|
2013-01-29 16:05:13 -08:00
|
|
|
pub struct root_map_key {
|
2013-07-27 10:25:59 +02:00
|
|
|
id: ast::NodeId,
|
2013-01-25 16:57:39 -08:00
|
|
|
derefs: uint
|
|
|
|
}
|
2012-11-28 16:20:41 -08:00
|
|
|
|
2013-03-15 15:24:24 -04:00
|
|
|
pub type BckResult<T> = Result<T, BckError>;
|
2012-11-28 16:20:41 -08:00
|
|
|
|
2013-03-20 11:40:02 -04:00
|
|
|
#[deriving(Eq)]
|
2013-03-15 15:24:24 -04:00
|
|
|
pub enum PartialTotal {
|
|
|
|
Partial, // Loan affects some portion
|
|
|
|
Total // Loan affects entire path
|
2012-11-28 16:20:41 -08:00
|
|
|
}
|
|
|
|
|
2013-03-15 15:24:24 -04:00
|
|
|
///////////////////////////////////////////////////////////////////////////
|
|
|
|
// Loans and loan paths
|
|
|
|
|
|
|
|
/// Record of a loan that was issued.
|
|
|
|
pub struct Loan {
|
|
|
|
index: uint,
|
|
|
|
loan_path: @LoanPath,
|
|
|
|
cmt: mc::cmt,
|
2014-02-09 14:08:03 -05:00
|
|
|
kind: ty::BorrowKind,
|
2013-03-15 15:24:24 -04:00
|
|
|
restrictions: ~[Restriction],
|
2013-07-27 10:25:59 +02:00
|
|
|
gen_scope: ast::NodeId,
|
|
|
|
kill_scope: ast::NodeId,
|
2013-08-31 18:13:04 +02:00
|
|
|
span: Span,
|
2014-02-09 14:08:03 -05:00
|
|
|
cause: LoanCause,
|
|
|
|
}
|
|
|
|
|
|
|
|
#[deriving(Eq)]
|
|
|
|
pub enum LoanCause {
|
|
|
|
ClosureCapture(Span),
|
|
|
|
AddrOf,
|
|
|
|
AutoRef,
|
|
|
|
RefBinding,
|
2013-01-10 10:59:58 -08:00
|
|
|
}
|
|
|
|
|
2013-05-22 06:54:35 -04:00
|
|
|
#[deriving(Eq, IterBytes)]
|
2013-03-15 15:24:24 -04:00
|
|
|
pub enum LoanPath {
|
2013-07-27 10:25:59 +02:00
|
|
|
LpVar(ast::NodeId), // `x` in doc.rs
|
2013-03-15 15:24:24 -04:00
|
|
|
LpExtend(@LoanPath, mc::MutabilityCategory, LoanPathElem)
|
|
|
|
}
|
2012-11-28 16:20:41 -08:00
|
|
|
|
2013-05-22 06:54:35 -04:00
|
|
|
#[deriving(Eq, IterBytes)]
|
2013-03-15 15:24:24 -04:00
|
|
|
pub enum LoanPathElem {
|
2013-08-20 17:37:49 -04:00
|
|
|
LpDeref(mc::PointerKind), // `*LV` in doc.rs
|
2013-05-17 21:12:50 -04:00
|
|
|
LpInterior(mc::InteriorKind) // `LV.f` in doc.rs
|
2013-02-08 22:21:45 -08:00
|
|
|
}
|
|
|
|
|
2013-05-31 15:17:22 -07:00
|
|
|
impl LoanPath {
|
2013-07-27 10:25:59 +02:00
|
|
|
pub fn node_id(&self) -> ast::NodeId {
|
2013-03-15 15:24:24 -04:00
|
|
|
match *self {
|
|
|
|
LpVar(local_id) => local_id,
|
|
|
|
LpExtend(base, _, _) => base.node_id()
|
|
|
|
}
|
|
|
|
}
|
2013-02-19 02:40:42 -05:00
|
|
|
}
|
2012-11-28 16:20:41 -08:00
|
|
|
|
2013-03-15 15:24:24 -04:00
|
|
|
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 {
|
2013-11-28 12:22:53 -08:00
|
|
|
mc::cat_rvalue(..) |
|
2013-03-15 15:24:24 -04:00
|
|
|
mc::cat_static_item |
|
2013-08-27 16:36:42 -04:00
|
|
|
mc::cat_copied_upvar(_) => {
|
2013-03-15 15:24:24 -04:00
|
|
|
None
|
|
|
|
}
|
|
|
|
|
2014-02-09 14:08:03 -05:00
|
|
|
mc::cat_local(id) |
|
|
|
|
mc::cat_arg(id) |
|
|
|
|
mc::cat_upvar(ty::UpvarId {var_id: id, ..}, _) => {
|
2013-03-15 15:24:24 -04:00
|
|
|
Some(@LpVar(id))
|
|
|
|
}
|
|
|
|
|
2013-08-20 17:37:49 -04:00
|
|
|
mc::cat_deref(cmt_base, _, pk) => {
|
2013-11-21 15:42:55 -08:00
|
|
|
opt_loan_path(cmt_base).map(|lp| {
|
2013-08-20 17:37:49 -04:00
|
|
|
@LpExtend(lp, cmt.mutbl, LpDeref(pk))
|
2013-11-21 15:42:55 -08:00
|
|
|
})
|
2013-03-15 15:24:24 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
mc::cat_interior(cmt_base, ik) => {
|
2013-11-21 15:42:55 -08:00
|
|
|
opt_loan_path(cmt_base).map(|lp| {
|
2013-08-04 14:59:36 -07:00
|
|
|
@LpExtend(lp, cmt.mutbl, LpInterior(ik))
|
2013-11-21 15:42:55 -08:00
|
|
|
})
|
2013-03-15 15:24:24 -04:00
|
|
|
}
|
|
|
|
|
2013-05-17 21:12:50 -04:00
|
|
|
mc::cat_downcast(cmt_base) |
|
2013-03-15 15:24:24 -04:00
|
|
|
mc::cat_discr(cmt_base, _) => {
|
|
|
|
opt_loan_path(cmt_base)
|
|
|
|
}
|
|
|
|
}
|
2013-02-19 02:40:42 -05:00
|
|
|
}
|
2012-11-28 16:20:41 -08:00
|
|
|
|
2013-03-15 15:24:24 -04:00
|
|
|
///////////////////////////////////////////////////////////////////////////
|
|
|
|
// Restrictions
|
|
|
|
//
|
|
|
|
// Borrowing an lvalue often results in *restrictions* that limit what
|
|
|
|
// can be done with this lvalue during the scope of the loan:
|
|
|
|
//
|
2014-02-09 14:08:03 -05:00
|
|
|
// - `RESTR_MUTATE`: The lvalue may not be modified or `&mut` borrowed.
|
2013-05-26 05:48:04 -04:00
|
|
|
// - `RESTR_FREEZE`: `&` borrows of the lvalue are forbidden.
|
2013-03-15 15:24:24 -04:00
|
|
|
//
|
|
|
|
// 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
|
2013-02-04 14:02:01 -08:00
|
|
|
}
|
|
|
|
|
2013-05-27 05:43:56 -04:00
|
|
|
#[deriving(Eq)]
|
2013-03-15 15:24:24 -04:00
|
|
|
pub struct RestrictionSet {
|
|
|
|
bits: u32
|
2012-11-28 16:20:41 -08:00
|
|
|
}
|
|
|
|
|
2013-05-26 05:48:04 -04:00
|
|
|
pub static RESTR_EMPTY: RestrictionSet = RestrictionSet {bits: 0b0000};
|
|
|
|
pub static RESTR_MUTATE: RestrictionSet = RestrictionSet {bits: 0b0001};
|
2014-02-09 14:08:03 -05:00
|
|
|
pub static RESTR_FREEZE: RestrictionSet = RestrictionSet {bits: 0b0010};
|
2013-03-15 15:24:24 -04:00
|
|
|
|
2013-05-31 15:17:22 -07:00
|
|
|
impl RestrictionSet {
|
|
|
|
pub fn intersects(&self, restr: RestrictionSet) -> bool {
|
2013-03-15 15:24:24 -04:00
|
|
|
(self.bits & restr.bits) != 0
|
2013-02-08 22:21:45 -08:00
|
|
|
}
|
|
|
|
|
2013-05-31 15:17:22 -07:00
|
|
|
pub fn contains_all(&self, restr: RestrictionSet) -> bool {
|
2013-03-15 15:24:24 -04:00
|
|
|
(self.bits & restr.bits) == restr.bits
|
2013-02-08 22:21:45 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-03-15 15:24:24 -04:00
|
|
|
impl BitOr<RestrictionSet,RestrictionSet> for RestrictionSet {
|
|
|
|
fn bitor(&self, rhs: &RestrictionSet) -> RestrictionSet {
|
|
|
|
RestrictionSet {bits: self.bits | rhs.bits}
|
|
|
|
}
|
|
|
|
}
|
2012-11-28 16:20:41 -08:00
|
|
|
|
2013-03-15 15:24:24 -04:00
|
|
|
impl BitAnd<RestrictionSet,RestrictionSet> for RestrictionSet {
|
|
|
|
fn bitand(&self, rhs: &RestrictionSet) -> RestrictionSet {
|
|
|
|
RestrictionSet {bits: self.bits & rhs.bits}
|
2012-11-28 16:20:41 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-02-09 14:08:03 -05:00
|
|
|
impl Repr for RestrictionSet {
|
|
|
|
fn repr(&self, _tcx: ty::ctxt) -> ~str {
|
|
|
|
format!("RestrictionSet(0x{:x})", self.bits as uint)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-03-15 15:24:24 -04:00
|
|
|
///////////////////////////////////////////////////////////////////////////
|
|
|
|
// 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 {
|
2013-07-27 10:25:59 +02:00
|
|
|
scope: ast::NodeId,
|
2013-03-15 15:24:24 -04:00
|
|
|
}
|
|
|
|
|
2013-12-19 19:54:52 -08:00
|
|
|
pub type root_map = @RefCell<HashMap<root_map_key, RootInfo>>;
|
2013-03-15 15:24:24 -04:00
|
|
|
|
2013-01-29 16:05:13 -08:00
|
|
|
pub fn root_map() -> root_map {
|
2013-12-19 19:54:52 -08:00
|
|
|
return @RefCell::new(HashMap::new());
|
2012-11-28 16:20:41 -08:00
|
|
|
}
|
|
|
|
|
2013-03-15 15:24:24 -04:00
|
|
|
///////////////////////////////////////////////////////////////////////////
|
|
|
|
// Errors
|
|
|
|
|
|
|
|
// Errors that can occur
|
|
|
|
#[deriving(Eq)]
|
|
|
|
pub enum bckerr_code {
|
2014-02-09 14:08:03 -05:00
|
|
|
err_mutbl,
|
2013-03-15 15:24:24 -04:00
|
|
|
err_out_of_root_scope(ty::Region, ty::Region), // superscope, subscope
|
|
|
|
err_out_of_scope(ty::Region, ty::Region), // superscope, subscope
|
2013-11-21 09:04:47 -05:00
|
|
|
err_borrowed_pointer_too_short(
|
|
|
|
ty::Region, ty::Region, RestrictionSet), // loan, ptr
|
2013-03-15 15:24:24 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
// Combination of an error code and the categorization of the expression
|
|
|
|
// that caused it
|
|
|
|
#[deriving(Eq)]
|
|
|
|
pub struct BckError {
|
2013-08-31 18:13:04 +02:00
|
|
|
span: Span,
|
2014-02-09 14:08:03 -05:00
|
|
|
cause: LoanCause,
|
2013-03-15 15:24:24 -04:00
|
|
|
cmt: mc::cmt,
|
|
|
|
code: bckerr_code
|
|
|
|
}
|
|
|
|
|
|
|
|
pub enum AliasableViolationKind {
|
|
|
|
MutabilityViolation,
|
2014-02-09 14:08:03 -05:00
|
|
|
BorrowViolation(LoanCause)
|
2013-03-15 15:24:24 -04:00
|
|
|
}
|
|
|
|
|
2013-05-22 06:54:35 -04:00
|
|
|
pub enum MovedValueUseKind {
|
|
|
|
MovedInUse,
|
|
|
|
MovedInCapture,
|
|
|
|
}
|
|
|
|
|
2013-03-15 15:24:24 -04:00
|
|
|
///////////////////////////////////////////////////////////////////////////
|
2012-11-28 16:20:41 -08:00
|
|
|
// Misc
|
|
|
|
|
2013-05-31 15:17:22 -07:00
|
|
|
impl BorrowckCtxt {
|
|
|
|
pub fn is_subregion_of(&self, r_sub: ty::Region, r_sup: ty::Region)
|
|
|
|
-> bool {
|
2013-04-01 22:32:37 -07:00
|
|
|
self.tcx.region_maps.is_subregion_of(r_sub, r_sup)
|
2012-11-28 16:20:41 -08:00
|
|
|
}
|
|
|
|
|
2013-07-27 10:25:59 +02:00
|
|
|
pub fn is_subscope_of(&self, r_sub: ast::NodeId, r_sup: ast::NodeId)
|
2013-05-31 15:17:22 -07:00
|
|
|
-> bool {
|
2013-03-15 15:24:24 -04:00
|
|
|
self.tcx.region_maps.is_subscope_of(r_sub, r_sup)
|
|
|
|
}
|
|
|
|
|
2013-07-27 10:25:59 +02:00
|
|
|
pub fn is_move(&self, id: ast::NodeId) -> bool {
|
2013-12-21 17:09:06 -08:00
|
|
|
let moves_map = self.moves_map.borrow();
|
|
|
|
moves_map.get().contains(&id)
|
2013-05-22 06:54:35 -04:00
|
|
|
}
|
|
|
|
|
2014-02-09 14:08:03 -05:00
|
|
|
pub fn mc(&self) -> mc::MemCategorizationContext<TcxTyper> {
|
|
|
|
mc::MemCategorizationContext {
|
|
|
|
typer: TcxTyper {
|
|
|
|
tcx: self.tcx,
|
|
|
|
method_map: self.method_map
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-01-06 14:00:46 +02:00
|
|
|
pub fn cat_expr(&self, expr: &ast::Expr) -> mc::cmt {
|
2014-02-09 14:08:03 -05:00
|
|
|
match self.mc().cat_expr(expr) {
|
|
|
|
Ok(c) => c,
|
|
|
|
Err(()) => {
|
|
|
|
self.tcx.sess.span_bug(expr.span, "error in mem categorization");
|
|
|
|
}
|
|
|
|
}
|
2012-11-28 16:20:41 -08:00
|
|
|
}
|
|
|
|
|
2014-01-06 14:00:46 +02:00
|
|
|
pub fn cat_expr_unadjusted(&self, expr: &ast::Expr) -> mc::cmt {
|
2014-02-09 14:08:03 -05:00
|
|
|
match self.mc().cat_expr_unadjusted(expr) {
|
|
|
|
Ok(c) => c,
|
|
|
|
Err(()) => {
|
|
|
|
self.tcx.sess.span_bug(expr.span, "error in mem categorization");
|
|
|
|
}
|
|
|
|
}
|
2012-11-28 16:20:41 -08:00
|
|
|
}
|
|
|
|
|
2013-05-31 15:17:22 -07:00
|
|
|
pub fn cat_expr_autoderefd(&self,
|
2014-01-06 14:00:46 +02:00
|
|
|
expr: &ast::Expr,
|
|
|
|
adj: &ty::AutoAdjustment)
|
2013-05-31 15:17:22 -07:00
|
|
|
-> mc::cmt {
|
2014-02-09 14:08:03 -05:00
|
|
|
let r = match *adj {
|
2013-12-26 13:54:41 -05:00
|
|
|
ty::AutoAddEnv(..) | ty::AutoObject(..) => {
|
2013-02-27 19:28:37 -05:00
|
|
|
// no autoderefs
|
2014-02-09 14:08:03 -05:00
|
|
|
self.mc().cat_expr_unadjusted(expr)
|
2013-02-27 19:28:37 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
ty::AutoDerefRef(
|
|
|
|
ty::AutoDerefRef {
|
2013-11-28 12:22:53 -08:00
|
|
|
autoderefs: autoderefs, ..}) => {
|
2014-02-09 14:08:03 -05:00
|
|
|
self.mc().cat_expr_autoderefd(expr, autoderefs)
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
match r {
|
|
|
|
Ok(c) => c,
|
|
|
|
Err(()) => {
|
|
|
|
self.tcx.sess.span_bug(expr.span,
|
|
|
|
"error in mem categorization");
|
2013-02-27 19:28:37 -05:00
|
|
|
}
|
|
|
|
}
|
2012-11-28 16:20:41 -08:00
|
|
|
}
|
|
|
|
|
2013-05-31 15:17:22 -07:00
|
|
|
pub fn cat_def(&self,
|
2013-07-27 10:25:59 +02:00
|
|
|
id: ast::NodeId,
|
2013-08-31 18:13:04 +02:00
|
|
|
span: Span,
|
2013-05-31 15:17:22 -07:00
|
|
|
ty: ty::t,
|
2013-09-02 03:45:37 +02:00
|
|
|
def: ast::Def)
|
2013-05-31 15:17:22 -07:00
|
|
|
-> mc::cmt {
|
2014-02-09 14:08:03 -05:00
|
|
|
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)
|
2012-11-28 16:20:41 -08:00
|
|
|
}
|
|
|
|
|
2013-07-27 10:25:59 +02:00
|
|
|
pub fn cat_discr(&self, cmt: mc::cmt, match_id: ast::NodeId) -> mc::cmt {
|
2013-03-15 15:24:24 -04:00
|
|
|
@mc::cmt_ {cat:mc::cat_discr(cmt, match_id),
|
|
|
|
mutbl:cmt.mutbl.inherit(),
|
|
|
|
..*cmt}
|
2012-11-28 16:20:41 -08:00
|
|
|
}
|
|
|
|
|
2013-05-31 15:17:22 -07:00
|
|
|
pub fn cat_pattern(&self,
|
|
|
|
cmt: mc::cmt,
|
2014-02-09 14:08:03 -05:00
|
|
|
pat: @ast::Pat,
|
2014-01-06 14:00:46 +02:00
|
|
|
op: |mc::cmt, &ast::Pat|) {
|
2014-02-09 14:08:03 -05:00
|
|
|
let r = self.mc().cat_pattern(cmt, pat, |_,x,y| op(x,y));
|
|
|
|
assert!(r.is_ok());
|
2012-11-28 16:20:41 -08:00
|
|
|
}
|
|
|
|
|
2013-05-31 15:17:22 -07:00
|
|
|
pub fn report(&self, err: BckError) {
|
2012-11-28 16:20:41 -08:00
|
|
|
self.span_err(
|
2013-03-15 15:24:24 -04:00
|
|
|
err.span,
|
|
|
|
self.bckerr_to_str(err));
|
2012-11-28 16:20:41 -08:00
|
|
|
self.note_and_explain_bckerr(err);
|
|
|
|
}
|
|
|
|
|
2013-05-31 15:17:22 -07:00
|
|
|
pub fn report_use_of_moved_value(&self,
|
2013-08-31 18:13:04 +02:00
|
|
|
use_span: Span,
|
2013-05-31 15:17:22 -07:00
|
|
|
use_kind: MovedValueUseKind,
|
2013-06-27 15:04:22 +02:00
|
|
|
lp: &LoanPath,
|
2013-05-31 15:17:22 -07:00
|
|
|
move: &move_data::Move,
|
|
|
|
moved_lp: @LoanPath) {
|
2013-05-22 06:54:35 -04:00
|
|
|
let verb = match use_kind {
|
|
|
|
MovedInUse => "use",
|
|
|
|
MovedInCapture => "capture",
|
|
|
|
};
|
|
|
|
|
|
|
|
match move.kind {
|
|
|
|
move_data::Declared => {
|
|
|
|
self.tcx.sess.span_err(
|
|
|
|
use_span,
|
2013-09-27 22:38:08 -07:00
|
|
|
format!("{} of possibly uninitialized value: `{}`",
|
2013-05-22 06:54:35 -04:00
|
|
|
verb,
|
|
|
|
self.loan_path_to_str(lp)));
|
|
|
|
}
|
|
|
|
_ => {
|
|
|
|
let partially = if lp == moved_lp {""} else {"partially "};
|
|
|
|
self.tcx.sess.span_err(
|
|
|
|
use_span,
|
2013-09-27 22:38:08 -07:00
|
|
|
format!("{} of {}moved value: `{}`",
|
2013-05-22 06:54:35 -04:00
|
|
|
verb,
|
|
|
|
partially,
|
|
|
|
self.loan_path_to_str(lp)));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
match move.kind {
|
|
|
|
move_data::Declared => {}
|
|
|
|
|
2014-01-06 14:00:46 +02:00
|
|
|
move_data::MoveExpr => {
|
2014-01-17 23:23:09 +11:00
|
|
|
let (expr_ty, expr_span) = match self.tcx.items.find(move.id) {
|
|
|
|
Some(ast_map::NodeExpr(expr)) => {
|
2014-01-06 14:00:46 +02:00
|
|
|
(ty::expr_ty_adjusted(self.tcx, expr), expr.span)
|
|
|
|
}
|
|
|
|
r => self.tcx.sess.bug(format!("MoveExpr({:?}) maps to {:?}, not Expr",
|
|
|
|
move.id, r))
|
|
|
|
};
|
2013-07-01 15:38:57 -04:00
|
|
|
let suggestion = move_suggestion(self.tcx, expr_ty,
|
|
|
|
"moved by default (use `copy` to override)");
|
2013-05-22 06:54:35 -04:00
|
|
|
self.tcx.sess.span_note(
|
2014-01-06 14:00:46 +02:00
|
|
|
expr_span,
|
2013-09-27 22:38:08 -07:00
|
|
|
format!("`{}` moved here because it has type `{}`, which is {}",
|
2013-05-22 06:54:35 -04:00
|
|
|
self.loan_path_to_str(moved_lp),
|
2013-07-01 15:38:57 -04:00
|
|
|
expr_ty.user_string(self.tcx), suggestion));
|
2013-05-22 06:54:35 -04:00
|
|
|
}
|
|
|
|
|
2014-01-06 14:00:46 +02:00
|
|
|
move_data::MovePat => {
|
|
|
|
let pat_ty = ty::node_id_to_type(self.tcx, move.id);
|
2013-05-22 06:54:35 -04:00
|
|
|
self.tcx.sess.span_note(
|
2014-01-06 14:00:46 +02:00
|
|
|
ast_map::node_span(self.tcx.items, move.id),
|
2013-09-27 22:38:08 -07:00
|
|
|
format!("`{}` moved here because it has type `{}`, \
|
2013-05-22 06:54:35 -04:00
|
|
|
which is moved by default (use `ref` to override)",
|
|
|
|
self.loan_path_to_str(moved_lp),
|
|
|
|
pat_ty.user_string(self.tcx)));
|
|
|
|
}
|
|
|
|
|
2014-01-06 14:00:46 +02:00
|
|
|
move_data::Captured => {
|
2014-01-17 23:23:09 +11:00
|
|
|
let (expr_ty, expr_span) = match self.tcx.items.find(move.id) {
|
|
|
|
Some(ast_map::NodeExpr(expr)) => {
|
2014-01-06 14:00:46 +02:00
|
|
|
(ty::expr_ty_adjusted(self.tcx, expr), expr.span)
|
|
|
|
}
|
|
|
|
r => self.tcx.sess.bug(format!("Captured({:?}) maps to {:?}, not Expr",
|
|
|
|
move.id, r))
|
|
|
|
};
|
2013-07-01 15:38:57 -04:00
|
|
|
let suggestion = move_suggestion(self.tcx, expr_ty,
|
|
|
|
"moved by default (make a copy and \
|
|
|
|
capture that instead to override)");
|
2013-05-22 06:54:35 -04:00
|
|
|
self.tcx.sess.span_note(
|
2014-01-06 14:00:46 +02:00
|
|
|
expr_span,
|
2013-09-27 22:38:08 -07:00
|
|
|
format!("`{}` moved into closure environment here because it \
|
|
|
|
has type `{}`, which is {}",
|
2013-07-01 15:38:57 -04:00
|
|
|
self.loan_path_to_str(moved_lp),
|
|
|
|
expr_ty.user_string(self.tcx), suggestion));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn move_suggestion(tcx: ty::ctxt, ty: ty::t, default_msg: &'static str)
|
|
|
|
-> &'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)",
|
2013-07-10 17:31:53 -07:00
|
|
|
_ if ty::type_moves_by_default(tcx, ty) =>
|
2013-07-01 15:38:57 -04:00
|
|
|
"non-copyable (perhaps you meant to use clone()?)",
|
|
|
|
_ => default_msg,
|
2013-05-22 06:54:35 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-05-31 15:17:22 -07:00
|
|
|
pub fn report_reassigned_immutable_variable(&self,
|
2013-08-31 18:13:04 +02:00
|
|
|
span: Span,
|
2013-06-27 15:04:22 +02:00
|
|
|
lp: &LoanPath,
|
2013-05-31 15:17:22 -07:00
|
|
|
assign:
|
|
|
|
&move_data::Assignment) {
|
2013-05-22 06:54:35 -04:00
|
|
|
self.tcx.sess.span_err(
|
|
|
|
span,
|
2013-09-27 22:38:08 -07:00
|
|
|
format!("re-assignment of immutable variable `{}`",
|
2013-05-22 06:54:35 -04:00
|
|
|
self.loan_path_to_str(lp)));
|
|
|
|
self.tcx.sess.span_note(
|
|
|
|
assign.span,
|
2013-09-27 22:38:08 -07:00
|
|
|
format!("prior assignment occurs here"));
|
2013-05-22 06:54:35 -04:00
|
|
|
}
|
|
|
|
|
2013-08-31 18:13:04 +02:00
|
|
|
pub fn span_err(&self, s: Span, m: &str) {
|
2012-11-28 16:20:41 -08:00
|
|
|
self.tcx.sess.span_err(s, m);
|
|
|
|
}
|
|
|
|
|
2013-08-31 18:13:04 +02:00
|
|
|
pub fn span_note(&self, s: Span, m: &str) {
|
2012-11-28 16:20:41 -08:00
|
|
|
self.tcx.sess.span_note(s, m);
|
|
|
|
}
|
|
|
|
|
2014-01-22 00:33:37 -05:00
|
|
|
pub fn span_end_note(&self, s: Span, m: &str) {
|
|
|
|
self.tcx.sess.span_end_note(s, m);
|
|
|
|
}
|
|
|
|
|
2013-05-31 15:17:22 -07:00
|
|
|
pub fn bckerr_to_str(&self, err: BckError) -> ~str {
|
2012-11-28 16:20:41 -08:00
|
|
|
match err.code {
|
2014-02-09 14:08:03 -05:00
|
|
|
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)
|
|
|
|
}
|
|
|
|
}
|
2012-11-28 16:20:41 -08:00
|
|
|
}
|
2013-11-28 12:22:53 -08:00
|
|
|
err_out_of_root_scope(..) => {
|
2013-09-27 22:38:08 -07:00
|
|
|
format!("cannot root managed value long enough")
|
2012-11-28 16:20:41 -08:00
|
|
|
}
|
2013-11-28 12:22:53 -08:00
|
|
|
err_out_of_scope(..) => {
|
2014-02-09 14:08:03 -05:00
|
|
|
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)
|
2012-11-28 16:20:41 -08:00
|
|
|
}
|
2013-12-09 12:45:13 -05:00
|
|
|
err_borrowed_pointer_too_short(..) => {
|
2013-11-16 17:30:45 -05:00
|
|
|
let descr = match opt_loan_path(err.cmt) {
|
|
|
|
Some(lp) => format!("`{}`", self.loan_path_to_str(lp)),
|
2013-11-21 09:04:47 -05:00
|
|
|
None => self.cmt_to_str(err.cmt),
|
2013-11-16 17:30:45 -05:00
|
|
|
};
|
|
|
|
|
2013-11-21 09:04:47 -05:00
|
|
|
format!("lifetime of {} is too short to guarantee \
|
|
|
|
its contents can be safely reborrowed",
|
|
|
|
descr)
|
2013-11-16 17:30:45 -05:00
|
|
|
}
|
2013-03-15 15:24:24 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-05-31 15:17:22 -07:00
|
|
|
pub fn report_aliasability_violation(&self,
|
2013-08-31 18:13:04 +02:00
|
|
|
span: Span,
|
2013-05-31 15:17:22 -07:00
|
|
|
kind: AliasableViolationKind,
|
|
|
|
cause: mc::AliasableReason) {
|
2013-03-15 15:24:24 -04:00
|
|
|
let prefix = match kind {
|
2014-02-09 14:08:03 -05:00
|
|
|
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"
|
|
|
|
}
|
2013-03-15 15:24:24 -04:00
|
|
|
};
|
|
|
|
|
|
|
|
match cause {
|
|
|
|
mc::AliasableOther => {
|
|
|
|
self.tcx.sess.span_err(
|
|
|
|
span,
|
2013-09-27 22:38:08 -07:00
|
|
|
format!("{} in an aliasable location", prefix));
|
2012-11-28 16:20:41 -08:00
|
|
|
}
|
2014-02-07 17:28:56 -05:00
|
|
|
mc::AliasableStatic |
|
|
|
|
mc::AliasableStaticMut => {
|
|
|
|
self.tcx.sess.span_err(
|
|
|
|
span,
|
|
|
|
format!("{} in a static location", prefix));
|
|
|
|
}
|
2013-12-30 18:57:48 -08:00
|
|
|
mc::AliasableManaged => {
|
2014-02-07 17:28:56 -05:00
|
|
|
self.tcx.sess.span_err(
|
|
|
|
span,
|
|
|
|
format!("{} in a `@` pointer", prefix));
|
2013-03-15 15:24:24 -04:00
|
|
|
}
|
2014-02-09 14:08:03 -05:00
|
|
|
mc::AliasableBorrowed => {
|
2013-03-15 15:24:24 -04:00
|
|
|
self.tcx.sess.span_err(
|
|
|
|
span,
|
2014-02-07 17:28:56 -05:00
|
|
|
format!("{} in a `&` reference", prefix));
|
2012-11-28 16:20:41 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-05-31 15:17:22 -07:00
|
|
|
pub fn note_and_explain_bckerr(&self, err: BckError) {
|
2012-11-28 16:20:41 -08:00
|
|
|
let code = err.code;
|
|
|
|
match code {
|
2014-02-09 14:08:03 -05:00
|
|
|
err_mutbl(..) => { }
|
2012-11-28 16:20:41 -08:00
|
|
|
|
|
|
|
err_out_of_root_scope(super_scope, sub_scope) => {
|
|
|
|
note_and_explain_region(
|
|
|
|
self.tcx,
|
2013-05-19 01:07:44 -04:00
|
|
|
"managed value would have to be rooted for ",
|
2012-11-28 16:20:41 -08:00
|
|
|
sub_scope,
|
2013-05-19 01:07:44 -04:00
|
|
|
"...");
|
2012-11-28 16:20:41 -08:00
|
|
|
note_and_explain_region(
|
|
|
|
self.tcx,
|
2013-05-19 01:07:44 -04:00
|
|
|
"...but can only be rooted for ",
|
2012-11-28 16:20:41 -08:00
|
|
|
super_scope,
|
2013-05-19 01:07:44 -04:00
|
|
|
"");
|
2012-11-28 16:20:41 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
err_out_of_scope(super_scope, sub_scope) => {
|
|
|
|
note_and_explain_region(
|
|
|
|
self.tcx,
|
2014-01-07 18:49:13 -08:00
|
|
|
"reference must be valid for ",
|
2012-11-28 16:20:41 -08:00
|
|
|
sub_scope,
|
2013-05-19 01:07:44 -04:00
|
|
|
"...");
|
2012-11-28 16:20:41 -08:00
|
|
|
note_and_explain_region(
|
|
|
|
self.tcx,
|
2013-05-19 01:07:44 -04:00
|
|
|
"...but borrowed value is only valid for ",
|
2012-11-28 16:20:41 -08:00
|
|
|
super_scope,
|
2013-05-19 01:07:44 -04:00
|
|
|
"");
|
2013-11-16 17:30:45 -05:00
|
|
|
}
|
|
|
|
|
2013-11-21 09:04:47 -05:00
|
|
|
err_borrowed_pointer_too_short(loan_scope, ptr_scope, _) => {
|
2013-11-16 17:30:45 -05:00
|
|
|
let descr = match opt_loan_path(err.cmt) {
|
|
|
|
Some(lp) => format!("`{}`", self.loan_path_to_str(lp)),
|
2013-11-21 09:04:47 -05:00
|
|
|
None => self.cmt_to_str(err.cmt),
|
2013-11-16 17:30:45 -05:00
|
|
|
};
|
|
|
|
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,
|
|
|
|
"");
|
|
|
|
}
|
2012-11-28 16:20:41 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-05-31 15:17:22 -07:00
|
|
|
pub fn append_loan_path_to_str(&self,
|
|
|
|
loan_path: &LoanPath,
|
|
|
|
out: &mut ~str) {
|
2013-03-15 15:24:24 -04:00
|
|
|
match *loan_path {
|
|
|
|
LpVar(id) => {
|
2014-02-09 14:08:03 -05:00
|
|
|
out.push_str(ty::local_var_name_str(self.tcx, id).get());
|
2013-03-15 15:24:24 -04:00
|
|
|
}
|
2012-11-28 16:20:41 -08:00
|
|
|
|
2013-05-17 21:12:50 -04:00
|
|
|
LpExtend(lp_base, _, LpInterior(mc::InteriorField(fname))) => {
|
2014-02-09 14:08:03 -05:00
|
|
|
self.append_autoderefd_loan_path_to_str(lp_base, out);
|
2013-05-17 21:12:50 -04:00
|
|
|
match fname {
|
2013-06-03 23:00:49 -07:00
|
|
|
mc::NamedField(ref fname) => {
|
2014-01-31 16:03:55 -08:00
|
|
|
let string = token::get_ident(*fname);
|
2013-06-10 17:42:24 +10:00
|
|
|
out.push_char('.');
|
2014-01-31 16:03:55 -08:00
|
|
|
out.push_str(string.get());
|
2013-05-17 21:12:50 -04:00
|
|
|
}
|
|
|
|
mc::PositionalField(idx) => {
|
2013-06-10 17:42:24 +10:00
|
|
|
out.push_char('#'); // invent a notation here
|
|
|
|
out.push_str(idx.to_str());
|
2013-05-17 21:12:50 -04:00
|
|
|
}
|
|
|
|
}
|
2013-03-15 15:24:24 -04:00
|
|
|
}
|
|
|
|
|
2013-05-17 21:12:50 -04:00
|
|
|
LpExtend(lp_base, _, LpInterior(mc::InteriorElement(_))) => {
|
2014-02-09 14:08:03 -05:00
|
|
|
self.append_autoderefd_loan_path_to_str(lp_base, out);
|
|
|
|
out.push_str("[..]");
|
2013-03-15 15:24:24 -04:00
|
|
|
}
|
|
|
|
|
2013-08-20 17:37:49 -04:00
|
|
|
LpExtend(lp_base, _, LpDeref(_)) => {
|
2013-06-10 17:42:24 +10:00
|
|
|
out.push_char('*');
|
2013-03-15 15:24:24 -04:00
|
|
|
self.append_loan_path_to_str(lp_base, out);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-02-09 14:08:03 -05:00
|
|
|
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)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-05-31 15:17:22 -07:00
|
|
|
pub fn loan_path_to_str(&self, loan_path: &LoanPath) -> ~str {
|
2013-03-15 15:24:24 -04:00
|
|
|
let mut result = ~"";
|
|
|
|
self.append_loan_path_to_str(loan_path, &mut result);
|
|
|
|
result
|
2012-11-28 16:20:41 -08:00
|
|
|
}
|
|
|
|
|
2013-05-31 15:17:22 -07:00
|
|
|
pub fn cmt_to_str(&self, cmt: mc::cmt) -> ~str {
|
2014-02-09 14:08:03 -05:00
|
|
|
self.mc().cmt_to_str(cmt)
|
2012-11-28 16:20:41 -08:00
|
|
|
}
|
|
|
|
|
2014-02-09 14:08:03 -05:00
|
|
|
pub fn mut_to_str(&self, mutbl: ast::Mutability) -> ~str {
|
|
|
|
self.mc().mut_to_str(mutbl)
|
2012-11-28 16:20:41 -08:00
|
|
|
}
|
|
|
|
|
2013-09-02 03:45:37 +02:00
|
|
|
pub fn mut_to_keyword(&self, mutbl: ast::Mutability) -> &'static str {
|
2013-03-15 15:24:24 -04:00
|
|
|
match mutbl {
|
2013-09-02 03:45:37 +02:00
|
|
|
ast::MutImmutable => "",
|
|
|
|
ast::MutMutable => "mut",
|
2013-02-08 22:21:45 -08:00
|
|
|
}
|
|
|
|
}
|
2013-03-15 15:24:24 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
impl DataFlowOperator for LoanDataFlowOperator {
|
2013-06-18 14:45:18 -07:00
|
|
|
#[inline]
|
2013-03-15 15:24:24 -04:00
|
|
|
fn initial_value(&self) -> bool {
|
|
|
|
false // no loans in scope by default
|
|
|
|
}
|
|
|
|
|
2013-06-18 14:45:18 -07:00
|
|
|
#[inline]
|
2013-03-15 15:24:24 -04:00
|
|
|
fn join(&self, succ: uint, pred: uint) -> uint {
|
|
|
|
succ | pred // loans from both preds are in scope
|
|
|
|
}
|
|
|
|
}
|
2013-02-08 22:21:45 -08:00
|
|
|
|
2013-03-15 15:24:24 -04:00
|
|
|
impl Repr for Loan {
|
|
|
|
fn repr(&self, tcx: ty::ctxt) -> ~str {
|
2013-09-27 22:38:08 -07:00
|
|
|
format!("Loan_{:?}({}, {:?}, {:?}-{:?}, {})",
|
2013-03-15 15:24:24 -04:00
|
|
|
self.index,
|
|
|
|
self.loan_path.repr(tcx),
|
2014-02-09 14:08:03 -05:00
|
|
|
self.kind,
|
2013-03-15 15:24:24 -04:00
|
|
|
self.gen_scope,
|
|
|
|
self.kill_scope,
|
|
|
|
self.restrictions.repr(tcx))
|
2012-11-28 16:20:41 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-03-15 15:24:24 -04:00
|
|
|
impl Repr for Restriction {
|
|
|
|
fn repr(&self, tcx: ty::ctxt) -> ~str {
|
2013-09-27 22:38:08 -07:00
|
|
|
format!("Restriction({}, {:x})",
|
2013-03-15 15:24:24 -04:00
|
|
|
self.loan_path.repr(tcx),
|
|
|
|
self.set.bits as uint)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Repr for LoanPath {
|
|
|
|
fn repr(&self, tcx: ty::ctxt) -> ~str {
|
|
|
|
match self {
|
|
|
|
&LpVar(id) => {
|
2014-01-10 18:30:06 -08:00
|
|
|
format!("$({})",
|
|
|
|
ast_map::node_id_to_str(tcx.items,
|
|
|
|
id,
|
|
|
|
token::get_ident_interner()))
|
2013-03-15 15:24:24 -04:00
|
|
|
}
|
|
|
|
|
2013-08-20 17:37:49 -04:00
|
|
|
&LpExtend(lp, _, LpDeref(_)) => {
|
2013-09-27 22:38:08 -07:00
|
|
|
format!("{}.*", lp.repr(tcx))
|
2013-03-15 15:24:24 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
&LpExtend(lp, _, LpInterior(ref interior)) => {
|
2013-09-27 22:38:08 -07:00
|
|
|
format!("{}.{}", lp.repr(tcx), interior.repr(tcx))
|
2013-03-15 15:24:24 -04:00
|
|
|
}
|
|
|
|
}
|
2012-11-28 16:20:41 -08:00
|
|
|
}
|
|
|
|
}
|
2014-02-09 14:08:03 -05:00
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
struct TcxTyper {
|
|
|
|
tcx: ty::ctxt,
|
|
|
|
method_map: typeck::method_map,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl mc::Typer for TcxTyper {
|
|
|
|
fn tcx(&self) -> ty::ctxt {
|
|
|
|
self.tcx
|
|
|
|
}
|
|
|
|
|
|
|
|
fn node_ty(&mut self, id: ast::NodeId) -> mc::McResult<ty::t> {
|
|
|
|
Ok(ty::node_id_to_type(self.tcx, id))
|
|
|
|
}
|
|
|
|
|
|
|
|
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 {
|
|
|
|
let method_map = self.method_map.borrow();
|
|
|
|
method_map.get().contains_key(&id)
|
|
|
|
}
|
|
|
|
|
|
|
|
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)
|
|
|
|
}
|
|
|
|
}
|