librustc: Parse, but do not fully turn on, the ref
keyword for
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 #12381.
This commit is contained in:
parent
28b5e4588f
commit
a63003fe1a
29 changed files with 254 additions and 72 deletions
|
@ -360,7 +360,8 @@ pub fn phase_3_run_analysis_passes(sess: Session,
|
||||||
plugin::build::find_plugin_registrar(
|
plugin::build::find_plugin_registrar(
|
||||||
sess.diagnostic(), krate)));
|
sess.diagnostic(), krate)));
|
||||||
|
|
||||||
let freevars = time(time_passes, "freevar finding", (), |_|
|
let (freevars, capture_modes) =
|
||||||
|
time(time_passes, "freevar finding", (), |_|
|
||||||
freevars::annotate_freevars(&def_map, krate));
|
freevars::annotate_freevars(&def_map, krate));
|
||||||
|
|
||||||
let region_map = time(time_passes, "region resolution", (), |_|
|
let region_map = time(time_passes, "region resolution", (), |_|
|
||||||
|
@ -372,8 +373,15 @@ pub fn phase_3_run_analysis_passes(sess: Session,
|
||||||
let stability_index = time(time_passes, "stability index", (), |_|
|
let stability_index = time(time_passes, "stability index", (), |_|
|
||||||
stability::Index::build(krate));
|
stability::Index::build(krate));
|
||||||
|
|
||||||
let ty_cx = ty::mk_ctxt(sess, def_map, named_region_map, ast_map,
|
let ty_cx = ty::mk_ctxt(sess,
|
||||||
freevars, region_map, lang_items, stability_index);
|
def_map,
|
||||||
|
named_region_map,
|
||||||
|
ast_map,
|
||||||
|
freevars,
|
||||||
|
capture_modes,
|
||||||
|
region_map,
|
||||||
|
lang_items,
|
||||||
|
stability_index);
|
||||||
|
|
||||||
// passes are timed inside typeck
|
// passes are timed inside typeck
|
||||||
typeck::check_crate(&ty_cx, trait_map, krate);
|
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_capture_map = 0x53,
|
||||||
tag_table_unboxed_closure_type = 0x54,
|
tag_table_unboxed_closure_type = 0x54,
|
||||||
tag_table_upvar_borrow_map = 0x55,
|
tag_table_upvar_borrow_map = 0x55,
|
||||||
|
tag_table_capture_modes = 0x56,
|
||||||
}
|
}
|
||||||
static first_astencode_tag: uint = tag_ast as uint;
|
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 {
|
impl astencode_tag {
|
||||||
pub fn from_uint(value : uint) -> Option<astencode_tag> {
|
pub fn from_uint(value : uint) -> Option<astencode_tag> {
|
||||||
let is_a_tag = first_astencode_tag <= value && value <= last_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 metadata::decoder;
|
||||||
use middle::def;
|
use middle::def;
|
||||||
use e = metadata::encoder;
|
use e = metadata::encoder;
|
||||||
|
use middle::freevars::{CaptureMode, freevar_entry};
|
||||||
use middle::freevars;
|
use middle::freevars;
|
||||||
use middle::freevars::freevar_entry;
|
|
||||||
use middle::region;
|
use middle::region;
|
||||||
use metadata::tydecode;
|
use metadata::tydecode;
|
||||||
use metadata::tydecode::{DefIdSource, NominalType, TypeWithId, TypeParameter,
|
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();
|
(*fv).encode(rbml_w).unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn encode_capture_mode(rbml_w: &mut Encoder, cm: CaptureMode) {
|
||||||
|
cm.encode(rbml_w).unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
trait rbml_decoder_helper {
|
trait rbml_decoder_helper {
|
||||||
fn read_freevar_entry(&mut self, xcx: &ExtendedDecodeContext)
|
fn read_freevar_entry(&mut self, xcx: &ExtendedDecodeContext)
|
||||||
-> freevar_entry;
|
-> freevar_entry;
|
||||||
|
fn read_capture_mode(&mut self) -> CaptureMode;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> rbml_decoder_helper for reader::Decoder<'a> {
|
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();
|
let fv: freevar_entry = Decodable::decode(self).unwrap();
|
||||||
fv.tr(xcx)
|
fv.tr(xcx)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn read_capture_mode(&mut self) -> CaptureMode {
|
||||||
|
let cm: CaptureMode = Decodable::decode(self).unwrap();
|
||||||
|
cm
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl tr for freevar_entry {
|
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 };
|
let lid = ast::DefId { krate: ast::LOCAL_CRATE, node: id };
|
||||||
for &pty in tcx.tcache.borrow().find(&lid).iter() {
|
for &pty in tcx.tcache.borrow().find(&lid).iter() {
|
||||||
rbml_w.tag(c::tag_table_tcache, |rbml_w| {
|
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();
|
let ub: ty::UpvarBorrow = Decodable::decode(val_dsr).unwrap();
|
||||||
dcx.tcx.upvar_borrow_map.borrow_mut().insert(upvar_id, ub.tr(xcx));
|
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 => {
|
c::tag_table_tcache => {
|
||||||
let pty = val_dsr.read_polytype(xcx);
|
let pty = val_dsr.read_polytype(xcx);
|
||||||
let lid = ast::DefId { krate: ast::LOCAL_CRATE, node: id };
|
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) {
|
match tcx.map.get(closure_id) {
|
||||||
ast_map::NodeExpr(expr) => match expr.node {
|
ast_map::NodeExpr(expr) => match expr.node {
|
||||||
ast::ExprProc(_decl, block) |
|
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-closure id: {}", closure_id)
|
||||||
},
|
},
|
||||||
_ => fail!("encountered non-expr 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_expr(&**e, cx);
|
||||||
self.visit_block(&**b, Loop);
|
self.visit_block(&**b, Loop);
|
||||||
}
|
}
|
||||||
ast::ExprFnBlock(_, ref b) |
|
ast::ExprFnBlock(_, _, ref b) |
|
||||||
ast::ExprProc(_, ref b) |
|
ast::ExprProc(_, ref b) |
|
||||||
ast::ExprUnboxedFn(_, ref b) => {
|
ast::ExprUnboxedFn(_, _, ref b) => {
|
||||||
self.visit_block(&**b, Closure);
|
self.visit_block(&**b, Closure);
|
||||||
}
|
}
|
||||||
ast::ExprBreak(_) => self.require_loop("break", cx, e.span),
|
ast::ExprBreak(_) => self.require_loop("break", cx, e.span),
|
||||||
|
|
|
@ -17,14 +17,14 @@ use middle::def;
|
||||||
use middle::mem_categorization::Typer;
|
use middle::mem_categorization::Typer;
|
||||||
use middle::resolve;
|
use middle::resolve;
|
||||||
use middle::ty;
|
use middle::ty;
|
||||||
use util::nodemap::{DefIdSet, NodeMap, NodeSet};
|
use util::nodemap::{NodeMap, NodeSet};
|
||||||
|
|
||||||
|
use syntax::ast;
|
||||||
use syntax::codemap::Span;
|
use syntax::codemap::Span;
|
||||||
use syntax::{ast};
|
|
||||||
use syntax::visit;
|
|
||||||
use syntax::visit::Visitor;
|
use syntax::visit::Visitor;
|
||||||
|
use syntax::visit;
|
||||||
|
|
||||||
#[deriving(Show)]
|
#[deriving(Clone, Decodable, Encodable, Show)]
|
||||||
pub enum CaptureMode {
|
pub enum CaptureMode {
|
||||||
/// Copy/move the value from this llvm ValueRef into the environment.
|
/// Copy/move the value from this llvm ValueRef into the environment.
|
||||||
CaptureByValue,
|
CaptureByValue,
|
||||||
|
@ -43,12 +43,13 @@ pub struct freevar_entry {
|
||||||
|
|
||||||
pub type freevar_map = NodeMap<Vec<freevar_entry>>;
|
pub type freevar_map = NodeMap<Vec<freevar_entry>>;
|
||||||
|
|
||||||
pub type UnboxedClosureList = DefIdSet;
|
pub type CaptureModeMap = NodeMap<CaptureMode>;
|
||||||
|
|
||||||
struct CollectFreevarsVisitor<'a> {
|
struct CollectFreevarsVisitor<'a> {
|
||||||
seen: NodeSet,
|
seen: NodeSet,
|
||||||
refs: Vec<freevar_entry>,
|
refs: Vec<freevar_entry>,
|
||||||
def_map: &'a resolve::DefMap,
|
def_map: &'a resolve::DefMap,
|
||||||
|
capture_mode_map: &'a mut CaptureModeMap,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Visitor<int> for CollectFreevarsVisitor<'a> {
|
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) {
|
fn visit_expr(&mut self, expr: &ast::Expr, depth: int) {
|
||||||
match expr.node {
|
match expr.node {
|
||||||
ast::ExprFnBlock(..) | ast::ExprProc(..) |
|
ast::ExprProc(..) => {
|
||||||
ast::ExprUnboxedFn(..) => {
|
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)
|
visit::walk_expr(self, expr, depth + 1)
|
||||||
}
|
}
|
||||||
ast::ExprPath(..) => {
|
ast::ExprPath(..) => {
|
||||||
|
@ -91,8 +111,6 @@ impl<'a> Visitor<int> for CollectFreevarsVisitor<'a> {
|
||||||
_ => visit::walk_expr(self, expr, depth)
|
_ => visit::walk_expr(self, expr, depth)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Searches through part of the AST for all references to locals or
|
// 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
|
// 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
|
// of the AST, we take a walker function that we invoke with a visitor
|
||||||
// in order to start the search.
|
// 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 {
|
let mut v = CollectFreevarsVisitor {
|
||||||
seen: NodeSet::new(),
|
seen: NodeSet::new(),
|
||||||
refs: Vec::new(),
|
refs: Vec::new(),
|
||||||
def_map: def_map,
|
def_map: def_map,
|
||||||
|
capture_mode_map: &mut *capture_mode_map,
|
||||||
};
|
};
|
||||||
|
|
||||||
v.visit_block(blk, 1);
|
v.visit_block(blk, 1);
|
||||||
|
|
||||||
v.refs
|
v.refs
|
||||||
}
|
}
|
||||||
|
|
||||||
struct AnnotateFreevarsVisitor<'a> {
|
struct AnnotateFreevarsVisitor<'a> {
|
||||||
def_map: &'a resolve::DefMap,
|
def_map: &'a resolve::DefMap,
|
||||||
freevars: freevar_map,
|
freevars: freevar_map,
|
||||||
|
capture_mode_map: CaptureModeMap,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Visitor<()> for AnnotateFreevarsVisitor<'a> {
|
impl<'a> Visitor<()> for AnnotateFreevarsVisitor<'a> {
|
||||||
fn visit_fn(&mut self, fk: &visit::FnKind, fd: &ast::FnDecl,
|
fn visit_fn(&mut self, fk: &visit::FnKind, fd: &ast::FnDecl,
|
||||||
blk: &ast::Block, s: Span, nid: ast::NodeId, _: ()) {
|
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);
|
self.freevars.insert(nid, vars);
|
||||||
visit::walk_fn(self, fk, fd, blk, s, ());
|
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
|
// node of interest rather than building up the free variables in
|
||||||
// one pass. This could be improved upon if it turns out to matter.
|
// one pass. This could be improved upon if it turns out to matter.
|
||||||
pub fn annotate_freevars(def_map: &resolve::DefMap, krate: &ast::Crate)
|
pub fn annotate_freevars(def_map: &resolve::DefMap, krate: &ast::Crate)
|
||||||
-> freevar_map {
|
-> (freevar_map, CaptureModeMap) {
|
||||||
let mut visitor = AnnotateFreevarsVisitor {
|
let mut visitor = AnnotateFreevarsVisitor {
|
||||||
def_map: def_map,
|
def_map: def_map,
|
||||||
freevars: NodeMap::new(),
|
freevars: NodeMap::new(),
|
||||||
|
capture_mode_map: NodeMap::new(),
|
||||||
};
|
};
|
||||||
visit::walk_crate(&mut visitor, krate, ());
|
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 {
|
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 {
|
pub fn get_capture_mode<T:Typer>(tcx: &T, closure_expr_id: ast::NodeId)
|
||||||
let fn_ty = tcx.node_ty(closure_expr_id).ok().expect("couldn't find closure ty?");
|
-> CaptureMode {
|
||||||
match ty::ty_closure_store(fn_ty) {
|
tcx.capture_mode(closure_expr_id)
|
||||||
ty::RegionTraitStore(..) => CaptureByRef,
|
|
||||||
ty::UniqTraitStore => CaptureByValue
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -965,9 +965,9 @@ impl<'a> Liveness<'a> {
|
||||||
self.propagate_through_expr(&**e, succ)
|
self.propagate_through_expr(&**e, succ)
|
||||||
}
|
}
|
||||||
|
|
||||||
ExprFnBlock(_, ref blk) |
|
ExprFnBlock(_, _, ref blk) |
|
||||||
ExprProc(_, ref blk) |
|
ExprProc(_, ref blk) |
|
||||||
ExprUnboxedFn(_, ref blk) => {
|
ExprUnboxedFn(_, _, ref blk) => {
|
||||||
debug!("{} is an ExprFnBlock, ExprProc, or ExprUnboxedFn",
|
debug!("{} is an ExprFnBlock, ExprProc, or ExprUnboxedFn",
|
||||||
expr_to_string(expr));
|
expr_to_string(expr));
|
||||||
|
|
||||||
|
|
|
@ -63,6 +63,7 @@
|
||||||
#![allow(non_camel_case_types)]
|
#![allow(non_camel_case_types)]
|
||||||
|
|
||||||
use middle::def;
|
use middle::def;
|
||||||
|
use middle::freevars;
|
||||||
use middle::ty;
|
use middle::ty;
|
||||||
use middle::typeck;
|
use middle::typeck;
|
||||||
use util::nodemap::NodeMap;
|
use util::nodemap::NodeMap;
|
||||||
|
@ -270,6 +271,8 @@ pub trait Typer {
|
||||||
fn is_method_call(&self, id: ast::NodeId) -> bool;
|
fn is_method_call(&self, id: ast::NodeId) -> bool;
|
||||||
fn temporary_scope(&self, rvalue_id: ast::NodeId) -> Option<ast::NodeId>;
|
fn temporary_scope(&self, rvalue_id: ast::NodeId) -> Option<ast::NodeId>;
|
||||||
fn upvar_borrow(&self, upvar_id: ty::UpvarId) -> ty::UpvarBorrow;
|
fn upvar_borrow(&self, upvar_id: ty::UpvarId) -> ty::UpvarBorrow;
|
||||||
|
fn capture_mode(&self, closure_expr_id: ast::NodeId)
|
||||||
|
-> freevars::CaptureMode;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl MutabilityCategory {
|
impl MutabilityCategory {
|
||||||
|
|
|
@ -5287,9 +5287,9 @@ impl<'a> Resolver<'a> {
|
||||||
visit::walk_expr(self, expr, ());
|
visit::walk_expr(self, expr, ());
|
||||||
}
|
}
|
||||||
|
|
||||||
ExprFnBlock(fn_decl, block) |
|
ExprFnBlock(_, fn_decl, block) |
|
||||||
ExprProc(fn_decl, block) |
|
ExprProc(fn_decl, block) |
|
||||||
ExprUnboxedFn(fn_decl, block) => {
|
ExprUnboxedFn(_, fn_decl, block) => {
|
||||||
self.resolve_function(FunctionRibKind(expr.id, block.id),
|
self.resolve_function(FunctionRibKind(expr.id, block.id),
|
||||||
Some(fn_decl), NoTypeParameters,
|
Some(fn_decl), NoTypeParameters,
|
||||||
block);
|
block);
|
||||||
|
|
|
@ -1237,7 +1237,7 @@ impl<'l> Visitor<DxrVisitorEnv> for DxrVisitor<'l> {
|
||||||
"Expected struct type, but not ty_struct"),
|
"Expected struct type, but not ty_struct"),
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
ast::ExprFnBlock(decl, body) => {
|
ast::ExprFnBlock(_, decl, body) => {
|
||||||
if generated_code(body.span) {
|
if generated_code(body.span) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
|
@ -1306,7 +1306,9 @@ fn has_nested_returns(tcx: &ty::ctxt, id: ast::NodeId) -> bool {
|
||||||
}
|
}
|
||||||
Some(ast_map::NodeExpr(e)) => {
|
Some(ast_map::NodeExpr(e)) => {
|
||||||
match e.node {
|
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 explicit = CheckForNestedReturnsVisitor { found: false };
|
||||||
let mut implicit = CheckForNestedReturnsVisitor { found: false };
|
let mut implicit = CheckForNestedReturnsVisitor { found: false };
|
||||||
visit::walk_expr(&mut explicit, &*e, false);
|
visit::walk_expr(&mut explicit, &*e, false);
|
||||||
|
|
|
@ -18,6 +18,7 @@ use llvm::{ValueRef, BasicBlockRef, BuilderRef};
|
||||||
use llvm::{True, False, Bool};
|
use llvm::{True, False, Bool};
|
||||||
use mc = middle::mem_categorization;
|
use mc = middle::mem_categorization;
|
||||||
use middle::def;
|
use middle::def;
|
||||||
|
use middle::freevars;
|
||||||
use middle::lang_items::LangItem;
|
use middle::lang_items::LangItem;
|
||||||
use middle::subst;
|
use middle::subst;
|
||||||
use middle::subst::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 {
|
fn upvar_borrow(&self, upvar_id: ty::UpvarId) -> ty::UpvarBorrow {
|
||||||
self.tcx().upvar_borrow_map.borrow().get_copy(&upvar_id)
|
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> {
|
pub struct Result<'a> {
|
||||||
|
|
|
@ -1150,9 +1150,9 @@ pub fn create_function_debug_context(cx: &CrateContext,
|
||||||
}
|
}
|
||||||
ast_map::NodeExpr(ref expr) => {
|
ast_map::NodeExpr(ref expr) => {
|
||||||
match expr.node {
|
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::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 = format!("fn{}", token::gensym("fn"));
|
||||||
let name = token::str_to_ident(name.as_slice());
|
let name = token::str_to_ident(name.as_slice());
|
||||||
(name, fn_decl,
|
(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::ExprProc(ref decl, ref block) |
|
||||||
ast::ExprUnboxedFn(ref decl, ref block) => {
|
ast::ExprUnboxedFn(_, ref decl, ref block) => {
|
||||||
with_new_scope(cx,
|
with_new_scope(cx,
|
||||||
block.span,
|
block.span,
|
||||||
scope_stack,
|
scope_stack,
|
||||||
|
|
|
@ -782,7 +782,7 @@ fn trans_rvalue_dps_unadjusted<'a>(bcx: &'a Block<'a>,
|
||||||
ast::ExprVec(..) | ast::ExprRepeat(..) => {
|
ast::ExprVec(..) | ast::ExprRepeat(..) => {
|
||||||
tvec::trans_fixed_vstore(bcx, expr, expr, dest)
|
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) => {
|
ast::ExprProc(ref decl, ref body) => {
|
||||||
let expr_ty = expr_ty(bcx, expr);
|
let expr_ty = expr_ty(bcx, expr);
|
||||||
let store = ty::ty_closure_store(expr_ty);
|
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));
|
expr_to_string(expr), expr_ty.repr(tcx));
|
||||||
closure::trans_expr_fn(bcx, store, &**decl, &**body, expr.id, dest)
|
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)
|
closure::trans_unboxed_closure(bcx, &*decl, &*body, expr.id, dest)
|
||||||
}
|
}
|
||||||
ast::ExprCall(ref f, ref args) => {
|
ast::ExprCall(ref f, ref args) => {
|
||||||
|
|
|
@ -18,14 +18,15 @@ use lint;
|
||||||
use middle::const_eval;
|
use middle::const_eval;
|
||||||
use middle::def;
|
use middle::def;
|
||||||
use middle::dependency_format;
|
use middle::dependency_format;
|
||||||
|
use middle::freevars::CaptureModeMap;
|
||||||
|
use middle::freevars;
|
||||||
use middle::lang_items::{FnMutTraitLangItem, OpaqueStructLangItem};
|
use middle::lang_items::{FnMutTraitLangItem, OpaqueStructLangItem};
|
||||||
use middle::lang_items::{TyDescStructLangItem, TyVisitorTraitLangItem};
|
use middle::lang_items::{TyDescStructLangItem, TyVisitorTraitLangItem};
|
||||||
use middle::freevars;
|
|
||||||
use middle::resolve;
|
use middle::resolve;
|
||||||
use middle::resolve_lifetime;
|
use middle::resolve_lifetime;
|
||||||
use middle::subst;
|
|
||||||
use middle::subst::{Subst, Substs, VecPerParamSpace};
|
|
||||||
use middle::stability;
|
use middle::stability;
|
||||||
|
use middle::subst::{Subst, Substs, VecPerParamSpace};
|
||||||
|
use middle::subst;
|
||||||
use middle::ty;
|
use middle::ty;
|
||||||
use middle::typeck;
|
use middle::typeck;
|
||||||
use middle::typeck::MethodCall;
|
use middle::typeck::MethodCall;
|
||||||
|
@ -384,6 +385,9 @@ pub struct ctxt {
|
||||||
|
|
||||||
/// Maps any item's def-id to its stability index.
|
/// Maps any item's def-id to its stability index.
|
||||||
pub stability: RefCell<stability::Index>,
|
pub stability: RefCell<stability::Index>,
|
||||||
|
|
||||||
|
/// Maps closures to their capture clauses.
|
||||||
|
pub capture_modes: RefCell<CaptureModeMap>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub enum tbox_flag {
|
pub enum tbox_flag {
|
||||||
|
@ -1057,6 +1061,7 @@ pub fn mk_ctxt(s: Session,
|
||||||
named_region_map: resolve_lifetime::NamedRegionMap,
|
named_region_map: resolve_lifetime::NamedRegionMap,
|
||||||
map: ast_map::Map,
|
map: ast_map::Map,
|
||||||
freevars: freevars::freevar_map,
|
freevars: freevars::freevar_map,
|
||||||
|
capture_modes: freevars::CaptureModeMap,
|
||||||
region_maps: middle::region::RegionMaps,
|
region_maps: middle::region::RegionMaps,
|
||||||
lang_items: middle::lang_items::LanguageItems,
|
lang_items: middle::lang_items::LanguageItems,
|
||||||
stability: stability::Index)
|
stability: stability::Index)
|
||||||
|
@ -1115,7 +1120,8 @@ pub fn mk_ctxt(s: Session,
|
||||||
unboxed_closure_types: RefCell::new(DefIdMap::new()),
|
unboxed_closure_types: RefCell::new(DefIdMap::new()),
|
||||||
node_lint_levels: RefCell::new(HashMap::new()),
|
node_lint_levels: RefCell::new(HashMap::new()),
|
||||||
transmute_restrictions: RefCell::new(Vec::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 {
|
fn upvar_borrow(&self, upvar_id: ty::UpvarId) -> ty::UpvarBorrow {
|
||||||
self.upvar_borrow_map.borrow().get_copy(&upvar_id)
|
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.
|
/// The category of explicit self.
|
||||||
|
|
|
@ -3390,7 +3390,7 @@ fn check_expr_with_unifier(fcx: &FnCtxt,
|
||||||
ast::ExprMatch(ref discrim, ref arms) => {
|
ast::ExprMatch(ref discrim, ref arms) => {
|
||||||
_match::check_match(fcx, expr, &**discrim, arms.as_slice());
|
_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,
|
let region = astconv::opt_ast_region_to_region(fcx,
|
||||||
fcx.infcx(),
|
fcx.infcx(),
|
||||||
expr.span,
|
expr.span,
|
||||||
|
@ -3402,7 +3402,7 @@ fn check_expr_with_unifier(fcx: &FnCtxt,
|
||||||
body.clone(),
|
body.clone(),
|
||||||
expected);
|
expected);
|
||||||
}
|
}
|
||||||
ast::ExprUnboxedFn(ref decl, ref body) => {
|
ast::ExprUnboxedFn(_, ref decl, ref body) => {
|
||||||
check_unboxed_closure(fcx,
|
check_unboxed_closure(fcx,
|
||||||
expr,
|
expr,
|
||||||
&**decl,
|
&**decl,
|
||||||
|
|
|
@ -290,6 +290,11 @@ impl<'fcx> mc::Typer for Rcx<'fcx> {
|
||||||
fn upvar_borrow(&self, id: ty::UpvarId) -> ty::UpvarBorrow {
|
fn upvar_borrow(&self, id: ty::UpvarId) -> ty::UpvarBorrow {
|
||||||
self.fcx.inh.upvar_borrow_map.borrow().get_copy(&id)
|
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) {
|
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, ());
|
visit::walk_expr(rcx, expr, ());
|
||||||
}
|
}
|
||||||
|
|
||||||
ast::ExprFnBlock(_, ref body) |
|
ast::ExprFnBlock(_, _, ref body) |
|
||||||
ast::ExprProc(_, ref body) |
|
ast::ExprProc(_, ref body) |
|
||||||
ast::ExprUnboxedFn(_, ref body) => {
|
ast::ExprUnboxedFn(_, _, ref body) => {
|
||||||
check_expr_fn_block(rcx, expr, &**body);
|
check_expr_fn_block(rcx, expr, &**body);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -132,9 +132,9 @@ impl<'cx> Visitor<()> for WritebackCx<'cx> {
|
||||||
MethodCall::expr(e.id));
|
MethodCall::expr(e.id));
|
||||||
|
|
||||||
match e.node {
|
match e.node {
|
||||||
ast::ExprFnBlock(ref decl, _) |
|
ast::ExprFnBlock(_, ref decl, _) |
|
||||||
ast::ExprProc(ref decl, _) |
|
ast::ExprProc(ref decl, _) |
|
||||||
ast::ExprUnboxedFn(ref decl, _) => {
|
ast::ExprUnboxedFn(_, ref decl, _) => {
|
||||||
for input in decl.inputs.iter() {
|
for input in decl.inputs.iter() {
|
||||||
let _ = self.visit_node_id(ResolvingExpr(e.span),
|
let _ = self.visit_node_id(ResolvingExpr(e.span),
|
||||||
input.id);
|
input.id);
|
||||||
|
|
|
@ -124,12 +124,20 @@ fn test_env(_test_name: &str,
|
||||||
let lang_items = lang_items::collect_language_items(&krate, &sess);
|
let lang_items = lang_items::collect_language_items(&krate, &sess);
|
||||||
let resolve::CrateMap { def_map: def_map, .. } =
|
let resolve::CrateMap { def_map: def_map, .. } =
|
||||||
resolve::resolve_crate(&sess, &lang_items, &krate);
|
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 named_region_map = resolve_lifetime::krate(&sess, &krate);
|
||||||
let region_map = region::resolve_crate(&sess, &krate);
|
let region_map = region::resolve_crate(&sess, &krate);
|
||||||
let stability_index = stability::Index::build(&krate);
|
let stability_index = stability::Index::build(&krate);
|
||||||
let tcx = ty::mk_ctxt(sess, def_map, named_region_map, ast_map,
|
let tcx = ty::mk_ctxt(sess,
|
||||||
freevars_map, region_map, lang_items, stability_index);
|
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 infcx = infer::new_infer_ctxt(&tcx);
|
||||||
let env = Env {krate: krate,
|
let env = Env {krate: krate,
|
||||||
tcx: &tcx,
|
tcx: &tcx,
|
||||||
|
|
|
@ -520,9 +520,9 @@ pub enum Expr_ {
|
||||||
// FIXME #6993: change to Option<Name> ... or not, if these are hygienic.
|
// FIXME #6993: change to Option<Name> ... or not, if these are hygienic.
|
||||||
ExprLoop(P<Block>, Option<Ident>),
|
ExprLoop(P<Block>, Option<Ident>),
|
||||||
ExprMatch(Gc<Expr>, Vec<Arm>),
|
ExprMatch(Gc<Expr>, Vec<Arm>),
|
||||||
ExprFnBlock(P<FnDecl>, P<Block>),
|
ExprFnBlock(CaptureClause, P<FnDecl>, P<Block>),
|
||||||
ExprProc(P<FnDecl>, P<Block>),
|
ExprProc(P<FnDecl>, P<Block>),
|
||||||
ExprUnboxedFn(P<FnDecl>, P<Block>),
|
ExprUnboxedFn(CaptureClause, P<FnDecl>, P<Block>),
|
||||||
ExprBlock(P<Block>),
|
ExprBlock(P<Block>),
|
||||||
|
|
||||||
ExprAssign(Gc<Expr>, Gc<Expr>),
|
ExprAssign(Gc<Expr>, Gc<Expr>),
|
||||||
|
@ -553,6 +553,12 @@ pub enum Expr_ {
|
||||||
ExprParen(Gc<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
|
/// 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
|
/// 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
|
/// 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::NodeMethod(ref m) => method(&**m),
|
||||||
ast_map::NodeExpr(ref e) => match e.node {
|
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)),
|
closure(ClosureParts::new(*decl, *block, e.id, e.span)),
|
||||||
ast::ExprProc(ref decl, ref block) =>
|
ast::ExprProc(ref decl, ref block) =>
|
||||||
closure(ClosureParts::new(*decl, *block, e.id, e.span)),
|
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 lambda_fn_decl(&self, span: Span,
|
||||||
fn_decl: P<ast::FnDecl>, blk: P<ast::Block>) -> Gc<ast::Expr> {
|
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> {
|
fn lambda(&self, span: Span, ids: Vec<ast::Ident> , blk: P<ast::Block>) -> Gc<ast::Expr> {
|
||||||
let fn_decl = self.fn_decl(
|
let fn_decl = self.fn_decl(
|
||||||
ids.iter().map(|id| self.arg(span, *id, self.ty_infer(span))).collect(),
|
ids.iter().map(|id| self.arg(span, *id, self.ty_infer(span))).collect(),
|
||||||
self.ty_infer(span));
|
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> {
|
fn lambda0(&self, span: Span, blk: P<ast::Block>) -> Gc<ast::Expr> {
|
||||||
self.lambda(span, Vec::new(), blk)
|
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))
|
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)
|
let (rewritten_fn_decl, rewritten_block)
|
||||||
= expand_and_rename_fn_decl_and_block(&*fn_decl, block, fld);
|
= 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)}
|
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),
|
ExprMatch(folder.fold_expr(expr),
|
||||||
arms.iter().map(|x| folder.fold_arm(x)).collect())
|
arms.iter().map(|x| folder.fold_arm(x)).collect())
|
||||||
}
|
}
|
||||||
ExprFnBlock(ref decl, ref body) => {
|
ExprFnBlock(capture_clause, ref decl, ref body) => {
|
||||||
ExprFnBlock(folder.fold_fn_decl(&**decl),
|
ExprFnBlock(capture_clause,
|
||||||
|
folder.fold_fn_decl(&**decl),
|
||||||
folder.fold_block(body.clone()))
|
folder.fold_block(body.clone()))
|
||||||
}
|
}
|
||||||
ExprProc(ref decl, ref body) => {
|
ExprProc(ref decl, ref body) => {
|
||||||
ExprProc(folder.fold_fn_decl(&**decl),
|
ExprProc(folder.fold_fn_decl(&**decl),
|
||||||
folder.fold_block(body.clone()))
|
folder.fold_block(body.clone()))
|
||||||
}
|
}
|
||||||
ExprUnboxedFn(ref decl, ref body) => {
|
ExprUnboxedFn(capture_clause, ref decl, ref body) => {
|
||||||
ExprUnboxedFn(folder.fold_fn_decl(&**decl),
|
ExprUnboxedFn(capture_clause,
|
||||||
|
folder.fold_fn_decl(&**decl),
|
||||||
folder.fold_block(*body))
|
folder.fold_block(*body))
|
||||||
}
|
}
|
||||||
ExprBlock(ref blk) => ExprBlock(folder.fold_block(*blk)),
|
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::{Mod, BiAdd, Arg, Arm, Attribute, BindByRef, BindByValue};
|
||||||
use ast::{BiBitAnd, BiBitOr, BiBitXor, Block};
|
use ast::{BiBitAnd, BiBitOr, BiBitXor, Block};
|
||||||
use ast::{BlockCheckMode, UnBox};
|
use ast::{BlockCheckMode, UnBox};
|
||||||
|
use ast::{CaptureByRef, CaptureByValue, CaptureClause};
|
||||||
use ast::{Crate, CrateConfig, Decl, DeclItem};
|
use ast::{Crate, CrateConfig, Decl, DeclItem};
|
||||||
use ast::{DeclLocal, DefaultBlock, UnDeref, BiDiv, EMPTY_CTXT, EnumDef, ExplicitSelf};
|
use ast::{DeclLocal, DefaultBlock, UnDeref, BiDiv, EMPTY_CTXT, EnumDef, ExplicitSelf};
|
||||||
use ast::{Expr, Expr_, ExprAddrOf, ExprMatch, ExprAgain};
|
use ast::{Expr, Expr_, ExprAddrOf, ExprMatch, ExprAgain};
|
||||||
|
@ -1985,7 +1986,7 @@ impl<'a> Parser<'a> {
|
||||||
ExprBlock(blk));
|
ExprBlock(blk));
|
||||||
},
|
},
|
||||||
token::BINOP(token::OR) | token::OROR => {
|
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
|
// FIXME #13626: Should be able to stick in
|
||||||
// token::SELF_KEYWORD_NAME
|
// token::SELF_KEYWORD_NAME
|
||||||
|
@ -2036,6 +2037,9 @@ impl<'a> Parser<'a> {
|
||||||
hi = self.last_span.hi;
|
hi = self.last_span.hi;
|
||||||
},
|
},
|
||||||
_ => {
|
_ => {
|
||||||
|
if self.eat_keyword(keywords::Ref) {
|
||||||
|
return self.parse_lambda_expr(CaptureByRef);
|
||||||
|
}
|
||||||
if self.eat_keyword(keywords::Proc) {
|
if self.eat_keyword(keywords::Proc) {
|
||||||
let decl = self.parse_proc_decl();
|
let decl = self.parse_proc_decl();
|
||||||
let body = self.parse_expr();
|
let body = self.parse_expr();
|
||||||
|
@ -2696,7 +2700,8 @@ impl<'a> Parser<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
// `|args| expr`
|
// `|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 lo = self.span.lo;
|
||||||
let (decl, is_unboxed) = self.parse_fn_block_decl();
|
let (decl, is_unboxed) = self.parse_fn_block_decl();
|
||||||
let body = self.parse_expr();
|
let body = self.parse_expr();
|
||||||
|
@ -2710,9 +2715,13 @@ impl<'a> Parser<'a> {
|
||||||
});
|
});
|
||||||
|
|
||||||
if is_unboxed {
|
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 {
|
} else {
|
||||||
self.mk_expr(lo, body.span.hi, ExprFnBlock(decl, fakeblock))
|
self.mk_expr(lo,
|
||||||
|
body.span.hi,
|
||||||
|
ExprFnBlock(capture_clause, decl, fakeblock))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1437,7 +1437,9 @@ impl<'a> State<'a> {
|
||||||
}
|
}
|
||||||
try!(self.bclose_(expr.span, indent_unit));
|
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
|
// in do/for blocks we don't want to show an empty
|
||||||
// argument list, but at this point we don't know which
|
// argument list, but at this point we don't know which
|
||||||
// we are inside.
|
// we are inside.
|
||||||
|
@ -1467,7 +1469,9 @@ impl<'a> State<'a> {
|
||||||
// empty box to satisfy the close.
|
// empty box to satisfy the close.
|
||||||
try!(self.ibox(0));
|
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
|
// in do/for blocks we don't want to show an empty
|
||||||
// argument list, but at this point we don't know which
|
// argument list, but at this point we don't know which
|
||||||
// we are inside.
|
// we are inside.
|
||||||
|
@ -2030,6 +2034,14 @@ impl<'a> State<'a> {
|
||||||
self.maybe_print_comment(decl.output.span.lo)
|
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<()> {
|
pub fn print_proc_args(&mut self, decl: &ast::FnDecl) -> IoResult<()> {
|
||||||
try!(word(&mut self.s, "proc"));
|
try!(word(&mut self.s, "proc"));
|
||||||
try!(word(&mut self.s, "("));
|
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())
|
visitor.visit_arm(arm, env.clone())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ExprFnBlock(ref function_declaration, ref body) => {
|
ExprFnBlock(_, ref function_declaration, ref body) => {
|
||||||
visitor.visit_fn(&FkFnBlock,
|
visitor.visit_fn(&FkFnBlock,
|
||||||
&**function_declaration,
|
&**function_declaration,
|
||||||
&**body,
|
&**body,
|
||||||
|
@ -795,7 +795,7 @@ pub fn walk_expr<E: Clone, V: Visitor<E>>(visitor: &mut V, expression: &Expr, en
|
||||||
expression.id,
|
expression.id,
|
||||||
env.clone())
|
env.clone())
|
||||||
}
|
}
|
||||||
ExprUnboxedFn(ref function_declaration, ref body) => {
|
ExprUnboxedFn(_, ref function_declaration, ref body) => {
|
||||||
visitor.visit_fn(&FkFnBlock,
|
visitor.visit_fn(&FkFnBlock,
|
||||||
&**function_declaration,
|
&**function_declaration,
|
||||||
&**body,
|
&**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…
Add table
Add a link
Reference in a new issue