提交 3fbfad35 编写于 作者: B bors

Auto merge of #21604 - nikomatsakis:closure-move-indiv-vars, r=eddyb

r? @EddyB 
......@@ -70,6 +70,7 @@
#![feature(lang_items, unsafe_destructor)]
#![feature(box_syntax)]
#![feature(optin_builtin_traits)]
#![feature(unboxed_closures)]
#![allow(unknown_features)] #![feature(int_uint)]
#![feature(core)]
#![feature(hash)]
......
......@@ -1183,6 +1183,7 @@ extern "rust-call" fn call_once(mut self, args: A) -> R {
#[unstable(feature = "core",
reason = "uncertain about variadic generics, input versus associated types")]
#[cfg(not(stage0))]
#[rustc_paren_sugar]
pub trait Fn<Args> {
type Output;
......@@ -1195,6 +1196,7 @@ pub trait Fn<Args> {
#[unstable(feature = "core",
reason = "uncertain about variadic generics, input versus associated types")]
#[cfg(not(stage0))]
#[rustc_paren_sugar]
pub trait FnMut<Args> {
type Output;
......@@ -1207,6 +1209,7 @@ pub trait FnMut<Args> {
#[unstable(feature = "core",
reason = "uncertain about variadic generics, input versus associated types")]
#[cfg(not(stage0))]
#[rustc_paren_sugar]
pub trait FnOnce<Args> {
type Output;
......
......@@ -670,6 +670,7 @@ fn check_attribute(&mut self, cx: &Context, attr: &ast::Attribute) {
// FIXME: #19470 this shouldn't be needed forever
"old_orphan_check",
"old_impl_check",
"rustc_paren_sugar", // FIXME: #18101 temporary unboxed closure hack
];
static CRATE_ATTRS: &'static [&'static str] = &[
......
......@@ -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,
}
......@@ -265,3 +265,5 @@ pub struct LinkMeta {
pub const tag_macro_defs: uint = 0xb5;
pub const tag_macro_def: uint = 0xb6;
pub const tag_macro_def_body: uint = 0xb7;
pub const tag_paren_sugar: uint = 0xb8;
......@@ -371,6 +371,11 @@ fn parse_unsafety(item_doc: rbml::Doc) -> ast::Unsafety {
}
}
fn parse_paren_sugar(item_doc: rbml::Doc) -> bool {
let paren_sugar_doc = reader::get_doc(item_doc, tag_paren_sugar);
reader::doc_as_u8(paren_sugar_doc) != 0
}
fn parse_polarity(item_doc: rbml::Doc) -> ast::ImplPolarity {
let polarity_doc = reader::get_doc(item_doc, tag_polarity);
if reader::doc_as_u8(polarity_doc) != 0 {
......@@ -400,8 +405,10 @@ pub fn get_trait_def<'tcx>(cdata: Cmd,
let bounds = trait_def_bounds(item_doc, tcx, cdata);
let unsafety = parse_unsafety(item_doc);
let associated_type_names = parse_associated_type_names(item_doc);
let paren_sugar = parse_paren_sugar(item_doc);
ty::TraitDef {
paren_sugar: paren_sugar,
unsafety: unsafety,
generics: generics,
bounds: bounds,
......
......@@ -1317,6 +1317,7 @@ fn add_to_index(item: &ast::Item, rbml_w: &Encoder,
encode_item_variances(rbml_w, ecx, item.id);
let trait_def = ty::lookup_trait_def(tcx, def_id);
encode_unsafety(rbml_w, trait_def.unsafety);
encode_paren_sugar(rbml_w, trait_def.paren_sugar);
encode_associated_type_names(rbml_w, trait_def.associated_type_names.as_slice());
encode_generics(rbml_w, ecx, &trait_def.generics, tag_item_generics);
encode_trait_ref(rbml_w, ecx, &*trait_def.trait_ref, tag_item_trait_ref);
......@@ -1697,6 +1698,11 @@ fn encode_unsafety(rbml_w: &mut Encoder, unsafety: ast::Unsafety) {
rbml_w.wr_tagged_u8(tag_unsafety, byte);
}
fn encode_paren_sugar(rbml_w: &mut Encoder, paren_sugar: bool) {
let byte: u8 = if paren_sugar {1} else {0};
rbml_w.wr_tagged_u8(tag_paren_sugar, byte);
}
fn encode_associated_type_names(rbml_w: &mut Encoder, names: &[ast::Name]) {
rbml_w.start_tag(tag_associated_type_names);
for &name in names.iter() {
......
......@@ -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 @@ fn tr(&self, dcx: &DecodeContext) -> 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);
......
......@@ -366,6 +366,9 @@ fn delegate_consume(&mut self,
consume_id: ast::NodeId,
consume_span: Span,
cmt: mc::cmt<'tcx>) {
debug!("delegate_consume(consume_id={}, cmt={})",
consume_id, cmt.repr(self.tcx()));
let mode = copy_or_move(self.typer, &cmt, DirectRefMove);
self.delegate.consume(consume_id, consume_span, cmt, mode);
}
......@@ -1208,53 +1211,32 @@ fn walk_captures(&mut self, closure_expr: &ast::Expr) {
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 @@ fn node_method_origin(&self, method_call: ty::MethodCall)
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 @@ pub fn cat_def(&self,
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 @@ fn cat_upvar(&self,
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 @@ fn cat_upvar(&self,
// 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!()
}
};
// 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)
});
// 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)
}
};
// First, switch by capture mode
Ok(match mode {
ast::CaptureByValue => {
let mut base = cmt_ {
// 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_upvar(Upvar {
id: upvar_id,
kind: kind
}),
mutbl: var_mutbl,
cat: cat_deref(Rc::new(cmt_result), 0, ptr),
mutbl: MutabilityCategory::from_borrow_kind(upvar_borrow.kind),
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)
note: NoteUpvarRef(upvar_id)
}
},
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 => {}
}
Ok(Rc::new(cmt_result))
}
// Look up upvar borrow so we can get its region
let upvar_borrow = self.typer.upvar_borrow(upvar_id).unwrap();
let ptr = BorrowedPtr(upvar_borrow.kind, upvar_borrow.region);
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!()
};
Rc::new(cmt_ {
id: id,
span: span,
cat: cat_deref(Rc::new(base), 0, ptr),
mutbl: MutabilityCategory::from_borrow_kind(upvar_borrow.kind),
ty: var_ty,
note: NoteUpvarRef(upvar_id)
})
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 @@ pub fn escapes_depth(&self, depth: u32) -> bool {
}
#[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),
......@@ -2253,6 +2221,12 @@ pub struct TypeScheme<'tcx> {
pub struct TraitDef<'tcx> {
pub unsafety: ast::Unsafety,
/// If `true`, then this trait had the `#[rustc_paren_sugar]`
/// attribute, indicating that it should be used with `Foo()`
/// sugar. This is a temporary thing -- eventually any trait wil
/// be usable with the sugar (or without it).
pub paren_sugar: bool,
/// Generic type definitions. Note that `Self` is listed in here
/// as having a single bound, the trait itself (e.g., in the trait
/// `Eq`, there is a single bound `Self : Eq`). This is so that
......@@ -2359,7 +2333,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 +2386,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 +2395,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 +5618,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 +5630,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
};
Some(UpvarCapture::ByRef(borrow)) => {
mk_rptr(tcx,
tcx.mk_region(borrow.region),
ty::mt {
ty: freevar_ty,
mutbl: borrow.kind.to_mutbl_lossy(),
})
}
// 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,
})
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 +6415,13 @@ pub fn to_user_str(&self) -> &'static str {
}
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 +6459,8 @@ fn temporary_scope(&self, rvalue_id: ast::NodeId) -> Option<region::CodeExtent>
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 @@ fn repr(&self, tcx: &ctxt) -> String {
}
}
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)
......
......@@ -560,7 +560,6 @@ pub fn phase_3_run_analysis_passes<'tcx>(sess: Session,
let resolve::CrateMap {
def_map,
freevars,
capture_mode_map,
export_map,
trait_map,
external_exports,
......@@ -606,7 +605,6 @@ pub fn phase_3_run_analysis_passes<'tcx>(sess: Session,
named_region_map,
ast_map,
freevars,
capture_mode_map,
region_map,
lang_items,
stability_index);
......
......@@ -121,7 +121,7 @@ fn test_env<F>(source_string: &str,
// run just enough stuff to build a tcx:
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);
let named_region_map = resolve_lifetime::krate(&sess, krate, &def_map);
let region_map = region::resolve_crate(&sess, krate);
......@@ -132,7 +132,6 @@ fn test_env<F>(source_string: &str,
named_region_map,
ast_map,
freevars,
capture_mode_map,
region_map,
lang_items,
stability_index);
......
......@@ -62,7 +62,7 @@
use rustc::middle::pat_util::pat_bindings;
use rustc::middle::privacy::*;
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::lev_distance::lev_distance;
......@@ -900,7 +900,6 @@ struct Resolver<'a, 'tcx:'a> {
def_map: DefMap,
freevars: RefCell<FreevarMap>,
freevars_seen: RefCell<NodeMap<NodeSet>>,
capture_mode_map: CaptureModeMap,
export_map: ExportMap,
trait_map: TraitMap,
external_exports: ExternalExports,
......@@ -974,7 +973,6 @@ fn new(session: &'a Session,
def_map: RefCell::new(NodeMap()),
freevars: RefCell::new(NodeMap()),
freevars_seen: RefCell::new(NodeMap()),
capture_mode_map: NodeMap(),
export_map: NodeMap(),
trait_map: NodeMap(),
used_imports: HashSet::new(),
......@@ -4523,8 +4521,7 @@ fn resolve_expr(&mut self, expr: &Expr) {
visit::walk_expr(self, expr);
}
ExprClosure(capture_clause, _, ref fn_decl, ref block) => {
self.capture_mode_map.insert(expr.id, capture_clause);
ExprClosure(_, _, ref fn_decl, ref block) => {
self.resolve_function(ClosureRibKind(expr.id),
Some(&**fn_decl), NoTypeParameters,
&**block);
......@@ -4835,7 +4832,6 @@ fn dump_module(&mut self, module_: Rc<Module>) {
pub struct CrateMap {
pub def_map: DefMap,
pub freevars: RefCell<FreevarMap>,
pub capture_mode_map: RefCell<CaptureModeMap>,
pub export_map: ExportMap,
pub trait_map: TraitMap,
pub external_exports: ExternalExports,
......@@ -4875,7 +4871,6 @@ pub fn resolve_crate<'a, 'tcx>(session: &'a Session,
CrateMap {
def_map: resolver.def_map,
freevars: resolver.freevars,
capture_mode_map: RefCell::new(resolver.capture_mode_map),
export_map: resolver.export_map,
trait_map: resolver.trait_map,
external_exports: resolver.external_exports,
......
......@@ -1775,7 +1775,7 @@ pub fn trans_closure<'a, 'b, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
_attributes: &[ast::Attribute],
output_type: ty::FnOutput<'tcx>,
abi: Abi,
closure_env: closure::ClosureEnv<'b, 'tcx>) {
closure_env: closure::ClosureEnv<'b>) {
ccx.stats().n_closures.set(ccx.stats().n_closures.get() + 1);
let _icx = push_ctxt("trans_closure");
......@@ -1784,12 +1784,17 @@ pub fn trans_closure<'a, 'b, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
debug!("trans_closure(..., param_substs={})",
param_substs.repr(ccx.tcx()));
let has_env = match closure_env {
closure::ClosureEnv::Closure(_) => true,
closure::ClosureEnv::NotClosure => false,
};
let (arena, fcx): (TypedArena<_>, FunctionContext);
arena = TypedArena::new();
fcx = new_fn_ctxt(ccx,
llfndecl,
fn_ast_id,
closure_env.kind != closure::NotClosure,
has_env,
output_type,
param_substs,
Some(body.span),
......@@ -1808,13 +1813,13 @@ pub fn trans_closure<'a, 'b, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
decl.inputs.iter()
.map(|arg| node_id_type(bcx, arg.id))
.collect::<Vec<_>>();
let monomorphized_arg_types = match closure_env.kind {
closure::NotClosure => {
let monomorphized_arg_types = match closure_env {
closure::ClosureEnv::NotClosure => {
monomorphized_arg_types
}
// Tuple up closure argument types for the "rust-call" ABI.
closure::Closure(..) => {
closure::ClosureEnv::Closure(_) => {
vec![ty::mk_tup(ccx.tcx(), monomorphized_arg_types)]
}
};
......@@ -1835,14 +1840,14 @@ pub fn trans_closure<'a, 'b, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
&monomorphized_arg_types[])
};
bcx = match closure_env.kind {
closure::NotClosure => {
bcx = match closure_env {
closure::ClosureEnv::NotClosure => {
copy_args_to_allocas(bcx,
arg_scope,
&decl.inputs[],
arg_datums)
}
closure::Closure(..) => {
closure::ClosureEnv::Closure(_) => {
copy_closure_args_to_allocas(
bcx,
arg_scope,
......@@ -1932,7 +1937,7 @@ pub fn trans_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
attrs,
output_type,
abi,
closure::ClosureEnv::new(&[], closure::NotClosure));
closure::ClosureEnv::NotClosure);
}
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
// except according to those terms.
pub use self::ClosureKind::*;
use back::link::mangle_internal_name_by_path_and_seq;
use middle::mem_categorization::Typer;
use trans::adt;
......@@ -33,9 +31,9 @@
fn load_closure_environment<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
arg_scope_id: ScopeId,
freevar_mode: ast::CaptureClause,
freevars: &[ty::Freevar])
-> Block<'blk, 'tcx> {
-> Block<'blk, 'tcx>
{
let _icx = push_ctxt("closure::load_closure_environment");
// 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() {
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 captured_by_ref = match freevar_mode {
ast::CaptureByRef => {
let captured_by_ref = match upvar_capture {
ty::UpvarCapture::ByValue => false,
ty::UpvarCapture::ByRef(..) => {
upvar_ptr = Load(bcx, upvar_ptr);
true
}
ast::CaptureByValue => false
};
let def_id = freevar.def.def_id();
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,
upvar_ptr,
node_id_type(bcx, def_id.node))
......@@ -96,38 +97,23 @@ fn load_closure_environment<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
bcx
}
#[derive(PartialEq)]
pub enum ClosureKind<'tcx> {
pub enum ClosureEnv<'a> {
NotClosure,
// See load_closure_environment.
Closure(ast::CaptureClause)
Closure(&'a [ty::Freevar]),
}
pub struct ClosureEnv<'a, 'tcx> {
freevars: &'a [ty::Freevar],
pub kind: ClosureKind<'tcx>
}
impl<'a, 'tcx> ClosureEnv<'a, 'tcx> {
pub fn new(freevars: &'a [ty::Freevar], kind: ClosureKind<'tcx>)
-> ClosureEnv<'a, 'tcx> {
ClosureEnv {
freevars: freevars,
kind: kind
}
}
pub fn load<'blk>(self, bcx: Block<'blk, 'tcx>, arg_scope: ScopeId)
-> Block<'blk, 'tcx> {
// Don't bother to create the block if there's nothing to load
if self.freevars.is_empty() {
return bcx;
}
match self.kind {
NotClosure => bcx,
Closure(freevar_mode) => {
load_closure_environment(bcx, arg_scope, freevar_mode, self.freevars)
impl<'a> ClosureEnv<'a> {
pub fn load<'blk,'tcx>(self, bcx: Block<'blk, 'tcx>, arg_scope: ScopeId)
-> Block<'blk, 'tcx>
{
match self {
ClosureEnv::NotClosure => bcx,
ClosureEnv::Closure(freevars) => {
if freevars.is_empty() {
bcx
} else {
load_closure_environment(bcx, arg_scope, freevars)
}
}
}
}
......@@ -212,7 +198,6 @@ pub fn trans_closure_expr<'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>,
let freevars: Vec<ty::Freevar> =
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);
......@@ -225,8 +210,7 @@ pub fn trans_closure_expr<'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>,
&[],
sig.output,
function_type.abi,
ClosureEnv::new(&freevars[],
Closure(freevar_mode)));
ClosureEnv::Closure(&freevars[]));
// 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
......@@ -249,11 +233,14 @@ pub fn trans_closure_expr<'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>,
dest_addr,
0,
i);
match freevar_mode {
ast::CaptureByValue => {
let upvar_id = ty::UpvarId { var_id: freevar.def.local_node_id(),
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);
}
ast::CaptureByRef => {
ty::UpvarCapture::ByRef(..) => {
Store(bcx, datum.to_llref(), upvar_slot_dest);
}
}
......
......@@ -679,13 +679,8 @@ fn temporary_scope(&self, rvalue_id: ast::NodeId) -> Option<region::CodeExtent>
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_modes.borrow()[closure_expr_id].clone()
fn upvar_capture(&self, upvar_id: ty::UpvarId) -> Option<ty::UpvarCapture> {
Some(self.tcx().upvar_capture_map.borrow()[upvar_id].clone())
}
fn type_moves_by_default(&self, span: Span, ty: Ty<'tcx>) -> bool {
......
......@@ -614,11 +614,9 @@ fn ast_path_to_trait_ref<'a,'tcx>(
let (regions, types, assoc_bindings) = match path.segments.last().unwrap().parameters {
ast::AngleBracketedParameters(ref data) => {
// For now, require that parenthetical notation be used
// For now, require that parenthetical5D notation be used
// only with `Fn()` etc.
if !this.tcx().sess.features.borrow().unboxed_closures &&
this.tcx().lang_items.fn_trait_kind(trait_def_id).is_some()
{
if !this.tcx().sess.features.borrow().unboxed_closures && trait_def.paren_sugar {
span_err!(this.tcx().sess, path.span, E0215,
"angle-bracket notation is not stable when \
used with the `Fn` family of traits, use parentheses");
......@@ -632,9 +630,7 @@ fn ast_path_to_trait_ref<'a,'tcx>(
ast::ParenthesizedParameters(ref data) => {
// For now, require that parenthetical notation be used
// only with `Fn()` etc.
if !this.tcx().sess.features.borrow().unboxed_closures &&
this.tcx().lang_items.fn_trait_kind(trait_def_id).is_none()
{
if !this.tcx().sess.features.borrow().unboxed_closures && !trait_def.paren_sugar {
span_err!(this.tcx().sess, path.span, E0216,
"parenthetical notation is only stable when \
used with the `Fn` family of traits");
......
......@@ -160,7 +160,7 @@ pub struct Inherited<'a, 'tcx: 'a> {
item_substs: RefCell<NodeMap<ty::ItemSubsts<'tcx>>>,
adjustments: RefCell<NodeMap<ty::AutoAdjustment<'tcx>>>,
method_map: MethodMap<'tcx>,
upvar_borrow_map: RefCell<ty::UpvarBorrowMap>,
upvar_capture_map: RefCell<ty::UpvarCaptureMap>,
closures: RefCell<DefIdMap<ty::Closure<'tcx>>>,
object_cast_map: ObjectCastMap<'tcx>,
......@@ -305,7 +305,7 @@ fn expr_ty_adjusted(&self, expr: &ast::Expr) -> McResult<Ty<'tcx>> {
}
fn type_moves_by_default(&self, span: Span, ty: Ty<'tcx>) -> bool {
let ty = self.infcx().resolve_type_vars_if_possible(&ty);
traits::type_known_to_meet_builtin_bound(self.infcx(), self, ty, ty::BoundCopy, span)
!traits::type_known_to_meet_builtin_bound(self.infcx(), self, ty, ty::BoundCopy, span)
}
fn node_method_ty(&self, method_call: ty::MethodCall)
-> Option<Ty<'tcx>> {
......@@ -330,12 +330,8 @@ fn is_method_call(&self, id: ast::NodeId) -> bool {
fn temporary_scope(&self, rvalue_id: ast::NodeId) -> Option<CodeExtent> {
self.param_env().temporary_scope(rvalue_id)
}
fn upvar_borrow(&self, upvar_id: ty::UpvarId) -> Option<ty::UpvarBorrow> {
self.inh.upvar_borrow_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)
fn upvar_capture(&self, upvar_id: ty::UpvarId) -> Option<ty::UpvarCapture> {
self.inh.upvar_capture_map.borrow().get(&upvar_id).cloned()
}
}
......@@ -378,7 +374,7 @@ fn new(tcx: &'a ty::ctxt<'tcx>,
adjustments: RefCell::new(NodeMap()),
method_map: RefCell::new(FnvHashMap()),
object_cast_map: RefCell::new(NodeMap()),
upvar_borrow_map: RefCell::new(FnvHashMap()),
upvar_capture_map: RefCell::new(FnvHashMap()),
closures: RefCell::new(DefIdMap()),
fn_sig_map: RefCell::new(NodeMap()),
fulfillment_cx: RefCell::new(traits::FulfillmentContext::new()),
......
......@@ -742,16 +742,9 @@ fn check_expr_fn_block(rcx: &mut Rcx,
match function_type.sty {
ty::ty_closure(_, region, _) => {
if tcx.capture_modes.borrow()[expr.id].clone() == ast::CaptureByRef {
ty::with_freevars(tcx, expr.id, |freevars| {
if !freevars.is_empty() {
// Variables being referenced must be constrained and registered
// in the upvar borrow map
constrain_free_variables_in_by_ref_closure(
rcx, *region, expr, freevars);
}
})
}
ty::with_freevars(tcx, expr.id, |freevars| {
constrain_captured_variables(rcx, *region, expr, freevars);
})
}
_ => { }
}
......@@ -799,14 +792,14 @@ fn ensure_free_variable_types_outlive_closure_bound(
let raw_var_ty = rcx.resolve_node_type(var_node_id);
let upvar_id = ty::UpvarId { var_id: var_node_id,
closure_expr_id: expr.id };
let var_ty = match rcx.fcx.inh.upvar_borrow_map.borrow().get(&upvar_id) {
Some(upvar_borrow) => {
let var_ty = match rcx.fcx.inh.upvar_capture_map.borrow()[upvar_id] {
ty::UpvarCapture::ByRef(ref upvar_borrow) => {
ty::mk_rptr(rcx.tcx(),
rcx.tcx().mk_region(upvar_borrow.region),
ty::mt { mutbl: upvar_borrow.kind.to_mutbl_lossy(),
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:
......@@ -824,17 +817,17 @@ fn ensure_free_variable_types_outlive_closure_bound(
/// 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.
fn constrain_free_variables_in_by_ref_closure(
fn constrain_captured_variables(
rcx: &mut Rcx,
region_bound: ty::Region,
expr: &ast::Expr,
freevars: &[ty::Freevar])
{
let tcx = rcx.fcx.ccx.tcx;
debug!("constrain_free_variables({}, {})",
debug!("constrain_captured_variables({}, {})",
region_bound.repr(tcx), expr.repr(tcx));
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.
let def = freevar.def;
......@@ -846,16 +839,20 @@ fn constrain_free_variables_in_by_ref_closure(
let upvar_id = ty::UpvarId { var_id: var_node_id,
closure_expr_id: expr.id };
let upvar_borrow = rcx.fcx.inh.upvar_borrow_map.borrow()[upvar_id];
rcx.fcx.mk_subr(infer::FreeVariable(freevar.span, var_node_id),
region_bound, upvar_borrow.region);
// Guarantee that the closure does not outlive the variable itself.
let enclosing_region = region_of_def(rcx.fcx, def);
debug!("enclosing_region = {}", enclosing_region.repr(tcx));
rcx.fcx.mk_subr(infer::FreeVariable(freevar.span, var_node_id),
region_bound, enclosing_region);
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),
region_bound, upvar_borrow.region);
// Guarantee that the closure does not outlive the variable itself.
let enclosing_region = region_of_def(rcx.fcx, def);
debug!("constrain_captured_variables: enclosing_region = {}",
enclosing_region.repr(tcx));
rcx.fcx.mk_subr(infer::FreeVariable(freevar.span, var_node_id),
region_bound, enclosing_region);
}
}
}
}
}
......@@ -1333,22 +1330,20 @@ fn link_reborrowed_region<'a, 'tcx>(rcx: &Rcx<'a, 'tcx>,
// Detect by-ref upvar `x`:
let cause = match note {
mc::NoteUpvarRef(ref upvar_id) => {
let mut upvar_borrow_map =
rcx.fcx.inh.upvar_borrow_map.borrow_mut();
match upvar_borrow_map.get_mut(upvar_id) {
Some(upvar_borrow) => {
let upvar_capture_map = rcx.fcx.inh.upvar_capture_map.borrow_mut();
match upvar_capture_map.get(upvar_id) {
Some(&ty::UpvarCapture::ByRef(ref upvar_borrow)) => {
// The mutability of the upvar may have been modified
// by the above adjustment, so update our local variable.
ref_kind = upvar_borrow.kind;
infer::ReborrowUpvar(span, *upvar_id)
}
None => {
_ => {
rcx.tcx().sess.span_bug(
span,
&format!("Illegal upvar id: {}",
upvar_id.repr(
rcx.tcx()))[]);
upvar_id.repr(rcx.tcx()))[]);
}
}
}
......
......@@ -121,25 +121,29 @@ fn check_closure(&mut self,
capture_clause: ast::CaptureClause,
_body: &ast::Block)
{
match capture_clause {
ast::CaptureByValue => {}
_ => {
ty::with_freevars(self.tcx(), expr.id, |freevars| {
for freevar in freevars.iter() {
let var_node_id = freevar.def.local_node_id();
let upvar_id = ty::UpvarId { var_id: var_node_id,
closure_expr_id: expr.id };
debug!("seed upvar_id {:?}", upvar_id);
ty::with_freevars(self.tcx(), expr.id, |freevars| {
for freevar in freevars.iter() {
let var_node_id = freevar.def.local_node_id();
let upvar_id = ty::UpvarId { var_id: var_node_id,
closure_expr_id: expr.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 freevar_region = self.infcx().next_region_var(origin);
let upvar_borrow = ty::UpvarBorrow { kind: ty::ImmBorrow,
region: freevar_region };
self.fcx.inh.upvar_borrow_map.borrow_mut().insert(upvar_id,
upvar_borrow);
ty::UpvarCapture::ByRef(upvar_borrow)
}
});
};
self.fcx.inh.upvar_capture_map.borrow_mut().insert(upvar_id, capture_kind);
}
}
});
}
}
......@@ -150,7 +154,7 @@ struct AdjustBorrowKind<'a,'tcx:'a> {
fcx: &'a FnCtxt<'a,'tcx>
}
impl<'a,'tcx> AdjustBorrowKind<'a,'tcx>{
impl<'a,'tcx> AdjustBorrowKind<'a,'tcx> {
fn new(fcx: &'a FnCtxt<'a,'tcx>) -> AdjustBorrowKind<'a,'tcx> {
AdjustBorrowKind { fcx: fcx }
}
......@@ -172,6 +176,41 @@ fn analyze_fn(&mut self, decl: &ast::FnDecl, body: &ast::Block) {
euv.walk_fn(decl, body);
}
fn adjust_upvar_borrow_kind_for_consume(&self,
cmt: mc::cmt<'tcx>,
mode: euv::ConsumeMode)
{
debug!("adjust_upvar_borrow_kind_for_consume(cmt={}, mode={:?})",
cmt.repr(self.tcx()), mode);
// we only care about moves
match mode {
euv::Copy => { return; }
euv::Move(_) => { }
}
// watch out for a move of the deref of a borrowed pointer;
// for that to be legal, the upvar would have to be borrowed
// by value instead
let guarantor = cmt.guarantor();
debug!("adjust_upvar_borrow_kind_for_consume: guarantor={}",
guarantor.repr(self.tcx()));
match guarantor.cat {
mc::cat_deref(_, _, mc::BorrowedPtr(..)) |
mc::cat_deref(_, _, mc::Implicit(..)) => {
if let mc::NoteUpvarRef(upvar_id) = cmt.note {
debug!("adjust_upvar_borrow_kind_for_consume: \
setting upvar_id={:?} to by value",
upvar_id);
let mut upvar_capture_map = self.fcx.inh.upvar_capture_map.borrow_mut();
upvar_capture_map.insert(upvar_id, ty::UpvarCapture::ByValue);
}
}
_ => { }
}
}
/// Indicates that `cmt` is being directly mutated (e.g., assigned
/// to). If cmt contains any by-ref upvars, this implies that
/// those upvars must be borrowed using an `&mut` borow.
......@@ -195,8 +234,8 @@ fn adjust_upvar_borrow_kind_for_mut(&mut self, cmt: mc::cmt<'tcx>) {
// upvar, then we need to modify the
// borrow_kind of the upvar to make sure it
// is inferred to mutable if necessary
let mut upvar_borrow_map = self.fcx.inh.upvar_borrow_map.borrow_mut();
let ub = &mut upvar_borrow_map[upvar_id];
let mut upvar_capture_map = self.fcx.inh.upvar_capture_map.borrow_mut();
let ub = &mut upvar_capture_map[upvar_id];
self.adjust_upvar_borrow_kind(upvar_id, ub, ty::MutBorrow);
} else {
// assignment to deref of an `&mut`
......@@ -237,7 +276,7 @@ fn adjust_upvar_borrow_kind_for_unique(&self, cmt: mc::cmt<'tcx>) {
// upvar, then we need to modify the
// borrow_kind of the upvar to make sure it
// 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];
self.adjust_upvar_borrow_kind(upvar_id, ub, ty::UniqueImmBorrow);
} else {
......@@ -262,23 +301,30 @@ fn adjust_upvar_borrow_kind_for_unique(&self, cmt: mc::cmt<'tcx>) {
/// some particular use.
fn adjust_upvar_borrow_kind(&self,
upvar_id: ty::UpvarId,
upvar_borrow: &mut ty::UpvarBorrow,
upvar_capture: &mut ty::UpvarCapture,
kind: ty::BorrowKind) {
debug!("adjust_upvar_borrow_kind: id={:?} kind=({:?} -> {:?})",
upvar_id, upvar_borrow.kind, kind);
match (upvar_borrow.kind, kind) {
// Take RHS:
(ty::ImmBorrow, ty::UniqueImmBorrow) |
(ty::ImmBorrow, ty::MutBorrow) |
(ty::UniqueImmBorrow, ty::MutBorrow) => {
upvar_borrow.kind = kind;
debug!("adjust_upvar_borrow_kind(upvar_id={:?}, upvar_capture={:?}, kind={:?})",
upvar_id, upvar_capture, kind);
match *upvar_capture {
ty::UpvarCapture::ByValue => {
// Upvar is already by-value, the strongest criteria.
}
// Take LHS:
(ty::ImmBorrow, ty::ImmBorrow) |
(ty::UniqueImmBorrow, ty::ImmBorrow) |
(ty::UniqueImmBorrow, ty::UniqueImmBorrow) |
(ty::MutBorrow, _) => {
ty::UpvarCapture::ByRef(ref mut upvar_borrow) => {
match (upvar_borrow.kind, kind) {
// Take RHS:
(ty::ImmBorrow, ty::UniqueImmBorrow) |
(ty::ImmBorrow, ty::MutBorrow) |
(ty::UniqueImmBorrow, ty::MutBorrow) => {
upvar_borrow.kind = kind;
}
// Take LHS:
(ty::ImmBorrow, ty::ImmBorrow) |
(ty::UniqueImmBorrow, ty::ImmBorrow) |
(ty::UniqueImmBorrow, ty::UniqueImmBorrow) |
(ty::MutBorrow, _) => {
}
}
}
}
}
......@@ -308,9 +354,12 @@ impl<'a,'tcx> euv::Delegate<'tcx> for AdjustBorrowKind<'a,'tcx> {
fn consume(&mut self,
_consume_id: ast::NodeId,
_consume_span: Span,
_cmt: mc::cmt<'tcx>,
_mode: euv::ConsumeMode)
{}
cmt: mc::cmt<'tcx>,
mode: euv::ConsumeMode)
{
debug!("consume(cmt={},mode={:?})", cmt.repr(self.tcx()), mode);
self.adjust_upvar_borrow_kind_for_consume(cmt, mode);
}
fn matched_pat(&mut self,
_matched_pat: &ast::Pat,
......@@ -320,9 +369,12 @@ fn matched_pat(&mut self,
fn consume_pat(&mut self,
_consume_pat: &ast::Pat,
_cmt: mc::cmt<'tcx>,
_mode: euv::ConsumeMode)
{}
cmt: mc::cmt<'tcx>,
mode: euv::ConsumeMode)
{
debug!("consume_pat(cmt={},mode={:?})", cmt.repr(self.tcx()), mode);
self.adjust_upvar_borrow_kind_for_consume(cmt, mode);
}
fn borrow(&mut self,
borrow_id: ast::NodeId,
......
......@@ -182,16 +182,20 @@ fn visit_upvar_borrow_map(&self) {
return;
}
for (upvar_id, upvar_borrow) in self.fcx.inh.upvar_borrow_map.borrow().iter() {
let r = upvar_borrow.region;
let r = self.resolve(&r, ResolvingUpvar(*upvar_id));
let new_upvar_borrow = ty::UpvarBorrow { kind: upvar_borrow.kind,
region: r };
debug!("Upvar borrow for {} resolved to {}",
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 = self.resolve(&r, ResolvingUpvar(*upvar_id));
ty::UpvarCapture::ByRef(
ty::UpvarBorrow { kind: upvar_borrow.kind, region: r })
}
};
debug!("Upvar capture for {} resolved to {}",
upvar_id.repr(self.tcx()),
new_upvar_borrow.repr(self.tcx()));
self.fcx.tcx().upvar_borrow_map.borrow_mut().insert(
*upvar_id, new_upvar_borrow);
new_upvar_capture.repr(self.tcx()));
self.fcx.tcx().upvar_capture_map.borrow_mut().insert(*upvar_id, new_upvar_capture);
}
}
......
......@@ -855,6 +855,17 @@ fn trait_def_of_item<'a, 'tcx>(ccx: &CollectCtxt<'a, 'tcx>,
}
};
let paren_sugar = ty::has_attr(tcx, def_id, "rustc_paren_sugar");
if paren_sugar && !ccx.tcx.sess.features.borrow().unboxed_closures {
ccx.tcx.sess.span_err(
it.span,
"the `#[rustc_paren_sugar]` attribute is a temporary means of controlling \
which traits can use parenthetical notation");
span_help!(ccx.tcx.sess, it.span,
"add `#![feature(unboxed_closures)]` to \
the crate attributes to use it");
}
let substs = ccx.tcx.mk_substs(mk_trait_substs(ccx, generics));
let ty_generics = ty_generics_for_trait(ccx,
......@@ -887,6 +898,7 @@ fn trait_def_of_item<'a, 'tcx>(ccx: &CollectCtxt<'a, 'tcx>,
});
let trait_def = Rc::new(ty::TraitDef {
paren_sugar: paren_sugar,
unsafety: unsafety,
generics: ty_generics,
bounds: bounds,
......
......@@ -58,8 +58,10 @@ fn test6() {
fn test7() {
fn foo<F>(_: F) where F: FnMut(Box<FnMut(isize)>, 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
foo(f); //~ ERROR: cannot move out of captured outer variable
f(box |a| {
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);
}
......
......@@ -19,24 +19,24 @@ fn main() {
// By-ref cases
{
let x = box 0us;
let f = |&:| drop(x); //~ cannot move
let f = |&:| drop(x); //~ ERROR cannot move
}
{
let x = box 0us;
let f = |&mut:| drop(x); //~ cannot move
let f = |&mut:| drop(x); //~ ERROR cannot move
}
{
let x = box 0us;
let f = |:| drop(x); //~ cannot move
let f = |:| drop(x); // OK -- FnOnce
}
// By-value cases
{
let x = box 0us;
let f = move |&:| drop(x); //~ cannot move
let f = move |&:| drop(x); //~ ERROR cannot move
}
{
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;
......
// 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 a by-ref `FnMut` closure gets an error when it tries to
// consume a value.
fn call<F>(f: F) where F : Fn() {
f();
}
fn main() {
let y = vec!(format!("World"));
call(|| {
y.into_iter();
//~^ ERROR cannot move out of captured outer variable in an `Fn` closure
});
}
// 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() { }
// 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 a by-ref `FnMut` closure gets an error when it tries to
// mutate a value.
fn call<F>(f: F) where F : Fn() {
f();
}
fn main() {
let mut counter = 0_u32;
call(|| {
counter += 1;
//~^ ERROR cannot assign to data in a captured outer variable in an `Fn` closure
});
}
// 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 mutate a counter on the stack only when we expect to.
fn call<F>(f: F) where F : FnOnce() {
f();
}
fn main() {
let y = vec!(format!("Hello"), format!("World"));
let mut counter = 22_u32;
call(|| {
// Move `y`, but do not move `counter`, even though it is read
// by value (note that it is also mutated).
for item in y.into_iter() {
let v = counter;
counter += v;
}
});
assert_eq!(counter, 88);
call(move || {
// this mutates a moved copy, and hence doesn't affect original
counter += 1;
});
assert_eq!(counter, 88);
}
// 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 in a by-ref once closure we move some variables even as
// we capture others by mutable reference.
fn call<F>(f: F) where F : FnOnce() {
f();
}
fn main() {
let mut x = vec!(format!("Hello"));
let y = vec!(format!("World"));
call(|| {
// Here: `x` must be captured with a mutable reference in
// order for us to append on it, and `y` must be captured by
// value.
for item in y.into_iter() {
x.push(item);
}
});
assert_eq!(x.len(), 2);
assert_eq!(&*x[0], "Hello");
assert_eq!(&*x[1], "World");
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册