Remove the capture mode map and just store the capture mode for individual variables.
Also add test. Fixes #16749.
This commit is contained in:
parent
e0f5980ead
commit
2f29cdeb4b
19 changed files with 418 additions and 439 deletions
|
|
@ -140,7 +140,7 @@ pub enum astencode_tag { // Reserves 0x40 -- 0x5f
|
|||
tag_table_moves_map = 0x52,
|
||||
tag_table_capture_map = 0x53,
|
||||
tag_table_closures = 0x54,
|
||||
tag_table_upvar_borrow_map = 0x55,
|
||||
tag_table_upvar_capture_map = 0x55,
|
||||
tag_table_capture_modes = 0x56,
|
||||
tag_table_object_cast_map = 0x57,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -518,10 +518,6 @@ fn encode_freevar_entry(rbml_w: &mut Encoder, fv: &ty::Freevar) {
|
|||
(*fv).encode(rbml_w).unwrap();
|
||||
}
|
||||
|
||||
fn encode_capture_mode(rbml_w: &mut Encoder, cm: ast::CaptureClause) {
|
||||
cm.encode(rbml_w).unwrap();
|
||||
}
|
||||
|
||||
trait rbml_decoder_helper {
|
||||
fn read_freevar_entry(&mut self, dcx: &DecodeContext)
|
||||
-> ty::Freevar;
|
||||
|
|
@ -559,6 +555,15 @@ impl tr for ty::UpvarBorrow {
|
|||
}
|
||||
}
|
||||
|
||||
impl tr for ty::UpvarCapture {
|
||||
fn tr(&self, dcx: &DecodeContext) -> ty::UpvarCapture {
|
||||
match *self {
|
||||
ty::UpvarCapture::ByValue => ty::UpvarCapture::ByValue,
|
||||
ty::UpvarCapture::ByRef(ref data) => ty::UpvarCapture::ByRef(data.tr(dcx)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ______________________________________________________________________
|
||||
// Encoding and decoding of MethodCallee
|
||||
|
||||
|
|
@ -1210,34 +1215,20 @@ fn encode_side_tables_for_id(ecx: &e::EncodeContext,
|
|||
});
|
||||
|
||||
for freevar in fv.iter() {
|
||||
match tcx.capture_mode(id) {
|
||||
ast::CaptureByRef => {
|
||||
rbml_w.tag(c::tag_table_upvar_borrow_map, |rbml_w| {
|
||||
rbml_w.id(id);
|
||||
rbml_w.tag(c::tag_table_val, |rbml_w| {
|
||||
let var_id = freevar.def.def_id().node;
|
||||
let upvar_id = ty::UpvarId {
|
||||
var_id: var_id,
|
||||
closure_expr_id: id
|
||||
};
|
||||
let upvar_borrow = tcx.upvar_borrow_map.borrow()[upvar_id].clone();
|
||||
var_id.encode(rbml_w);
|
||||
upvar_borrow.encode(rbml_w);
|
||||
})
|
||||
})
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for &cm in tcx.capture_modes.borrow().get(&id).iter() {
|
||||
rbml_w.tag(c::tag_table_capture_modes, |rbml_w| {
|
||||
rbml_w.id(id);
|
||||
rbml_w.tag(c::tag_table_val, |rbml_w| {
|
||||
encode_capture_mode(rbml_w, *cm);
|
||||
rbml_w.tag(c::tag_table_upvar_capture_map, |rbml_w| {
|
||||
rbml_w.id(id);
|
||||
rbml_w.tag(c::tag_table_val, |rbml_w| {
|
||||
let var_id = freevar.def.def_id().node;
|
||||
let upvar_id = ty::UpvarId {
|
||||
var_id: var_id,
|
||||
closure_expr_id: id
|
||||
};
|
||||
let upvar_capture = tcx.upvar_capture_map.borrow()[upvar_id].clone();
|
||||
var_id.encode(rbml_w);
|
||||
upvar_capture.encode(rbml_w);
|
||||
})
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
let lid = ast::DefId { krate: ast::LOCAL_CRATE, node: id };
|
||||
|
|
@ -1911,21 +1902,14 @@ fn decode_side_tables(dcx: &DecodeContext,
|
|||
}).unwrap().into_iter().collect();
|
||||
dcx.tcx.freevars.borrow_mut().insert(id, fv_info);
|
||||
}
|
||||
c::tag_table_upvar_borrow_map => {
|
||||
c::tag_table_upvar_capture_map => {
|
||||
let var_id: ast::NodeId = Decodable::decode(val_dsr).unwrap();
|
||||
let upvar_id = ty::UpvarId {
|
||||
var_id: dcx.tr_id(var_id),
|
||||
closure_expr_id: id
|
||||
};
|
||||
let ub: ty::UpvarBorrow = Decodable::decode(val_dsr).unwrap();
|
||||
dcx.tcx.upvar_borrow_map.borrow_mut().insert(upvar_id, ub.tr(dcx));
|
||||
}
|
||||
c::tag_table_capture_modes => {
|
||||
let capture_mode = val_dsr.read_capture_mode();
|
||||
dcx.tcx
|
||||
.capture_modes
|
||||
.borrow_mut()
|
||||
.insert(id, capture_mode);
|
||||
let ub: ty::UpvarCapture = Decodable::decode(val_dsr).unwrap();
|
||||
dcx.tcx.upvar_capture_map.borrow_mut().insert(upvar_id, ub.tr(dcx));
|
||||
}
|
||||
c::tag_table_tcache => {
|
||||
let type_scheme = val_dsr.read_type_scheme(dcx);
|
||||
|
|
|
|||
|
|
@ -1208,53 +1208,32 @@ impl<'d,'t,'tcx,TYPER:mc::Typer<'tcx>> ExprUseVisitor<'d,'t,'tcx,TYPER> {
|
|||
debug!("walk_captures({})", closure_expr.repr(self.tcx()));
|
||||
|
||||
ty::with_freevars(self.tcx(), closure_expr.id, |freevars| {
|
||||
match self.tcx().capture_mode(closure_expr.id) {
|
||||
ast::CaptureByRef => {
|
||||
self.walk_by_ref_captures(closure_expr, freevars);
|
||||
}
|
||||
ast::CaptureByValue => {
|
||||
self.walk_by_value_captures(closure_expr, freevars);
|
||||
for freevar in freevars.iter() {
|
||||
let id_var = freevar.def.def_id().node;
|
||||
let upvar_id = ty::UpvarId { var_id: id_var,
|
||||
closure_expr_id: closure_expr.id };
|
||||
let upvar_capture = self.typer.upvar_capture(upvar_id).unwrap();
|
||||
let cmt_var = return_if_err!(self.cat_captured_var(closure_expr.id,
|
||||
closure_expr.span,
|
||||
freevar.def));
|
||||
match upvar_capture {
|
||||
ty::UpvarCapture::ByValue => {
|
||||
let mode = copy_or_move(self.typer, &cmt_var, CaptureMove);
|
||||
self.delegate.consume(closure_expr.id, freevar.span, cmt_var, mode);
|
||||
}
|
||||
ty::UpvarCapture::ByRef(upvar_borrow) => {
|
||||
self.delegate.borrow(closure_expr.id,
|
||||
closure_expr.span,
|
||||
cmt_var,
|
||||
upvar_borrow.region,
|
||||
upvar_borrow.kind,
|
||||
ClosureCapture(freevar.span));
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
fn walk_by_ref_captures(&mut self,
|
||||
closure_expr: &ast::Expr,
|
||||
freevars: &[ty::Freevar]) {
|
||||
for freevar in freevars.iter() {
|
||||
let id_var = freevar.def.def_id().node;
|
||||
let cmt_var = return_if_err!(self.cat_captured_var(closure_expr.id,
|
||||
closure_expr.span,
|
||||
freevar.def));
|
||||
|
||||
// Lookup the kind of borrow the callee requires, as
|
||||
// inferred by regionbk
|
||||
let upvar_id = ty::UpvarId { var_id: id_var,
|
||||
closure_expr_id: closure_expr.id };
|
||||
let upvar_borrow = self.typer.upvar_borrow(upvar_id).unwrap();
|
||||
|
||||
self.delegate.borrow(closure_expr.id,
|
||||
closure_expr.span,
|
||||
cmt_var,
|
||||
upvar_borrow.region,
|
||||
upvar_borrow.kind,
|
||||
ClosureCapture(freevar.span));
|
||||
}
|
||||
}
|
||||
|
||||
fn walk_by_value_captures(&mut self,
|
||||
closure_expr: &ast::Expr,
|
||||
freevars: &[ty::Freevar]) {
|
||||
for freevar in freevars.iter() {
|
||||
let cmt_var = return_if_err!(self.cat_captured_var(closure_expr.id,
|
||||
closure_expr.span,
|
||||
freevar.def));
|
||||
let mode = copy_or_move(self.typer, &cmt_var, CaptureMove);
|
||||
self.delegate.consume(closure_expr.id, freevar.span, cmt_var, mode);
|
||||
}
|
||||
}
|
||||
|
||||
fn cat_captured_var(&mut self,
|
||||
closure_id: ast::NodeId,
|
||||
closure_span: Span,
|
||||
|
|
|
|||
|
|
@ -277,9 +277,7 @@ pub trait Typer<'tcx> : ty::ClosureTyper<'tcx> {
|
|||
fn adjustments<'a>(&'a self) -> &'a RefCell<NodeMap<ty::AutoAdjustment<'tcx>>>;
|
||||
fn is_method_call(&self, id: ast::NodeId) -> bool;
|
||||
fn temporary_scope(&self, rvalue_id: ast::NodeId) -> Option<region::CodeExtent>;
|
||||
fn upvar_borrow(&self, upvar_id: ty::UpvarId) -> Option<ty::UpvarBorrow>;
|
||||
fn capture_mode(&self, closure_expr_id: ast::NodeId)
|
||||
-> ast::CaptureClause;
|
||||
fn upvar_capture(&self, upvar_id: ty::UpvarId) -> Option<ty::UpvarCapture>;
|
||||
}
|
||||
|
||||
impl MutabilityCategory {
|
||||
|
|
@ -595,8 +593,7 @@ impl<'t,'tcx,TYPER:Typer<'tcx>> MemCategorizationContext<'t,TYPER> {
|
|||
match ty.sty {
|
||||
ty::ty_closure(closure_id, _, _) => {
|
||||
let kind = self.typer.closure_kind(closure_id);
|
||||
let mode = self.typer.capture_mode(fn_node_id);
|
||||
self.cat_upvar(id, span, var_id, fn_node_id, kind, mode)
|
||||
self.cat_upvar(id, span, var_id, fn_node_id, kind)
|
||||
}
|
||||
_ => {
|
||||
self.tcx().sess.span_bug(
|
||||
|
|
@ -628,10 +625,13 @@ impl<'t,'tcx,TYPER:Typer<'tcx>> MemCategorizationContext<'t,TYPER> {
|
|||
span: Span,
|
||||
var_id: ast::NodeId,
|
||||
fn_node_id: ast::NodeId,
|
||||
kind: ty::ClosureKind,
|
||||
mode: ast::CaptureClause)
|
||||
-> McResult<cmt<'tcx>> {
|
||||
// An upvar can have up to 3 components. The base is a
|
||||
kind: ty::ClosureKind)
|
||||
-> McResult<cmt<'tcx>>
|
||||
{
|
||||
// An upvar can have up to 3 components. We translate first to a
|
||||
// `cat_upvar`, which is itself a fiction -- it represents the reference to the
|
||||
// field from the environment.
|
||||
//
|
||||
// `cat_upvar`. Next, we add a deref through the implicit
|
||||
// environment pointer with an anonymous free region 'env and
|
||||
// appropriate borrow kind for closure kinds that take self by
|
||||
|
|
@ -650,135 +650,130 @@ impl<'t,'tcx,TYPER:Typer<'tcx>> MemCategorizationContext<'t,TYPER> {
|
|||
// Fn | copied -> &'env | upvar -> &'env -> &'up bk
|
||||
// FnMut | copied -> &'env mut | upvar -> &'env mut -> &'up bk
|
||||
// FnOnce | copied | upvar -> &'up bk
|
||||
let var_ty = try!(self.node_ty(var_id));
|
||||
|
||||
let upvar_id = ty::UpvarId { var_id: var_id,
|
||||
closure_expr_id: fn_node_id };
|
||||
let var_ty = try!(self.node_ty(var_id));
|
||||
|
||||
// Mutability of original variable itself
|
||||
let var_mutbl = MutabilityCategory::from_local(self.tcx(), var_id);
|
||||
|
||||
// Construct information about env pointer dereference, if any
|
||||
let mutbl = match kind {
|
||||
ty::FnOnceClosureKind => None, // None, env is by-value
|
||||
ty::FnMutClosureKind => match mode { // Depends on capture type
|
||||
ast::CaptureByValue => Some(var_mutbl), // Mutable if the original var is
|
||||
ast::CaptureByRef => Some(McDeclared) // Mutable regardless
|
||||
},
|
||||
ty::FnClosureKind => Some(McImmutable) // Never mutable
|
||||
// Construct the upvar. This represents access to the field
|
||||
// from the environment (perhaps we should eventually desugar
|
||||
// this field further, but it will do for now).
|
||||
let cmt_result = cmt_ {
|
||||
id: id,
|
||||
span: span,
|
||||
cat: cat_upvar(Upvar {id: upvar_id, kind: kind}),
|
||||
mutbl: var_mutbl,
|
||||
ty: var_ty,
|
||||
note: NoteNone
|
||||
};
|
||||
let env_info = mutbl.map(|env_mutbl| {
|
||||
// Look up the node ID of the closure body so we can construct
|
||||
// a free region within it
|
||||
let fn_body_id = {
|
||||
let fn_expr = match self.tcx().map.find(fn_node_id) {
|
||||
Some(ast_map::NodeExpr(e)) => e,
|
||||
_ => unreachable!()
|
||||
};
|
||||
|
||||
match fn_expr.node {
|
||||
ast::ExprClosure(_, _, _, ref body) => body.id,
|
||||
_ => unreachable!()
|
||||
}
|
||||
};
|
||||
// If this is a `FnMut` or `Fn` closure, then the above is
|
||||
// conceptually a `&mut` or `&` reference, so we have to add a
|
||||
// deref.
|
||||
let cmt_result = match kind {
|
||||
ty::FnOnceClosureKind => {
|
||||
cmt_result
|
||||
}
|
||||
ty::FnMutClosureKind => {
|
||||
self.env_deref(id, span, upvar_id, var_mutbl, ty::MutBorrow, cmt_result)
|
||||
}
|
||||
ty::FnClosureKind => {
|
||||
self.env_deref(id, span, upvar_id, var_mutbl, ty::ImmBorrow, cmt_result)
|
||||
}
|
||||
};
|
||||
|
||||
// Region of environment pointer
|
||||
let env_region = ty::ReFree(ty::FreeRegion {
|
||||
scope: region::CodeExtent::from_node_id(fn_body_id),
|
||||
bound_region: ty::BrEnv
|
||||
});
|
||||
|
||||
let env_ptr = BorrowedPtr(if env_mutbl.is_mutable() {
|
||||
ty::MutBorrow
|
||||
} else {
|
||||
ty::ImmBorrow
|
||||
}, env_region);
|
||||
|
||||
(env_mutbl, env_ptr)
|
||||
});
|
||||
|
||||
// First, switch by capture mode
|
||||
Ok(match mode {
|
||||
ast::CaptureByValue => {
|
||||
let mut base = cmt_ {
|
||||
id: id,
|
||||
span: span,
|
||||
cat: cat_upvar(Upvar {
|
||||
id: upvar_id,
|
||||
kind: kind
|
||||
}),
|
||||
mutbl: var_mutbl,
|
||||
ty: var_ty,
|
||||
note: NoteNone
|
||||
};
|
||||
|
||||
match env_info {
|
||||
Some((env_mutbl, env_ptr)) => {
|
||||
// We need to add the env deref. This means
|
||||
// that the above is actually immutable and
|
||||
// has a ref type. However, nothing should
|
||||
// actually look at the type, so we can get
|
||||
// away with stuffing a `ty_err` in there
|
||||
// instead of bothering to construct a proper
|
||||
// one.
|
||||
base.mutbl = McImmutable;
|
||||
base.ty = self.tcx().types.err;
|
||||
Rc::new(cmt_ {
|
||||
id: id,
|
||||
span: span,
|
||||
cat: cat_deref(Rc::new(base), 0, env_ptr),
|
||||
mutbl: env_mutbl,
|
||||
ty: var_ty,
|
||||
note: NoteClosureEnv(upvar_id)
|
||||
})
|
||||
}
|
||||
None => Rc::new(base)
|
||||
}
|
||||
},
|
||||
ast::CaptureByRef => {
|
||||
// The type here is actually a ref (or ref of a ref),
|
||||
// but we can again get away with not constructing one
|
||||
// properly since it will never be used.
|
||||
let mut base = cmt_ {
|
||||
id: id,
|
||||
span: span,
|
||||
cat: cat_upvar(Upvar {
|
||||
id: upvar_id,
|
||||
kind: kind
|
||||
}),
|
||||
mutbl: McImmutable,
|
||||
ty: self.tcx().types.err,
|
||||
note: NoteNone
|
||||
};
|
||||
|
||||
match env_info {
|
||||
Some((env_mutbl, env_ptr)) => {
|
||||
base = cmt_ {
|
||||
id: id,
|
||||
span: span,
|
||||
cat: cat_deref(Rc::new(base), 0, env_ptr),
|
||||
mutbl: env_mutbl,
|
||||
ty: self.tcx().types.err,
|
||||
note: NoteClosureEnv(upvar_id)
|
||||
};
|
||||
}
|
||||
None => {}
|
||||
}
|
||||
|
||||
// Look up upvar borrow so we can get its region
|
||||
let upvar_borrow = self.typer.upvar_borrow(upvar_id).unwrap();
|
||||
// If this is a by-ref capture, then the upvar we loaded is
|
||||
// actually a reference, so we have to add an implicit deref
|
||||
// for that.
|
||||
let upvar_id = ty::UpvarId { var_id: var_id,
|
||||
closure_expr_id: fn_node_id };
|
||||
let upvar_capture = self.typer.upvar_capture(upvar_id).unwrap();
|
||||
let cmt_result = match upvar_capture {
|
||||
ty::UpvarCapture::ByValue => {
|
||||
cmt_result
|
||||
}
|
||||
ty::UpvarCapture::ByRef(upvar_borrow) => {
|
||||
let ptr = BorrowedPtr(upvar_borrow.kind, upvar_borrow.region);
|
||||
|
||||
Rc::new(cmt_ {
|
||||
cmt_ {
|
||||
id: id,
|
||||
span: span,
|
||||
cat: cat_deref(Rc::new(base), 0, ptr),
|
||||
cat: cat_deref(Rc::new(cmt_result), 0, ptr),
|
||||
mutbl: MutabilityCategory::from_borrow_kind(upvar_borrow.kind),
|
||||
ty: var_ty,
|
||||
note: NoteUpvarRef(upvar_id)
|
||||
})
|
||||
}
|
||||
}
|
||||
})
|
||||
};
|
||||
|
||||
Ok(Rc::new(cmt_result))
|
||||
}
|
||||
|
||||
fn env_deref(&self,
|
||||
id: ast::NodeId,
|
||||
span: Span,
|
||||
upvar_id: ty::UpvarId,
|
||||
upvar_mutbl: MutabilityCategory,
|
||||
env_borrow_kind: ty::BorrowKind,
|
||||
cmt_result: cmt_<'tcx>)
|
||||
-> cmt_<'tcx>
|
||||
{
|
||||
// Look up the node ID of the closure body so we can construct
|
||||
// a free region within it
|
||||
let fn_body_id = {
|
||||
let fn_expr = match self.tcx().map.find(upvar_id.closure_expr_id) {
|
||||
Some(ast_map::NodeExpr(e)) => e,
|
||||
_ => unreachable!()
|
||||
};
|
||||
|
||||
match fn_expr.node {
|
||||
ast::ExprClosure(_, _, _, ref body) => body.id,
|
||||
_ => unreachable!()
|
||||
}
|
||||
};
|
||||
|
||||
// Region of environment pointer
|
||||
let env_region = ty::ReFree(ty::FreeRegion {
|
||||
scope: region::CodeExtent::from_node_id(fn_body_id),
|
||||
bound_region: ty::BrEnv
|
||||
});
|
||||
|
||||
let env_ptr = BorrowedPtr(env_borrow_kind, env_region);
|
||||
|
||||
let var_ty = cmt_result.ty;
|
||||
|
||||
// We need to add the env deref. This means
|
||||
// that the above is actually immutable and
|
||||
// has a ref type. However, nothing should
|
||||
// actually look at the type, so we can get
|
||||
// away with stuffing a `ty_err` in there
|
||||
// instead of bothering to construct a proper
|
||||
// one.
|
||||
let cmt_result = cmt_ {
|
||||
mutbl: McImmutable,
|
||||
ty: self.tcx().types.err,
|
||||
..cmt_result
|
||||
};
|
||||
|
||||
let mut deref_mutbl = MutabilityCategory::from_borrow_kind(env_borrow_kind);
|
||||
|
||||
// Issue #18335. If variable is declared as immutable, override the
|
||||
// mutability from the environment and substitute an `&T` anyway.
|
||||
match upvar_mutbl {
|
||||
McImmutable => { deref_mutbl = McImmutable; }
|
||||
McDeclared | McInherited => { }
|
||||
}
|
||||
|
||||
cmt_ {
|
||||
id: id,
|
||||
span: span,
|
||||
cat: cat_deref(Rc::new(cmt_result), 0, env_ptr),
|
||||
mutbl: deref_mutbl,
|
||||
ty: var_ty,
|
||||
note: NoteClosureEnv(upvar_id)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn cat_rvalue_node(&self,
|
||||
|
|
|
|||
|
|
@ -777,7 +777,7 @@ pub struct ctxt<'tcx> {
|
|||
pub populated_external_traits: RefCell<DefIdSet>,
|
||||
|
||||
/// Borrows
|
||||
pub upvar_borrow_map: RefCell<UpvarBorrowMap>,
|
||||
pub upvar_capture_map: RefCell<UpvarCaptureMap>,
|
||||
|
||||
/// These two caches are used by const_eval when decoding external statics
|
||||
/// and variants that are found.
|
||||
|
|
@ -803,9 +803,6 @@ pub struct ctxt<'tcx> {
|
|||
/// Maps any item's def-id to its stability index.
|
||||
pub stability: RefCell<stability::Index>,
|
||||
|
||||
/// Maps closures to their capture clauses.
|
||||
pub capture_modes: RefCell<CaptureModeMap>,
|
||||
|
||||
/// Maps def IDs to true if and only if they're associated types.
|
||||
pub associated_types: RefCell<DefIdMap<bool>>,
|
||||
|
||||
|
|
@ -1247,60 +1244,31 @@ pub enum BorrowKind {
|
|||
MutBorrow
|
||||
}
|
||||
|
||||
/// Information describing the borrowing of an upvar. This is computed
|
||||
/// during `typeck`, specifically by `regionck`. The general idea is
|
||||
/// that the compiler analyses treat closures like:
|
||||
///
|
||||
/// let closure: &'e fn() = || {
|
||||
/// x = 1; // upvar x is assigned to
|
||||
/// use(y); // upvar y is read
|
||||
/// foo(&z); // upvar z is borrowed immutably
|
||||
/// };
|
||||
///
|
||||
/// as if they were "desugared" to something loosely like:
|
||||
///
|
||||
/// struct Vars<'x,'y,'z> { x: &'x mut int,
|
||||
/// y: &'y const int,
|
||||
/// z: &'z int }
|
||||
/// let closure: &'e fn() = {
|
||||
/// fn f(env: &Vars) {
|
||||
/// *env.x = 1;
|
||||
/// use(*env.y);
|
||||
/// foo(env.z);
|
||||
/// }
|
||||
/// let env: &'e mut Vars<'x,'y,'z> = &mut Vars { x: &'x mut x,
|
||||
/// y: &'y const y,
|
||||
/// z: &'z z };
|
||||
/// (env, f)
|
||||
/// };
|
||||
///
|
||||
/// This is basically what happens at runtime. The closure is basically
|
||||
/// an existentially quantified version of the `(env, f)` pair.
|
||||
///
|
||||
/// This data structure indicates the region and mutability of a single
|
||||
/// one of the `x...z` borrows.
|
||||
///
|
||||
/// It may not be obvious why each borrowed variable gets its own
|
||||
/// lifetime (in the desugared version of the example, these are indicated
|
||||
/// by the lifetime parameters `'x`, `'y`, and `'z` in the `Vars` definition).
|
||||
/// Each such lifetime must encompass the lifetime `'e` of the closure itself,
|
||||
/// but need not be identical to it. The reason that this makes sense:
|
||||
///
|
||||
/// - Callers are only permitted to invoke the closure, and hence to
|
||||
/// use the pointers, within the lifetime `'e`, so clearly `'e` must
|
||||
/// be a sublifetime of `'x...'z`.
|
||||
/// - The closure creator knows which upvars were borrowed by the closure
|
||||
/// and thus `x...z` will be reserved for `'x...'z` respectively.
|
||||
/// - Through mutation, the borrowed upvars can actually escape
|
||||
/// the closure, so sometimes it is necessary for them to be larger
|
||||
/// than the closure lifetime itself.
|
||||
/// Information describing the capture of an upvar. This is computed
|
||||
/// during `typeck`, specifically by `regionck`.
|
||||
#[derive(PartialEq, Clone, RustcEncodable, RustcDecodable, Debug, Copy)]
|
||||
pub enum UpvarCapture {
|
||||
/// Upvar is captured by value. This is always true when the
|
||||
/// closure is labeled `move`, but can also be true in other cases
|
||||
/// depending on inference.
|
||||
ByValue,
|
||||
|
||||
/// Upvar is captured by reference.
|
||||
ByRef(UpvarBorrow),
|
||||
}
|
||||
|
||||
#[derive(PartialEq, Clone, RustcEncodable, RustcDecodable, Debug, Copy)]
|
||||
pub struct UpvarBorrow {
|
||||
/// The kind of borrow: by-ref upvars have access to shared
|
||||
/// immutable borrows, which are not part of the normal language
|
||||
/// syntax.
|
||||
pub kind: BorrowKind,
|
||||
|
||||
/// Region of the resulting reference.
|
||||
pub region: ty::Region,
|
||||
}
|
||||
|
||||
pub type UpvarBorrowMap = FnvHashMap<UpvarId, UpvarBorrow>;
|
||||
pub type UpvarCaptureMap = FnvHashMap<UpvarId, UpvarCapture>;
|
||||
|
||||
impl Region {
|
||||
pub fn is_bound(&self) -> bool {
|
||||
|
|
@ -1320,7 +1288,7 @@ impl Region {
|
|||
}
|
||||
|
||||
#[derive(Clone, PartialEq, PartialOrd, Eq, Ord, Hash,
|
||||
RustcEncodable, RustcDecodable, Debug, Copy)]
|
||||
RustcEncodable, RustcDecodable, Debug, Copy)]
|
||||
/// A "free" region `fr` can be interpreted as "some region
|
||||
/// at least as big as the scope `fr.scope`".
|
||||
pub struct FreeRegion {
|
||||
|
|
@ -1329,7 +1297,7 @@ pub struct FreeRegion {
|
|||
}
|
||||
|
||||
#[derive(Clone, PartialEq, PartialOrd, Eq, Ord, Hash,
|
||||
RustcEncodable, RustcDecodable, Debug, Copy)]
|
||||
RustcEncodable, RustcDecodable, Debug, Copy)]
|
||||
pub enum BoundRegion {
|
||||
/// An anonymous region parameter for a given fn (&T)
|
||||
BrAnon(u32),
|
||||
|
|
@ -2359,7 +2327,6 @@ pub fn mk_ctxt<'tcx>(s: Session,
|
|||
named_region_map: resolve_lifetime::NamedRegionMap,
|
||||
map: ast_map::Map<'tcx>,
|
||||
freevars: RefCell<FreevarMap>,
|
||||
capture_modes: RefCell<CaptureModeMap>,
|
||||
region_maps: middle::region::RegionMaps,
|
||||
lang_items: middle::lang_items::LanguageItems,
|
||||
stability: stability::Index) -> ctxt<'tcx>
|
||||
|
|
@ -2413,7 +2380,7 @@ pub fn mk_ctxt<'tcx>(s: Session,
|
|||
used_mut_nodes: RefCell::new(NodeSet()),
|
||||
populated_external_types: RefCell::new(DefIdSet()),
|
||||
populated_external_traits: RefCell::new(DefIdSet()),
|
||||
upvar_borrow_map: RefCell::new(FnvHashMap()),
|
||||
upvar_capture_map: RefCell::new(FnvHashMap()),
|
||||
extern_const_statics: RefCell::new(DefIdMap()),
|
||||
extern_const_variants: RefCell::new(DefIdMap()),
|
||||
method_map: RefCell::new(FnvHashMap()),
|
||||
|
|
@ -2422,7 +2389,6 @@ pub fn mk_ctxt<'tcx>(s: Session,
|
|||
node_lint_levels: RefCell::new(FnvHashMap()),
|
||||
transmute_restrictions: RefCell::new(Vec::new()),
|
||||
stability: RefCell::new(stability),
|
||||
capture_modes: capture_modes,
|
||||
associated_types: RefCell::new(DefIdMap()),
|
||||
selection_cache: traits::SelectionCache::new(),
|
||||
repr_hint_cache: RefCell::new(DefIdMap()),
|
||||
|
|
@ -5646,7 +5612,6 @@ pub fn closure_upvars<'tcx>(typer: &mc::Typer<'tcx>,
|
|||
// implemented.
|
||||
assert!(closure_id.krate == ast::LOCAL_CRATE);
|
||||
let tcx = typer.tcx();
|
||||
let capture_mode = tcx.capture_modes.borrow()[closure_id.node].clone();
|
||||
match tcx.freevars.borrow().get(&closure_id.node) {
|
||||
None => Some(vec![]),
|
||||
Some(ref freevars) => {
|
||||
|
|
@ -5659,43 +5624,38 @@ pub fn closure_upvars<'tcx>(typer: &mc::Typer<'tcx>,
|
|||
};
|
||||
let freevar_ty = freevar_ty.subst(tcx, substs);
|
||||
|
||||
match capture_mode {
|
||||
ast::CaptureByValue => {
|
||||
Some(ClosureUpvar { def: freevar.def,
|
||||
span: freevar.span,
|
||||
ty: freevar_ty })
|
||||
let upvar_id = ty::UpvarId {
|
||||
var_id: freevar_def_id.node,
|
||||
closure_expr_id: closure_id.node
|
||||
};
|
||||
|
||||
let captured_freevar_ty = match typer.upvar_capture(upvar_id) {
|
||||
Some(UpvarCapture::ByValue) => {
|
||||
freevar_ty
|
||||
}
|
||||
|
||||
ast::CaptureByRef => {
|
||||
let upvar_id = ty::UpvarId {
|
||||
var_id: freevar_def_id.node,
|
||||
closure_expr_id: closure_id.node
|
||||
};
|
||||
|
||||
// FIXME
|
||||
let freevar_ref_ty = match typer.upvar_borrow(upvar_id) {
|
||||
Some(borrow) => {
|
||||
mk_rptr(tcx,
|
||||
tcx.mk_region(borrow.region),
|
||||
ty::mt {
|
||||
ty: freevar_ty,
|
||||
mutbl: borrow.kind.to_mutbl_lossy(),
|
||||
})
|
||||
}
|
||||
None => {
|
||||
// FIXME(#16640) we should really return None here;
|
||||
// but that requires better inference integration,
|
||||
// for now gin up something.
|
||||
freevar_ty
|
||||
}
|
||||
};
|
||||
Some(ClosureUpvar {
|
||||
def: freevar.def,
|
||||
span: freevar.span,
|
||||
ty: freevar_ref_ty,
|
||||
})
|
||||
Some(UpvarCapture::ByRef(borrow)) => {
|
||||
mk_rptr(tcx,
|
||||
tcx.mk_region(borrow.region),
|
||||
ty::mt {
|
||||
ty: freevar_ty,
|
||||
mutbl: borrow.kind.to_mutbl_lossy(),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
None => {
|
||||
// FIXME(#16640) we should really return None here;
|
||||
// but that requires better inference integration,
|
||||
// for now gin up something.
|
||||
freevar_ty
|
||||
}
|
||||
};
|
||||
|
||||
Some(ClosureUpvar {
|
||||
def: freevar.def,
|
||||
span: freevar.span,
|
||||
ty: captured_freevar_ty,
|
||||
})
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
|
@ -6449,14 +6409,13 @@ impl BorrowKind {
|
|||
}
|
||||
|
||||
impl<'tcx> ctxt<'tcx> {
|
||||
pub fn capture_mode(&self, closure_expr_id: ast::NodeId)
|
||||
-> ast::CaptureClause {
|
||||
self.capture_modes.borrow()[closure_expr_id].clone()
|
||||
}
|
||||
|
||||
pub fn is_method_call(&self, expr_id: ast::NodeId) -> bool {
|
||||
self.method_map.borrow().contains_key(&MethodCall::expr(expr_id))
|
||||
}
|
||||
|
||||
pub fn upvar_capture(&self, upvar_id: ty::UpvarId) -> Option<ty::UpvarCapture> {
|
||||
Some(self.upvar_capture_map.borrow()[upvar_id].clone())
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a,'tcx> mc::Typer<'tcx> for ParameterEnvironment<'a,'tcx> {
|
||||
|
|
@ -6494,13 +6453,8 @@ impl<'a,'tcx> mc::Typer<'tcx> for ParameterEnvironment<'a,'tcx> {
|
|||
self.tcx.region_maps.temporary_scope(rvalue_id)
|
||||
}
|
||||
|
||||
fn upvar_borrow(&self, upvar_id: ty::UpvarId) -> Option<ty::UpvarBorrow> {
|
||||
Some(self.tcx.upvar_borrow_map.borrow()[upvar_id].clone())
|
||||
}
|
||||
|
||||
fn capture_mode(&self, closure_expr_id: ast::NodeId)
|
||||
-> ast::CaptureClause {
|
||||
self.tcx.capture_mode(closure_expr_id)
|
||||
fn upvar_capture(&self, upvar_id: ty::UpvarId) -> Option<ty::UpvarCapture> {
|
||||
self.tcx.upvar_capture(upvar_id)
|
||||
}
|
||||
|
||||
fn type_moves_by_default(&self, span: Span, ty: Ty<'tcx>) -> bool {
|
||||
|
|
|
|||
|
|
@ -1292,6 +1292,15 @@ impl<'tcx> Repr<'tcx> for ty::UpvarBorrow {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'tcx> Repr<'tcx> for ty::UpvarCapture {
|
||||
fn repr(&self, tcx: &ctxt) -> String {
|
||||
match *self {
|
||||
ty::UpvarCapture::ByValue => format!("ByValue"),
|
||||
ty::UpvarCapture::ByRef(ref data) => format!("ByRef({})", data.repr(tcx)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> Repr<'tcx> for ty::IntVid {
|
||||
fn repr(&self, _tcx: &ctxt) -> String {
|
||||
format!("{:?}", self)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue