889 lines
29 KiB
Rust
Raw Normal View History

// 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;
use middle::ty;
use middle::typeck;
use middle::moves;
2013-03-15 15:24:24 -04:00
use middle::dataflow::DataFlowContext;
use middle::dataflow::DataFlowOperator;
use util::ppaux::{note_and_explain_region, Repr, UserString};
use std::cell::{Cell, RefCell};
use std::hashmap::HashMap;
use std::ops::{BitOr, BitAnd};
use std::result::{Result};
use syntax::ast;
2013-03-15 15:24:24 -04:00
use syntax::ast_map;
use syntax::codemap::Span;
use syntax::parse::token;
use syntax::visit;
use syntax::visit::{Visitor,fn_kind};
2014-01-06 14:00:46 +02:00
use syntax::ast::{fn_decl,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;
pub mod check_loans;
2013-03-15 15:24:24 -04:00
pub mod gather_loans;
2013-03-15 15:24:24 -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
/// XXX(pcwalton): Should just be #[deriving(Clone)], but that doesn't work
/// 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
impl Visitor<()> for BorrowckCtxt {
2014-01-06 14:00:46 +02:00
fn visit_fn(&mut self, fk: &fn_kind, fd: &fn_decl,
b: &Block, s: Span, n: NodeId, _: ()) {
borrowck_fn(self, fk, fd, b, s, n);
}
}
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,
crate: &ast::Crate)
-> root_map {
let mut bccx = BorrowckCtxt {
tcx: tcx,
method_map: method_map,
moves_map: moves_map,
2013-03-15 15:24:24 -04:00
moved_variables_set: moved_variables_set,
capture_map: capture_map,
root_map: root_map(),
2013-12-21 18:17:29 -08:00
stats: @BorrowStats {
loaned_paths_same: Cell::new(0),
loaned_paths_imm: Cell::new(0),
stable_paths: Cell::new(0),
guaranteed_paths: Cell::new(0),
}
};
let bccx = &mut bccx;
2012-11-28 16:20:41 -08:00
visit::walk_crate(bccx, crate, ());
2012-11-28 16:20:41 -08:00
if tcx.sess.borrowck_stats() {
println("--- borrowck stats ---");
println!("paths requiring guarantees: {}",
bccx.stats.guaranteed_paths.get());
println!("paths requiring loans : {}",
make_stat(bccx, bccx.stats.loaned_paths_same.get()));
println!("paths requiring imm loans : {}",
make_stat(bccx, bccx.stats.loaned_paths_imm.get()));
println!("stable paths : {}",
make_stat(bccx, bccx.stats.stable_paths.get()));
2012-11-28 16:20:41 -08:00
}
return bccx.root_map;
2012-11-28 16:20:41 -08:00
fn make_stat(bccx: &mut BorrowckCtxt, stat: uint) -> ~str {
let stat_f = stat as f64;
let total = bccx.stats.guaranteed_paths.get() as f64;
format!("{} ({:.0f}%)", stat , stat_f * 100.0 / total)
2012-11-28 16:20:41 -08:00
}
}
fn borrowck_fn(this: &mut BorrowckCtxt,
fk: &visit::fn_kind,
2013-03-15 15:24:24 -04:00
decl: &ast::fn_decl,
2014-01-06 14:00:46 +02:00
body: &ast::Block,
sp: Span,
id: ast::NodeId) {
2013-03-15 15:24:24 -04:00
match fk {
2013-11-28 12:22:53 -08:00
&visit::fk_fn_block(..) => {
2013-03-15 15:24:24 -04:00
// Closures are checked as part of their containing fn item.
}
2013-11-28 12:22:53 -08:00
&visit::fk_item_fn(..) |
&visit::fk_method(..) => {
debug!("borrowck_fn(id={:?})", id);
2013-03-15 15:24:24 -04:00
// 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);
2013-03-15 15:24:24 -04:00
}
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
}
}
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
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,
capture_map: moves::CaptureMap,
root_map: root_map,
// Statistics:
2013-12-21 18:17:29 -08:00
stats: @BorrowStats
}
pub struct BorrowStats {
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
}
// 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.
//
// Note that implicit dereferences also occur with indexing of `@[]`,
// `@str`, etc. The same rules apply. So, for example, given a
// variable `x` of type `@[@[...]]`, if I have an instance of the
// expression `x[0]` which is then auto-slice'd, there would be two
// potential entries in the root map, both with the id of the `x[0]`
// expression. The entry with `derefs==0` refers to the deref of `x`
// used as part of evaluating `x[0]`. The entry with `derefs==1`
// refers to the deref of the `x[0]` that occurs as part of the
// auto-slice.
2013-03-15 15:24:24 -04:00
#[deriving(Eq, IterBytes)]
pub struct root_map_key {
id: ast::NodeId,
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
#[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
#[deriving(Clone, Eq)]
pub enum LoanMutability {
ImmutableMutability,
ConstMutability,
MutableMutability,
}
impl LoanMutability {
pub fn from_ast_mutability(ast_mutability: ast::Mutability)
-> LoanMutability {
match ast_mutability {
ast::MutImmutable => ImmutableMutability,
ast::MutMutable => MutableMutability,
}
}
}
impl ToStr for LoanMutability {
fn to_str(&self) -> ~str {
match *self {
ImmutableMutability => ~"immutable",
ConstMutability => ~"read-only",
MutableMutability => ~"mutable",
}
}
}
2013-03-15 15:24:24 -04:00
/// Record of a loan that was issued.
pub struct Loan {
index: uint,
loan_path: @LoanPath,
cmt: mc::cmt,
mutbl: LoanMutability,
2013-03-15 15:24:24 -04:00
restrictions: ~[Restriction],
gen_scope: ast::NodeId,
kill_scope: ast::NodeId,
span: Span,
}
#[deriving(Eq, IterBytes)]
2013-03-15 15:24:24 -04:00
pub enum LoanPath {
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
#[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
LpInterior(mc::InteriorKind) // `LV.f` in doc.rs
}
impl LoanPath {
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()
}
}
}
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
}
mc::cat_local(id) |
mc::cat_arg(id) |
2013-03-15 15:24:24 -04:00
mc::cat_self(id) => {
Some(@LpVar(id))
}
2013-08-20 17:37:49 -04:00
mc::cat_deref(cmt_base, _, pk) => {
opt_loan_path(cmt_base).map(|lp| {
2013-08-20 17:37:49 -04:00
@LpExtend(lp, cmt.mutbl, LpDeref(pk))
})
2013-03-15 15:24:24 -04:00
}
mc::cat_interior(cmt_base, ik) => {
opt_loan_path(cmt_base).map(|lp| {
@LpExtend(lp, cmt.mutbl, LpInterior(ik))
})
2013-03-15 15:24:24 -04:00
}
mc::cat_downcast(cmt_base) |
2013-03-15 15:24:24 -04:00
mc::cat_stack_upvar(cmt_base) |
mc::cat_discr(cmt_base, _) => {
opt_loan_path(cmt_base)
}
}
}
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:
//
// - `RESTR_MUTATE`: The lvalue may not be modified.
// - `RESTR_CLAIM`: `&mut` borrows of the lvalue are forbidden.
// - `RESTR_FREEZE`: `&` borrows of the lvalue are forbidden.
// - `RESTR_ALIAS`: All 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
}
#[deriving(Eq)]
2013-03-15 15:24:24 -04:00
pub struct RestrictionSet {
bits: u32
2012-11-28 16:20:41 -08:00
}
pub static RESTR_EMPTY: RestrictionSet = RestrictionSet {bits: 0b0000};
pub static RESTR_MUTATE: RestrictionSet = RestrictionSet {bits: 0b0001};
pub static RESTR_CLAIM: RestrictionSet = RestrictionSet {bits: 0b0010};
pub static RESTR_FREEZE: RestrictionSet = RestrictionSet {bits: 0b0100};
pub static RESTR_ALIAS: RestrictionSet = RestrictionSet {bits: 0b1000};
2013-03-15 15:24:24 -04:00
impl RestrictionSet {
pub fn intersects(&self, restr: RestrictionSet) -> bool {
2013-03-15 15:24:24 -04:00
(self.bits & restr.bits) != 0
}
pub fn contains_all(&self, restr: RestrictionSet) -> bool {
2013-03-15 15:24:24 -04:00
(self.bits & restr.bits) == restr.bits
}
}
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
}
}
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 {
scope: ast::NodeId,
2013-03-15 15:24:24 -04:00
}
pub type root_map = @RefCell<HashMap<root_map_key, RootInfo>>;
2013-03-15 15:24:24 -04:00
pub fn root_map() -> root_map {
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 {
err_mutbl(LoanMutability),
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
err_freeze_aliasable_const,
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 {
span: Span,
2013-03-15 15:24:24 -04:00
cmt: mc::cmt,
code: bckerr_code
}
pub enum AliasableViolationKind {
MutabilityViolation,
BorrowViolation
}
pub enum MovedValueUseKind {
MovedInUse,
MovedInCapture,
}
2013-03-15 15:24:24 -04:00
///////////////////////////////////////////////////////////////////////////
2012-11-28 16:20:41 -08:00
// Misc
impl BorrowckCtxt {
pub fn is_subregion_of(&self, r_sub: ty::Region, r_sup: ty::Region)
-> bool {
self.tcx.region_maps.is_subregion_of(r_sub, r_sup)
2012-11-28 16:20:41 -08:00
}
pub fn is_subscope_of(&self, r_sub: ast::NodeId, r_sup: ast::NodeId)
-> bool {
2013-03-15 15:24:24 -04:00
self.tcx.region_maps.is_subscope_of(r_sub, r_sup)
}
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)
}
2014-01-06 14:00:46 +02:00
pub fn cat_expr(&self, expr: &ast::Expr) -> mc::cmt {
2013-03-15 15:24:24 -04:00
mc::cat_expr(self.tcx, self.method_map, expr)
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 {
2013-03-15 15:24:24 -04:00
mc::cat_expr_unadjusted(self.tcx, self.method_map, expr)
2012-11-28 16:20:41 -08:00
}
pub fn cat_expr_autoderefd(&self,
2014-01-06 14:00:46 +02:00
expr: &ast::Expr,
adj: &ty::AutoAdjustment)
-> mc::cmt {
match *adj {
ty::AutoAddEnv(..) | ty::AutoObject(..) => {
// no autoderefs
2013-03-15 15:24:24 -04:00
mc::cat_expr_unadjusted(self.tcx, self.method_map, expr)
}
ty::AutoDerefRef(
ty::AutoDerefRef {
2013-11-28 12:22:53 -08:00
autoderefs: autoderefs, ..}) => {
2013-03-15 15:24:24 -04:00
mc::cat_expr_autoderefd(self.tcx, self.method_map, expr,
autoderefs)
}
}
2012-11-28 16:20:41 -08:00
}
pub fn cat_def(&self,
id: ast::NodeId,
span: Span,
ty: ty::t,
def: ast::Def)
-> mc::cmt {
2013-03-15 15:24:24 -04:00
mc::cat_def(self.tcx, self.method_map, id, span, ty, def)
2012-11-28 16:20:41 -08: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
}
pub fn mc_ctxt(&self) -> mc::mem_categorization_ctxt {
2013-03-15 15:24:24 -04:00
mc::mem_categorization_ctxt {tcx: self.tcx,
method_map: self.method_map}
}
pub fn cat_pattern(&self,
cmt: mc::cmt,
2014-01-06 14:00:46 +02:00
pat: &ast::Pat,
op: |mc::cmt, &ast::Pat|) {
let mc = self.mc_ctxt();
2012-11-28 16:20:41 -08:00
mc.cat_pattern(cmt, pat, op);
}
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);
}
pub fn report_use_of_moved_value(&self,
use_span: Span,
use_kind: MovedValueUseKind,
lp: &LoanPath,
move: &move_data::Move,
moved_lp: @LoanPath) {
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: `{}`",
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: `{}`",
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 => {
let items = self.tcx.items.borrow();
let (expr_ty, expr_span) = match items.get().find(&move.id) {
Some(&ast_map::node_expr(expr)) => {
(ty::expr_ty_adjusted(self.tcx, expr), expr.span)
}
r => self.tcx.sess.bug(format!("MoveExpr({:?}) maps to {:?}, not Expr",
move.id, r))
};
let suggestion = move_suggestion(self.tcx, expr_ty,
"moved by default (use `copy` to override)");
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 {}",
self.loan_path_to_str(moved_lp),
expr_ty.user_string(self.tcx), suggestion));
}
2014-01-06 14:00:46 +02:00
move_data::MovePat => {
let pat_ty = ty::node_id_to_type(self.tcx, move.id);
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 `{}`, \
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 => {
let items = self.tcx.items.borrow();
let (expr_ty, expr_span) = match items.get().find(&move.id) {
Some(&ast_map::node_expr(expr)) => {
(ty::expr_ty_adjusted(self.tcx, expr), expr.span)
}
r => self.tcx.sess.bug(format!("Captured({:?}) maps to {:?}, not Expr",
move.id, r))
};
let suggestion = move_suggestion(self.tcx, expr_ty,
"moved by default (make a copy and \
capture that instead to override)");
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 {}",
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)",
_ if ty::type_moves_by_default(tcx, ty) =>
"non-copyable (perhaps you meant to use clone()?)",
_ => default_msg,
}
}
}
pub fn report_reassigned_immutable_variable(&self,
span: Span,
lp: &LoanPath,
assign:
&move_data::Assignment) {
self.tcx.sess.span_err(
span,
2013-09-27 22:38:08 -07:00
format!("re-assignment of immutable variable `{}`",
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"));
}
pub fn span_err(&self, s: Span, m: &str) {
2012-11-28 16:20:41 -08:00
self.tcx.sess.span_err(s, m);
}
pub fn span_note(&self, s: Span, m: &str) {
2012-11-28 16:20:41 -08:00
self.tcx.sess.span_note(s, m);
}
pub fn bckerr_to_str(&self, err: BckError) -> ~str {
2012-11-28 16:20:41 -08:00
match err.code {
err_mutbl(lk) => {
2013-09-27 22:38:08 -07:00
format!("cannot borrow {} {} as {}",
2013-03-15 15:24:24 -04:00
err.cmt.mutbl.to_user_str(),
self.cmt_to_str(err.cmt),
self.mut_to_str(lk))
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(..) => {
2013-09-27 22:38:08 -07:00
format!("borrowed value does not live long enough")
2012-11-28 16:20:41 -08:00
}
2013-03-15 15:24:24 -04:00
err_freeze_aliasable_const => {
// Means that the user borrowed a ~T or enum value
// residing in &const or @const pointer. Terrible
// error message, but then &const and @const are
// supposed to be going away.
2013-09-27 22:38:08 -07:00
format!("unsafe borrow of aliasable, const value")
2012-11-28 16:20:41 -08:00
}
2013-12-09 12:45:13 -05:00
err_borrowed_pointer_too_short(..) => {
let descr = match opt_loan_path(err.cmt) {
Some(lp) => format!("`{}`", self.loan_path_to_str(lp)),
None => self.cmt_to_str(err.cmt),
};
format!("lifetime of {} is too short to guarantee \
its contents can be safely reborrowed",
descr)
}
2013-03-15 15:24:24 -04:00
}
}
pub fn report_aliasability_violation(&self,
span: Span,
kind: AliasableViolationKind,
cause: mc::AliasableReason) {
2013-03-15 15:24:24 -04:00
let prefix = match kind {
MutabilityViolation => "cannot assign to an `&mut`",
BorrowViolation => "cannot borrow an `&mut`"
};
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
}
mc::AliasableManaged => {
self.tcx.sess.span_err(span, format!("{} in a `@` pointer",
prefix))
2013-03-15 15:24:24 -04:00
}
mc::AliasableBorrowed(m) => {
self.tcx.sess.span_err(
span,
2013-09-27 22:38:08 -07:00
format!("{} in a `&{}` pointer; \
2013-03-15 15:24:24 -04:00
try an `&mut` instead",
prefix,
self.mut_to_keyword(m)));
2012-11-28 16:20:41 -08:00
}
}
}
pub fn note_and_explain_bckerr(&self, err: BckError) {
2012-11-28 16:20:41 -08:00
let code = err.code;
match code {
2013-11-28 12:22:53 -08:00
err_mutbl(..) | err_freeze_aliasable_const(..) => {}
2012-11-28 16:20:41 -08:00
err_out_of_root_scope(super_scope, sub_scope) => {
note_and_explain_region(
self.tcx,
"managed value would have to be rooted for ",
2012-11-28 16:20:41 -08:00
sub_scope,
"...");
2012-11-28 16:20:41 -08:00
note_and_explain_region(
self.tcx,
"...but can only be rooted for ",
2012-11-28 16:20:41 -08:00
super_scope,
"");
2012-11-28 16:20:41 -08:00
}
err_out_of_scope(super_scope, sub_scope) => {
note_and_explain_region(
self.tcx,
"borrowed pointer must be valid for ",
2012-11-28 16:20:41 -08:00
sub_scope,
"...");
2012-11-28 16:20:41 -08:00
note_and_explain_region(
self.tcx,
"...but borrowed value is only valid for ",
2012-11-28 16:20:41 -08:00
super_scope,
"");
}
err_borrowed_pointer_too_short(loan_scope, ptr_scope, _) => {
let descr = match opt_loan_path(err.cmt) {
Some(lp) => format!("`{}`", self.loan_path_to_str(lp)),
None => self.cmt_to_str(err.cmt),
};
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
}
}
pub fn append_loan_path_to_str_from_interior(&self,
loan_path: &LoanPath,
out: &mut ~str) {
2013-03-15 15:24:24 -04:00
match *loan_path {
2013-08-20 17:37:49 -04:00
LpExtend(_, _, LpDeref(_)) => {
out.push_char('(');
2013-03-15 15:24:24 -04:00
self.append_loan_path_to_str(loan_path, out);
out.push_char(')');
2013-03-15 15:24:24 -04:00
}
LpExtend(_, _, LpInterior(_)) |
LpVar(_) => {
self.append_loan_path_to_str(loan_path, out);
}
}
}
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) => {
2013-12-27 16:09:29 -08:00
let items = self.tcx.items.borrow();
match items.get().find(&id) {
2014-01-06 14:00:46 +02:00
Some(&ast_map::node_local(ref ident, _)) => {
out.push_str(token::ident_to_str(ident));
2013-03-15 15:24:24 -04:00
}
r => {
self.tcx.sess.bug(
2013-09-27 22:38:08 -07:00
format!("Loan path LpVar({:?}) maps to {:?}, not local",
2013-03-15 15:24:24 -04:00
id, r));
}
}
}
2012-11-28 16:20:41 -08:00
LpExtend(lp_base, _, LpInterior(mc::InteriorField(fname))) => {
2013-03-15 15:24:24 -04:00
self.append_loan_path_to_str_from_interior(lp_base, out);
match fname {
mc::NamedField(ref fname) => {
out.push_char('.');
2013-07-10 13:44:58 -07:00
out.push_str(token::interner_get(*fname));
}
mc::PositionalField(idx) => {
out.push_char('#'); // invent a notation here
out.push_str(idx.to_str());
}
}
2013-03-15 15:24:24 -04:00
}
LpExtend(lp_base, _, LpInterior(mc::InteriorElement(_))) => {
2013-03-15 15:24:24 -04:00
self.append_loan_path_to_str_from_interior(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(_)) => {
out.push_char('*');
2013-03-15 15:24:24 -04:00
self.append_loan_path_to_str(lp_base, out);
}
}
}
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
}
pub fn cmt_to_str(&self, cmt: mc::cmt) -> ~str {
2013-03-15 15:24:24 -04:00
let mc = &mc::mem_categorization_ctxt {tcx: self.tcx,
method_map: self.method_map};
mc.cmt_to_str(cmt)
2012-11-28 16:20:41 -08:00
}
pub fn mut_to_str(&self, mutbl: LoanMutability) -> ~str {
mutbl.to_str()
2012-11-28 16:20:41 -08:00
}
pub fn mut_to_keyword(&self, mutbl: ast::Mutability) -> &'static str {
2013-03-15 15:24:24 -04:00
match mutbl {
ast::MutImmutable => "",
ast::MutMutable => "mut",
}
}
2013-03-15 15:24:24 -04:00
}
impl DataFlowOperator for LoanDataFlowOperator {
#[inline]
2013-03-15 15:24:24 -04:00
fn initial_value(&self) -> bool {
false // no loans in scope by default
}
#[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
}
#[inline]
2013-03-15 15:24:24 -04:00
fn walk_closures(&self) -> bool {
true
}
}
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),
self.mutbl,
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) => {
2013-09-27 22:38:08 -07:00
format!("$({:?})", id)
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
}
}