Skip to content

Commit 9d45d63

Browse files
committed
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
2 parents aa98b25 + a63003f commit 9d45d63

29 files changed

+254
-72
lines changed

src/librustc/driver/driver.rs

+12-4
Original file line numberDiff line numberDiff line change
@@ -360,8 +360,9 @@ pub fn phase_3_run_analysis_passes(sess: Session,
360360
plugin::build::find_plugin_registrar(
361361
sess.diagnostic(), krate)));
362362

363-
let freevars = time(time_passes, "freevar finding", (), |_|
364-
freevars::annotate_freevars(&def_map, krate));
363+
let (freevars, capture_modes) =
364+
time(time_passes, "freevar finding", (), |_|
365+
freevars::annotate_freevars(&def_map, krate));
365366

366367
let region_map = time(time_passes, "region resolution", (), |_|
367368
middle::region::resolve_crate(&sess, krate));
@@ -372,8 +373,15 @@ pub fn phase_3_run_analysis_passes(sess: Session,
372373
let stability_index = time(time_passes, "stability index", (), |_|
373374
stability::Index::build(krate));
374375

375-
let ty_cx = ty::mk_ctxt(sess, def_map, named_region_map, ast_map,
376-
freevars, region_map, lang_items, stability_index);
376+
let ty_cx = ty::mk_ctxt(sess,
377+
def_map,
378+
named_region_map,
379+
ast_map,
380+
freevars,
381+
capture_modes,
382+
region_map,
383+
lang_items,
384+
stability_index);
377385

378386
// passes are timed inside typeck
379387
typeck::check_crate(&ty_cx, trait_map, krate);

src/librustc/metadata/common.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -141,9 +141,10 @@ pub enum astencode_tag { // Reserves 0x40 -- 0x5f
141141
tag_table_capture_map = 0x53,
142142
tag_table_unboxed_closure_type = 0x54,
143143
tag_table_upvar_borrow_map = 0x55,
144+
tag_table_capture_modes = 0x56,
144145
}
145146
static first_astencode_tag: uint = tag_ast as uint;
146-
static last_astencode_tag: uint = tag_table_upvar_borrow_map as uint;
147+
static last_astencode_tag: uint = tag_table_capture_modes as uint;
147148
impl astencode_tag {
148149
pub fn from_uint(value : uint) -> Option<astencode_tag> {
149150
let is_a_tag = first_astencode_tag <= value && value <= last_astencode_tag;

src/librustc/middle/astencode.rs

+27-1
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,8 @@ use driver::session::Session;
1818
use metadata::decoder;
1919
use middle::def;
2020
use e = metadata::encoder;
21+
use middle::freevars::{CaptureMode, freevar_entry};
2122
use middle::freevars;
22-
use middle::freevars::freevar_entry;
2323
use middle::region;
2424
use metadata::tydecode;
2525
use metadata::tydecode::{DefIdSource, NominalType, TypeWithId, TypeParameter,
@@ -530,9 +530,14 @@ fn encode_freevar_entry(rbml_w: &mut Encoder, fv: &freevar_entry) {
530530
(*fv).encode(rbml_w).unwrap();
531531
}
532532

533+
fn encode_capture_mode(rbml_w: &mut Encoder, cm: CaptureMode) {
534+
cm.encode(rbml_w).unwrap();
535+
}
536+
533537
trait rbml_decoder_helper {
534538
fn read_freevar_entry(&mut self, xcx: &ExtendedDecodeContext)
535539
-> freevar_entry;
540+
fn read_capture_mode(&mut self) -> CaptureMode;
536541
}
537542

538543
impl<'a> rbml_decoder_helper for reader::Decoder<'a> {
@@ -541,6 +546,11 @@ impl<'a> rbml_decoder_helper for reader::Decoder<'a> {
541546
let fv: freevar_entry = Decodable::decode(self).unwrap();
542547
fv.tr(xcx)
543548
}
549+
550+
fn read_capture_mode(&mut self) -> CaptureMode {
551+
let cm: CaptureMode = Decodable::decode(self).unwrap();
552+
cm
553+
}
544554
}
545555

546556
impl tr for freevar_entry {
@@ -1096,6 +1106,15 @@ fn encode_side_tables_for_id(ecx: &e::EncodeContext,
10961106
}
10971107
}
10981108

1109+
for &cm in tcx.capture_modes.borrow().find(&id).iter() {
1110+
rbml_w.tag(c::tag_table_capture_modes, |rbml_w| {
1111+
rbml_w.id(id);
1112+
rbml_w.tag(c::tag_table_val, |rbml_w| {
1113+
encode_capture_mode(rbml_w, *cm);
1114+
})
1115+
})
1116+
}
1117+
10991118
let lid = ast::DefId { krate: ast::LOCAL_CRATE, node: id };
11001119
for &pty in tcx.tcache.borrow().find(&lid).iter() {
11011120
rbml_w.tag(c::tag_table_tcache, |rbml_w| {
@@ -1509,6 +1528,13 @@ fn decode_side_tables(xcx: &ExtendedDecodeContext,
15091528
let ub: ty::UpvarBorrow = Decodable::decode(val_dsr).unwrap();
15101529
dcx.tcx.upvar_borrow_map.borrow_mut().insert(upvar_id, ub.tr(xcx));
15111530
}
1531+
c::tag_table_capture_modes => {
1532+
let capture_mode = val_dsr.read_capture_mode();
1533+
dcx.tcx
1534+
.capture_modes
1535+
.borrow_mut()
1536+
.insert(id, capture_mode);
1537+
}
15121538
c::tag_table_tcache => {
15131539
let pty = val_dsr.read_polytype(xcx);
15141540
let lid = ast::DefId { krate: ast::LOCAL_CRATE, node: id };

src/librustc/middle/borrowck/mod.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -291,7 +291,7 @@ pub fn closure_to_block(closure_id: ast::NodeId,
291291
match tcx.map.get(closure_id) {
292292
ast_map::NodeExpr(expr) => match expr.node {
293293
ast::ExprProc(_decl, block) |
294-
ast::ExprFnBlock(_decl, block) => { block.id }
294+
ast::ExprFnBlock(_, _decl, block) => { block.id }
295295
_ => fail!("encountered non-closure id: {}", closure_id)
296296
},
297297
_ => fail!("encountered non-expr id: {}", closure_id)

src/librustc/middle/check_loop.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -46,9 +46,9 @@ impl<'a> Visitor<Context> for CheckLoopVisitor<'a> {
4646
self.visit_expr(&**e, cx);
4747
self.visit_block(&**b, Loop);
4848
}
49-
ast::ExprFnBlock(_, ref b) |
49+
ast::ExprFnBlock(_, _, ref b) |
5050
ast::ExprProc(_, ref b) |
51-
ast::ExprUnboxedFn(_, ref b) => {
51+
ast::ExprUnboxedFn(_, _, ref b) => {
5252
self.visit_block(&**b, Closure);
5353
}
5454
ast::ExprBreak(_) => self.require_loop("break", cx, e.span),

src/librustc/middle/freevars.rs

+48-19
Original file line numberDiff line numberDiff line change
@@ -17,14 +17,14 @@ use middle::def;
1717
use middle::mem_categorization::Typer;
1818
use middle::resolve;
1919
use middle::ty;
20-
use util::nodemap::{DefIdSet, NodeMap, NodeSet};
20+
use util::nodemap::{NodeMap, NodeSet};
2121

22+
use syntax::ast;
2223
use syntax::codemap::Span;
23-
use syntax::{ast};
24-
use syntax::visit;
2524
use syntax::visit::Visitor;
25+
use syntax::visit;
2626

27-
#[deriving(Show)]
27+
#[deriving(Clone, Decodable, Encodable, Show)]
2828
pub enum CaptureMode {
2929
/// Copy/move the value from this llvm ValueRef into the environment.
3030
CaptureByValue,
@@ -43,12 +43,13 @@ pub struct freevar_entry {
4343

4444
pub type freevar_map = NodeMap<Vec<freevar_entry>>;
4545

46-
pub type UnboxedClosureList = DefIdSet;
46+
pub type CaptureModeMap = NodeMap<CaptureMode>;
4747

4848
struct CollectFreevarsVisitor<'a> {
4949
seen: NodeSet,
5050
refs: Vec<freevar_entry>,
5151
def_map: &'a resolve::DefMap,
52+
capture_mode_map: &'a mut CaptureModeMap,
5253
}
5354

5455
impl<'a> Visitor<int> for CollectFreevarsVisitor<'a> {
@@ -58,8 +59,27 @@ impl<'a> Visitor<int> for CollectFreevarsVisitor<'a> {
5859

5960
fn visit_expr(&mut self, expr: &ast::Expr, depth: int) {
6061
match expr.node {
61-
ast::ExprFnBlock(..) | ast::ExprProc(..) |
62-
ast::ExprUnboxedFn(..) => {
62+
ast::ExprProc(..) => {
63+
self.capture_mode_map.insert(expr.id, CaptureByValue);
64+
visit::walk_expr(self, expr, depth + 1)
65+
}
66+
ast::ExprFnBlock(_, _, _) => {
67+
// NOTE(stage0): After snapshot, change to:
68+
//
69+
//let capture_mode = match capture_clause {
70+
// ast::CaptureByValue => CaptureByValue,
71+
// ast::CaptureByRef => CaptureByRef,
72+
//};
73+
let capture_mode = CaptureByRef;
74+
self.capture_mode_map.insert(expr.id, capture_mode);
75+
visit::walk_expr(self, expr, depth + 1)
76+
}
77+
ast::ExprUnboxedFn(capture_clause, _, _) => {
78+
let capture_mode = match capture_clause {
79+
ast::CaptureByValue => CaptureByValue,
80+
ast::CaptureByRef => CaptureByRef,
81+
};
82+
self.capture_mode_map.insert(expr.id, capture_mode);
6383
visit::walk_expr(self, expr, depth + 1)
6484
}
6585
ast::ExprPath(..) => {
@@ -91,35 +111,41 @@ impl<'a> Visitor<int> for CollectFreevarsVisitor<'a> {
91111
_ => visit::walk_expr(self, expr, depth)
92112
}
93113
}
94-
95-
96114
}
97115

98116
// Searches through part of the AST for all references to locals or
99117
// upvars in this frame and returns the list of definition IDs thus found.
100118
// Since we want to be able to collect upvars in some arbitrary piece
101119
// of the AST, we take a walker function that we invoke with a visitor
102120
// in order to start the search.
103-
fn collect_freevars(def_map: &resolve::DefMap, blk: &ast::Block) -> Vec<freevar_entry> {
121+
fn collect_freevars(def_map: &resolve::DefMap,
122+
blk: &ast::Block,
123+
capture_mode_map: &mut CaptureModeMap)
124+
-> Vec<freevar_entry> {
104125
let mut v = CollectFreevarsVisitor {
105126
seen: NodeSet::new(),
106127
refs: Vec::new(),
107128
def_map: def_map,
129+
capture_mode_map: &mut *capture_mode_map,
108130
};
109131

110132
v.visit_block(blk, 1);
133+
111134
v.refs
112135
}
113136

114137
struct AnnotateFreevarsVisitor<'a> {
115138
def_map: &'a resolve::DefMap,
116139
freevars: freevar_map,
140+
capture_mode_map: CaptureModeMap,
117141
}
118142

119143
impl<'a> Visitor<()> for AnnotateFreevarsVisitor<'a> {
120144
fn visit_fn(&mut self, fk: &visit::FnKind, fd: &ast::FnDecl,
121145
blk: &ast::Block, s: Span, nid: ast::NodeId, _: ()) {
122-
let vars = collect_freevars(self.def_map, blk);
146+
let vars = collect_freevars(self.def_map,
147+
blk,
148+
&mut self.capture_mode_map);
123149
self.freevars.insert(nid, vars);
124150
visit::walk_fn(self, fk, fd, blk, s, ());
125151
}
@@ -131,14 +157,20 @@ impl<'a> Visitor<()> for AnnotateFreevarsVisitor<'a> {
131157
// node of interest rather than building up the free variables in
132158
// one pass. This could be improved upon if it turns out to matter.
133159
pub fn annotate_freevars(def_map: &resolve::DefMap, krate: &ast::Crate)
134-
-> freevar_map {
160+
-> (freevar_map, CaptureModeMap) {
135161
let mut visitor = AnnotateFreevarsVisitor {
136162
def_map: def_map,
137163
freevars: NodeMap::new(),
164+
capture_mode_map: NodeMap::new(),
138165
};
139166
visit::walk_crate(&mut visitor, krate, ());
140167

141-
visitor.freevars
168+
let AnnotateFreevarsVisitor {
169+
freevars,
170+
capture_mode_map,
171+
..
172+
} = visitor;
173+
(freevars, capture_mode_map)
142174
}
143175

144176
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]|
148180
}
149181
}
150182

151-
pub fn get_capture_mode<T: Typer>(tcx: &T, closure_expr_id: ast::NodeId) -> CaptureMode {
152-
let fn_ty = tcx.node_ty(closure_expr_id).ok().expect("couldn't find closure ty?");
153-
match ty::ty_closure_store(fn_ty) {
154-
ty::RegionTraitStore(..) => CaptureByRef,
155-
ty::UniqTraitStore => CaptureByValue
156-
}
183+
pub fn get_capture_mode<T:Typer>(tcx: &T, closure_expr_id: ast::NodeId)
184+
-> CaptureMode {
185+
tcx.capture_mode(closure_expr_id)
157186
}

src/librustc/middle/liveness.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -965,9 +965,9 @@ impl<'a> Liveness<'a> {
965965
self.propagate_through_expr(&**e, succ)
966966
}
967967

968-
ExprFnBlock(_, ref blk) |
968+
ExprFnBlock(_, _, ref blk) |
969969
ExprProc(_, ref blk) |
970-
ExprUnboxedFn(_, ref blk) => {
970+
ExprUnboxedFn(_, _, ref blk) => {
971971
debug!("{} is an ExprFnBlock, ExprProc, or ExprUnboxedFn",
972972
expr_to_string(expr));
973973

src/librustc/middle/mem_categorization.rs

+3
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@
6363
#![allow(non_camel_case_types)]
6464

6565
use middle::def;
66+
use middle::freevars;
6667
use middle::ty;
6768
use middle::typeck;
6869
use util::nodemap::NodeMap;
@@ -270,6 +271,8 @@ pub trait Typer {
270271
fn is_method_call(&self, id: ast::NodeId) -> bool;
271272
fn temporary_scope(&self, rvalue_id: ast::NodeId) -> Option<ast::NodeId>;
272273
fn upvar_borrow(&self, upvar_id: ty::UpvarId) -> ty::UpvarBorrow;
274+
fn capture_mode(&self, closure_expr_id: ast::NodeId)
275+
-> freevars::CaptureMode;
273276
}
274277

275278
impl MutabilityCategory {

src/librustc/middle/resolve.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -5287,9 +5287,9 @@ impl<'a> Resolver<'a> {
52875287
visit::walk_expr(self, expr, ());
52885288
}
52895289

5290-
ExprFnBlock(fn_decl, block) |
5290+
ExprFnBlock(_, fn_decl, block) |
52915291
ExprProc(fn_decl, block) |
5292-
ExprUnboxedFn(fn_decl, block) => {
5292+
ExprUnboxedFn(_, fn_decl, block) => {
52935293
self.resolve_function(FunctionRibKind(expr.id, block.id),
52945294
Some(fn_decl), NoTypeParameters,
52955295
block);

src/librustc/middle/save/mod.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1237,7 +1237,7 @@ impl<'l> Visitor<DxrVisitorEnv> for DxrVisitor<'l> {
12371237
"Expected struct type, but not ty_struct"),
12381238
}
12391239
},
1240-
ast::ExprFnBlock(decl, body) => {
1240+
ast::ExprFnBlock(_, decl, body) => {
12411241
if generated_code(body.span) {
12421242
return
12431243
}

src/librustc/middle/trans/base.rs

+3-1
Original file line numberDiff line numberDiff line change
@@ -1306,7 +1306,9 @@ fn has_nested_returns(tcx: &ty::ctxt, id: ast::NodeId) -> bool {
13061306
}
13071307
Some(ast_map::NodeExpr(e)) => {
13081308
match e.node {
1309-
ast::ExprFnBlock(_, blk) | ast::ExprProc(_, blk) | ast::ExprUnboxedFn(_, blk) => {
1309+
ast::ExprFnBlock(_, _, blk) |
1310+
ast::ExprProc(_, blk) |
1311+
ast::ExprUnboxedFn(_, _, blk) => {
13101312
let mut explicit = CheckForNestedReturnsVisitor { found: false };
13111313
let mut implicit = CheckForNestedReturnsVisitor { found: false };
13121314
visit::walk_expr(&mut explicit, &*e, false);

src/librustc/middle/trans/common.rs

+6
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ use llvm::{ValueRef, BasicBlockRef, BuilderRef};
1818
use llvm::{True, False, Bool};
1919
use mc = middle::mem_categorization;
2020
use middle::def;
21+
use middle::freevars;
2122
use middle::lang_items::LangItem;
2223
use middle::subst;
2324
use middle::subst::Subst;
@@ -516,6 +517,11 @@ impl<'a> mc::Typer for Block<'a> {
516517
fn upvar_borrow(&self, upvar_id: ty::UpvarId) -> ty::UpvarBorrow {
517518
self.tcx().upvar_borrow_map.borrow().get_copy(&upvar_id)
518519
}
520+
521+
fn capture_mode(&self, closure_expr_id: ast::NodeId)
522+
-> freevars::CaptureMode {
523+
self.tcx().capture_modes.borrow().get_copy(&closure_expr_id)
524+
}
519525
}
520526

521527
pub struct Result<'a> {

src/librustc/middle/trans/debuginfo.rs

+4-4
Original file line numberDiff line numberDiff line change
@@ -1150,9 +1150,9 @@ pub fn create_function_debug_context(cx: &CrateContext,
11501150
}
11511151
ast_map::NodeExpr(ref expr) => {
11521152
match expr.node {
1153-
ast::ExprFnBlock(fn_decl, top_level_block) |
1153+
ast::ExprFnBlock(_, fn_decl, top_level_block) |
11541154
ast::ExprProc(fn_decl, top_level_block) |
1155-
ast::ExprUnboxedFn(fn_decl, top_level_block) => {
1155+
ast::ExprUnboxedFn(_, fn_decl, top_level_block) => {
11561156
let name = format!("fn{}", token::gensym("fn"));
11571157
let name = token::str_to_ident(name.as_slice());
11581158
(name, fn_decl,
@@ -3618,9 +3618,9 @@ fn populate_scope_map(cx: &CrateContext,
36183618
})
36193619
}
36203620

3621-
ast::ExprFnBlock(ref decl, ref block) |
3621+
ast::ExprFnBlock(_, ref decl, ref block) |
36223622
ast::ExprProc(ref decl, ref block) |
3623-
ast::ExprUnboxedFn(ref decl, ref block) => {
3623+
ast::ExprUnboxedFn(_, ref decl, ref block) => {
36243624
with_new_scope(cx,
36253625
block.span,
36263626
scope_stack,

src/librustc/middle/trans/expr.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -782,15 +782,15 @@ fn trans_rvalue_dps_unadjusted<'a>(bcx: &'a Block<'a>,
782782
ast::ExprVec(..) | ast::ExprRepeat(..) => {
783783
tvec::trans_fixed_vstore(bcx, expr, expr, dest)
784784
}
785-
ast::ExprFnBlock(ref decl, ref body) |
785+
ast::ExprFnBlock(_, ref decl, ref body) |
786786
ast::ExprProc(ref decl, ref body) => {
787787
let expr_ty = expr_ty(bcx, expr);
788788
let store = ty::ty_closure_store(expr_ty);
789789
debug!("translating block function {} with type {}",
790790
expr_to_string(expr), expr_ty.repr(tcx));
791791
closure::trans_expr_fn(bcx, store, &**decl, &**body, expr.id, dest)
792792
}
793-
ast::ExprUnboxedFn(decl, body) => {
793+
ast::ExprUnboxedFn(_, decl, body) => {
794794
closure::trans_unboxed_closure(bcx, &*decl, &*body, expr.id, dest)
795795
}
796796
ast::ExprCall(ref f, ref args) => {

0 commit comments

Comments
 (0)