auto merge of #15929 : pcwalton/rust/by-ref-closures, r=alexcrichton
by-reference upvars. This partially implements RFC 38. A snapshot will be needed to turn this on, because stage0 cannot yet parse the keyword. Part of #12831. r? @alexcrichton
This commit is contained in:
commit
9d45d63d0d
@ -360,8 +360,9 @@ pub fn phase_3_run_analysis_passes(sess: Session,
|
||||
plugin::build::find_plugin_registrar(
|
||||
sess.diagnostic(), krate)));
|
||||
|
||||
let freevars = time(time_passes, "freevar finding", (), |_|
|
||||
freevars::annotate_freevars(&def_map, krate));
|
||||
let (freevars, capture_modes) =
|
||||
time(time_passes, "freevar finding", (), |_|
|
||||
freevars::annotate_freevars(&def_map, krate));
|
||||
|
||||
let region_map = time(time_passes, "region resolution", (), |_|
|
||||
middle::region::resolve_crate(&sess, krate));
|
||||
@ -372,8 +373,15 @@ pub fn phase_3_run_analysis_passes(sess: Session,
|
||||
let stability_index = time(time_passes, "stability index", (), |_|
|
||||
stability::Index::build(krate));
|
||||
|
||||
let ty_cx = ty::mk_ctxt(sess, def_map, named_region_map, ast_map,
|
||||
freevars, region_map, lang_items, stability_index);
|
||||
let ty_cx = ty::mk_ctxt(sess,
|
||||
def_map,
|
||||
named_region_map,
|
||||
ast_map,
|
||||
freevars,
|
||||
capture_modes,
|
||||
region_map,
|
||||
lang_items,
|
||||
stability_index);
|
||||
|
||||
// passes are timed inside typeck
|
||||
typeck::check_crate(&ty_cx, trait_map, krate);
|
||||
|
@ -141,9 +141,10 @@ pub enum astencode_tag { // Reserves 0x40 -- 0x5f
|
||||
tag_table_capture_map = 0x53,
|
||||
tag_table_unboxed_closure_type = 0x54,
|
||||
tag_table_upvar_borrow_map = 0x55,
|
||||
tag_table_capture_modes = 0x56,
|
||||
}
|
||||
static first_astencode_tag: uint = tag_ast as uint;
|
||||
static last_astencode_tag: uint = tag_table_upvar_borrow_map as uint;
|
||||
static last_astencode_tag: uint = tag_table_capture_modes as uint;
|
||||
impl astencode_tag {
|
||||
pub fn from_uint(value : uint) -> Option<astencode_tag> {
|
||||
let is_a_tag = first_astencode_tag <= value && value <= last_astencode_tag;
|
||||
|
@ -18,8 +18,8 @@ use driver::session::Session;
|
||||
use metadata::decoder;
|
||||
use middle::def;
|
||||
use e = metadata::encoder;
|
||||
use middle::freevars::{CaptureMode, freevar_entry};
|
||||
use middle::freevars;
|
||||
use middle::freevars::freevar_entry;
|
||||
use middle::region;
|
||||
use metadata::tydecode;
|
||||
use metadata::tydecode::{DefIdSource, NominalType, TypeWithId, TypeParameter,
|
||||
@ -530,9 +530,14 @@ fn encode_freevar_entry(rbml_w: &mut Encoder, fv: &freevar_entry) {
|
||||
(*fv).encode(rbml_w).unwrap();
|
||||
}
|
||||
|
||||
fn encode_capture_mode(rbml_w: &mut Encoder, cm: CaptureMode) {
|
||||
cm.encode(rbml_w).unwrap();
|
||||
}
|
||||
|
||||
trait rbml_decoder_helper {
|
||||
fn read_freevar_entry(&mut self, xcx: &ExtendedDecodeContext)
|
||||
-> freevar_entry;
|
||||
fn read_capture_mode(&mut self) -> CaptureMode;
|
||||
}
|
||||
|
||||
impl<'a> rbml_decoder_helper for reader::Decoder<'a> {
|
||||
@ -541,6 +546,11 @@ impl<'a> rbml_decoder_helper for reader::Decoder<'a> {
|
||||
let fv: freevar_entry = Decodable::decode(self).unwrap();
|
||||
fv.tr(xcx)
|
||||
}
|
||||
|
||||
fn read_capture_mode(&mut self) -> CaptureMode {
|
||||
let cm: CaptureMode = Decodable::decode(self).unwrap();
|
||||
cm
|
||||
}
|
||||
}
|
||||
|
||||
impl tr for freevar_entry {
|
||||
@ -1096,6 +1106,15 @@ fn encode_side_tables_for_id(ecx: &e::EncodeContext,
|
||||
}
|
||||
}
|
||||
|
||||
for &cm in tcx.capture_modes.borrow().find(&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 };
|
||||
for &pty in tcx.tcache.borrow().find(&lid).iter() {
|
||||
rbml_w.tag(c::tag_table_tcache, |rbml_w| {
|
||||
@ -1509,6 +1528,13 @@ fn decode_side_tables(xcx: &ExtendedDecodeContext,
|
||||
let ub: ty::UpvarBorrow = Decodable::decode(val_dsr).unwrap();
|
||||
dcx.tcx.upvar_borrow_map.borrow_mut().insert(upvar_id, ub.tr(xcx));
|
||||
}
|
||||
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 => {
|
||||
let pty = val_dsr.read_polytype(xcx);
|
||||
let lid = ast::DefId { krate: ast::LOCAL_CRATE, node: id };
|
||||
|
@ -291,7 +291,7 @@ pub fn closure_to_block(closure_id: ast::NodeId,
|
||||
match tcx.map.get(closure_id) {
|
||||
ast_map::NodeExpr(expr) => match expr.node {
|
||||
ast::ExprProc(_decl, block) |
|
||||
ast::ExprFnBlock(_decl, block) => { block.id }
|
||||
ast::ExprFnBlock(_, _decl, block) => { block.id }
|
||||
_ => fail!("encountered non-closure id: {}", closure_id)
|
||||
},
|
||||
_ => fail!("encountered non-expr id: {}", closure_id)
|
||||
|
@ -46,9 +46,9 @@ impl<'a> Visitor<Context> for CheckLoopVisitor<'a> {
|
||||
self.visit_expr(&**e, cx);
|
||||
self.visit_block(&**b, Loop);
|
||||
}
|
||||
ast::ExprFnBlock(_, ref b) |
|
||||
ast::ExprFnBlock(_, _, ref b) |
|
||||
ast::ExprProc(_, ref b) |
|
||||
ast::ExprUnboxedFn(_, ref b) => {
|
||||
ast::ExprUnboxedFn(_, _, ref b) => {
|
||||
self.visit_block(&**b, Closure);
|
||||
}
|
||||
ast::ExprBreak(_) => self.require_loop("break", cx, e.span),
|
||||
|
@ -17,14 +17,14 @@ use middle::def;
|
||||
use middle::mem_categorization::Typer;
|
||||
use middle::resolve;
|
||||
use middle::ty;
|
||||
use util::nodemap::{DefIdSet, NodeMap, NodeSet};
|
||||
use util::nodemap::{NodeMap, NodeSet};
|
||||
|
||||
use syntax::ast;
|
||||
use syntax::codemap::Span;
|
||||
use syntax::{ast};
|
||||
use syntax::visit;
|
||||
use syntax::visit::Visitor;
|
||||
use syntax::visit;
|
||||
|
||||
#[deriving(Show)]
|
||||
#[deriving(Clone, Decodable, Encodable, Show)]
|
||||
pub enum CaptureMode {
|
||||
/// Copy/move the value from this llvm ValueRef into the environment.
|
||||
CaptureByValue,
|
||||
@ -43,12 +43,13 @@ pub struct freevar_entry {
|
||||
|
||||
pub type freevar_map = NodeMap<Vec<freevar_entry>>;
|
||||
|
||||
pub type UnboxedClosureList = DefIdSet;
|
||||
pub type CaptureModeMap = NodeMap<CaptureMode>;
|
||||
|
||||
struct CollectFreevarsVisitor<'a> {
|
||||
seen: NodeSet,
|
||||
refs: Vec<freevar_entry>,
|
||||
def_map: &'a resolve::DefMap,
|
||||
capture_mode_map: &'a mut CaptureModeMap,
|
||||
}
|
||||
|
||||
impl<'a> Visitor<int> for CollectFreevarsVisitor<'a> {
|
||||
@ -58,8 +59,27 @@ impl<'a> Visitor<int> for CollectFreevarsVisitor<'a> {
|
||||
|
||||
fn visit_expr(&mut self, expr: &ast::Expr, depth: int) {
|
||||
match expr.node {
|
||||
ast::ExprFnBlock(..) | ast::ExprProc(..) |
|
||||
ast::ExprUnboxedFn(..) => {
|
||||
ast::ExprProc(..) => {
|
||||
self.capture_mode_map.insert(expr.id, CaptureByValue);
|
||||
visit::walk_expr(self, expr, depth + 1)
|
||||
}
|
||||
ast::ExprFnBlock(_, _, _) => {
|
||||
// NOTE(stage0): After snapshot, change to:
|
||||
//
|
||||
//let capture_mode = match capture_clause {
|
||||
// ast::CaptureByValue => CaptureByValue,
|
||||
// ast::CaptureByRef => CaptureByRef,
|
||||
//};
|
||||
let capture_mode = CaptureByRef;
|
||||
self.capture_mode_map.insert(expr.id, capture_mode);
|
||||
visit::walk_expr(self, expr, depth + 1)
|
||||
}
|
||||
ast::ExprUnboxedFn(capture_clause, _, _) => {
|
||||
let capture_mode = match capture_clause {
|
||||
ast::CaptureByValue => CaptureByValue,
|
||||
ast::CaptureByRef => CaptureByRef,
|
||||
};
|
||||
self.capture_mode_map.insert(expr.id, capture_mode);
|
||||
visit::walk_expr(self, expr, depth + 1)
|
||||
}
|
||||
ast::ExprPath(..) => {
|
||||
@ -91,8 +111,6 @@ impl<'a> Visitor<int> for CollectFreevarsVisitor<'a> {
|
||||
_ => visit::walk_expr(self, expr, depth)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
// Searches through part of the AST for all references to locals or
|
||||
@ -100,26 +118,34 @@ impl<'a> Visitor<int> for CollectFreevarsVisitor<'a> {
|
||||
// Since we want to be able to collect upvars in some arbitrary piece
|
||||
// of the AST, we take a walker function that we invoke with a visitor
|
||||
// in order to start the search.
|
||||
fn collect_freevars(def_map: &resolve::DefMap, blk: &ast::Block) -> Vec<freevar_entry> {
|
||||
fn collect_freevars(def_map: &resolve::DefMap,
|
||||
blk: &ast::Block,
|
||||
capture_mode_map: &mut CaptureModeMap)
|
||||
-> Vec<freevar_entry> {
|
||||
let mut v = CollectFreevarsVisitor {
|
||||
seen: NodeSet::new(),
|
||||
refs: Vec::new(),
|
||||
def_map: def_map,
|
||||
capture_mode_map: &mut *capture_mode_map,
|
||||
};
|
||||
|
||||
v.visit_block(blk, 1);
|
||||
|
||||
v.refs
|
||||
}
|
||||
|
||||
struct AnnotateFreevarsVisitor<'a> {
|
||||
def_map: &'a resolve::DefMap,
|
||||
freevars: freevar_map,
|
||||
capture_mode_map: CaptureModeMap,
|
||||
}
|
||||
|
||||
impl<'a> Visitor<()> for AnnotateFreevarsVisitor<'a> {
|
||||
fn visit_fn(&mut self, fk: &visit::FnKind, fd: &ast::FnDecl,
|
||||
blk: &ast::Block, s: Span, nid: ast::NodeId, _: ()) {
|
||||
let vars = collect_freevars(self.def_map, blk);
|
||||
let vars = collect_freevars(self.def_map,
|
||||
blk,
|
||||
&mut self.capture_mode_map);
|
||||
self.freevars.insert(nid, vars);
|
||||
visit::walk_fn(self, fk, fd, blk, s, ());
|
||||
}
|
||||
@ -131,14 +157,20 @@ impl<'a> Visitor<()> for AnnotateFreevarsVisitor<'a> {
|
||||
// node of interest rather than building up the free variables in
|
||||
// one pass. This could be improved upon if it turns out to matter.
|
||||
pub fn annotate_freevars(def_map: &resolve::DefMap, krate: &ast::Crate)
|
||||
-> freevar_map {
|
||||
-> (freevar_map, CaptureModeMap) {
|
||||
let mut visitor = AnnotateFreevarsVisitor {
|
||||
def_map: def_map,
|
||||
freevars: NodeMap::new(),
|
||||
capture_mode_map: NodeMap::new(),
|
||||
};
|
||||
visit::walk_crate(&mut visitor, krate, ());
|
||||
|
||||
visitor.freevars
|
||||
let AnnotateFreevarsVisitor {
|
||||
freevars,
|
||||
capture_mode_map,
|
||||
..
|
||||
} = visitor;
|
||||
(freevars, capture_mode_map)
|
||||
}
|
||||
|
||||
pub fn with_freevars<T>(tcx: &ty::ctxt, fid: ast::NodeId, f: |&[freevar_entry]| -> T) -> T {
|
||||
@ -148,10 +180,7 @@ pub fn with_freevars<T>(tcx: &ty::ctxt, fid: ast::NodeId, f: |&[freevar_entry]|
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_capture_mode<T: Typer>(tcx: &T, closure_expr_id: ast::NodeId) -> CaptureMode {
|
||||
let fn_ty = tcx.node_ty(closure_expr_id).ok().expect("couldn't find closure ty?");
|
||||
match ty::ty_closure_store(fn_ty) {
|
||||
ty::RegionTraitStore(..) => CaptureByRef,
|
||||
ty::UniqTraitStore => CaptureByValue
|
||||
}
|
||||
pub fn get_capture_mode<T:Typer>(tcx: &T, closure_expr_id: ast::NodeId)
|
||||
-> CaptureMode {
|
||||
tcx.capture_mode(closure_expr_id)
|
||||
}
|
||||
|
@ -965,9 +965,9 @@ impl<'a> Liveness<'a> {
|
||||
self.propagate_through_expr(&**e, succ)
|
||||
}
|
||||
|
||||
ExprFnBlock(_, ref blk) |
|
||||
ExprFnBlock(_, _, ref blk) |
|
||||
ExprProc(_, ref blk) |
|
||||
ExprUnboxedFn(_, ref blk) => {
|
||||
ExprUnboxedFn(_, _, ref blk) => {
|
||||
debug!("{} is an ExprFnBlock, ExprProc, or ExprUnboxedFn",
|
||||
expr_to_string(expr));
|
||||
|
||||
|
@ -63,6 +63,7 @@
|
||||
#![allow(non_camel_case_types)]
|
||||
|
||||
use middle::def;
|
||||
use middle::freevars;
|
||||
use middle::ty;
|
||||
use middle::typeck;
|
||||
use util::nodemap::NodeMap;
|
||||
@ -270,6 +271,8 @@ pub trait Typer {
|
||||
fn is_method_call(&self, id: ast::NodeId) -> bool;
|
||||
fn temporary_scope(&self, rvalue_id: ast::NodeId) -> Option<ast::NodeId>;
|
||||
fn upvar_borrow(&self, upvar_id: ty::UpvarId) -> ty::UpvarBorrow;
|
||||
fn capture_mode(&self, closure_expr_id: ast::NodeId)
|
||||
-> freevars::CaptureMode;
|
||||
}
|
||||
|
||||
impl MutabilityCategory {
|
||||
|
@ -5287,9 +5287,9 @@ impl<'a> Resolver<'a> {
|
||||
visit::walk_expr(self, expr, ());
|
||||
}
|
||||
|
||||
ExprFnBlock(fn_decl, block) |
|
||||
ExprFnBlock(_, fn_decl, block) |
|
||||
ExprProc(fn_decl, block) |
|
||||
ExprUnboxedFn(fn_decl, block) => {
|
||||
ExprUnboxedFn(_, fn_decl, block) => {
|
||||
self.resolve_function(FunctionRibKind(expr.id, block.id),
|
||||
Some(fn_decl), NoTypeParameters,
|
||||
block);
|
||||
|
@ -1237,7 +1237,7 @@ impl<'l> Visitor<DxrVisitorEnv> for DxrVisitor<'l> {
|
||||
"Expected struct type, but not ty_struct"),
|
||||
}
|
||||
},
|
||||
ast::ExprFnBlock(decl, body) => {
|
||||
ast::ExprFnBlock(_, decl, body) => {
|
||||
if generated_code(body.span) {
|
||||
return
|
||||
}
|
||||
|
@ -1306,7 +1306,9 @@ fn has_nested_returns(tcx: &ty::ctxt, id: ast::NodeId) -> bool {
|
||||
}
|
||||
Some(ast_map::NodeExpr(e)) => {
|
||||
match e.node {
|
||||
ast::ExprFnBlock(_, blk) | ast::ExprProc(_, blk) | ast::ExprUnboxedFn(_, blk) => {
|
||||
ast::ExprFnBlock(_, _, blk) |
|
||||
ast::ExprProc(_, blk) |
|
||||
ast::ExprUnboxedFn(_, _, blk) => {
|
||||
let mut explicit = CheckForNestedReturnsVisitor { found: false };
|
||||
let mut implicit = CheckForNestedReturnsVisitor { found: false };
|
||||
visit::walk_expr(&mut explicit, &*e, false);
|
||||
|
@ -18,6 +18,7 @@ use llvm::{ValueRef, BasicBlockRef, BuilderRef};
|
||||
use llvm::{True, False, Bool};
|
||||
use mc = middle::mem_categorization;
|
||||
use middle::def;
|
||||
use middle::freevars;
|
||||
use middle::lang_items::LangItem;
|
||||
use middle::subst;
|
||||
use middle::subst::Subst;
|
||||
@ -516,6 +517,11 @@ impl<'a> mc::Typer for Block<'a> {
|
||||
fn upvar_borrow(&self, upvar_id: ty::UpvarId) -> ty::UpvarBorrow {
|
||||
self.tcx().upvar_borrow_map.borrow().get_copy(&upvar_id)
|
||||
}
|
||||
|
||||
fn capture_mode(&self, closure_expr_id: ast::NodeId)
|
||||
-> freevars::CaptureMode {
|
||||
self.tcx().capture_modes.borrow().get_copy(&closure_expr_id)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Result<'a> {
|
||||
|
@ -1150,9 +1150,9 @@ pub fn create_function_debug_context(cx: &CrateContext,
|
||||
}
|
||||
ast_map::NodeExpr(ref expr) => {
|
||||
match expr.node {
|
||||
ast::ExprFnBlock(fn_decl, top_level_block) |
|
||||
ast::ExprFnBlock(_, fn_decl, top_level_block) |
|
||||
ast::ExprProc(fn_decl, top_level_block) |
|
||||
ast::ExprUnboxedFn(fn_decl, top_level_block) => {
|
||||
ast::ExprUnboxedFn(_, fn_decl, top_level_block) => {
|
||||
let name = format!("fn{}", token::gensym("fn"));
|
||||
let name = token::str_to_ident(name.as_slice());
|
||||
(name, fn_decl,
|
||||
@ -3618,9 +3618,9 @@ fn populate_scope_map(cx: &CrateContext,
|
||||
})
|
||||
}
|
||||
|
||||
ast::ExprFnBlock(ref decl, ref block) |
|
||||
ast::ExprFnBlock(_, ref decl, ref block) |
|
||||
ast::ExprProc(ref decl, ref block) |
|
||||
ast::ExprUnboxedFn(ref decl, ref block) => {
|
||||
ast::ExprUnboxedFn(_, ref decl, ref block) => {
|
||||
with_new_scope(cx,
|
||||
block.span,
|
||||
scope_stack,
|
||||
|
@ -782,7 +782,7 @@ fn trans_rvalue_dps_unadjusted<'a>(bcx: &'a Block<'a>,
|
||||
ast::ExprVec(..) | ast::ExprRepeat(..) => {
|
||||
tvec::trans_fixed_vstore(bcx, expr, expr, dest)
|
||||
}
|
||||
ast::ExprFnBlock(ref decl, ref body) |
|
||||
ast::ExprFnBlock(_, ref decl, ref body) |
|
||||
ast::ExprProc(ref decl, ref body) => {
|
||||
let expr_ty = expr_ty(bcx, expr);
|
||||
let store = ty::ty_closure_store(expr_ty);
|
||||
@ -790,7 +790,7 @@ fn trans_rvalue_dps_unadjusted<'a>(bcx: &'a Block<'a>,
|
||||
expr_to_string(expr), expr_ty.repr(tcx));
|
||||
closure::trans_expr_fn(bcx, store, &**decl, &**body, expr.id, dest)
|
||||
}
|
||||
ast::ExprUnboxedFn(decl, body) => {
|
||||
ast::ExprUnboxedFn(_, decl, body) => {
|
||||
closure::trans_unboxed_closure(bcx, &*decl, &*body, expr.id, dest)
|
||||
}
|
||||
ast::ExprCall(ref f, ref args) => {
|
||||
|
@ -18,14 +18,15 @@ use lint;
|
||||
use middle::const_eval;
|
||||
use middle::def;
|
||||
use middle::dependency_format;
|
||||
use middle::freevars::CaptureModeMap;
|
||||
use middle::freevars;
|
||||
use middle::lang_items::{FnMutTraitLangItem, OpaqueStructLangItem};
|
||||
use middle::lang_items::{TyDescStructLangItem, TyVisitorTraitLangItem};
|
||||
use middle::freevars;
|
||||
use middle::resolve;
|
||||
use middle::resolve_lifetime;
|
||||
use middle::subst;
|
||||
use middle::subst::{Subst, Substs, VecPerParamSpace};
|
||||
use middle::stability;
|
||||
use middle::subst::{Subst, Substs, VecPerParamSpace};
|
||||
use middle::subst;
|
||||
use middle::ty;
|
||||
use middle::typeck;
|
||||
use middle::typeck::MethodCall;
|
||||
@ -384,6 +385,9 @@ pub struct ctxt {
|
||||
|
||||
/// 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>,
|
||||
}
|
||||
|
||||
pub enum tbox_flag {
|
||||
@ -1057,6 +1061,7 @@ pub fn mk_ctxt(s: Session,
|
||||
named_region_map: resolve_lifetime::NamedRegionMap,
|
||||
map: ast_map::Map,
|
||||
freevars: freevars::freevar_map,
|
||||
capture_modes: freevars::CaptureModeMap,
|
||||
region_maps: middle::region::RegionMaps,
|
||||
lang_items: middle::lang_items::LanguageItems,
|
||||
stability: stability::Index)
|
||||
@ -1115,7 +1120,8 @@ pub fn mk_ctxt(s: Session,
|
||||
unboxed_closure_types: RefCell::new(DefIdMap::new()),
|
||||
node_lint_levels: RefCell::new(HashMap::new()),
|
||||
transmute_restrictions: RefCell::new(Vec::new()),
|
||||
stability: RefCell::new(stability)
|
||||
stability: RefCell::new(stability),
|
||||
capture_modes: RefCell::new(capture_modes),
|
||||
}
|
||||
}
|
||||
|
||||
@ -4862,6 +4868,11 @@ impl mc::Typer for ty::ctxt {
|
||||
fn upvar_borrow(&self, upvar_id: ty::UpvarId) -> ty::UpvarBorrow {
|
||||
self.upvar_borrow_map.borrow().get_copy(&upvar_id)
|
||||
}
|
||||
|
||||
fn capture_mode(&self, closure_expr_id: ast::NodeId)
|
||||
-> freevars::CaptureMode {
|
||||
self.capture_modes.borrow().get_copy(&closure_expr_id)
|
||||
}
|
||||
}
|
||||
|
||||
/// The category of explicit self.
|
||||
|
@ -3390,7 +3390,7 @@ fn check_expr_with_unifier(fcx: &FnCtxt,
|
||||
ast::ExprMatch(ref discrim, ref arms) => {
|
||||
_match::check_match(fcx, expr, &**discrim, arms.as_slice());
|
||||
}
|
||||
ast::ExprFnBlock(ref decl, ref body) => {
|
||||
ast::ExprFnBlock(_, ref decl, ref body) => {
|
||||
let region = astconv::opt_ast_region_to_region(fcx,
|
||||
fcx.infcx(),
|
||||
expr.span,
|
||||
@ -3402,7 +3402,7 @@ fn check_expr_with_unifier(fcx: &FnCtxt,
|
||||
body.clone(),
|
||||
expected);
|
||||
}
|
||||
ast::ExprUnboxedFn(ref decl, ref body) => {
|
||||
ast::ExprUnboxedFn(_, ref decl, ref body) => {
|
||||
check_unboxed_closure(fcx,
|
||||
expr,
|
||||
&**decl,
|
||||
|
@ -290,6 +290,11 @@ impl<'fcx> mc::Typer for Rcx<'fcx> {
|
||||
fn upvar_borrow(&self, id: ty::UpvarId) -> ty::UpvarBorrow {
|
||||
self.fcx.inh.upvar_borrow_map.borrow().get_copy(&id)
|
||||
}
|
||||
|
||||
fn capture_mode(&self, closure_expr_id: ast::NodeId)
|
||||
-> freevars::CaptureMode {
|
||||
self.tcx().capture_modes.borrow().get_copy(&closure_expr_id)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn regionck_expr(fcx: &FnCtxt, e: &ast::Expr) {
|
||||
@ -587,9 +592,9 @@ fn visit_expr(rcx: &mut Rcx, expr: &ast::Expr) {
|
||||
visit::walk_expr(rcx, expr, ());
|
||||
}
|
||||
|
||||
ast::ExprFnBlock(_, ref body) |
|
||||
ast::ExprFnBlock(_, _, ref body) |
|
||||
ast::ExprProc(_, ref body) |
|
||||
ast::ExprUnboxedFn(_, ref body) => {
|
||||
ast::ExprUnboxedFn(_, _, ref body) => {
|
||||
check_expr_fn_block(rcx, expr, &**body);
|
||||
}
|
||||
|
||||
|
@ -132,9 +132,9 @@ impl<'cx> Visitor<()> for WritebackCx<'cx> {
|
||||
MethodCall::expr(e.id));
|
||||
|
||||
match e.node {
|
||||
ast::ExprFnBlock(ref decl, _) |
|
||||
ast::ExprFnBlock(_, ref decl, _) |
|
||||
ast::ExprProc(ref decl, _) |
|
||||
ast::ExprUnboxedFn(ref decl, _) => {
|
||||
ast::ExprUnboxedFn(_, ref decl, _) => {
|
||||
for input in decl.inputs.iter() {
|
||||
let _ = self.visit_node_id(ResolvingExpr(e.span),
|
||||
input.id);
|
||||
|
@ -124,12 +124,20 @@ fn test_env(_test_name: &str,
|
||||
let lang_items = lang_items::collect_language_items(&krate, &sess);
|
||||
let resolve::CrateMap { def_map: def_map, .. } =
|
||||
resolve::resolve_crate(&sess, &lang_items, &krate);
|
||||
let freevars_map = freevars::annotate_freevars(&def_map, &krate);
|
||||
let (freevars_map, captures_map) = freevars::annotate_freevars(&def_map,
|
||||
&krate);
|
||||
let named_region_map = resolve_lifetime::krate(&sess, &krate);
|
||||
let region_map = region::resolve_crate(&sess, &krate);
|
||||
let stability_index = stability::Index::build(&krate);
|
||||
let tcx = ty::mk_ctxt(sess, def_map, named_region_map, ast_map,
|
||||
freevars_map, region_map, lang_items, stability_index);
|
||||
let tcx = ty::mk_ctxt(sess,
|
||||
def_map,
|
||||
named_region_map,
|
||||
ast_map,
|
||||
freevars_map,
|
||||
captures_map,
|
||||
region_map,
|
||||
lang_items,
|
||||
stability_index);
|
||||
let infcx = infer::new_infer_ctxt(&tcx);
|
||||
let env = Env {krate: krate,
|
||||
tcx: &tcx,
|
||||
|
@ -526,9 +526,9 @@ pub enum Expr_ {
|
||||
// FIXME #6993: change to Option<Name> ... or not, if these are hygienic.
|
||||
ExprLoop(P<Block>, Option<Ident>),
|
||||
ExprMatch(Gc<Expr>, Vec<Arm>),
|
||||
ExprFnBlock(P<FnDecl>, P<Block>),
|
||||
ExprFnBlock(CaptureClause, P<FnDecl>, P<Block>),
|
||||
ExprProc(P<FnDecl>, P<Block>),
|
||||
ExprUnboxedFn(P<FnDecl>, P<Block>),
|
||||
ExprUnboxedFn(CaptureClause, P<FnDecl>, P<Block>),
|
||||
ExprBlock(P<Block>),
|
||||
|
||||
ExprAssign(Gc<Expr>, Gc<Expr>),
|
||||
@ -559,6 +559,12 @@ pub enum Expr_ {
|
||||
ExprParen(Gc<Expr>)
|
||||
}
|
||||
|
||||
#[deriving(Clone, PartialEq, Eq, Encodable, Decodable, Hash, Show)]
|
||||
pub enum CaptureClause {
|
||||
CaptureByValue,
|
||||
CaptureByRef,
|
||||
}
|
||||
|
||||
/// When the main rust parser encounters a syntax-extension invocation, it
|
||||
/// parses the arguments to the invocation as a token-tree. This is a very
|
||||
/// loose structure, such that all sorts of different AST-fragments can
|
||||
|
@ -206,7 +206,7 @@ impl FnLikeNode {
|
||||
},
|
||||
ast_map::NodeMethod(ref m) => method(&**m),
|
||||
ast_map::NodeExpr(ref e) => match e.node {
|
||||
ast::ExprFnBlock(ref decl, ref block) =>
|
||||
ast::ExprFnBlock(_, ref decl, ref block) =>
|
||||
closure(ClosureParts::new(*decl, *block, e.id, e.span)),
|
||||
ast::ExprProc(ref decl, ref block) =>
|
||||
closure(ClosureParts::new(*decl, *block, e.id, e.span)),
|
||||
|
@ -876,14 +876,14 @@ impl<'a> AstBuilder for ExtCtxt<'a> {
|
||||
|
||||
fn lambda_fn_decl(&self, span: Span,
|
||||
fn_decl: P<ast::FnDecl>, blk: P<ast::Block>) -> Gc<ast::Expr> {
|
||||
self.expr(span, ast::ExprFnBlock(fn_decl, blk))
|
||||
self.expr(span, ast::ExprFnBlock(ast::CaptureByRef, fn_decl, blk))
|
||||
}
|
||||
fn lambda(&self, span: Span, ids: Vec<ast::Ident> , blk: P<ast::Block>) -> Gc<ast::Expr> {
|
||||
let fn_decl = self.fn_decl(
|
||||
ids.iter().map(|id| self.arg(span, *id, self.ty_infer(span))).collect(),
|
||||
self.ty_infer(span));
|
||||
|
||||
self.expr(span, ast::ExprFnBlock(fn_decl, blk))
|
||||
self.expr(span, ast::ExprFnBlock(ast::CaptureByRef, fn_decl, blk))
|
||||
}
|
||||
fn lambda0(&self, span: Span, blk: P<ast::Block>) -> Gc<ast::Expr> {
|
||||
self.lambda(span, Vec::new(), blk)
|
||||
|
@ -74,10 +74,12 @@ fn expand_expr(e: Gc<ast::Expr>, fld: &mut MacroExpander) -> Gc<ast::Expr> {
|
||||
fld.cx.expr(e.span, ast::ExprForLoop(pat, head, body, opt_ident))
|
||||
}
|
||||
|
||||
ast::ExprFnBlock(fn_decl, block) => {
|
||||
ast::ExprFnBlock(capture_clause, fn_decl, block) => {
|
||||
let (rewritten_fn_decl, rewritten_block)
|
||||
= expand_and_rename_fn_decl_and_block(&*fn_decl, block, fld);
|
||||
let new_node = ast::ExprFnBlock(rewritten_fn_decl, rewritten_block);
|
||||
let new_node = ast::ExprFnBlock(capture_clause,
|
||||
rewritten_fn_decl,
|
||||
rewritten_block);
|
||||
box(GC) ast::Expr{id:e.id, node: new_node, span: fld.new_span(e.span)}
|
||||
}
|
||||
|
||||
|
@ -1094,16 +1094,18 @@ pub fn noop_fold_expr<T: Folder>(e: Gc<Expr>, folder: &mut T) -> Gc<Expr> {
|
||||
ExprMatch(folder.fold_expr(expr),
|
||||
arms.iter().map(|x| folder.fold_arm(x)).collect())
|
||||
}
|
||||
ExprFnBlock(ref decl, ref body) => {
|
||||
ExprFnBlock(folder.fold_fn_decl(&**decl),
|
||||
ExprFnBlock(capture_clause, ref decl, ref body) => {
|
||||
ExprFnBlock(capture_clause,
|
||||
folder.fold_fn_decl(&**decl),
|
||||
folder.fold_block(body.clone()))
|
||||
}
|
||||
ExprProc(ref decl, ref body) => {
|
||||
ExprProc(folder.fold_fn_decl(&**decl),
|
||||
folder.fold_block(body.clone()))
|
||||
}
|
||||
ExprUnboxedFn(ref decl, ref body) => {
|
||||
ExprUnboxedFn(folder.fold_fn_decl(&**decl),
|
||||
ExprUnboxedFn(capture_clause, ref decl, ref body) => {
|
||||
ExprUnboxedFn(capture_clause,
|
||||
folder.fold_fn_decl(&**decl),
|
||||
folder.fold_block(*body))
|
||||
}
|
||||
ExprBlock(ref blk) => ExprBlock(folder.fold_block(*blk)),
|
||||
|
@ -17,6 +17,7 @@ use ast::{Provided, Public, FnStyle};
|
||||
use ast::{Mod, BiAdd, Arg, Arm, Attribute, BindByRef, BindByValue};
|
||||
use ast::{BiBitAnd, BiBitOr, BiBitXor, Block};
|
||||
use ast::{BlockCheckMode, UnBox};
|
||||
use ast::{CaptureByRef, CaptureByValue, CaptureClause};
|
||||
use ast::{Crate, CrateConfig, Decl, DeclItem};
|
||||
use ast::{DeclLocal, DefaultBlock, UnDeref, BiDiv, EMPTY_CTXT, EnumDef, ExplicitSelf};
|
||||
use ast::{Expr, Expr_, ExprAddrOf, ExprMatch, ExprAgain};
|
||||
@ -1985,7 +1986,7 @@ impl<'a> Parser<'a> {
|
||||
ExprBlock(blk));
|
||||
},
|
||||
token::BINOP(token::OR) | token::OROR => {
|
||||
return self.parse_lambda_expr();
|
||||
return self.parse_lambda_expr(CaptureByValue);
|
||||
},
|
||||
// FIXME #13626: Should be able to stick in
|
||||
// token::SELF_KEYWORD_NAME
|
||||
@ -2036,6 +2037,9 @@ impl<'a> Parser<'a> {
|
||||
hi = self.last_span.hi;
|
||||
},
|
||||
_ => {
|
||||
if self.eat_keyword(keywords::Ref) {
|
||||
return self.parse_lambda_expr(CaptureByRef);
|
||||
}
|
||||
if self.eat_keyword(keywords::Proc) {
|
||||
let decl = self.parse_proc_decl();
|
||||
let body = self.parse_expr();
|
||||
@ -2696,7 +2700,8 @@ impl<'a> Parser<'a> {
|
||||
}
|
||||
|
||||
// `|args| expr`
|
||||
pub fn parse_lambda_expr(&mut self) -> Gc<Expr> {
|
||||
pub fn parse_lambda_expr(&mut self, capture_clause: CaptureClause)
|
||||
-> Gc<Expr> {
|
||||
let lo = self.span.lo;
|
||||
let (decl, is_unboxed) = self.parse_fn_block_decl();
|
||||
let body = self.parse_expr();
|
||||
@ -2710,9 +2715,13 @@ impl<'a> Parser<'a> {
|
||||
});
|
||||
|
||||
if is_unboxed {
|
||||
self.mk_expr(lo, body.span.hi, ExprUnboxedFn(decl, fakeblock))
|
||||
self.mk_expr(lo,
|
||||
body.span.hi,
|
||||
ExprUnboxedFn(capture_clause, decl, fakeblock))
|
||||
} else {
|
||||
self.mk_expr(lo, body.span.hi, ExprFnBlock(decl, fakeblock))
|
||||
self.mk_expr(lo,
|
||||
body.span.hi,
|
||||
ExprFnBlock(capture_clause, decl, fakeblock))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1473,7 +1473,9 @@ impl<'a> State<'a> {
|
||||
}
|
||||
try!(self.bclose_(expr.span, indent_unit));
|
||||
}
|
||||
ast::ExprFnBlock(ref decl, ref body) => {
|
||||
ast::ExprFnBlock(capture_clause, ref decl, ref body) => {
|
||||
try!(self.print_capture_clause(capture_clause));
|
||||
|
||||
// in do/for blocks we don't want to show an empty
|
||||
// argument list, but at this point we don't know which
|
||||
// we are inside.
|
||||
@ -1503,7 +1505,9 @@ impl<'a> State<'a> {
|
||||
// empty box to satisfy the close.
|
||||
try!(self.ibox(0));
|
||||
}
|
||||
ast::ExprUnboxedFn(ref decl, ref body) => {
|
||||
ast::ExprUnboxedFn(capture_clause, ref decl, ref body) => {
|
||||
try!(self.print_capture_clause(capture_clause));
|
||||
|
||||
// in do/for blocks we don't want to show an empty
|
||||
// argument list, but at this point we don't know which
|
||||
// we are inside.
|
||||
@ -2071,6 +2075,14 @@ impl<'a> State<'a> {
|
||||
self.maybe_print_comment(decl.output.span.lo)
|
||||
}
|
||||
|
||||
pub fn print_capture_clause(&mut self, capture_clause: ast::CaptureClause)
|
||||
-> IoResult<()> {
|
||||
match capture_clause {
|
||||
ast::CaptureByValue => Ok(()),
|
||||
ast::CaptureByRef => self.word_space("ref"),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn print_proc_args(&mut self, decl: &ast::FnDecl) -> IoResult<()> {
|
||||
try!(word(&mut self.s, "proc"));
|
||||
try!(word(&mut self.s, "("));
|
||||
|
@ -787,7 +787,7 @@ pub fn walk_expr<E: Clone, V: Visitor<E>>(visitor: &mut V, expression: &Expr, en
|
||||
visitor.visit_arm(arm, env.clone())
|
||||
}
|
||||
}
|
||||
ExprFnBlock(ref function_declaration, ref body) => {
|
||||
ExprFnBlock(_, ref function_declaration, ref body) => {
|
||||
visitor.visit_fn(&FkFnBlock,
|
||||
&**function_declaration,
|
||||
&**body,
|
||||
@ -795,7 +795,7 @@ pub fn walk_expr<E: Clone, V: Visitor<E>>(visitor: &mut V, expression: &Expr, en
|
||||
expression.id,
|
||||
env.clone())
|
||||
}
|
||||
ExprUnboxedFn(ref function_declaration, ref body) => {
|
||||
ExprUnboxedFn(_, ref function_declaration, ref body) => {
|
||||
visitor.visit_fn(&FkFnBlock,
|
||||
&**function_declaration,
|
||||
&**body,
|
||||
|
23
src/test/run-pass/capture-clauses-boxed-closures.rs
Normal file
23
src/test/run-pass/capture-clauses-boxed-closures.rs
Normal file
@ -0,0 +1,23 @@
|
||||
// Copyright 2014 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.
|
||||
|
||||
fn each<T>(x: &[T], f: |&T|) {
|
||||
for val in x.iter() {
|
||||
f(val)
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let mut sum = 0u;
|
||||
let elems = [ 1u, 2, 3, 4, 5 ];
|
||||
each(elems, ref |val| sum += *val);
|
||||
assert_eq!(sum, 15);
|
||||
}
|
||||
|
29
src/test/run-pass/capture-clauses-unboxed-closures.rs
Normal file
29
src/test/run-pass/capture-clauses-unboxed-closures.rs
Normal file
@ -0,0 +1,29 @@
|
||||
// Copyright 2014 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.
|
||||
|
||||
// ignore-test
|
||||
//
|
||||
// This is ignored because it depends on #16122.
|
||||
|
||||
#![feature(overloaded_calls, unboxed_closures)]
|
||||
|
||||
fn each<'a,T,F:|&mut: &'a T|>(x: &'a [T], mut f: F) {
|
||||
for val in x.iter() {
|
||||
f(val)
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let mut sum = 0u;
|
||||
let elems = [ 1u, 2, 3, 4, 5 ];
|
||||
each(elems, ref |&mut: val: &uint| sum += *val);
|
||||
assert_eq!(sum, 15);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user