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:
bors 2014-08-14 03:46:22 +00:00
commit 9d45d63d0d
29 changed files with 254 additions and 72 deletions

View File

@ -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);

View File

@ -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;

View File

@ -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 };

View File

@ -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)

View File

@ -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),

View File

@ -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)
}

View File

@ -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));

View File

@ -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 {

View File

@ -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);

View File

@ -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
}

View File

@ -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);

View File

@ -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> {

View File

@ -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,

View File

@ -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) => {

View File

@ -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.

View File

@ -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,

View File

@ -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);
}

View File

@ -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);

View File

@ -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,

View File

@ -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

View File

@ -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)),

View File

@ -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)

View File

@ -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)}
}

View File

@ -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)),

View File

@ -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))
}
}

View File

@ -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, "("));

View File

@ -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,

View 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);
}

View 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);
}