Add ty to LoanPath.

To make this clean, refactored old `LoanPath` enum into a
`LoanPath` struct with a `ty::t` and a newly-added `LoanPathVariant` enum.

This enabled me to get rid of the ugly and fragile `LoanPath::to_type`
method, and I can probably also get rid of other stuff that was
supporting it, maybe.
This commit is contained in:
Felix S. Klock II 2014-09-18 07:58:26 +02:00
parent d6c8f3b726
commit 91b88c54c2
8 changed files with 206 additions and 175 deletions

View File

@ -19,6 +19,8 @@
use self::UseError::*;
use middle::borrowck::*;
use middle::borrowck::LoanPathElem::*;
use middle::borrowck::LoanPathKind::*;
use middle::expr_use_visitor as euv;
use middle::mem_categorization as mc;
use middle::region;
@ -33,51 +35,51 @@ use std::rc::Rc;
// be less precise in its handling of Box while still allowing moves out of a
// Box. They should be removed when OwnedPtr is removed from LoanPath.
fn owned_ptr_base_path<'a>(loan_path: &'a LoanPath) -> &'a LoanPath {
fn owned_ptr_base_path<'a, 'tcx>(loan_path: &'a LoanPath<'tcx>) -> &'a LoanPath<'tcx> {
//! Returns the base of the leftmost dereference of an OwnedPtr in
//! `loan_path`. If there is no dereference of an OwnedPtr in `loan_path`,
//! then it just returns `loan_path` itself.
return match owned_ptr_base_path_helper(loan_path) {
return match helper(loan_path) {
Some(new_loan_path) => new_loan_path,
None => loan_path.clone()
};
fn owned_ptr_base_path_helper<'a>(loan_path: &'a LoanPath) -> Option<&'a LoanPath> {
match *loan_path {
fn helper<'a, 'tcx>(loan_path: &'a LoanPath<'tcx>) -> Option<&'a LoanPath<'tcx>> {
match loan_path.kind {
LpVar(_) | LpUpvar(_) => None,
LpExtend(ref lp_base, _, LpDeref(mc::OwnedPtr)) => {
match owned_ptr_base_path_helper(&**lp_base) {
match helper(&**lp_base) {
v @ Some(_) => v,
None => Some(&**lp_base)
}
}
LpDowncast(ref lp_base, _) |
LpExtend(ref lp_base, _, _) => owned_ptr_base_path_helper(&**lp_base)
LpExtend(ref lp_base, _, _) => helper(&**lp_base)
}
}
}
fn owned_ptr_base_path_rc(loan_path: &Rc<LoanPath>) -> Rc<LoanPath> {
fn owned_ptr_base_path_rc<'tcx>(loan_path: &Rc<LoanPath<'tcx>>) -> Rc<LoanPath<'tcx>> {
//! The equivalent of `owned_ptr_base_path` for an &Rc<LoanPath> rather than
//! a &LoanPath.
return match owned_ptr_base_path_helper(loan_path) {
return match helper(loan_path) {
Some(new_loan_path) => new_loan_path,
None => loan_path.clone()
};
fn owned_ptr_base_path_helper(loan_path: &Rc<LoanPath>) -> Option<Rc<LoanPath>> {
match **loan_path {
fn helper<'tcx>(loan_path: &Rc<LoanPath<'tcx>>) -> Option<Rc<LoanPath<'tcx>>> {
match loan_path.kind {
LpVar(_) | LpUpvar(_) => None,
LpExtend(ref lp_base, _, LpDeref(mc::OwnedPtr)) => {
match owned_ptr_base_path_helper(lp_base) {
match helper(lp_base) {
v @ Some(_) => v,
None => Some(lp_base.clone())
}
}
LpDowncast(ref lp_base, _) |
LpExtend(ref lp_base, _, _) => owned_ptr_base_path_helper(lp_base)
LpExtend(ref lp_base, _, _) => helper(lp_base)
}
}
}
@ -86,7 +88,7 @@ struct CheckLoanCtxt<'a, 'tcx: 'a> {
bccx: &'a BorrowckCtxt<'a, 'tcx>,
dfcx_loans: &'a LoanDataFlow<'a, 'tcx>,
move_data: move_data::FlowedMoveData<'a, 'tcx>,
all_loans: &'a [Loan],
all_loans: &'a [Loan<'tcx>],
}
impl<'a, 'tcx> euv::Delegate<'tcx> for CheckLoanCtxt<'a, 'tcx> {
@ -185,7 +187,7 @@ impl<'a, 'tcx> euv::Delegate<'tcx> for CheckLoanCtxt<'a, 'tcx> {
pub fn check_loans<'a, 'b, 'c, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>,
dfcx_loans: &LoanDataFlow<'b, 'tcx>,
move_data: move_data::FlowedMoveData<'c, 'tcx>,
all_loans: &[Loan],
all_loans: &[Loan<'tcx>],
decl: &ast::FnDecl,
body: &ast::Block) {
debug!("check_loans(body id={})", body.id);
@ -204,9 +206,9 @@ pub fn check_loans<'a, 'b, 'c, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>,
}
#[deriving(PartialEq)]
enum UseError {
enum UseError<'tcx> {
UseOk,
UseWhileBorrowed(/*loan*/Rc<LoanPath>, /*loan*/Span)
UseWhileBorrowed(/*loan*/Rc<LoanPath<'tcx>>, /*loan*/Span)
}
fn compatible_borrow_kinds(borrow_kind1: ty::BorrowKind,
@ -218,7 +220,7 @@ fn compatible_borrow_kinds(borrow_kind1: ty::BorrowKind,
impl<'a, 'tcx> CheckLoanCtxt<'a, 'tcx> {
pub fn tcx(&self) -> &'a ty::ctxt<'tcx> { self.bccx.tcx }
pub fn each_issued_loan(&self, scope: region::CodeExtent, op: |&Loan| -> bool)
pub fn each_issued_loan(&self, scope: region::CodeExtent, op: |&Loan<'tcx>| -> bool)
-> bool {
//! Iterates over each loan that has been issued
//! on entrance to `scope`, regardless of whether it is
@ -234,7 +236,7 @@ impl<'a, 'tcx> CheckLoanCtxt<'a, 'tcx> {
pub fn each_in_scope_loan(&self,
scope: region::CodeExtent,
op: |&Loan| -> bool)
op: |&Loan<'tcx>| -> bool)
-> bool {
//! Like `each_issued_loan()`, but only considers loans that are
//! currently in scope.
@ -251,8 +253,8 @@ impl<'a, 'tcx> CheckLoanCtxt<'a, 'tcx> {
fn each_in_scope_loan_affecting_path(&self,
scope: region::CodeExtent,
loan_path: &LoanPath,
op: |&Loan| -> bool)
loan_path: &LoanPath<'tcx>,
op: |&Loan<'tcx>| -> bool)
-> bool {
//! Iterates through all of the in-scope loans affecting `loan_path`,
//! calling `op`, and ceasing iteration if `false` is returned.
@ -296,7 +298,7 @@ impl<'a, 'tcx> CheckLoanCtxt<'a, 'tcx> {
let mut loan_path = loan_path;
loop {
match *loan_path {
match loan_path.kind {
LpVar(_) | LpUpvar(_) => {
break;
}
@ -366,8 +368,8 @@ impl<'a, 'tcx> CheckLoanCtxt<'a, 'tcx> {
}
pub fn report_error_if_loans_conflict(&self,
old_loan: &Loan,
new_loan: &Loan) {
old_loan: &Loan<'tcx>,
new_loan: &Loan<'tcx>) {
//! Checks whether `old_loan` and `new_loan` can safely be issued
//! simultaneously.
@ -386,10 +388,10 @@ impl<'a, 'tcx> CheckLoanCtxt<'a, 'tcx> {
}
pub fn report_error_if_loan_conflicts_with_restriction(&self,
loan1: &Loan,
loan2: &Loan,
old_loan: &Loan,
new_loan: &Loan)
loan1: &Loan<'tcx>,
loan2: &Loan<'tcx>,
old_loan: &Loan<'tcx>,
new_loan: &Loan<'tcx>)
-> bool {
//! Checks whether the restrictions introduced by `loan1` would
//! prohibit `loan2`. Returns false if an error is reported.
@ -552,7 +554,7 @@ impl<'a, 'tcx> CheckLoanCtxt<'a, 'tcx> {
true
}
fn is_local_variable_or_arg(&self, cmt: mc::cmt) -> bool {
fn is_local_variable_or_arg(&self, cmt: mc::cmt<'tcx>) -> bool {
match cmt.cat {
mc::cat_local(_) => true,
_ => false
@ -562,7 +564,7 @@ impl<'a, 'tcx> CheckLoanCtxt<'a, 'tcx> {
fn consume_common(&self,
id: ast::NodeId,
span: Span,
cmt: mc::cmt,
cmt: mc::cmt<'tcx>,
mode: euv::ConsumeMode) {
match opt_loan_path(&cmt) {
Some(lp) => {
@ -603,7 +605,7 @@ impl<'a, 'tcx> CheckLoanCtxt<'a, 'tcx> {
fn check_for_copy_of_frozen_path(&self,
id: ast::NodeId,
span: Span,
copy_path: &LoanPath) {
copy_path: &LoanPath<'tcx>) {
match self.analyze_restrictions_on_use(id, copy_path, ty::ImmBorrow) {
UseOk => { }
UseWhileBorrowed(loan_path, loan_span) => {
@ -624,7 +626,7 @@ impl<'a, 'tcx> CheckLoanCtxt<'a, 'tcx> {
fn check_for_move_of_borrowed_path(&self,
id: ast::NodeId,
span: Span,
move_path: &LoanPath,
move_path: &LoanPath<'tcx>,
move_kind: move_data::MoveKind) {
// We want to detect if there are any loans at all, so we search for
// any loans incompatible with MutBorrrow, since all other kinds of
@ -655,9 +657,9 @@ impl<'a, 'tcx> CheckLoanCtxt<'a, 'tcx> {
pub fn analyze_restrictions_on_use(&self,
expr_id: ast::NodeId,
use_path: &LoanPath,
use_path: &LoanPath<'tcx>,
borrow_kind: ty::BorrowKind)
-> UseError {
-> UseError<'tcx> {
debug!("analyze_restrictions_on_use(expr_id={}, use_path={})",
self.tcx().map.node_to_string(expr_id),
use_path.repr(self.tcx()));
@ -681,7 +683,7 @@ impl<'a, 'tcx> CheckLoanCtxt<'a, 'tcx> {
id: ast::NodeId,
span: Span,
use_kind: MovedValueUseKind,
lp: &Rc<LoanPath>) {
lp: &Rc<LoanPath<'tcx>>) {
/*!
* Reports an error if `expr` (which should be a path)
* is using a moved/uninitialized value
@ -705,7 +707,7 @@ impl<'a, 'tcx> CheckLoanCtxt<'a, 'tcx> {
id: ast::NodeId,
span: Span,
use_kind: MovedValueUseKind,
lp: &Rc<LoanPath>)
lp: &Rc<LoanPath<'tcx>>)
{
/*!
* Reports an error if assigning to `lp` will use a
@ -725,7 +727,7 @@ impl<'a, 'tcx> CheckLoanCtxt<'a, 'tcx> {
* (*p).x = 22; // not ok, p is uninitialized, can't deref
*/
match **lp {
match lp.kind {
LpVar(_) | LpUpvar(_) => {
// assigning to `x` does not require that `x` is initialized
}
@ -923,11 +925,11 @@ impl<'a, 'tcx> CheckLoanCtxt<'a, 'tcx> {
}
}
fn check_for_assignment_to_borrowed_path(
this: &CheckLoanCtxt,
fn check_for_assignment_to_borrowed_path<'a, 'tcx>(
this: &CheckLoanCtxt<'a, 'tcx>,
assignment_id: ast::NodeId,
assignment_span: Span,
assignee_cmt: mc::cmt)
assignee_cmt: mc::cmt<'tcx>)
{
//! Check for assignments that violate the terms of an
//! outstanding loan.
@ -947,7 +949,7 @@ impl<'a, 'tcx> CheckLoanCtxt<'a, 'tcx> {
pub fn report_illegal_mutation(&self,
span: Span,
loan_path: &LoanPath,
loan_path: &LoanPath<'tcx>,
loan: &Loan) {
self.bccx.span_err(
span,

View File

@ -13,6 +13,7 @@
*/
use middle::borrowck::*;
use middle::borrowck::LoanPathKind::*;
use middle::borrowck::gather_loans::move_error::MoveSpanAndPath;
use middle::borrowck::gather_loans::move_error::{MoveError, MoveErrorCollector};
use middle::borrowck::move_data::*;
@ -32,17 +33,18 @@ struct GatherMoveInfo<'tcx> {
span_path_opt: Option<MoveSpanAndPath>
}
pub fn gather_decl(bccx: &BorrowckCtxt,
move_data: &MoveData,
decl_id: ast::NodeId,
_decl_span: Span,
var_id: ast::NodeId) {
let loan_path = Rc::new(LpVar(var_id));
pub fn gather_decl<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>,
move_data: &MoveData<'tcx>,
decl_id: ast::NodeId,
_decl_span: Span,
var_id: ast::NodeId) {
let ty = ty::node_id_to_type(bccx.tcx, var_id);
let loan_path = Rc::new(LoanPath::new(LpVar(var_id), ty));
move_data.add_move(bccx.tcx, loan_path, decl_id, Declared);
}
pub fn gather_move_from_expr<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>,
move_data: &MoveData,
move_data: &MoveData<'tcx>,
move_error_collector: &MoveErrorCollector<'tcx>,
move_expr_id: ast::NodeId,
cmt: mc::cmt<'tcx>,
@ -61,7 +63,7 @@ pub fn gather_move_from_expr<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>,
}
pub fn gather_move_from_pat<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>,
move_data: &MoveData,
move_data: &MoveData<'tcx>,
move_error_collector: &MoveErrorCollector<'tcx>,
move_pat: &ast::Pat,
cmt: mc::cmt<'tcx>) {
@ -82,7 +84,7 @@ pub fn gather_move_from_pat<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>,
}
fn gather_move<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>,
move_data: &MoveData,
move_data: &MoveData<'tcx>,
move_error_collector: &MoveErrorCollector<'tcx>,
move_info: GatherMoveInfo<'tcx>) {
debug!("gather_move(move_id={}, cmt={})",
@ -112,13 +114,13 @@ fn gather_move<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>,
}
}
pub fn gather_assignment(bccx: &BorrowckCtxt,
move_data: &MoveData,
assignment_id: ast::NodeId,
assignment_span: Span,
assignee_loan_path: Rc<LoanPath>,
assignee_id: ast::NodeId,
mode: euv::MutateMode) {
pub fn gather_assignment<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>,
move_data: &MoveData<'tcx>,
assignment_id: ast::NodeId,
assignment_span: Span,
assignee_loan_path: Rc<LoanPath<'tcx>>,
assignee_id: ast::NodeId,
mode: euv::MutateMode) {
move_data.add_assignment(bccx.tcx,
assignee_loan_path,
assignment_id,

View File

@ -17,6 +17,7 @@
// sure that all of these loans are honored.
use middle::borrowck::*;
use middle::borrowck::LoanPathKind::*;
use middle::borrowck::move_data::MoveData;
use middle::expr_use_visitor as euv;
use middle::mem_categorization as mc;
@ -35,10 +36,10 @@ mod restrictions;
mod gather_moves;
mod move_error;
pub fn gather_loans_in_fn(bccx: &BorrowckCtxt,
decl: &ast::FnDecl,
body: &ast::Block)
-> (Vec<Loan>, move_data::MoveData)
pub fn gather_loans_in_fn<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>,
decl: &ast::FnDecl,
body: &ast::Block)
-> (Vec<Loan<'tcx>>, move_data::MoveData<'tcx>)
{
let mut glcx = GatherLoanCtxt {
bccx: bccx,
@ -60,9 +61,9 @@ pub fn gather_loans_in_fn(bccx: &BorrowckCtxt,
struct GatherLoanCtxt<'a, 'tcx: 'a> {
bccx: &'a BorrowckCtxt<'a, 'tcx>,
move_data: move_data::MoveData,
move_data: move_data::MoveData<'tcx>,
move_error_collector: move_error::MoveErrorCollector<'tcx>,
all_loans: Vec<Loan>,
all_loans: Vec<Loan<'tcx>>,
/// `item_ub` is used as an upper-bound on the lifetime whenever we
/// ask for the scope of an expression categorized as an upvar.
item_ub: region::CodeExtent,
@ -395,7 +396,7 @@ impl<'a, 'tcx> GatherLoanCtxt<'a, 'tcx> {
//! For mutable loans of content whose mutability derives
//! from a local variable, mark the mutability decl as necessary.
match *loan_path {
match loan_path.kind {
LpVar(local_id) |
LpUpvar(ty::UpvarId{ var_id: local_id, closure_expr_id: _ }) => {
self.tcx().used_mut_nodes.borrow_mut().insert(local_id);
@ -427,7 +428,7 @@ impl<'a, 'tcx> GatherLoanCtxt<'a, 'tcx> {
}
}
pub fn compute_kill_scope(&self, loan_scope: region::CodeExtent, lp: &LoanPath)
pub fn compute_kill_scope(&self, loan_scope: region::CodeExtent, lp: &LoanPath<'tcx>)
-> region::CodeExtent {
//! Determine when the loan restrictions go out of scope.
//! This is either when the lifetime expires or when the

View File

@ -15,6 +15,8 @@
pub use self::RestrictionResult::*;
use middle::borrowck::*;
use middle::borrowck::LoanPathElem::*;
use middle::borrowck::LoanPathKind::*;
use middle::expr_use_visitor as euv;
use middle::mem_categorization as mc;
use middle::ty;
@ -24,9 +26,9 @@ use util::ppaux::Repr;
use std::rc::Rc;
#[deriving(Show)]
pub enum RestrictionResult {
pub enum RestrictionResult<'tcx> {
Safe,
SafeIf(Rc<LoanPath>, Vec<Rc<LoanPath>>)
SafeIf(Rc<LoanPath<'tcx>>, Vec<Rc<LoanPath<'tcx>>>)
}
pub fn compute_restrictions<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>,
@ -34,7 +36,7 @@ pub fn compute_restrictions<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>,
cause: euv::LoanCause,
cmt: mc::cmt<'tcx>,
loan_region: ty::Region)
-> RestrictionResult {
-> RestrictionResult<'tcx> {
let ctxt = RestrictionsContext {
bccx: bccx,
span: span,
@ -57,9 +59,11 @@ struct RestrictionsContext<'a, 'tcx: 'a> {
impl<'a, 'tcx> RestrictionsContext<'a, 'tcx> {
fn restrict(&self,
cmt: mc::cmt<'tcx>) -> RestrictionResult {
cmt: mc::cmt<'tcx>) -> RestrictionResult<'tcx> {
debug!("restrict(cmt={})", cmt.repr(self.bccx.tcx));
let new_lp = |v: LoanPathKind<'tcx>| Rc::new(LoanPath::new(v, cmt.ty));
match cmt.cat.clone() {
mc::cat_rvalue(..) => {
// Effectively, rvalues are stored into a
@ -72,13 +76,13 @@ impl<'a, 'tcx> RestrictionsContext<'a, 'tcx> {
mc::cat_local(local_id) => {
// R-Variable, locally declared
let lp = Rc::new(LpVar(local_id));
let lp = new_lp(LpVar(local_id));
SafeIf(lp.clone(), vec![lp])
}
mc::cat_upvar(mc::Upvar { id, .. }) => {
// R-Variable, captured into closure
let lp = Rc::new(LpUpvar(id));
let lp = new_lp(LpUpvar(id));
SafeIf(lp.clone(), vec![lp])
}
@ -96,10 +100,9 @@ impl<'a, 'tcx> RestrictionsContext<'a, 'tcx> {
// the memory, so no additional restrictions are
// needed.
let result = self.restrict(cmt_base);
self.extend(result, cmt.mutbl, LpInterior(i))
self.extend(result, &cmt, LpInterior(i))
}
mc::cat_static_item(..) => {
Safe
}
@ -116,7 +119,7 @@ impl<'a, 'tcx> RestrictionsContext<'a, 'tcx> {
// Eventually we should make these non-special and
// just rely on Deref<T> implementation.
let result = self.restrict(cmt_base);
self.extend(result, cmt.mutbl, LpDeref(pk))
self.extend(result, &cmt, LpDeref(pk))
}
mc::Implicit(bk, lt) | mc::BorrowedPtr(bk, lt) => {
// R-Deref-[Mut-]Borrowed
@ -140,7 +143,7 @@ impl<'a, 'tcx> RestrictionsContext<'a, 'tcx> {
// references lifetime ends (by a newly-unfrozen
// borrow).
let result = self.restrict(cmt_base);
self.extend(result, cmt.mutbl, LpDeref(pk))
self.extend(result, &cmt, LpDeref(pk))
}
}
}
@ -152,13 +155,14 @@ impl<'a, 'tcx> RestrictionsContext<'a, 'tcx> {
}
fn extend(&self,
result: RestrictionResult,
mc: mc::MutabilityCategory,
elem: LoanPathElem) -> RestrictionResult {
result: RestrictionResult<'tcx>,
cmt: &mc::cmt<'tcx>,
elem: LoanPathElem) -> RestrictionResult<'tcx> {
match result {
Safe => Safe,
SafeIf(base_lp, mut base_vec) => {
let lp = Rc::new(LpExtend(base_lp, mc, elem));
let v = LpExtend(base_lp, cmt.mutbl, elem);
let lp = Rc::new(LoanPath::new(v, cmt.ty));
base_vec.push(lp.clone());
SafeIf(lp, base_vec)
}

View File

@ -80,7 +80,7 @@ impl<'a, 'tcx> DataflowLabeller<'a, 'tcx> {
e: EntryOrExit,
cfgidx: CFGIndex,
dfcx: &DataFlowContext<'a, 'tcx, O>,
to_lp: |uint| -> Rc<LoanPath>) -> String {
to_lp: |uint| -> Rc<LoanPath<'tcx>>) -> String {
let mut saw_some = false;
let mut set = "{".to_string();
dfcx.each_bit_for_node(e, cfgidx, |index| {

View File

@ -12,7 +12,7 @@
#![allow(non_camel_case_types)]
pub use self::LoanPath::*;
pub use self::LoanPathKind::*;
pub use self::LoanPathElem::*;
pub use self::bckerr_code::*;
pub use self::AliasableViolationKind::*;
@ -125,7 +125,7 @@ fn borrowck_item(this: &mut BorrowckCtxt, item: &ast::Item) {
/// Collection of conclusions determined via borrow checker analyses.
pub struct AnalysisData<'a, 'tcx: 'a> {
pub all_loans: Vec<Loan>,
pub all_loans: Vec<Loan<'tcx>>,
pub loans: DataFlowContext<'a, 'tcx, LoanDataFlowOperator>,
pub move_data: move_data::FlowedMoveData<'a, 'tcx>,
}
@ -254,11 +254,11 @@ pub type BckResult<'tcx, T> = Result<T, BckError<'tcx>>;
// Loans and loan paths
/// Record of a loan that was issued.
pub struct Loan {
pub struct Loan<'tcx> {
index: uint,
loan_path: Rc<LoanPath>,
loan_path: Rc<LoanPath<'tcx>>,
kind: ty::BorrowKind,
restricted_paths: Vec<Rc<LoanPath>>,
restricted_paths: Vec<Rc<LoanPath<'tcx>>>,
/// gen_scope indicates where loan is introduced. Typically the
/// loan is introduced at the point of the borrow, but in some
@ -276,33 +276,31 @@ pub struct Loan {
cause: euv::LoanCause,
}
impl Loan {
pub fn loan_path(&self) -> Rc<LoanPath> {
impl<'tcx> Loan<'tcx> {
pub fn loan_path(&self) -> Rc<LoanPath<'tcx>> {
self.loan_path.clone()
}
}
#[deriving(PartialEq, Eq, Hash, Show)]
pub enum LoanPath {
LpVar(ast::NodeId), // `x` in doc.rs
LpUpvar(ty::UpvarId), // `x` captured by-value into closure
LpDowncast(Rc<LoanPath>, ast::DefId), // `x` downcast to particular enum variant
LpExtend(Rc<LoanPath>, mc::MutabilityCategory, LoanPathElem)
pub struct LoanPath<'tcx> {
kind: LoanPathKind<'tcx>,
ty: ty::Ty<'tcx>,
}
impl LoanPath {
fn kill_id(&self, tcx: &ty::ctxt) -> ast::NodeId {
//! Returns the lifetime of the local variable that forms the
//! base of this path. (See move_data::add_gen_kills.)
match *self {
LpVar(id) =>
tcx.region_maps.var_scope(id),
LpUpvar(ty::UpvarId { var_id: _, closure_expr_id }) =>
closure_to_block(closure_expr_id, tcx),
LpDowncast(ref base_lp, _) | LpExtend(ref base_lp, _, _) =>
base_lp.kill_id(tcx),
}
#[deriving(PartialEq, Eq, Hash, Show)]
pub enum LoanPathKind<'tcx> {
LpVar(ast::NodeId), // `x` in doc.rs
LpUpvar(ty::UpvarId), // `x` captured by-value into closure
LpDowncast(Rc<LoanPath<'tcx>>, ast::DefId), // `x` downcast to particular enum variant
LpExtend(Rc<LoanPath<'tcx>>, mc::MutabilityCategory, LoanPathElem)
}
impl<'tcx> LoanPath<'tcx> {
fn new(kind: LoanPathKind<'tcx>, ty: ty::Ty<'tcx>) -> LoanPath<'tcx> {
LoanPath { kind: kind, ty: ty }
}
}
#[deriving(PartialEq, Eq, Hash, Show)]
@ -312,7 +310,7 @@ pub enum LoanPathElem {
}
pub fn closure_to_block(closure_id: ast::NodeId,
tcx: &ty::ctxt) -> ast::NodeId {
tcx: &ty::ctxt) -> ast::NodeId {
match tcx.map.get(closure_id) {
ast_map::NodeExpr(expr) => match expr.node {
ast::ExprProc(_, ref block) |
@ -327,9 +325,9 @@ pub fn closure_to_block(closure_id: ast::NodeId,
}
}
impl LoanPath {
pub fn kill_scope(&self, tcx: &ty::ctxt) -> region::CodeExtent {
match *self {
impl<'tcx> LoanPath<'tcx> {
pub fn kill_scope(&self, tcx: &ty::ctxt<'tcx>) -> region::CodeExtent {
match self.kind {
LpVar(local_id) => tcx.region_maps.var_scope(local_id),
LpUpvar(upvar_id) => {
let block_id = closure_to_block(upvar_id.closure_expr_id, tcx);
@ -340,8 +338,8 @@ impl LoanPath {
}
}
fn has_fork(&self, other: &LoanPath) -> bool {
match (self, other) {
fn has_fork(&self, other: &LoanPath<'tcx>) -> bool {
match (&self.kind, &other.kind) {
(&LpExtend(ref base, _, LpInterior(id)), &LpExtend(ref base2, _, LpInterior(id2))) =>
if id == id2 {
base.has_fork(&**base2)
@ -355,44 +353,66 @@ impl LoanPath {
}
fn depth(&self) -> uint {
match *self {
match self.kind {
LpExtend(ref base, _, LpDeref(_)) => base.depth(),
LpExtend(ref base, _, LpInterior(_)) => base.depth() + 1,
_ => 0,
}
}
fn common(&self, other: &LoanPath) -> Option<LoanPath> {
match (self, other) {
(&LpExtend(ref base, a, LpInterior(id)), &LpExtend(ref base2, _, LpInterior(id2))) =>
fn common(&self, other: &LoanPath<'tcx>) -> Option<LoanPath<'tcx>> {
match (&self.kind, &other.kind) {
(&LpExtend(ref base, a, LpInterior(id)),
&LpExtend(ref base2, _, LpInterior(id2))) => {
if id == id2 {
assert!(self.ty == other.ty);
base.common(&**base2).map(|x| {
let xd = x.depth();
if base.depth() == xd && base2.depth() == xd {
LpExtend(Rc::new(x), a, LpInterior(id))
LoanPath {
kind: LpExtend(Rc::new(x), a, LpInterior(id)),
ty: self.ty,
}
} else {
x
}
})
} else {
base.common(&**base2)
},
}
}
(&LpExtend(ref base, _, LpDeref(_)), _) => base.common(other),
(_, &LpExtend(ref other, _, LpDeref(_))) => self.common(&**other),
(&LpVar(id), &LpVar(id2)) => if id == id2 { Some(LpVar(id)) } else { None },
(&LpUpvar(id), &LpUpvar(id2)) => if id == id2 { Some(LpUpvar(id)) } else { None },
(&LpVar(id), &LpVar(id2)) => {
if id == id2 {
assert!(self.ty == other.ty);
Some(LoanPath { kind: LpVar(id), ty: self.ty })
} else {
None
}
}
(&LpUpvar(id), &LpUpvar(id2)) => {
if id == id2 {
assert!(self.ty == other.ty);
Some(LoanPath { kind: LpUpvar(id), ty: self.ty })
} else {
None
}
}
_ => None,
}
}
}
pub fn opt_loan_path(cmt: &mc::cmt) -> Option<Rc<LoanPath>> {
pub fn opt_loan_path<'tcx>(cmt: &mc::cmt<'tcx>) -> Option<Rc<LoanPath<'tcx>>> {
//! 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.
let new_lp = |v: LoanPathKind<'tcx>| Rc::new(LoanPath::new(v, cmt.ty));
match cmt.cat {
mc::cat_rvalue(..) |
mc::cat_static_item => {
@ -400,29 +420,29 @@ pub fn opt_loan_path(cmt: &mc::cmt) -> Option<Rc<LoanPath>> {
}
mc::cat_local(id) => {
Some(Rc::new(LpVar(id)))
Some(new_lp(LpVar(id)))
}
mc::cat_upvar(mc::Upvar { id, .. }) => {
Some(Rc::new(LpUpvar(id)))
Some(new_lp(LpUpvar(id)))
}
mc::cat_deref(ref cmt_base, _, pk) => {
opt_loan_path(cmt_base).map(|lp| {
Rc::new(LpExtend(lp, cmt.mutbl, LpDeref(pk)))
new_lp(LpExtend(lp, cmt.mutbl, LpDeref(pk)))
})
}
mc::cat_interior(ref cmt_base, ik) => {
opt_loan_path(cmt_base).map(|lp| {
Rc::new(LpExtend(lp, cmt.mutbl, LpInterior(ik)))
new_lp(LpExtend(lp, cmt.mutbl, LpInterior(ik)))
})
}
mc::cat_downcast(ref cmt_base, variant_def_id) =>
opt_loan_path(cmt_base)
.map(|lp| {
Rc::new(LpDowncast(lp, variant_def_id))
new_lp(LpDowncast(lp, variant_def_id))
}),
}
@ -492,9 +512,9 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> {
pub fn report_use_of_moved_value(&self,
use_span: Span,
use_kind: MovedValueUseKind,
lp: &LoanPath,
lp: &LoanPath<'tcx>,
the_move: &move_data::Move,
moved_lp: &LoanPath) {
moved_lp: &LoanPath<'tcx>) {
let verb = match use_kind {
MovedInUse => "use",
MovedInCapture => "capture",
@ -643,7 +663,7 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> {
pub fn report_reassigned_immutable_variable(&self,
span: Span,
lp: &LoanPath,
lp: &LoanPath<'tcx>,
assign:
&move_data::Assignment) {
self.tcx.sess.span_err(
@ -874,9 +894,9 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> {
}
pub fn append_loan_path_to_string(&self,
loan_path: &LoanPath,
out: &mut String) {
match *loan_path {
loan_path: &LoanPath<'tcx>,
out: &mut String) {
match loan_path.kind {
LpUpvar(ty::UpvarId{ var_id: id, closure_expr_id: _ }) |
LpVar(id) => {
out.push_str(ty::local_var_name_str(self.tcx, id).get());
@ -918,9 +938,9 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> {
}
pub fn append_autoderefd_loan_path_to_string(&self,
loan_path: &LoanPath,
out: &mut String) {
match *loan_path {
loan_path: &LoanPath<'tcx>,
out: &mut String) {
match loan_path.kind {
LpExtend(ref lp_base, _, LpDeref(_)) => {
// For a path like `(*x).f` or `(*x)[3]`, autoderef
// rules would normally allow users to omit the `*x`.
@ -942,7 +962,7 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> {
}
}
pub fn loan_path_to_string(&self, loan_path: &LoanPath) -> String {
pub fn loan_path_to_string(&self, loan_path: &LoanPath<'tcx>) -> String {
let mut result = String::new();
self.append_loan_path_to_string(loan_path, &mut result);
result
@ -979,8 +999,8 @@ impl DataFlowOperator for LoanDataFlowOperator {
}
}
impl<'tcx> Repr<'tcx> for Loan {
fn repr(&self, tcx: &ty::ctxt) -> String {
impl<'tcx> Repr<'tcx> for Loan<'tcx> {
fn repr(&self, tcx: &ty::ctxt<'tcx>) -> String {
format!("Loan_{}({}, {}, {}-{}, {})",
self.index,
self.loan_path.repr(tcx),
@ -991,19 +1011,19 @@ impl<'tcx> Repr<'tcx> for Loan {
}
}
impl<'tcx> Repr<'tcx> for LoanPath {
fn repr(&self, tcx: &ty::ctxt) -> String {
match self {
&LpVar(id) => {
impl<'tcx> Repr<'tcx> for LoanPath<'tcx> {
fn repr(&self, tcx: &ty::ctxt<'tcx>) -> String {
match self.kind {
LpVar(id) => {
format!("$({})", tcx.map.node_to_string(id))
}
&LpUpvar(ty::UpvarId{ var_id, closure_expr_id }) => {
LpUpvar(ty::UpvarId{ var_id, closure_expr_id }) => {
let s = tcx.map.node_to_string(var_id);
format!("$({} captured by id={})", s, closure_expr_id)
}
&LpDowncast(ref lp, variant_def_id) => {
LpDowncast(ref lp, variant_def_id) => {
let variant_str = if variant_def_id.krate == ast::LOCAL_CRATE {
ty::item_path_str(tcx, variant_def_id)
} else {
@ -1012,11 +1032,11 @@ impl<'tcx> Repr<'tcx> for LoanPath {
format!("({}->{})", lp.repr(tcx), variant_str)
}
&LpExtend(ref lp, _, LpDeref(_)) => {
LpExtend(ref lp, _, LpDeref(_)) => {
format!("{}.*", lp.repr(tcx))
}
&LpExtend(ref lp, _, LpInterior(ref interior)) => {
LpExtend(ref lp, _, LpInterior(ref interior)) => {
format!("{}.{}", lp.repr(tcx), interior.repr(tcx))
}
}

View File

@ -21,6 +21,8 @@ use std::cell::RefCell;
use std::rc::Rc;
use std::uint;
use middle::borrowck::*;
use middle::borrowck::LoanPathKind::{LpVar, LpUpvar, LpDowncast, LpExtend};
use middle::borrowck::LoanPathElem::{LpInterior};
use middle::cfg;
use middle::dataflow::DataFlowContext;
use middle::dataflow::BitwiseOperator;
@ -34,12 +36,12 @@ use syntax::codemap::Span;
use util::nodemap::{FnvHashMap, NodeSet};
use util::ppaux::Repr;
pub struct MoveData {
pub struct MoveData<'tcx> {
/// Move paths. See section "Move paths" in `doc.rs`.
pub paths: RefCell<Vec<MovePath>>,
pub paths: RefCell<Vec<MovePath<'tcx>>>,
/// Cache of loan path to move path index, for easy lookup.
pub path_map: RefCell<FnvHashMap<Rc<LoanPath>, MovePathIndex>>,
pub path_map: RefCell<FnvHashMap<Rc<LoanPath<'tcx>>, MovePathIndex>>,
/// Each move or uninitialized variable gets an entry here.
pub moves: RefCell<Vec<Move>>,
@ -59,7 +61,7 @@ pub struct MoveData {
}
pub struct FlowedMoveData<'a, 'tcx: 'a> {
pub move_data: MoveData,
pub move_data: MoveData<'tcx>,
pub dfcx_moves: MoveDataFlow<'a, 'tcx>,
@ -103,9 +105,9 @@ impl MoveIndex {
static InvalidMoveIndex: MoveIndex =
MoveIndex(uint::MAX);
pub struct MovePath {
pub struct MovePath<'tcx> {
/// Loan path corresponding to this move path
pub loan_path: Rc<LoanPath>,
pub loan_path: Rc<LoanPath<'tcx>>,
/// Parent pointer, `InvalidMovePathIndex` if root
pub parent: MovePathIndex,
@ -166,7 +168,7 @@ pub struct AssignDataFlowOperator;
pub type AssignDataFlow<'a, 'tcx> = DataFlowContext<'a, 'tcx, AssignDataFlowOperator>;
fn loan_path_is_precise(loan_path: &LoanPath) -> bool {
match *loan_path {
match loan_path.kind {
LpVar(_) | LpUpvar(_) => {
true
}
@ -182,8 +184,8 @@ fn loan_path_is_precise(loan_path: &LoanPath) -> bool {
}
}
impl MoveData {
pub fn new() -> MoveData {
impl<'tcx> MoveData<'tcx> {
pub fn new() -> MoveData<'tcx> {
MoveData {
paths: RefCell::new(Vec::new()),
path_map: RefCell::new(FnvHashMap::new()),
@ -194,7 +196,7 @@ impl MoveData {
}
}
pub fn path_loan_path(&self, index: MovePathIndex) -> Rc<LoanPath> {
pub fn path_loan_path(&self, index: MovePathIndex) -> Rc<LoanPath<'tcx>> {
(*self.paths.borrow())[index.get()].loan_path.clone()
}
@ -237,8 +239,8 @@ impl MoveData {
}
pub fn move_path(&self,
tcx: &ty::ctxt,
lp: Rc<LoanPath>) -> MovePathIndex {
tcx: &ty::ctxt<'tcx>,
lp: Rc<LoanPath<'tcx>>) -> MovePathIndex {
/*!
* Returns the existing move path index for `lp`, if any,
* and otherwise adds a new index for `lp` and any of its
@ -252,7 +254,7 @@ impl MoveData {
None => {}
}
let index = match *lp {
let index = match lp.kind {
LpVar(..) | LpUpvar(..) => {
let index = MovePathIndex(self.paths.borrow().len());
@ -297,19 +299,19 @@ impl MoveData {
return index;
}
fn existing_move_path(&self, lp: &Rc<LoanPath>)
fn existing_move_path(&self, lp: &Rc<LoanPath<'tcx>>)
-> Option<MovePathIndex> {
self.path_map.borrow().get(lp).cloned()
}
fn existing_base_paths(&self, lp: &Rc<LoanPath>)
fn existing_base_paths(&self, lp: &Rc<LoanPath<'tcx>>)
-> Vec<MovePathIndex> {
let mut result = vec!();
self.add_existing_base_paths(lp, &mut result);
result
}
fn add_existing_base_paths(&self, lp: &Rc<LoanPath>,
fn add_existing_base_paths(&self, lp: &Rc<LoanPath<'tcx>>,
result: &mut Vec<MovePathIndex>) {
/*!
* Adds any existing move path indices for `lp` and any base
@ -324,7 +326,7 @@ impl MoveData {
});
}
None => {
match **lp {
match lp.kind {
LpVar(..) | LpUpvar(..) => { }
LpDowncast(ref b, _) |
LpExtend(ref b, _, _) => {
@ -337,8 +339,8 @@ impl MoveData {
}
pub fn add_move(&self,
tcx: &ty::ctxt,
lp: Rc<LoanPath>,
tcx: &ty::ctxt<'tcx>,
lp: Rc<LoanPath<'tcx>>,
id: ast::NodeId,
kind: MoveKind) {
/*!
@ -366,8 +368,8 @@ impl MoveData {
}
pub fn add_assignment(&self,
tcx: &ty::ctxt,
lp: Rc<LoanPath>,
tcx: &ty::ctxt<'tcx>,
lp: Rc<LoanPath<'tcx>>,
assign_id: ast::NodeId,
span: Span,
assignee_id: ast::NodeId,
@ -409,7 +411,7 @@ impl MoveData {
}
fn add_gen_kills(&self,
tcx: &ty::ctxt,
tcx: &ty::ctxt<'tcx>,
dfcx_moves: &mut MoveDataFlow,
dfcx_assign: &mut AssignDataFlow) {
/*!
@ -436,10 +438,10 @@ impl MoveData {
// Kill all moves related to a variable `x` when it goes out
// of scope:
for path in self.paths.borrow().iter() {
match *path.loan_path {
match path.loan_path.kind {
LpVar(..) | LpUpvar(..) | LpDowncast(..) => {
let kill_scope = path.loan_path.kill_scope(tcx);
let path = *self.path_map.borrow().get(&path.loan_path);
let path = self.path_map.borrow()[path.loan_path];
self.kill_moves(path, kill_scope.node_id(), dfcx_moves);
}
LpExtend(..) => {}
@ -450,7 +452,7 @@ impl MoveData {
for (assignment_index, assignment) in
self.var_assignments.borrow().iter().enumerate() {
let lp = self.path_loan_path(assignment.path);
match *lp {
match lp.kind {
LpVar(..) | LpUpvar(..) | LpDowncast(..) => {
let kill_scope = lp.kill_scope(tcx);
dfcx_assign.add_kill(kill_scope.node_id(), assignment_index);
@ -531,7 +533,7 @@ impl MoveData {
}
impl<'a, 'tcx> FlowedMoveData<'a, 'tcx> {
pub fn new(move_data: MoveData,
pub fn new(move_data: MoveData<'tcx>,
tcx: &'a ty::ctxt<'tcx>,
cfg: &cfg::CFG,
id_range: ast_util::IdRange,
@ -569,7 +571,7 @@ impl<'a, 'tcx> FlowedMoveData<'a, 'tcx> {
pub fn kind_of_move_of_path(&self,
id: ast::NodeId,
loan_path: &Rc<LoanPath>)
loan_path: &Rc<LoanPath<'tcx>>)
-> Option<MoveKind> {
//! Returns the kind of a move of `loan_path` by `id`, if one exists.
@ -591,8 +593,8 @@ impl<'a, 'tcx> FlowedMoveData<'a, 'tcx> {
pub fn each_move_of(&self,
id: ast::NodeId,
loan_path: &Rc<LoanPath>,
f: |&Move, &LoanPath| -> bool)
loan_path: &Rc<LoanPath<'tcx>>,
f: |&Move, &LoanPath<'tcx>| -> bool)
-> bool {
/*!
* Iterates through each move of `loan_path` (or some base path
@ -651,7 +653,7 @@ impl<'a, 'tcx> FlowedMoveData<'a, 'tcx> {
pub fn each_assignment_of(&self,
id: ast::NodeId,
loan_path: &Rc<LoanPath>,
loan_path: &Rc<LoanPath<'tcx>>,
f: |&Assignment| -> bool)
-> bool {
/*!

View File

@ -98,7 +98,7 @@ pub enum categorization<'tcx> {
cat_local(ast::NodeId), // local variable
cat_deref(cmt<'tcx>, uint, PointerKind), // deref of a ptr
cat_interior(cmt<'tcx>, InteriorKind), // something interior: field, tuple, etc
cat_downcast(cmt, ast::DefId), // selects a particular enum variant (*1)
cat_downcast(cmt<'tcx>, ast::DefId), // selects a particular enum variant (*1)
// (*1) downcast is only required if the enum has more than one variant
}
@ -1118,7 +1118,7 @@ impl<'t,'tcx,TYPER:Typer<'tcx>> MemCategorizationContext<'t,TYPER> {
pub fn cat_pattern(&self,
cmt: cmt<'tcx>,
pat: &ast::Pat,
op: |&MemCategorizationContext<TYPER>,
op: |&MemCategorizationContext<'t,TYPER>,
cmt<'tcx>,
&ast::Pat|)
-> McResult<()> {