Add LpDowncast
, LoanPath
variant tracking downcasts in match arms.
`LpDowncast` carries the `DefId` of the variant itself. To support this, added the enum variant `DefId` to the `cat_downcast` variant in `mem_categorization::categorization`. (updated to fix mem_categorization to handle downcast of enum struct-variants properly.)
This commit is contained in:
parent
e31fc9dd4f
commit
d6c8f3b726
@ -52,6 +52,7 @@ fn owned_ptr_base_path<'a>(loan_path: &'a LoanPath) -> &'a LoanPath {
|
||||
None => Some(&**lp_base)
|
||||
}
|
||||
}
|
||||
LpDowncast(ref lp_base, _) |
|
||||
LpExtend(ref lp_base, _, _) => owned_ptr_base_path_helper(&**lp_base)
|
||||
}
|
||||
}
|
||||
@ -75,6 +76,7 @@ fn owned_ptr_base_path_rc(loan_path: &Rc<LoanPath>) -> Rc<LoanPath> {
|
||||
None => Some(lp_base.clone())
|
||||
}
|
||||
}
|
||||
LpDowncast(ref lp_base, _) |
|
||||
LpExtend(ref lp_base, _, _) => owned_ptr_base_path_helper(lp_base)
|
||||
}
|
||||
}
|
||||
@ -298,6 +300,7 @@ impl<'a, 'tcx> CheckLoanCtxt<'a, 'tcx> {
|
||||
LpVar(_) | LpUpvar(_) => {
|
||||
break;
|
||||
}
|
||||
LpDowncast(ref lp_base, _) |
|
||||
LpExtend(ref lp_base, _, _) => {
|
||||
loan_path = &**lp_base;
|
||||
}
|
||||
@ -726,6 +729,11 @@ impl<'a, 'tcx> CheckLoanCtxt<'a, 'tcx> {
|
||||
LpVar(_) | LpUpvar(_) => {
|
||||
// assigning to `x` does not require that `x` is initialized
|
||||
}
|
||||
LpDowncast(ref lp_base, _) => {
|
||||
// assigning to `(P->Variant).f` is ok if assigning to `P` is ok
|
||||
self.check_if_assigned_path_is_moved(id, span,
|
||||
use_kind, lp_base);
|
||||
}
|
||||
LpExtend(ref lp_base, _, LpInterior(_)) => {
|
||||
// assigning to `P.f` is ok if assigning to `P` is ok
|
||||
self.check_if_assigned_path_is_moved(id, span,
|
||||
@ -864,7 +872,7 @@ impl<'a, 'tcx> CheckLoanCtxt<'a, 'tcx> {
|
||||
cmt = b;
|
||||
}
|
||||
|
||||
mc::cat_downcast(b) |
|
||||
mc::cat_downcast(b, _) |
|
||||
mc::cat_interior(b, _) => {
|
||||
assert_eq!(cmt.mutbl, mc::McInherited);
|
||||
cmt = b;
|
||||
|
@ -144,7 +144,7 @@ fn check_and_get_illegal_move_origin<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>,
|
||||
None
|
||||
}
|
||||
|
||||
mc::cat_downcast(ref b) |
|
||||
mc::cat_downcast(ref b, _) |
|
||||
mc::cat_interior(ref b, _) => {
|
||||
match b.ty.sty {
|
||||
ty::ty_struct(did, _) | ty::ty_enum(did, _) => {
|
||||
|
@ -85,7 +85,7 @@ impl<'a, 'tcx> GuaranteeLifetimeContext<'a, 'tcx> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
mc::cat_downcast(ref base) |
|
||||
mc::cat_downcast(ref base, _) |
|
||||
mc::cat_deref(ref base, _, mc::OwnedPtr) | // L-Deref-Send
|
||||
mc::cat_interior(ref base, _) => { // L-Field
|
||||
self.check(base, discr_scope)
|
||||
@ -130,7 +130,7 @@ impl<'a, 'tcx> GuaranteeLifetimeContext<'a, 'tcx> {
|
||||
mc::cat_deref(_, _, mc::Implicit(_, r)) => {
|
||||
r
|
||||
}
|
||||
mc::cat_downcast(ref cmt) |
|
||||
mc::cat_downcast(ref cmt, _) |
|
||||
mc::cat_deref(ref cmt, _, mc::OwnedPtr) |
|
||||
mc::cat_interior(ref cmt, _) => {
|
||||
self.scope(cmt)
|
||||
|
@ -400,6 +400,7 @@ impl<'a, 'tcx> GatherLoanCtxt<'a, 'tcx> {
|
||||
LpUpvar(ty::UpvarId{ var_id: local_id, closure_expr_id: _ }) => {
|
||||
self.tcx().used_mut_nodes.borrow_mut().insert(local_id);
|
||||
}
|
||||
LpDowncast(ref base, _) |
|
||||
LpExtend(ref base, mc::McInherited, _) |
|
||||
LpExtend(ref base, mc::McDeclared, _) => {
|
||||
self.mark_loan_path_as_mutated(&**base);
|
||||
|
@ -124,7 +124,7 @@ fn report_cannot_move_out_of<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>,
|
||||
bccx.cmt_to_string(&*move_from)).as_slice());
|
||||
}
|
||||
|
||||
mc::cat_downcast(ref b) |
|
||||
mc::cat_downcast(ref b, _) |
|
||||
mc::cat_interior(ref b, _) => {
|
||||
match b.ty.sty {
|
||||
ty::ty_struct(did, _)
|
||||
|
@ -82,7 +82,7 @@ impl<'a, 'tcx> RestrictionsContext<'a, 'tcx> {
|
||||
SafeIf(lp.clone(), vec![lp])
|
||||
}
|
||||
|
||||
mc::cat_downcast(cmt_base) => {
|
||||
mc::cat_downcast(cmt_base, _) => {
|
||||
// When we borrow the interior of an enum, we have to
|
||||
// ensure the enum itself is not mutated, because that
|
||||
// could cause the type of the memory to change.
|
||||
|
@ -284,11 +284,27 @@ impl Loan {
|
||||
|
||||
#[deriving(PartialEq, Eq, Hash, Show)]
|
||||
pub enum LoanPath {
|
||||
LpVar(ast::NodeId), // `x` in doc.rs
|
||||
LpUpvar(ty::UpvarId), // `x` captured by-value into closure
|
||||
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)
|
||||
}
|
||||
|
||||
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 LoanPathElem {
|
||||
LpDeref(mc::PointerKind), // `*LV` in doc.rs
|
||||
@ -319,6 +335,7 @@ impl LoanPath {
|
||||
let block_id = closure_to_block(upvar_id.closure_expr_id, tcx);
|
||||
region::CodeExtent::from_node_id(block_id)
|
||||
}
|
||||
LpDowncast(ref base, _) |
|
||||
LpExtend(ref base, _, _) => base.kill_scope(tcx),
|
||||
}
|
||||
}
|
||||
@ -402,9 +419,12 @@ pub fn opt_loan_path(cmt: &mc::cmt) -> Option<Rc<LoanPath>> {
|
||||
})
|
||||
}
|
||||
|
||||
mc::cat_downcast(ref cmt_base) => {
|
||||
mc::cat_downcast(ref cmt_base, variant_def_id) =>
|
||||
opt_loan_path(cmt_base)
|
||||
}
|
||||
.map(|lp| {
|
||||
Rc::new(LpDowncast(lp, variant_def_id))
|
||||
}),
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@ -862,6 +882,15 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> {
|
||||
out.push_str(ty::local_var_name_str(self.tcx, id).get());
|
||||
}
|
||||
|
||||
LpDowncast(ref lp_base, variant_def_id) => {
|
||||
out.push('(');
|
||||
self.append_loan_path_to_string(&**lp_base, out);
|
||||
out.push_str("->");
|
||||
out.push_str(ty::item_path_str(self.tcx, variant_def_id).as_slice());
|
||||
out.push(')');
|
||||
}
|
||||
|
||||
|
||||
LpExtend(ref lp_base, _, LpInterior(mc::InteriorField(fname))) => {
|
||||
self.append_autoderefd_loan_path_to_string(&**lp_base, out);
|
||||
match fname {
|
||||
@ -899,6 +928,14 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> {
|
||||
self.append_autoderefd_loan_path_to_string(&**lp_base, out)
|
||||
}
|
||||
|
||||
LpDowncast(ref lp_base, variant_def_id) => {
|
||||
out.push('(');
|
||||
self.append_autoderefd_loan_path_to_string(&**lp_base, out);
|
||||
out.push(':');
|
||||
out.push_str(ty::item_path_str(self.tcx, variant_def_id).as_slice());
|
||||
out.push(')');
|
||||
}
|
||||
|
||||
LpVar(..) | LpUpvar(..) | LpExtend(_, _, LpInterior(..)) => {
|
||||
self.append_loan_path_to_string(loan_path, out)
|
||||
}
|
||||
@ -966,6 +1003,15 @@ impl<'tcx> Repr<'tcx> for LoanPath {
|
||||
format!("$({} captured by id={})", s, closure_expr_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 {
|
||||
variant_def_id.repr(tcx)
|
||||
};
|
||||
format!("({}->{})", lp.repr(tcx), variant_str)
|
||||
}
|
||||
|
||||
&LpExtend(ref lp, _, LpDeref(_)) => {
|
||||
format!("{}.*", lp.repr(tcx))
|
||||
}
|
||||
|
@ -175,6 +175,7 @@ fn loan_path_is_precise(loan_path: &LoanPath) -> bool {
|
||||
// location, as there is no accurate tracking of the indices.
|
||||
false
|
||||
}
|
||||
LpDowncast(ref lp_base, _) |
|
||||
LpExtend(ref lp_base, _, _) => {
|
||||
loan_path_is_precise(&**lp_base)
|
||||
}
|
||||
@ -266,6 +267,7 @@ impl MoveData {
|
||||
index
|
||||
}
|
||||
|
||||
LpDowncast(ref base, _) |
|
||||
LpExtend(ref base, _, _) => {
|
||||
let parent_index = self.move_path(tcx, base.clone());
|
||||
|
||||
@ -324,6 +326,7 @@ impl MoveData {
|
||||
None => {
|
||||
match **lp {
|
||||
LpVar(..) | LpUpvar(..) => { }
|
||||
LpDowncast(ref b, _) |
|
||||
LpExtend(ref b, _, _) => {
|
||||
self.add_existing_base_paths(b, result);
|
||||
}
|
||||
@ -434,16 +437,11 @@ impl MoveData {
|
||||
// of scope:
|
||||
for path in self.paths.borrow().iter() {
|
||||
match *path.loan_path {
|
||||
LpVar(id) => {
|
||||
let kill_scope = tcx.region_maps.var_scope(id);
|
||||
let path = (*self.path_map.borrow())[path.loan_path];
|
||||
LpVar(..) | LpUpvar(..) | LpDowncast(..) => {
|
||||
let kill_scope = path.loan_path.kill_scope(tcx);
|
||||
let path = *self.path_map.borrow().get(&path.loan_path);
|
||||
self.kill_moves(path, kill_scope.node_id(), dfcx_moves);
|
||||
}
|
||||
LpUpvar(ty::UpvarId { var_id: _, closure_expr_id }) => {
|
||||
let kill_id = closure_to_block(closure_expr_id, tcx);
|
||||
let path = (*self.path_map.borrow())[path.loan_path];
|
||||
self.kill_moves(path, kill_id, dfcx_moves);
|
||||
}
|
||||
LpExtend(..) => {}
|
||||
}
|
||||
}
|
||||
@ -451,15 +449,12 @@ impl MoveData {
|
||||
// Kill all assignments when the variable goes out of scope:
|
||||
for (assignment_index, assignment) in
|
||||
self.var_assignments.borrow().iter().enumerate() {
|
||||
match *self.path_loan_path(assignment.path) {
|
||||
LpVar(id) => {
|
||||
let kill_scope = tcx.region_maps.var_scope(id);
|
||||
let lp = self.path_loan_path(assignment.path);
|
||||
match *lp {
|
||||
LpVar(..) | LpUpvar(..) | LpDowncast(..) => {
|
||||
let kill_scope = lp.kill_scope(tcx);
|
||||
dfcx_assign.add_kill(kill_scope.node_id(), assignment_index);
|
||||
}
|
||||
LpUpvar(ty::UpvarId { var_id: _, closure_expr_id }) => {
|
||||
let kill_id = closure_to_block(closure_expr_id, tcx);
|
||||
dfcx_assign.add_kill(kill_id, assignment_index);
|
||||
}
|
||||
LpExtend(..) => {
|
||||
tcx.sess.bug("var assignment for non var path");
|
||||
}
|
||||
|
@ -270,7 +270,7 @@ impl<'tcx> euv::Delegate<'tcx> for GlobalChecker {
|
||||
break
|
||||
}
|
||||
mc::cat_deref(ref cmt, _, _) |
|
||||
mc::cat_downcast(ref cmt) |
|
||||
mc::cat_downcast(ref cmt, _) |
|
||||
mc::cat_interior(ref cmt, _) => cur = cmt,
|
||||
|
||||
mc::cat_rvalue(..) |
|
||||
|
@ -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<'tcx>), // selects a particular enum variant (*1)
|
||||
cat_downcast(cmt, ast::DefId), // selects a particular enum variant (*1)
|
||||
|
||||
// (*1) downcast is only required if the enum has more than one variant
|
||||
}
|
||||
@ -1102,13 +1102,14 @@ impl<'t,'tcx,TYPER:Typer<'tcx>> MemCategorizationContext<'t,TYPER> {
|
||||
pub fn cat_downcast<N:ast_node>(&self,
|
||||
node: &N,
|
||||
base_cmt: cmt<'tcx>,
|
||||
downcast_ty: Ty<'tcx>)
|
||||
downcast_ty: Ty<'tcx>,
|
||||
variant_did: ast::DefId)
|
||||
-> cmt<'tcx> {
|
||||
Rc::new(cmt_ {
|
||||
id: node.id(),
|
||||
span: node.span(),
|
||||
mutbl: base_cmt.mutbl.inherit(),
|
||||
cat: cat_downcast(base_cmt),
|
||||
cat: cat_downcast(base_cmt, variant_did),
|
||||
ty: downcast_ty,
|
||||
note: NoteNone
|
||||
})
|
||||
@ -1172,6 +1173,21 @@ impl<'t,'tcx,TYPER:Typer<'tcx>> MemCategorizationContext<'t,TYPER> {
|
||||
|
||||
op(self, cmt.clone(), pat);
|
||||
|
||||
let def_map = self.tcx().def_map.borrow();
|
||||
let opt_def = def_map.get(&pat.id);
|
||||
|
||||
// Note: This goes up here (rather than within the PatEnum arm
|
||||
// alone) because struct patterns can refer to struct types or
|
||||
// to struct variants within enums.
|
||||
let cmt = match opt_def {
|
||||
Some(&def::DefVariant(enum_did, variant_did, _))
|
||||
// univariant enums do not need downcasts
|
||||
if !ty::enum_is_univariant(self.tcx(), enum_did) => {
|
||||
self.cat_downcast(pat, cmt.clone(), cmt.ty, variant_did)
|
||||
}
|
||||
_ => cmt
|
||||
};
|
||||
|
||||
match pat.node {
|
||||
ast::PatWild(_) => {
|
||||
// _
|
||||
@ -1181,24 +1197,15 @@ impl<'t,'tcx,TYPER:Typer<'tcx>> MemCategorizationContext<'t,TYPER> {
|
||||
// variant(..)
|
||||
}
|
||||
ast::PatEnum(_, Some(ref subpats)) => {
|
||||
match self.tcx().def_map.borrow().get(&pat.id) {
|
||||
Some(&def::DefVariant(enum_did, _, _)) => {
|
||||
match opt_def {
|
||||
Some(&def::DefVariant(..)) => {
|
||||
// variant(x, y, z)
|
||||
|
||||
let downcast_cmt = {
|
||||
if ty::enum_is_univariant(self.tcx(), enum_did) {
|
||||
cmt // univariant, no downcast needed
|
||||
} else {
|
||||
self.cat_downcast(pat, cmt.clone(), cmt.ty)
|
||||
}
|
||||
};
|
||||
|
||||
for (i, subpat) in subpats.iter().enumerate() {
|
||||
let subpat_ty = if_ok!(self.pat_ty(&**subpat)); // see (*2)
|
||||
|
||||
let subcmt =
|
||||
self.cat_imm_interior(
|
||||
pat, downcast_cmt.clone(), subpat_ty,
|
||||
pat, cmt.clone(), subpat_ty,
|
||||
InteriorField(PositionalField(i)));
|
||||
|
||||
if_ok!(self.cat_pattern(subcmt, &**subpat, |x,y,z| op(x,y,z)));
|
||||
@ -1356,7 +1363,7 @@ impl<'t,'tcx,TYPER:Typer<'tcx>> MemCategorizationContext<'t,TYPER> {
|
||||
cat_upvar(ref var) => {
|
||||
upvar_to_string(var, true)
|
||||
}
|
||||
cat_downcast(ref cmt) => {
|
||||
cat_downcast(ref cmt, _) => {
|
||||
self.cmt_to_string(&**cmt)
|
||||
}
|
||||
}
|
||||
@ -1392,7 +1399,7 @@ impl<'tcx> cmt_<'tcx> {
|
||||
cat_upvar(..) => {
|
||||
Rc::new((*self).clone())
|
||||
}
|
||||
cat_downcast(ref b) |
|
||||
cat_downcast(ref b, _) |
|
||||
cat_interior(ref b, _) |
|
||||
cat_deref(ref b, _, OwnedPtr) => {
|
||||
b.guarantor()
|
||||
@ -1416,7 +1423,7 @@ impl<'tcx> cmt_<'tcx> {
|
||||
cat_deref(ref b, _, Implicit(ty::MutBorrow, _)) |
|
||||
cat_deref(ref b, _, BorrowedPtr(ty::UniqueImmBorrow, _)) |
|
||||
cat_deref(ref b, _, Implicit(ty::UniqueImmBorrow, _)) |
|
||||
cat_downcast(ref b) |
|
||||
cat_downcast(ref b, _) |
|
||||
cat_deref(ref b, _, OwnedPtr) |
|
||||
cat_interior(ref b, _) => {
|
||||
// Aliasability depends on base cmt
|
||||
@ -1500,7 +1507,7 @@ impl<'tcx> Repr<'tcx> for categorization<'tcx> {
|
||||
cat_interior(ref cmt, interior) => {
|
||||
format!("{}.{}", cmt.cat.repr(tcx), interior.repr(tcx))
|
||||
}
|
||||
cat_downcast(ref cmt) => {
|
||||
cat_downcast(ref cmt, _) => {
|
||||
format!("{}->(enum)", cmt.cat.repr(tcx))
|
||||
}
|
||||
}
|
||||
|
@ -1503,7 +1503,7 @@ fn link_region<'a, 'tcx>(rcx: &Rcx<'a, 'tcx>,
|
||||
}
|
||||
}
|
||||
|
||||
mc::cat_downcast(cmt_base) |
|
||||
mc::cat_downcast(cmt_base, _) |
|
||||
mc::cat_deref(cmt_base, _, mc::OwnedPtr) |
|
||||
mc::cat_interior(cmt_base, _) => {
|
||||
// Borrowing interior or owned data requires the base
|
||||
@ -1744,7 +1744,7 @@ fn adjust_upvar_borrow_kind_for_mut<'a, 'tcx>(rcx: &Rcx<'a, 'tcx>,
|
||||
match cmt.cat.clone() {
|
||||
mc::cat_deref(base, _, mc::OwnedPtr) |
|
||||
mc::cat_interior(base, _) |
|
||||
mc::cat_downcast(base) => {
|
||||
mc::cat_downcast(base, _) => {
|
||||
// Interior or owned data is mutable if base is
|
||||
// mutable, so iterate to the base.
|
||||
cmt = base;
|
||||
@ -1795,7 +1795,7 @@ fn adjust_upvar_borrow_kind_for_unique<'a, 'tcx>(rcx: &Rcx<'a, 'tcx>, cmt: mc::c
|
||||
match cmt.cat.clone() {
|
||||
mc::cat_deref(base, _, mc::OwnedPtr) |
|
||||
mc::cat_interior(base, _) |
|
||||
mc::cat_downcast(base) => {
|
||||
mc::cat_downcast(base, _) => {
|
||||
// Interior or owned data is unique if base is
|
||||
// unique.
|
||||
cmt = base;
|
||||
|
Loading…
x
Reference in New Issue
Block a user