Track kind of closure in upvar categorization

Keep track of the kind of closure responsible for an upvar
This commit is contained in:
Brian Koropoff 2014-10-04 14:04:10 -07:00
parent 20f4c45bad
commit ea3ab731a3
6 changed files with 61 additions and 33 deletions

View File

@ -133,16 +133,15 @@ fn check_and_get_illegal_move_origin(bccx: &BorrowckCtxt,
mc::cat_deref(_, _, mc::BorrowedPtr(..)) |
mc::cat_deref(_, _, mc::Implicit(..)) |
mc::cat_deref(_, _, mc::UnsafePtr(..)) |
mc::cat_upvar(..) | mc::cat_static_item |
mc::cat_copied_upvar(mc::CopiedUpvar { onceness: ast::Many, .. }) => {
mc::cat_upvar(..) | mc::cat_static_item => {
Some(cmt.clone())
}
// Can move out of captured upvars only if the destination closure
// type is 'once'. 1-shot stack closures emit the copied_upvar form
// (see mem_categorization.rs).
mc::cat_copied_upvar(mc::CopiedUpvar { onceness: ast::Once, .. }) => {
None
mc::cat_copied_upvar(mc::CopiedUpvar { kind: kind, .. }) => {
match kind.onceness() {
ast::Once => None,
ast::Many => Some(cmt.clone())
}
}
mc::cat_rvalue(..) |

View File

@ -115,8 +115,15 @@ fn report_cannot_move_out_of(bccx: &BorrowckCtxt, move_from: mc::cmt) {
mc::cat_deref(_, _, mc::BorrowedPtr(..)) |
mc::cat_deref(_, _, mc::Implicit(..)) |
mc::cat_deref(_, _, mc::UnsafePtr(..)) |
mc::cat_upvar(..) | mc::cat_static_item |
mc::cat_copied_upvar(mc::CopiedUpvar { onceness: ast::Many, .. }) => {
mc::cat_upvar(..) | mc::cat_static_item => {
bccx.span_err(
move_from.span,
format!("cannot move out of {}",
bccx.cmt_to_string(&*move_from)).as_slice());
}
mc::cat_copied_upvar(mc::CopiedUpvar { kind: kind, .. })
if kind.onceness() == ast::Many => {
bccx.span_err(
move_from.span,
format!("cannot move out of {}",

View File

@ -72,7 +72,7 @@ impl<'a, 'tcx> RestrictionsContext<'a, 'tcx> {
SafeIf(lp.clone(), vec![lp])
}
mc::cat_upvar(upvar_id, _) => {
mc::cat_upvar(upvar_id, _, _) => {
// R-Variable, captured into closure
let lp = Rc::new(LpUpvar(upvar_id));
SafeIf(lp.clone(), vec![lp])

View File

@ -354,8 +354,12 @@ pub fn opt_loan_path(cmt: &mc::cmt) -> Option<Rc<LoanPath>> {
match cmt.cat {
mc::cat_rvalue(..) |
mc::cat_static_item |
mc::cat_copied_upvar(mc::CopiedUpvar { onceness: ast::Many, .. }) => {
mc::cat_static_item => {
None
}
mc::cat_copied_upvar(mc::CopiedUpvar { kind: kind, .. })
if kind.onceness() == ast::Many => {
None
}
@ -363,9 +367,9 @@ pub fn opt_loan_path(cmt: &mc::cmt) -> Option<Rc<LoanPath>> {
Some(Rc::new(LpVar(id)))
}
mc::cat_upvar(ty::UpvarId {var_id: id, closure_expr_id: proc_id}, _) |
mc::cat_upvar(ty::UpvarId {var_id: id, closure_expr_id: proc_id}, _, _) |
mc::cat_copied_upvar(mc::CopiedUpvar { upvar_id: id,
onceness: _,
kind: _,
capturing_proc: proc_id }) => {
let upvar_id = ty::UpvarId{ var_id: id, closure_expr_id: proc_id };
Some(Rc::new(LpUpvar(upvar_id)))

View File

@ -83,7 +83,7 @@ pub enum categorization {
cat_rvalue(ty::Region), // temporary val, argument is its scope
cat_static_item,
cat_copied_upvar(CopiedUpvar), // upvar copied into proc env
cat_upvar(ty::UpvarId, ty::UpvarBorrow), // by ref upvar from stack closure
cat_upvar(ty::UpvarId, ty::UpvarBorrow, Option<ty::UnboxedClosureKind>), // by ref upvar from stack or unboxed closure
cat_local(ast::NodeId), // local variable
cat_deref(cmt, uint, PointerKind), // deref of a ptr
cat_interior(cmt, InteriorKind), // something interior: field, tuple, etc
@ -93,10 +93,27 @@ pub enum categorization {
// (*1) downcast is only required if the enum has more than one variant
}
#[deriving(Clone, PartialEq)]
pub enum CopiedUpvarKind {
Boxed(ast::Onceness),
Unboxed(ty::UnboxedClosureKind)
}
impl CopiedUpvarKind {
pub fn onceness(&self) -> ast::Onceness {
match *self {
Boxed(onceness) => onceness,
Unboxed(ty::FnUnboxedClosureKind) |
Unboxed(ty::FnMutUnboxedClosureKind) => ast::Many,
Unboxed(ty::FnOnceUnboxedClosureKind) => ast::Once
}
}
}
#[deriving(Clone, PartialEq)]
pub struct CopiedUpvar {
pub upvar_id: ast::NodeId,
pub onceness: ast::Onceness,
pub kind: CopiedUpvarKind,
pub capturing_proc: ast::NodeId,
}
@ -571,14 +588,14 @@ impl<'t,'tcx,TYPER:Typer<'tcx>> MemCategorizationContext<'t,TYPER> {
};
if var_is_refd {
self.cat_upvar(id, span, var_id, fn_node_id)
self.cat_upvar(id, span, var_id, fn_node_id, None)
} else {
Ok(Rc::new(cmt_ {
id:id,
span:span,
cat:cat_copied_upvar(CopiedUpvar {
upvar_id: var_id,
onceness: closure_ty.onceness,
kind: Boxed(closure_ty.onceness),
capturing_proc: fn_node_id,
}),
mutbl: MutabilityCategory::from_local(self.tcx(), var_id),
@ -591,20 +608,15 @@ impl<'t,'tcx,TYPER:Typer<'tcx>> MemCategorizationContext<'t,TYPER> {
.unboxed_closures()
.borrow();
let kind = unboxed_closures.get(&closure_id).kind;
let onceness = match kind {
ty::FnUnboxedClosureKind |
ty::FnMutUnboxedClosureKind => ast::Many,
ty::FnOnceUnboxedClosureKind => ast::Once,
};
if self.typer.capture_mode(fn_node_id) == ast::CaptureByRef {
self.cat_upvar(id, span, var_id, fn_node_id)
self.cat_upvar(id, span, var_id, fn_node_id, Some(kind))
} else {
Ok(Rc::new(cmt_ {
id: id,
span: span,
cat: cat_copied_upvar(CopiedUpvar {
upvar_id: var_id,
onceness: onceness,
kind: Unboxed(kind),
capturing_proc: fn_node_id,
}),
mutbl: MutabilityCategory::from_local(self.tcx(), var_id),
@ -638,7 +650,8 @@ impl<'t,'tcx,TYPER:Typer<'tcx>> MemCategorizationContext<'t,TYPER> {
id: ast::NodeId,
span: Span,
var_id: ast::NodeId,
fn_node_id: ast::NodeId)
fn_node_id: ast::NodeId,
kind: Option<ty::UnboxedClosureKind>)
-> McResult<cmt> {
/*!
* Upvars through a closure are in fact indirect
@ -666,7 +679,7 @@ impl<'t,'tcx,TYPER:Typer<'tcx>> MemCategorizationContext<'t,TYPER> {
let base_cmt = Rc::new(cmt_ {
id:id,
span:span,
cat:cat_upvar(upvar_id, upvar_borrow),
cat:cat_upvar(upvar_id, upvar_borrow, kind),
mutbl:McImmutable,
ty:upvar_ty,
});
@ -1287,7 +1300,6 @@ impl cmt_ {
b.freely_aliasable(ctxt)
}
cat_copied_upvar(CopiedUpvar {onceness: ast::Once, ..}) |
cat_rvalue(..) |
cat_local(..) |
cat_upvar(..) |
@ -1295,8 +1307,14 @@ impl cmt_ {
None
}
cat_copied_upvar(CopiedUpvar {onceness: ast::Many, ..}) => {
Some(AliasableOther)
cat_copied_upvar(CopiedUpvar {kind: kind, capturing_proc: id, ..}) => {
match kind {
Boxed(ast::Once) |
Unboxed(ty::FnOnceUnboxedClosureKind) |
Unboxed(ty::FnMutUnboxedClosureKind) => None,
Boxed(_) => Some(AliasableOther),
Unboxed(_) => Some(AliasableClosure(id))
}
}
cat_static_item(..) => {

View File

@ -1552,7 +1552,7 @@ fn link_reborrowed_region(rcx: &Rcx,
// Detect references to an upvar `x`:
let cause = match ref_cmt.cat {
mc::cat_upvar(ref upvar_id, _) => {
mc::cat_upvar(ref upvar_id, _, _) => {
let mut upvar_borrow_map =
rcx.fcx.inh.upvar_borrow_map.borrow_mut();
match upvar_borrow_map.find_mut(upvar_id) {
@ -1686,7 +1686,7 @@ fn adjust_upvar_borrow_kind_for_mut(rcx: &Rcx,
mc::cat_deref(base, _, mc::BorrowedPtr(..)) |
mc::cat_deref(base, _, mc::Implicit(..)) => {
match base.cat {
mc::cat_upvar(ref upvar_id, _) => {
mc::cat_upvar(ref upvar_id, _, _) => {
// if this is an implicit deref of an
// upvar, then we need to modify the
// borrow_kind of the upvar to make sure it
@ -1739,7 +1739,7 @@ fn adjust_upvar_borrow_kind_for_unique(rcx: &Rcx, cmt: mc::cmt) {
mc::cat_deref(base, _, mc::BorrowedPtr(..)) |
mc::cat_deref(base, _, mc::Implicit(..)) => {
match base.cat {
mc::cat_upvar(ref upvar_id, _) => {
mc::cat_upvar(ref upvar_id, _, _) => {
// if this is an implicit deref of an
// upvar, then we need to modify the
// borrow_kind of the upvar to make sure it