mirror of
https://github.com/rust-lang/rust.git
synced 2025-05-14 02:49:40 +00:00
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
@ -140,7 +140,7 @@ pub enum astencode_tag { // Reserves 0x40 -- 0x5f
|
|||||||
tag_table_moves_map = 0x52,
|
tag_table_moves_map = 0x52,
|
||||||
tag_table_capture_map = 0x53,
|
tag_table_capture_map = 0x53,
|
||||||
tag_table_closures = 0x54,
|
tag_table_closures = 0x54,
|
||||||
tag_table_upvar_borrow_map = 0x55,
|
tag_table_upvar_capture_map = 0x55,
|
||||||
tag_table_capture_modes = 0x56,
|
tag_table_capture_modes = 0x56,
|
||||||
tag_table_object_cast_map = 0x57,
|
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();
|
(*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 {
|
trait rbml_decoder_helper {
|
||||||
fn read_freevar_entry(&mut self, dcx: &DecodeContext)
|
fn read_freevar_entry(&mut self, dcx: &DecodeContext)
|
||||||
-> ty::Freevar;
|
-> 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
|
// Encoding and decoding of MethodCallee
|
||||||
|
|
||||||
@ -1210,9 +1215,7 @@ fn encode_side_tables_for_id(ecx: &e::EncodeContext,
|
|||||||
});
|
});
|
||||||
|
|
||||||
for freevar in fv.iter() {
|
for freevar in fv.iter() {
|
||||||
match tcx.capture_mode(id) {
|
rbml_w.tag(c::tag_table_upvar_capture_map, |rbml_w| {
|
||||||
ast::CaptureByRef => {
|
|
||||||
rbml_w.tag(c::tag_table_upvar_borrow_map, |rbml_w| {
|
|
||||||
rbml_w.id(id);
|
rbml_w.id(id);
|
||||||
rbml_w.tag(c::tag_table_val, |rbml_w| {
|
rbml_w.tag(c::tag_table_val, |rbml_w| {
|
||||||
let var_id = freevar.def.def_id().node;
|
let var_id = freevar.def.def_id().node;
|
||||||
@ -1220,24 +1223,12 @@ fn encode_side_tables_for_id(ecx: &e::EncodeContext,
|
|||||||
var_id: var_id,
|
var_id: var_id,
|
||||||
closure_expr_id: id
|
closure_expr_id: id
|
||||||
};
|
};
|
||||||
let upvar_borrow = tcx.upvar_borrow_map.borrow()[upvar_id].clone();
|
let upvar_capture = tcx.upvar_capture_map.borrow()[upvar_id].clone();
|
||||||
var_id.encode(rbml_w);
|
var_id.encode(rbml_w);
|
||||||
upvar_borrow.encode(rbml_w);
|
upvar_capture.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);
|
|
||||||
})
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let lid = ast::DefId { krate: ast::LOCAL_CRATE, node: id };
|
let lid = ast::DefId { krate: ast::LOCAL_CRATE, node: id };
|
||||||
@ -1911,21 +1902,14 @@ fn decode_side_tables(dcx: &DecodeContext,
|
|||||||
}).unwrap().into_iter().collect();
|
}).unwrap().into_iter().collect();
|
||||||
dcx.tcx.freevars.borrow_mut().insert(id, fv_info);
|
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 var_id: ast::NodeId = Decodable::decode(val_dsr).unwrap();
|
||||||
let upvar_id = ty::UpvarId {
|
let upvar_id = ty::UpvarId {
|
||||||
var_id: dcx.tr_id(var_id),
|
var_id: dcx.tr_id(var_id),
|
||||||
closure_expr_id: id
|
closure_expr_id: id
|
||||||
};
|
};
|
||||||
let ub: ty::UpvarBorrow = Decodable::decode(val_dsr).unwrap();
|
let ub: ty::UpvarCapture = Decodable::decode(val_dsr).unwrap();
|
||||||
dcx.tcx.upvar_borrow_map.borrow_mut().insert(upvar_id, ub.tr(dcx));
|
dcx.tcx.upvar_capture_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);
|
|
||||||
}
|
}
|
||||||
c::tag_table_tcache => {
|
c::tag_table_tcache => {
|
||||||
let type_scheme = val_dsr.read_type_scheme(dcx);
|
let type_scheme = val_dsr.read_type_scheme(dcx);
|
||||||
|
@ -1208,32 +1208,20 @@ impl<'d,'t,'tcx,TYPER:mc::Typer<'tcx>> ExprUseVisitor<'d,'t,'tcx,TYPER> {
|
|||||||
debug!("walk_captures({})", closure_expr.repr(self.tcx()));
|
debug!("walk_captures({})", closure_expr.repr(self.tcx()));
|
||||||
|
|
||||||
ty::with_freevars(self.tcx(), closure_expr.id, |freevars| {
|
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
fn walk_by_ref_captures(&mut self,
|
|
||||||
closure_expr: &ast::Expr,
|
|
||||||
freevars: &[ty::Freevar]) {
|
|
||||||
for freevar in freevars.iter() {
|
for freevar in freevars.iter() {
|
||||||
let id_var = freevar.def.def_id().node;
|
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,
|
let cmt_var = return_if_err!(self.cat_captured_var(closure_expr.id,
|
||||||
closure_expr.span,
|
closure_expr.span,
|
||||||
freevar.def));
|
freevar.def));
|
||||||
|
match upvar_capture {
|
||||||
// Lookup the kind of borrow the callee requires, as
|
ty::UpvarCapture::ByValue => {
|
||||||
// inferred by regionbk
|
let mode = copy_or_move(self.typer, &cmt_var, CaptureMove);
|
||||||
let upvar_id = ty::UpvarId { var_id: id_var,
|
self.delegate.consume(closure_expr.id, freevar.span, cmt_var, mode);
|
||||||
closure_expr_id: closure_expr.id };
|
}
|
||||||
let upvar_borrow = self.typer.upvar_borrow(upvar_id).unwrap();
|
ty::UpvarCapture::ByRef(upvar_borrow) => {
|
||||||
|
|
||||||
self.delegate.borrow(closure_expr.id,
|
self.delegate.borrow(closure_expr.id,
|
||||||
closure_expr.span,
|
closure_expr.span,
|
||||||
cmt_var,
|
cmt_var,
|
||||||
@ -1242,17 +1230,8 @@ impl<'d,'t,'tcx,TYPER:mc::Typer<'tcx>> ExprUseVisitor<'d,'t,'tcx,TYPER> {
|
|||||||
ClosureCapture(freevar.span));
|
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,
|
fn cat_captured_var(&mut self,
|
||||||
|
@ -277,9 +277,7 @@ pub trait Typer<'tcx> : ty::ClosureTyper<'tcx> {
|
|||||||
fn adjustments<'a>(&'a self) -> &'a RefCell<NodeMap<ty::AutoAdjustment<'tcx>>>;
|
fn adjustments<'a>(&'a self) -> &'a RefCell<NodeMap<ty::AutoAdjustment<'tcx>>>;
|
||||||
fn is_method_call(&self, id: ast::NodeId) -> bool;
|
fn is_method_call(&self, id: ast::NodeId) -> bool;
|
||||||
fn temporary_scope(&self, rvalue_id: ast::NodeId) -> Option<region::CodeExtent>;
|
fn temporary_scope(&self, rvalue_id: ast::NodeId) -> Option<region::CodeExtent>;
|
||||||
fn upvar_borrow(&self, upvar_id: ty::UpvarId) -> Option<ty::UpvarBorrow>;
|
fn upvar_capture(&self, upvar_id: ty::UpvarId) -> Option<ty::UpvarCapture>;
|
||||||
fn capture_mode(&self, closure_expr_id: ast::NodeId)
|
|
||||||
-> ast::CaptureClause;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl MutabilityCategory {
|
impl MutabilityCategory {
|
||||||
@ -595,8 +593,7 @@ impl<'t,'tcx,TYPER:Typer<'tcx>> MemCategorizationContext<'t,TYPER> {
|
|||||||
match ty.sty {
|
match ty.sty {
|
||||||
ty::ty_closure(closure_id, _, _) => {
|
ty::ty_closure(closure_id, _, _) => {
|
||||||
let kind = self.typer.closure_kind(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)
|
||||||
self.cat_upvar(id, span, var_id, fn_node_id, kind, mode)
|
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
self.tcx().sess.span_bug(
|
self.tcx().sess.span_bug(
|
||||||
@ -628,10 +625,13 @@ impl<'t,'tcx,TYPER:Typer<'tcx>> MemCategorizationContext<'t,TYPER> {
|
|||||||
span: Span,
|
span: Span,
|
||||||
var_id: ast::NodeId,
|
var_id: ast::NodeId,
|
||||||
fn_node_id: ast::NodeId,
|
fn_node_id: ast::NodeId,
|
||||||
kind: ty::ClosureKind,
|
kind: ty::ClosureKind)
|
||||||
mode: ast::CaptureClause)
|
-> McResult<cmt<'tcx>>
|
||||||
-> McResult<cmt<'tcx>> {
|
{
|
||||||
// An upvar can have up to 3 components. The base is a
|
// 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
|
// `cat_upvar`. Next, we add a deref through the implicit
|
||||||
// environment pointer with an anonymous free region 'env and
|
// environment pointer with an anonymous free region 'env and
|
||||||
// appropriate borrow kind for closure kinds that take self by
|
// appropriate borrow kind for closure kinds that take self by
|
||||||
@ -650,28 +650,80 @@ impl<'t,'tcx,TYPER:Typer<'tcx>> MemCategorizationContext<'t,TYPER> {
|
|||||||
// Fn | copied -> &'env | upvar -> &'env -> &'up bk
|
// Fn | copied -> &'env | upvar -> &'env -> &'up bk
|
||||||
// FnMut | copied -> &'env mut | upvar -> &'env mut -> &'up bk
|
// FnMut | copied -> &'env mut | upvar -> &'env mut -> &'up bk
|
||||||
// FnOnce | copied | upvar -> &'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,
|
let upvar_id = ty::UpvarId { var_id: var_id,
|
||||||
closure_expr_id: fn_node_id };
|
closure_expr_id: fn_node_id };
|
||||||
|
let var_ty = try!(self.node_ty(var_id));
|
||||||
|
|
||||||
// Mutability of original variable itself
|
// Mutability of original variable itself
|
||||||
let var_mutbl = MutabilityCategory::from_local(self.tcx(), var_id);
|
let var_mutbl = MutabilityCategory::from_local(self.tcx(), var_id);
|
||||||
|
|
||||||
// Construct information about env pointer dereference, if any
|
// Construct the upvar. This represents access to the field
|
||||||
let mutbl = match kind {
|
// from the environment (perhaps we should eventually desugar
|
||||||
ty::FnOnceClosureKind => None, // None, env is by-value
|
// this field further, but it will do for now).
|
||||||
ty::FnMutClosureKind => match mode { // Depends on capture type
|
let cmt_result = cmt_ {
|
||||||
ast::CaptureByValue => Some(var_mutbl), // Mutable if the original var is
|
id: id,
|
||||||
ast::CaptureByRef => Some(McDeclared) // Mutable regardless
|
span: span,
|
||||||
},
|
cat: cat_upvar(Upvar {id: upvar_id, kind: kind}),
|
||||||
ty::FnClosureKind => Some(McImmutable) // Never mutable
|
mutbl: var_mutbl,
|
||||||
|
ty: var_ty,
|
||||||
|
note: NoteNone
|
||||||
};
|
};
|
||||||
let env_info = mutbl.map(|env_mutbl| {
|
|
||||||
|
// 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)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 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);
|
||||||
|
cmt_ {
|
||||||
|
id: id,
|
||||||
|
span: span,
|
||||||
|
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
|
// Look up the node ID of the closure body so we can construct
|
||||||
// a free region within it
|
// a free region within it
|
||||||
let fn_body_id = {
|
let fn_body_id = {
|
||||||
let fn_expr = match self.tcx().map.find(fn_node_id) {
|
let fn_expr = match self.tcx().map.find(upvar_id.closure_expr_id) {
|
||||||
Some(ast_map::NodeExpr(e)) => e,
|
Some(ast_map::NodeExpr(e)) => e,
|
||||||
_ => unreachable!()
|
_ => unreachable!()
|
||||||
};
|
};
|
||||||
@ -688,32 +740,10 @@ impl<'t,'tcx,TYPER:Typer<'tcx>> MemCategorizationContext<'t,TYPER> {
|
|||||||
bound_region: ty::BrEnv
|
bound_region: ty::BrEnv
|
||||||
});
|
});
|
||||||
|
|
||||||
let env_ptr = BorrowedPtr(if env_mutbl.is_mutable() {
|
let env_ptr = BorrowedPtr(env_borrow_kind, env_region);
|
||||||
ty::MutBorrow
|
|
||||||
} else {
|
|
||||||
ty::ImmBorrow
|
|
||||||
}, env_region);
|
|
||||||
|
|
||||||
(env_mutbl, env_ptr)
|
let var_ty = cmt_result.ty;
|
||||||
});
|
|
||||||
|
|
||||||
// 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
|
// We need to add the env deref. This means
|
||||||
// that the above is actually immutable and
|
// that the above is actually immutable and
|
||||||
// has a ref type. However, nothing should
|
// has a ref type. However, nothing should
|
||||||
@ -721,64 +751,29 @@ impl<'t,'tcx,TYPER:Typer<'tcx>> MemCategorizationContext<'t,TYPER> {
|
|||||||
// away with stuffing a `ty_err` in there
|
// away with stuffing a `ty_err` in there
|
||||||
// instead of bothering to construct a proper
|
// instead of bothering to construct a proper
|
||||||
// one.
|
// one.
|
||||||
base.mutbl = McImmutable;
|
let cmt_result = cmt_ {
|
||||||
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,
|
mutbl: McImmutable,
|
||||||
ty: self.tcx().types.err,
|
ty: self.tcx().types.err,
|
||||||
note: NoteNone
|
..cmt_result
|
||||||
};
|
};
|
||||||
|
|
||||||
match env_info {
|
let mut deref_mutbl = MutabilityCategory::from_borrow_kind(env_borrow_kind);
|
||||||
Some((env_mutbl, env_ptr)) => {
|
|
||||||
base = cmt_ {
|
// Issue #18335. If variable is declared as immutable, override the
|
||||||
id: id,
|
// mutability from the environment and substitute an `&T` anyway.
|
||||||
span: span,
|
match upvar_mutbl {
|
||||||
cat: cat_deref(Rc::new(base), 0, env_ptr),
|
McImmutable => { deref_mutbl = McImmutable; }
|
||||||
mutbl: env_mutbl,
|
McDeclared | McInherited => { }
|
||||||
ty: self.tcx().types.err,
|
|
||||||
note: NoteClosureEnv(upvar_id)
|
|
||||||
};
|
|
||||||
}
|
|
||||||
None => {}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Look up upvar borrow so we can get its region
|
cmt_ {
|
||||||
let upvar_borrow = self.typer.upvar_borrow(upvar_id).unwrap();
|
|
||||||
let ptr = BorrowedPtr(upvar_borrow.kind, upvar_borrow.region);
|
|
||||||
|
|
||||||
Rc::new(cmt_ {
|
|
||||||
id: id,
|
id: id,
|
||||||
span: span,
|
span: span,
|
||||||
cat: cat_deref(Rc::new(base), 0, ptr),
|
cat: cat_deref(Rc::new(cmt_result), 0, env_ptr),
|
||||||
mutbl: MutabilityCategory::from_borrow_kind(upvar_borrow.kind),
|
mutbl: deref_mutbl,
|
||||||
ty: var_ty,
|
ty: var_ty,
|
||||||
note: NoteUpvarRef(upvar_id)
|
note: NoteClosureEnv(upvar_id)
|
||||||
})
|
|
||||||
}
|
}
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn cat_rvalue_node(&self,
|
pub fn cat_rvalue_node(&self,
|
||||||
|
@ -777,7 +777,7 @@ pub struct ctxt<'tcx> {
|
|||||||
pub populated_external_traits: RefCell<DefIdSet>,
|
pub populated_external_traits: RefCell<DefIdSet>,
|
||||||
|
|
||||||
/// Borrows
|
/// 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
|
/// These two caches are used by const_eval when decoding external statics
|
||||||
/// and variants that are found.
|
/// and variants that are found.
|
||||||
@ -803,9 +803,6 @@ pub struct ctxt<'tcx> {
|
|||||||
/// Maps any item's def-id to its stability index.
|
/// Maps any item's def-id to its stability index.
|
||||||
pub stability: RefCell<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.
|
/// Maps def IDs to true if and only if they're associated types.
|
||||||
pub associated_types: RefCell<DefIdMap<bool>>,
|
pub associated_types: RefCell<DefIdMap<bool>>,
|
||||||
|
|
||||||
@ -1247,60 +1244,31 @@ pub enum BorrowKind {
|
|||||||
MutBorrow
|
MutBorrow
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Information describing the borrowing of an upvar. This is computed
|
/// Information describing the capture of an upvar. This is computed
|
||||||
/// during `typeck`, specifically by `regionck`. The general idea is
|
/// during `typeck`, specifically by `regionck`.
|
||||||
/// that the compiler analyses treat closures like:
|
#[derive(PartialEq, Clone, RustcEncodable, RustcDecodable, Debug, Copy)]
|
||||||
///
|
pub enum UpvarCapture {
|
||||||
/// let closure: &'e fn() = || {
|
/// Upvar is captured by value. This is always true when the
|
||||||
/// x = 1; // upvar x is assigned to
|
/// closure is labeled `move`, but can also be true in other cases
|
||||||
/// use(y); // upvar y is read
|
/// depending on inference.
|
||||||
/// foo(&z); // upvar z is borrowed immutably
|
ByValue,
|
||||||
/// };
|
|
||||||
///
|
/// Upvar is captured by reference.
|
||||||
/// as if they were "desugared" to something loosely like:
|
ByRef(UpvarBorrow),
|
||||||
///
|
}
|
||||||
/// 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.
|
|
||||||
#[derive(PartialEq, Clone, RustcEncodable, RustcDecodable, Debug, Copy)]
|
#[derive(PartialEq, Clone, RustcEncodable, RustcDecodable, Debug, Copy)]
|
||||||
pub struct UpvarBorrow {
|
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,
|
pub kind: BorrowKind,
|
||||||
|
|
||||||
|
/// Region of the resulting reference.
|
||||||
pub region: ty::Region,
|
pub region: ty::Region,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub type UpvarBorrowMap = FnvHashMap<UpvarId, UpvarBorrow>;
|
pub type UpvarCaptureMap = FnvHashMap<UpvarId, UpvarCapture>;
|
||||||
|
|
||||||
impl Region {
|
impl Region {
|
||||||
pub fn is_bound(&self) -> bool {
|
pub fn is_bound(&self) -> bool {
|
||||||
@ -2359,7 +2327,6 @@ pub fn mk_ctxt<'tcx>(s: Session,
|
|||||||
named_region_map: resolve_lifetime::NamedRegionMap,
|
named_region_map: resolve_lifetime::NamedRegionMap,
|
||||||
map: ast_map::Map<'tcx>,
|
map: ast_map::Map<'tcx>,
|
||||||
freevars: RefCell<FreevarMap>,
|
freevars: RefCell<FreevarMap>,
|
||||||
capture_modes: RefCell<CaptureModeMap>,
|
|
||||||
region_maps: middle::region::RegionMaps,
|
region_maps: middle::region::RegionMaps,
|
||||||
lang_items: middle::lang_items::LanguageItems,
|
lang_items: middle::lang_items::LanguageItems,
|
||||||
stability: stability::Index) -> ctxt<'tcx>
|
stability: stability::Index) -> ctxt<'tcx>
|
||||||
@ -2413,7 +2380,7 @@ pub fn mk_ctxt<'tcx>(s: Session,
|
|||||||
used_mut_nodes: RefCell::new(NodeSet()),
|
used_mut_nodes: RefCell::new(NodeSet()),
|
||||||
populated_external_types: RefCell::new(DefIdSet()),
|
populated_external_types: RefCell::new(DefIdSet()),
|
||||||
populated_external_traits: 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_statics: RefCell::new(DefIdMap()),
|
||||||
extern_const_variants: RefCell::new(DefIdMap()),
|
extern_const_variants: RefCell::new(DefIdMap()),
|
||||||
method_map: RefCell::new(FnvHashMap()),
|
method_map: RefCell::new(FnvHashMap()),
|
||||||
@ -2422,7 +2389,6 @@ pub fn mk_ctxt<'tcx>(s: Session,
|
|||||||
node_lint_levels: RefCell::new(FnvHashMap()),
|
node_lint_levels: RefCell::new(FnvHashMap()),
|
||||||
transmute_restrictions: RefCell::new(Vec::new()),
|
transmute_restrictions: RefCell::new(Vec::new()),
|
||||||
stability: RefCell::new(stability),
|
stability: RefCell::new(stability),
|
||||||
capture_modes: capture_modes,
|
|
||||||
associated_types: RefCell::new(DefIdMap()),
|
associated_types: RefCell::new(DefIdMap()),
|
||||||
selection_cache: traits::SelectionCache::new(),
|
selection_cache: traits::SelectionCache::new(),
|
||||||
repr_hint_cache: RefCell::new(DefIdMap()),
|
repr_hint_cache: RefCell::new(DefIdMap()),
|
||||||
@ -5646,7 +5612,6 @@ pub fn closure_upvars<'tcx>(typer: &mc::Typer<'tcx>,
|
|||||||
// implemented.
|
// implemented.
|
||||||
assert!(closure_id.krate == ast::LOCAL_CRATE);
|
assert!(closure_id.krate == ast::LOCAL_CRATE);
|
||||||
let tcx = typer.tcx();
|
let tcx = typer.tcx();
|
||||||
let capture_mode = tcx.capture_modes.borrow()[closure_id.node].clone();
|
|
||||||
match tcx.freevars.borrow().get(&closure_id.node) {
|
match tcx.freevars.borrow().get(&closure_id.node) {
|
||||||
None => Some(vec![]),
|
None => Some(vec![]),
|
||||||
Some(ref freevars) => {
|
Some(ref freevars) => {
|
||||||
@ -5659,22 +5624,17 @@ pub fn closure_upvars<'tcx>(typer: &mc::Typer<'tcx>,
|
|||||||
};
|
};
|
||||||
let freevar_ty = freevar_ty.subst(tcx, substs);
|
let freevar_ty = freevar_ty.subst(tcx, substs);
|
||||||
|
|
||||||
match capture_mode {
|
|
||||||
ast::CaptureByValue => {
|
|
||||||
Some(ClosureUpvar { def: freevar.def,
|
|
||||||
span: freevar.span,
|
|
||||||
ty: freevar_ty })
|
|
||||||
}
|
|
||||||
|
|
||||||
ast::CaptureByRef => {
|
|
||||||
let upvar_id = ty::UpvarId {
|
let upvar_id = ty::UpvarId {
|
||||||
var_id: freevar_def_id.node,
|
var_id: freevar_def_id.node,
|
||||||
closure_expr_id: closure_id.node
|
closure_expr_id: closure_id.node
|
||||||
};
|
};
|
||||||
|
|
||||||
// FIXME
|
let captured_freevar_ty = match typer.upvar_capture(upvar_id) {
|
||||||
let freevar_ref_ty = match typer.upvar_borrow(upvar_id) {
|
Some(UpvarCapture::ByValue) => {
|
||||||
Some(borrow) => {
|
freevar_ty
|
||||||
|
}
|
||||||
|
|
||||||
|
Some(UpvarCapture::ByRef(borrow)) => {
|
||||||
mk_rptr(tcx,
|
mk_rptr(tcx,
|
||||||
tcx.mk_region(borrow.region),
|
tcx.mk_region(borrow.region),
|
||||||
ty::mt {
|
ty::mt {
|
||||||
@ -5682,6 +5642,7 @@ pub fn closure_upvars<'tcx>(typer: &mc::Typer<'tcx>,
|
|||||||
mutbl: borrow.kind.to_mutbl_lossy(),
|
mutbl: borrow.kind.to_mutbl_lossy(),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
None => {
|
None => {
|
||||||
// FIXME(#16640) we should really return None here;
|
// FIXME(#16640) we should really return None here;
|
||||||
// but that requires better inference integration,
|
// but that requires better inference integration,
|
||||||
@ -5689,13 +5650,12 @@ pub fn closure_upvars<'tcx>(typer: &mc::Typer<'tcx>,
|
|||||||
freevar_ty
|
freevar_ty
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
Some(ClosureUpvar {
|
Some(ClosureUpvar {
|
||||||
def: freevar.def,
|
def: freevar.def,
|
||||||
span: freevar.span,
|
span: freevar.span,
|
||||||
ty: freevar_ref_ty,
|
ty: captured_freevar_ty,
|
||||||
})
|
})
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
@ -6449,14 +6409,13 @@ impl BorrowKind {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<'tcx> ctxt<'tcx> {
|
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 {
|
pub fn is_method_call(&self, expr_id: ast::NodeId) -> bool {
|
||||||
self.method_map.borrow().contains_key(&MethodCall::expr(expr_id))
|
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> {
|
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)
|
self.tcx.region_maps.temporary_scope(rvalue_id)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn upvar_borrow(&self, upvar_id: ty::UpvarId) -> Option<ty::UpvarBorrow> {
|
fn upvar_capture(&self, upvar_id: ty::UpvarId) -> Option<ty::UpvarCapture> {
|
||||||
Some(self.tcx.upvar_borrow_map.borrow()[upvar_id].clone())
|
self.tcx.upvar_capture(upvar_id)
|
||||||
}
|
|
||||||
|
|
||||||
fn capture_mode(&self, closure_expr_id: ast::NodeId)
|
|
||||||
-> ast::CaptureClause {
|
|
||||||
self.tcx.capture_mode(closure_expr_id)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn type_moves_by_default(&self, span: Span, ty: Ty<'tcx>) -> bool {
|
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 {
|
impl<'tcx> Repr<'tcx> for ty::IntVid {
|
||||||
fn repr(&self, _tcx: &ctxt) -> String {
|
fn repr(&self, _tcx: &ctxt) -> String {
|
||||||
format!("{:?}", self)
|
format!("{:?}", self)
|
||||||
|
@ -560,7 +560,6 @@ pub fn phase_3_run_analysis_passes<'tcx>(sess: Session,
|
|||||||
let resolve::CrateMap {
|
let resolve::CrateMap {
|
||||||
def_map,
|
def_map,
|
||||||
freevars,
|
freevars,
|
||||||
capture_mode_map,
|
|
||||||
export_map,
|
export_map,
|
||||||
trait_map,
|
trait_map,
|
||||||
external_exports,
|
external_exports,
|
||||||
@ -606,7 +605,6 @@ pub fn phase_3_run_analysis_passes<'tcx>(sess: Session,
|
|||||||
named_region_map,
|
named_region_map,
|
||||||
ast_map,
|
ast_map,
|
||||||
freevars,
|
freevars,
|
||||||
capture_mode_map,
|
|
||||||
region_map,
|
region_map,
|
||||||
lang_items,
|
lang_items,
|
||||||
stability_index);
|
stability_index);
|
||||||
|
@ -121,7 +121,7 @@ fn test_env<F>(source_string: &str,
|
|||||||
|
|
||||||
// run just enough stuff to build a tcx:
|
// run just enough stuff to build a tcx:
|
||||||
let lang_items = lang_items::collect_language_items(krate, &sess);
|
let lang_items = lang_items::collect_language_items(krate, &sess);
|
||||||
let resolve::CrateMap { def_map, freevars, capture_mode_map, .. } =
|
let resolve::CrateMap { def_map, freevars, .. } =
|
||||||
resolve::resolve_crate(&sess, &ast_map, &lang_items, krate, resolve::MakeGlobMap::No);
|
resolve::resolve_crate(&sess, &ast_map, &lang_items, krate, resolve::MakeGlobMap::No);
|
||||||
let named_region_map = resolve_lifetime::krate(&sess, krate, &def_map);
|
let named_region_map = resolve_lifetime::krate(&sess, krate, &def_map);
|
||||||
let region_map = region::resolve_crate(&sess, krate);
|
let region_map = region::resolve_crate(&sess, krate);
|
||||||
@ -132,7 +132,6 @@ fn test_env<F>(source_string: &str,
|
|||||||
named_region_map,
|
named_region_map,
|
||||||
ast_map,
|
ast_map,
|
||||||
freevars,
|
freevars,
|
||||||
capture_mode_map,
|
|
||||||
region_map,
|
region_map,
|
||||||
lang_items,
|
lang_items,
|
||||||
stability_index);
|
stability_index);
|
||||||
|
@ -62,7 +62,7 @@ use rustc::middle::lang_items::LanguageItems;
|
|||||||
use rustc::middle::pat_util::pat_bindings;
|
use rustc::middle::pat_util::pat_bindings;
|
||||||
use rustc::middle::privacy::*;
|
use rustc::middle::privacy::*;
|
||||||
use rustc::middle::subst::{ParamSpace, FnSpace, TypeSpace};
|
use rustc::middle::subst::{ParamSpace, FnSpace, TypeSpace};
|
||||||
use rustc::middle::ty::{CaptureModeMap, Freevar, FreevarMap, TraitMap, GlobMap};
|
use rustc::middle::ty::{Freevar, FreevarMap, TraitMap, GlobMap};
|
||||||
use rustc::util::nodemap::{NodeMap, NodeSet, DefIdSet, FnvHashMap};
|
use rustc::util::nodemap::{NodeMap, NodeSet, DefIdSet, FnvHashMap};
|
||||||
use rustc::util::lev_distance::lev_distance;
|
use rustc::util::lev_distance::lev_distance;
|
||||||
|
|
||||||
@ -900,7 +900,6 @@ struct Resolver<'a, 'tcx:'a> {
|
|||||||
def_map: DefMap,
|
def_map: DefMap,
|
||||||
freevars: RefCell<FreevarMap>,
|
freevars: RefCell<FreevarMap>,
|
||||||
freevars_seen: RefCell<NodeMap<NodeSet>>,
|
freevars_seen: RefCell<NodeMap<NodeSet>>,
|
||||||
capture_mode_map: CaptureModeMap,
|
|
||||||
export_map: ExportMap,
|
export_map: ExportMap,
|
||||||
trait_map: TraitMap,
|
trait_map: TraitMap,
|
||||||
external_exports: ExternalExports,
|
external_exports: ExternalExports,
|
||||||
@ -974,7 +973,6 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
|
|||||||
def_map: RefCell::new(NodeMap()),
|
def_map: RefCell::new(NodeMap()),
|
||||||
freevars: RefCell::new(NodeMap()),
|
freevars: RefCell::new(NodeMap()),
|
||||||
freevars_seen: RefCell::new(NodeMap()),
|
freevars_seen: RefCell::new(NodeMap()),
|
||||||
capture_mode_map: NodeMap(),
|
|
||||||
export_map: NodeMap(),
|
export_map: NodeMap(),
|
||||||
trait_map: NodeMap(),
|
trait_map: NodeMap(),
|
||||||
used_imports: HashSet::new(),
|
used_imports: HashSet::new(),
|
||||||
@ -4523,8 +4521,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
|
|||||||
visit::walk_expr(self, expr);
|
visit::walk_expr(self, expr);
|
||||||
}
|
}
|
||||||
|
|
||||||
ExprClosure(capture_clause, _, ref fn_decl, ref block) => {
|
ExprClosure(_, _, ref fn_decl, ref block) => {
|
||||||
self.capture_mode_map.insert(expr.id, capture_clause);
|
|
||||||
self.resolve_function(ClosureRibKind(expr.id),
|
self.resolve_function(ClosureRibKind(expr.id),
|
||||||
Some(&**fn_decl), NoTypeParameters,
|
Some(&**fn_decl), NoTypeParameters,
|
||||||
&**block);
|
&**block);
|
||||||
@ -4835,7 +4832,6 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
|
|||||||
pub struct CrateMap {
|
pub struct CrateMap {
|
||||||
pub def_map: DefMap,
|
pub def_map: DefMap,
|
||||||
pub freevars: RefCell<FreevarMap>,
|
pub freevars: RefCell<FreevarMap>,
|
||||||
pub capture_mode_map: RefCell<CaptureModeMap>,
|
|
||||||
pub export_map: ExportMap,
|
pub export_map: ExportMap,
|
||||||
pub trait_map: TraitMap,
|
pub trait_map: TraitMap,
|
||||||
pub external_exports: ExternalExports,
|
pub external_exports: ExternalExports,
|
||||||
@ -4875,7 +4871,6 @@ pub fn resolve_crate<'a, 'tcx>(session: &'a Session,
|
|||||||
CrateMap {
|
CrateMap {
|
||||||
def_map: resolver.def_map,
|
def_map: resolver.def_map,
|
||||||
freevars: resolver.freevars,
|
freevars: resolver.freevars,
|
||||||
capture_mode_map: RefCell::new(resolver.capture_mode_map),
|
|
||||||
export_map: resolver.export_map,
|
export_map: resolver.export_map,
|
||||||
trait_map: resolver.trait_map,
|
trait_map: resolver.trait_map,
|
||||||
external_exports: resolver.external_exports,
|
external_exports: resolver.external_exports,
|
||||||
|
@ -1789,7 +1789,7 @@ pub fn trans_closure<'a, 'b, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
|
|||||||
fcx = new_fn_ctxt(ccx,
|
fcx = new_fn_ctxt(ccx,
|
||||||
llfndecl,
|
llfndecl,
|
||||||
fn_ast_id,
|
fn_ast_id,
|
||||||
closure_env.kind != closure::NotClosure,
|
closure_env.kind != closure::ClosureKind::NotClosure,
|
||||||
output_type,
|
output_type,
|
||||||
param_substs,
|
param_substs,
|
||||||
Some(body.span),
|
Some(body.span),
|
||||||
@ -1809,12 +1809,12 @@ pub fn trans_closure<'a, 'b, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
|
|||||||
.map(|arg| node_id_type(bcx, arg.id))
|
.map(|arg| node_id_type(bcx, arg.id))
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
let monomorphized_arg_types = match closure_env.kind {
|
let monomorphized_arg_types = match closure_env.kind {
|
||||||
closure::NotClosure => {
|
closure::ClosureKind::NotClosure => {
|
||||||
monomorphized_arg_types
|
monomorphized_arg_types
|
||||||
}
|
}
|
||||||
|
|
||||||
// Tuple up closure argument types for the "rust-call" ABI.
|
// Tuple up closure argument types for the "rust-call" ABI.
|
||||||
closure::Closure(..) => {
|
closure::ClosureKind::Closure => {
|
||||||
vec![ty::mk_tup(ccx.tcx(), monomorphized_arg_types)]
|
vec![ty::mk_tup(ccx.tcx(), monomorphized_arg_types)]
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -1836,13 +1836,13 @@ pub fn trans_closure<'a, 'b, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
|
|||||||
};
|
};
|
||||||
|
|
||||||
bcx = match closure_env.kind {
|
bcx = match closure_env.kind {
|
||||||
closure::NotClosure => {
|
closure::ClosureKind::NotClosure => {
|
||||||
copy_args_to_allocas(bcx,
|
copy_args_to_allocas(bcx,
|
||||||
arg_scope,
|
arg_scope,
|
||||||
&decl.inputs[],
|
&decl.inputs[],
|
||||||
arg_datums)
|
arg_datums)
|
||||||
}
|
}
|
||||||
closure::Closure(..) => {
|
closure::ClosureKind::Closure => {
|
||||||
copy_closure_args_to_allocas(
|
copy_closure_args_to_allocas(
|
||||||
bcx,
|
bcx,
|
||||||
arg_scope,
|
arg_scope,
|
||||||
@ -1932,7 +1932,7 @@ pub fn trans_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
|
|||||||
attrs,
|
attrs,
|
||||||
output_type,
|
output_type,
|
||||||
abi,
|
abi,
|
||||||
closure::ClosureEnv::new(&[], closure::NotClosure));
|
closure::ClosureEnv::new(&[], closure::ClosureKind::NotClosure));
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn trans_enum_variant<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
|
pub fn trans_enum_variant<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
|
||||||
|
@ -8,8 +8,6 @@
|
|||||||
// option. This file may not be copied, modified, or distributed
|
// option. This file may not be copied, modified, or distributed
|
||||||
// except according to those terms.
|
// except according to those terms.
|
||||||
|
|
||||||
pub use self::ClosureKind::*;
|
|
||||||
|
|
||||||
use back::link::mangle_internal_name_by_path_and_seq;
|
use back::link::mangle_internal_name_by_path_and_seq;
|
||||||
use middle::mem_categorization::Typer;
|
use middle::mem_categorization::Typer;
|
||||||
use trans::adt;
|
use trans::adt;
|
||||||
@ -33,9 +31,9 @@ use syntax::ast_util;
|
|||||||
|
|
||||||
fn load_closure_environment<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
|
fn load_closure_environment<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
|
||||||
arg_scope_id: ScopeId,
|
arg_scope_id: ScopeId,
|
||||||
freevar_mode: ast::CaptureClause,
|
|
||||||
freevars: &[ty::Freevar])
|
freevars: &[ty::Freevar])
|
||||||
-> Block<'blk, 'tcx> {
|
-> Block<'blk, 'tcx>
|
||||||
|
{
|
||||||
let _icx = push_ctxt("closure::load_closure_environment");
|
let _icx = push_ctxt("closure::load_closure_environment");
|
||||||
|
|
||||||
// Special case for small by-value selfs.
|
// Special case for small by-value selfs.
|
||||||
@ -65,18 +63,21 @@ fn load_closure_environment<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
|
|||||||
};
|
};
|
||||||
|
|
||||||
for (i, freevar) in freevars.iter().enumerate() {
|
for (i, freevar) in freevars.iter().enumerate() {
|
||||||
|
let upvar_id = ty::UpvarId { var_id: freevar.def.local_node_id(),
|
||||||
|
closure_expr_id: closure_id.node };
|
||||||
|
let upvar_capture = bcx.tcx().upvar_capture(upvar_id).unwrap();
|
||||||
let mut upvar_ptr = GEPi(bcx, llenv, &[0, i]);
|
let mut upvar_ptr = GEPi(bcx, llenv, &[0, i]);
|
||||||
let captured_by_ref = match freevar_mode {
|
let captured_by_ref = match upvar_capture {
|
||||||
ast::CaptureByRef => {
|
ty::UpvarCapture::ByValue => false,
|
||||||
|
ty::UpvarCapture::ByRef(..) => {
|
||||||
upvar_ptr = Load(bcx, upvar_ptr);
|
upvar_ptr = Load(bcx, upvar_ptr);
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
ast::CaptureByValue => false
|
|
||||||
};
|
};
|
||||||
let def_id = freevar.def.def_id();
|
let def_id = freevar.def.def_id();
|
||||||
bcx.fcx.llupvars.borrow_mut().insert(def_id.node, upvar_ptr);
|
bcx.fcx.llupvars.borrow_mut().insert(def_id.node, upvar_ptr);
|
||||||
|
|
||||||
if kind == ty::FnOnceClosureKind && freevar_mode == ast::CaptureByValue {
|
if kind == ty::FnOnceClosureKind && !captured_by_ref {
|
||||||
bcx.fcx.schedule_drop_mem(arg_scope_id,
|
bcx.fcx.schedule_drop_mem(arg_scope_id,
|
||||||
upvar_ptr,
|
upvar_ptr,
|
||||||
node_id_type(bcx, def_id.node))
|
node_id_type(bcx, def_id.node))
|
||||||
@ -99,8 +100,7 @@ fn load_closure_environment<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
|
|||||||
#[derive(PartialEq)]
|
#[derive(PartialEq)]
|
||||||
pub enum ClosureKind<'tcx> {
|
pub enum ClosureKind<'tcx> {
|
||||||
NotClosure,
|
NotClosure,
|
||||||
// See load_closure_environment.
|
Closure,
|
||||||
Closure(ast::CaptureClause)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct ClosureEnv<'a, 'tcx> {
|
pub struct ClosureEnv<'a, 'tcx> {
|
||||||
@ -125,9 +125,9 @@ impl<'a, 'tcx> ClosureEnv<'a, 'tcx> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
match self.kind {
|
match self.kind {
|
||||||
NotClosure => bcx,
|
ClosureKind::NotClosure => bcx,
|
||||||
Closure(freevar_mode) => {
|
ClosureKind::Closure => {
|
||||||
load_closure_environment(bcx, arg_scope, freevar_mode, self.freevars)
|
load_closure_environment(bcx, arg_scope, self.freevars)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -212,7 +212,6 @@ pub fn trans_closure_expr<'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>,
|
|||||||
|
|
||||||
let freevars: Vec<ty::Freevar> =
|
let freevars: Vec<ty::Freevar> =
|
||||||
ty::with_freevars(bcx.tcx(), id, |fv| fv.iter().map(|&fv| fv).collect());
|
ty::with_freevars(bcx.tcx(), id, |fv| fv.iter().map(|&fv| fv).collect());
|
||||||
let freevar_mode = bcx.tcx().capture_mode(id);
|
|
||||||
|
|
||||||
let sig = ty::erase_late_bound_regions(bcx.tcx(), &function_type.sig);
|
let sig = ty::erase_late_bound_regions(bcx.tcx(), &function_type.sig);
|
||||||
|
|
||||||
@ -225,8 +224,7 @@ pub fn trans_closure_expr<'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>,
|
|||||||
&[],
|
&[],
|
||||||
sig.output,
|
sig.output,
|
||||||
function_type.abi,
|
function_type.abi,
|
||||||
ClosureEnv::new(&freevars[],
|
ClosureEnv::new(&freevars[], ClosureKind::Closure));
|
||||||
Closure(freevar_mode)));
|
|
||||||
|
|
||||||
// Don't hoist this to the top of the function. It's perfectly legitimate
|
// Don't hoist this to the top of the function. It's perfectly legitimate
|
||||||
// to have a zero-size closure (in which case dest will be `Ignore`) and
|
// to have a zero-size closure (in which case dest will be `Ignore`) and
|
||||||
@ -249,11 +247,14 @@ pub fn trans_closure_expr<'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>,
|
|||||||
dest_addr,
|
dest_addr,
|
||||||
0,
|
0,
|
||||||
i);
|
i);
|
||||||
match freevar_mode {
|
let upvar_id = ty::UpvarId { var_id: freevar.def.local_node_id(),
|
||||||
ast::CaptureByValue => {
|
closure_expr_id: id };
|
||||||
|
let upvar_capture = bcx.tcx().upvar_capture(upvar_id).unwrap();
|
||||||
|
match upvar_capture {
|
||||||
|
ty::UpvarCapture::ByValue => {
|
||||||
bcx = datum.store_to(bcx, upvar_slot_dest);
|
bcx = datum.store_to(bcx, upvar_slot_dest);
|
||||||
}
|
}
|
||||||
ast::CaptureByRef => {
|
ty::UpvarCapture::ByRef(..) => {
|
||||||
Store(bcx, datum.to_llref(), upvar_slot_dest);
|
Store(bcx, datum.to_llref(), upvar_slot_dest);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -679,13 +679,8 @@ impl<'blk, 'tcx> mc::Typer<'tcx> for BlockS<'blk, 'tcx> {
|
|||||||
self.tcx().region_maps.temporary_scope(rvalue_id)
|
self.tcx().region_maps.temporary_scope(rvalue_id)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn upvar_borrow(&self, upvar_id: ty::UpvarId) -> Option<ty::UpvarBorrow> {
|
fn upvar_capture(&self, upvar_id: ty::UpvarId) -> Option<ty::UpvarCapture> {
|
||||||
Some(self.tcx().upvar_borrow_map.borrow()[upvar_id].clone())
|
Some(self.tcx().upvar_capture_map.borrow()[upvar_id].clone())
|
||||||
}
|
|
||||||
|
|
||||||
fn capture_mode(&self, closure_expr_id: ast::NodeId)
|
|
||||||
-> ast::CaptureClause {
|
|
||||||
self.tcx().capture_modes.borrow()[closure_expr_id].clone()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn type_moves_by_default(&self, span: Span, ty: Ty<'tcx>) -> bool {
|
fn type_moves_by_default(&self, span: Span, ty: Ty<'tcx>) -> bool {
|
||||||
|
@ -160,7 +160,7 @@ pub struct Inherited<'a, 'tcx: 'a> {
|
|||||||
item_substs: RefCell<NodeMap<ty::ItemSubsts<'tcx>>>,
|
item_substs: RefCell<NodeMap<ty::ItemSubsts<'tcx>>>,
|
||||||
adjustments: RefCell<NodeMap<ty::AutoAdjustment<'tcx>>>,
|
adjustments: RefCell<NodeMap<ty::AutoAdjustment<'tcx>>>,
|
||||||
method_map: MethodMap<'tcx>,
|
method_map: MethodMap<'tcx>,
|
||||||
upvar_borrow_map: RefCell<ty::UpvarBorrowMap>,
|
upvar_capture_map: RefCell<ty::UpvarCaptureMap>,
|
||||||
closures: RefCell<DefIdMap<ty::Closure<'tcx>>>,
|
closures: RefCell<DefIdMap<ty::Closure<'tcx>>>,
|
||||||
object_cast_map: ObjectCastMap<'tcx>,
|
object_cast_map: ObjectCastMap<'tcx>,
|
||||||
|
|
||||||
@ -330,12 +330,8 @@ impl<'a, 'tcx> mc::Typer<'tcx> for FnCtxt<'a, 'tcx> {
|
|||||||
fn temporary_scope(&self, rvalue_id: ast::NodeId) -> Option<CodeExtent> {
|
fn temporary_scope(&self, rvalue_id: ast::NodeId) -> Option<CodeExtent> {
|
||||||
self.param_env().temporary_scope(rvalue_id)
|
self.param_env().temporary_scope(rvalue_id)
|
||||||
}
|
}
|
||||||
fn upvar_borrow(&self, upvar_id: ty::UpvarId) -> Option<ty::UpvarBorrow> {
|
fn upvar_capture(&self, upvar_id: ty::UpvarId) -> Option<ty::UpvarCapture> {
|
||||||
self.inh.upvar_borrow_map.borrow().get(&upvar_id).cloned()
|
self.inh.upvar_capture_map.borrow().get(&upvar_id).cloned()
|
||||||
}
|
|
||||||
fn capture_mode(&self, closure_expr_id: ast::NodeId)
|
|
||||||
-> ast::CaptureClause {
|
|
||||||
self.ccx.tcx.capture_mode(closure_expr_id)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -378,7 +374,7 @@ impl<'a, 'tcx> Inherited<'a, 'tcx> {
|
|||||||
adjustments: RefCell::new(NodeMap()),
|
adjustments: RefCell::new(NodeMap()),
|
||||||
method_map: RefCell::new(FnvHashMap()),
|
method_map: RefCell::new(FnvHashMap()),
|
||||||
object_cast_map: RefCell::new(NodeMap()),
|
object_cast_map: RefCell::new(NodeMap()),
|
||||||
upvar_borrow_map: RefCell::new(FnvHashMap()),
|
upvar_capture_map: RefCell::new(FnvHashMap()),
|
||||||
closures: RefCell::new(DefIdMap()),
|
closures: RefCell::new(DefIdMap()),
|
||||||
fn_sig_map: RefCell::new(NodeMap()),
|
fn_sig_map: RefCell::new(NodeMap()),
|
||||||
fulfillment_cx: RefCell::new(traits::FulfillmentContext::new()),
|
fulfillment_cx: RefCell::new(traits::FulfillmentContext::new()),
|
||||||
|
@ -742,17 +742,10 @@ fn check_expr_fn_block(rcx: &mut Rcx,
|
|||||||
|
|
||||||
match function_type.sty {
|
match function_type.sty {
|
||||||
ty::ty_closure(_, region, _) => {
|
ty::ty_closure(_, region, _) => {
|
||||||
if tcx.capture_modes.borrow()[expr.id].clone() == ast::CaptureByRef {
|
|
||||||
ty::with_freevars(tcx, expr.id, |freevars| {
|
ty::with_freevars(tcx, expr.id, |freevars| {
|
||||||
if !freevars.is_empty() {
|
constrain_captured_variables(rcx, *region, expr, freevars);
|
||||||
// Variables being referenced must be constrained and registered
|
|
||||||
// in the upvar borrow map
|
|
||||||
constrain_free_variables_in_by_ref_closure(
|
|
||||||
rcx, *region, expr, freevars);
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
|
||||||
_ => { }
|
_ => { }
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -799,14 +792,14 @@ fn check_expr_fn_block(rcx: &mut Rcx,
|
|||||||
let raw_var_ty = rcx.resolve_node_type(var_node_id);
|
let raw_var_ty = rcx.resolve_node_type(var_node_id);
|
||||||
let upvar_id = ty::UpvarId { var_id: var_node_id,
|
let upvar_id = ty::UpvarId { var_id: var_node_id,
|
||||||
closure_expr_id: expr.id };
|
closure_expr_id: expr.id };
|
||||||
let var_ty = match rcx.fcx.inh.upvar_borrow_map.borrow().get(&upvar_id) {
|
let var_ty = match rcx.fcx.inh.upvar_capture_map.borrow()[upvar_id] {
|
||||||
Some(upvar_borrow) => {
|
ty::UpvarCapture::ByRef(ref upvar_borrow) => {
|
||||||
ty::mk_rptr(rcx.tcx(),
|
ty::mk_rptr(rcx.tcx(),
|
||||||
rcx.tcx().mk_region(upvar_borrow.region),
|
rcx.tcx().mk_region(upvar_borrow.region),
|
||||||
ty::mt { mutbl: upvar_borrow.kind.to_mutbl_lossy(),
|
ty::mt { mutbl: upvar_borrow.kind.to_mutbl_lossy(),
|
||||||
ty: raw_var_ty })
|
ty: raw_var_ty })
|
||||||
}
|
}
|
||||||
None => raw_var_ty
|
ty::UpvarCapture::ByValue => raw_var_ty,
|
||||||
};
|
};
|
||||||
|
|
||||||
// Check that the type meets the criteria of the existential bounds:
|
// Check that the type meets the criteria of the existential bounds:
|
||||||
@ -824,17 +817,17 @@ fn check_expr_fn_block(rcx: &mut Rcx,
|
|||||||
|
|
||||||
/// Make sure that all free variables referenced inside the closure outlive the closure's
|
/// Make sure that all free variables referenced inside the closure outlive the closure's
|
||||||
/// lifetime bound. Also, create an entry in the upvar_borrows map with a region.
|
/// lifetime bound. Also, create an entry in the upvar_borrows map with a region.
|
||||||
fn constrain_free_variables_in_by_ref_closure(
|
fn constrain_captured_variables(
|
||||||
rcx: &mut Rcx,
|
rcx: &mut Rcx,
|
||||||
region_bound: ty::Region,
|
region_bound: ty::Region,
|
||||||
expr: &ast::Expr,
|
expr: &ast::Expr,
|
||||||
freevars: &[ty::Freevar])
|
freevars: &[ty::Freevar])
|
||||||
{
|
{
|
||||||
let tcx = rcx.fcx.ccx.tcx;
|
let tcx = rcx.fcx.ccx.tcx;
|
||||||
debug!("constrain_free_variables({}, {})",
|
debug!("constrain_captured_variables({}, {})",
|
||||||
region_bound.repr(tcx), expr.repr(tcx));
|
region_bound.repr(tcx), expr.repr(tcx));
|
||||||
for freevar in freevars.iter() {
|
for freevar in freevars.iter() {
|
||||||
debug!("freevar def is {:?}", freevar.def);
|
debug!("constrain_captured_variables: freevar.def={:?}", freevar.def);
|
||||||
|
|
||||||
// Identify the variable being closed over and its node-id.
|
// Identify the variable being closed over and its node-id.
|
||||||
let def = freevar.def;
|
let def = freevar.def;
|
||||||
@ -846,19 +839,23 @@ fn check_expr_fn_block(rcx: &mut Rcx,
|
|||||||
let upvar_id = ty::UpvarId { var_id: var_node_id,
|
let upvar_id = ty::UpvarId { var_id: var_node_id,
|
||||||
closure_expr_id: expr.id };
|
closure_expr_id: expr.id };
|
||||||
|
|
||||||
let upvar_borrow = rcx.fcx.inh.upvar_borrow_map.borrow()[upvar_id];
|
match rcx.fcx.inh.upvar_capture_map.borrow()[upvar_id] {
|
||||||
|
ty::UpvarCapture::ByValue => { }
|
||||||
|
ty::UpvarCapture::ByRef(upvar_borrow) => {
|
||||||
rcx.fcx.mk_subr(infer::FreeVariable(freevar.span, var_node_id),
|
rcx.fcx.mk_subr(infer::FreeVariable(freevar.span, var_node_id),
|
||||||
region_bound, upvar_borrow.region);
|
region_bound, upvar_borrow.region);
|
||||||
|
|
||||||
// Guarantee that the closure does not outlive the variable itself.
|
// Guarantee that the closure does not outlive the variable itself.
|
||||||
let enclosing_region = region_of_def(rcx.fcx, def);
|
let enclosing_region = region_of_def(rcx.fcx, def);
|
||||||
debug!("enclosing_region = {}", enclosing_region.repr(tcx));
|
debug!("constrain_captured_variables: enclosing_region = {}",
|
||||||
|
enclosing_region.repr(tcx));
|
||||||
rcx.fcx.mk_subr(infer::FreeVariable(freevar.span, var_node_id),
|
rcx.fcx.mk_subr(infer::FreeVariable(freevar.span, var_node_id),
|
||||||
region_bound, enclosing_region);
|
region_bound, enclosing_region);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn constrain_callee(rcx: &mut Rcx,
|
fn constrain_callee(rcx: &mut Rcx,
|
||||||
callee_id: ast::NodeId,
|
callee_id: ast::NodeId,
|
||||||
@ -1333,22 +1330,20 @@ fn link_reborrowed_region<'a, 'tcx>(rcx: &Rcx<'a, 'tcx>,
|
|||||||
// Detect by-ref upvar `x`:
|
// Detect by-ref upvar `x`:
|
||||||
let cause = match note {
|
let cause = match note {
|
||||||
mc::NoteUpvarRef(ref upvar_id) => {
|
mc::NoteUpvarRef(ref upvar_id) => {
|
||||||
let mut upvar_borrow_map =
|
let upvar_capture_map = rcx.fcx.inh.upvar_capture_map.borrow_mut();
|
||||||
rcx.fcx.inh.upvar_borrow_map.borrow_mut();
|
match upvar_capture_map.get(upvar_id) {
|
||||||
match upvar_borrow_map.get_mut(upvar_id) {
|
Some(&ty::UpvarCapture::ByRef(ref upvar_borrow)) => {
|
||||||
Some(upvar_borrow) => {
|
|
||||||
// The mutability of the upvar may have been modified
|
// The mutability of the upvar may have been modified
|
||||||
// by the above adjustment, so update our local variable.
|
// by the above adjustment, so update our local variable.
|
||||||
ref_kind = upvar_borrow.kind;
|
ref_kind = upvar_borrow.kind;
|
||||||
|
|
||||||
infer::ReborrowUpvar(span, *upvar_id)
|
infer::ReborrowUpvar(span, *upvar_id)
|
||||||
}
|
}
|
||||||
None => {
|
_ => {
|
||||||
rcx.tcx().sess.span_bug(
|
rcx.tcx().sess.span_bug(
|
||||||
span,
|
span,
|
||||||
&format!("Illegal upvar id: {}",
|
&format!("Illegal upvar id: {}",
|
||||||
upvar_id.repr(
|
upvar_id.repr(rcx.tcx()))[]);
|
||||||
rcx.tcx()))[]);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -121,27 +121,31 @@ impl<'a,'tcx> SeedBorrowKind<'a,'tcx> {
|
|||||||
capture_clause: ast::CaptureClause,
|
capture_clause: ast::CaptureClause,
|
||||||
_body: &ast::Block)
|
_body: &ast::Block)
|
||||||
{
|
{
|
||||||
match capture_clause {
|
|
||||||
ast::CaptureByValue => {}
|
|
||||||
_ => {
|
|
||||||
ty::with_freevars(self.tcx(), expr.id, |freevars| {
|
ty::with_freevars(self.tcx(), expr.id, |freevars| {
|
||||||
for freevar in freevars.iter() {
|
for freevar in freevars.iter() {
|
||||||
let var_node_id = freevar.def.local_node_id();
|
let var_node_id = freevar.def.local_node_id();
|
||||||
let upvar_id = ty::UpvarId { var_id: var_node_id,
|
let upvar_id = ty::UpvarId { var_id: var_node_id,
|
||||||
closure_expr_id: expr.id };
|
closure_expr_id: expr.id };
|
||||||
debug!("seed upvar_id {:?}", upvar_id);
|
debug!("seed upvar_id {:?}", upvar_id);
|
||||||
|
|
||||||
|
let capture_kind = match capture_clause {
|
||||||
|
ast::CaptureByValue => {
|
||||||
|
ty::UpvarCapture::ByValue
|
||||||
|
}
|
||||||
|
ast::CaptureByRef => {
|
||||||
let origin = UpvarRegion(upvar_id, expr.span);
|
let origin = UpvarRegion(upvar_id, expr.span);
|
||||||
let freevar_region = self.infcx().next_region_var(origin);
|
let freevar_region = self.infcx().next_region_var(origin);
|
||||||
let upvar_borrow = ty::UpvarBorrow { kind: ty::ImmBorrow,
|
let upvar_borrow = ty::UpvarBorrow { kind: ty::ImmBorrow,
|
||||||
region: freevar_region };
|
region: freevar_region };
|
||||||
self.fcx.inh.upvar_borrow_map.borrow_mut().insert(upvar_id,
|
ty::UpvarCapture::ByRef(upvar_borrow)
|
||||||
upvar_borrow);
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
self.fcx.inh.upvar_capture_map.borrow_mut().insert(upvar_id, capture_kind);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////
|
||||||
// ADJUST BORROW KIND
|
// ADJUST BORROW KIND
|
||||||
@ -195,8 +199,8 @@ impl<'a,'tcx> AdjustBorrowKind<'a,'tcx>{
|
|||||||
// upvar, then we need to modify the
|
// upvar, then we need to modify the
|
||||||
// borrow_kind of the upvar to make sure it
|
// borrow_kind of the upvar to make sure it
|
||||||
// is inferred to mutable if necessary
|
// is inferred to mutable if necessary
|
||||||
let mut upvar_borrow_map = self.fcx.inh.upvar_borrow_map.borrow_mut();
|
let mut upvar_capture_map = self.fcx.inh.upvar_capture_map.borrow_mut();
|
||||||
let ub = &mut upvar_borrow_map[upvar_id];
|
let ub = &mut upvar_capture_map[upvar_id];
|
||||||
self.adjust_upvar_borrow_kind(upvar_id, ub, ty::MutBorrow);
|
self.adjust_upvar_borrow_kind(upvar_id, ub, ty::MutBorrow);
|
||||||
} else {
|
} else {
|
||||||
// assignment to deref of an `&mut`
|
// assignment to deref of an `&mut`
|
||||||
@ -237,7 +241,7 @@ impl<'a,'tcx> AdjustBorrowKind<'a,'tcx>{
|
|||||||
// upvar, then we need to modify the
|
// upvar, then we need to modify the
|
||||||
// borrow_kind of the upvar to make sure it
|
// borrow_kind of the upvar to make sure it
|
||||||
// is inferred to unique if necessary
|
// is inferred to unique if necessary
|
||||||
let mut ub = self.fcx.inh.upvar_borrow_map.borrow_mut();
|
let mut ub = self.fcx.inh.upvar_capture_map.borrow_mut();
|
||||||
let ub = &mut ub[upvar_id];
|
let ub = &mut ub[upvar_id];
|
||||||
self.adjust_upvar_borrow_kind(upvar_id, ub, ty::UniqueImmBorrow);
|
self.adjust_upvar_borrow_kind(upvar_id, ub, ty::UniqueImmBorrow);
|
||||||
} else {
|
} else {
|
||||||
@ -262,11 +266,16 @@ impl<'a,'tcx> AdjustBorrowKind<'a,'tcx>{
|
|||||||
/// some particular use.
|
/// some particular use.
|
||||||
fn adjust_upvar_borrow_kind(&self,
|
fn adjust_upvar_borrow_kind(&self,
|
||||||
upvar_id: ty::UpvarId,
|
upvar_id: ty::UpvarId,
|
||||||
upvar_borrow: &mut ty::UpvarBorrow,
|
upvar_capture: &mut ty::UpvarCapture,
|
||||||
kind: ty::BorrowKind) {
|
kind: ty::BorrowKind) {
|
||||||
debug!("adjust_upvar_borrow_kind: id={:?} kind=({:?} -> {:?})",
|
debug!("adjust_upvar_borrow_kind(upvar_id={:?}, upvar_capture={:?}, kind={:?})",
|
||||||
upvar_id, upvar_borrow.kind, kind);
|
upvar_id, upvar_capture, kind);
|
||||||
|
|
||||||
|
match *upvar_capture {
|
||||||
|
ty::UpvarCapture::ByValue => {
|
||||||
|
// Upvar is already by-value, the strongest criteria.
|
||||||
|
}
|
||||||
|
ty::UpvarCapture::ByRef(ref mut upvar_borrow) => {
|
||||||
match (upvar_borrow.kind, kind) {
|
match (upvar_borrow.kind, kind) {
|
||||||
// Take RHS:
|
// Take RHS:
|
||||||
(ty::ImmBorrow, ty::UniqueImmBorrow) |
|
(ty::ImmBorrow, ty::UniqueImmBorrow) |
|
||||||
@ -283,6 +292,8 @@ impl<'a,'tcx> AdjustBorrowKind<'a,'tcx>{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<'a, 'tcx, 'v> Visitor<'v> for AdjustBorrowKind<'a, 'tcx> {
|
impl<'a, 'tcx, 'v> Visitor<'v> for AdjustBorrowKind<'a, 'tcx> {
|
||||||
fn visit_fn(&mut self,
|
fn visit_fn(&mut self,
|
||||||
|
@ -182,16 +182,20 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (upvar_id, upvar_borrow) in self.fcx.inh.upvar_borrow_map.borrow().iter() {
|
for (upvar_id, upvar_capture) in self.fcx.inh.upvar_capture_map.borrow().iter() {
|
||||||
|
let new_upvar_capture = match *upvar_capture {
|
||||||
|
ty::UpvarCapture::ByValue => ty::UpvarCapture::ByValue,
|
||||||
|
ty::UpvarCapture::ByRef(ref upvar_borrow) => {
|
||||||
let r = upvar_borrow.region;
|
let r = upvar_borrow.region;
|
||||||
let r = self.resolve(&r, ResolvingUpvar(*upvar_id));
|
let r = self.resolve(&r, ResolvingUpvar(*upvar_id));
|
||||||
let new_upvar_borrow = ty::UpvarBorrow { kind: upvar_borrow.kind,
|
ty::UpvarCapture::ByRef(
|
||||||
region: r };
|
ty::UpvarBorrow { kind: upvar_borrow.kind, region: r })
|
||||||
debug!("Upvar borrow for {} resolved to {}",
|
}
|
||||||
|
};
|
||||||
|
debug!("Upvar capture for {} resolved to {}",
|
||||||
upvar_id.repr(self.tcx()),
|
upvar_id.repr(self.tcx()),
|
||||||
new_upvar_borrow.repr(self.tcx()));
|
new_upvar_capture.repr(self.tcx()));
|
||||||
self.fcx.tcx().upvar_borrow_map.borrow_mut().insert(
|
self.fcx.tcx().upvar_capture_map.borrow_mut().insert(*upvar_id, new_upvar_capture);
|
||||||
*upvar_id, new_upvar_borrow);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -58,8 +58,10 @@ fn test6() {
|
|||||||
fn test7() {
|
fn test7() {
|
||||||
fn foo<F>(_: F) where F: FnMut(Box<FnMut(isize)>, isize) {}
|
fn foo<F>(_: F) where F: FnMut(Box<FnMut(isize)>, isize) {}
|
||||||
let mut f = |&mut: g: Box<FnMut(isize)>, b: isize| {};
|
let mut f = |&mut: g: Box<FnMut(isize)>, b: isize| {};
|
||||||
f(box |a| { //~ ERROR: cannot borrow `f` as immutable because it is also borrowed as mutable
|
f(box |a| {
|
||||||
foo(f); //~ ERROR: cannot move out of captured outer variable
|
foo(f);
|
||||||
|
//~^ ERROR cannot move `f` into closure because it is borrowed
|
||||||
|
//~| ERROR cannot move out of captured outer variable in an `FnMut` closure
|
||||||
}, 3);
|
}, 3);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -19,24 +19,24 @@ fn main() {
|
|||||||
// By-ref cases
|
// By-ref cases
|
||||||
{
|
{
|
||||||
let x = box 0us;
|
let x = box 0us;
|
||||||
let f = |&:| drop(x); //~ cannot move
|
let f = |&:| drop(x); //~ ERROR cannot move
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
let x = box 0us;
|
let x = box 0us;
|
||||||
let f = |&mut:| drop(x); //~ cannot move
|
let f = |&mut:| drop(x); //~ ERROR cannot move
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
let x = box 0us;
|
let x = box 0us;
|
||||||
let f = |:| drop(x); //~ cannot move
|
let f = |:| drop(x); // OK -- FnOnce
|
||||||
}
|
}
|
||||||
// By-value cases
|
// By-value cases
|
||||||
{
|
{
|
||||||
let x = box 0us;
|
let x = box 0us;
|
||||||
let f = move |&:| drop(x); //~ cannot move
|
let f = move |&:| drop(x); //~ ERROR cannot move
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
let x = box 0us;
|
let x = box 0us;
|
||||||
let f = move |&mut:| drop(x); //~ cannot move
|
let f = move |&mut:| drop(x); //~ ERROR cannot move
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
let x = box 0us;
|
let x = box 0us;
|
||||||
|
62
src/test/compile-fail/unboxed-closures-mutate-upvar.rs
Normal file
62
src/test/compile-fail/unboxed-closures-mutate-upvar.rs
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
// Copyright 2015 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.
|
||||||
|
|
||||||
|
// Test that we cannot mutate an outer variable that is not declared
|
||||||
|
// as `mut` through a closure. Also test that we CAN mutate a moved copy,
|
||||||
|
// unless this is a `Fn` closure. Issue #16749.
|
||||||
|
|
||||||
|
use std::mem;
|
||||||
|
|
||||||
|
fn a() {
|
||||||
|
let n = 0u8;
|
||||||
|
let mut f = |&mut:| { //~ ERROR closure cannot assign
|
||||||
|
n += 1;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
fn b() {
|
||||||
|
let mut n = 0u8;
|
||||||
|
let mut f = |&mut:| {
|
||||||
|
n += 1; // OK
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
fn c() {
|
||||||
|
let n = 0u8;
|
||||||
|
let mut f = move |&mut:| {
|
||||||
|
// If we just did a straight-forward desugaring, this would
|
||||||
|
// compile, but we do something a bit more subtle, and hence
|
||||||
|
// we get an error.
|
||||||
|
n += 1; //~ ERROR cannot assign
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
fn d() {
|
||||||
|
let mut n = 0u8;
|
||||||
|
let mut f = move |&mut:| {
|
||||||
|
n += 1; // OK
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
fn e() {
|
||||||
|
let n = 0u8;
|
||||||
|
let mut f = move |&:| {
|
||||||
|
n += 1; //~ ERROR cannot assign
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
fn f() {
|
||||||
|
let mut n = 0u8;
|
||||||
|
let mut f = move |&:| {
|
||||||
|
n += 1; //~ ERROR cannot assign
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() { }
|
Loading…
Reference in New Issue
Block a user