Skip to content

Commit

Permalink
auto merge of #15929 : pcwalton/rust/by-ref-closures, r=alexcrichton
Browse files Browse the repository at this point in the history
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
  • Loading branch information
bors committed Aug 14, 2014
2 parents aa98b25 + a63003f commit 9d45d63
Show file tree
Hide file tree
Showing 29 changed files with 254 additions and 72 deletions.
16 changes: 12 additions & 4 deletions src/librustc/driver/driver.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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));
Expand All @@ -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);
Expand Down
3 changes: 2 additions & 1 deletion src/librustc/metadata/common.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
28 changes: 27 additions & 1 deletion src/librustc/middle/astencode.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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> {
Expand All @@ -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 {
Expand Down Expand Up @@ -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| {
Expand Down Expand Up @@ -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 };
Expand Down
2 changes: 1 addition & 1 deletion src/librustc/middle/borrowck/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
4 changes: 2 additions & 2 deletions src/librustc/middle/check_loop.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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),
Expand Down
67 changes: 48 additions & 19 deletions src/librustc/middle/freevars.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -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> {
Expand All @@ -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(..) => {
Expand Down Expand Up @@ -91,35 +111,41 @@ 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
// upvars in this frame and returns the list of definition IDs thus found.
// 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, ());
}
Expand All @@ -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 {
Expand All @@ -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)
}
4 changes: 2 additions & 2 deletions src/librustc/middle/liveness.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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));

Expand Down
3 changes: 3 additions & 0 deletions src/librustc/middle/mem_categorization.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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 {
Expand Down
4 changes: 2 additions & 2 deletions src/librustc/middle/resolve.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
2 changes: 1 addition & 1 deletion src/librustc/middle/save/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
Expand Down
4 changes: 3 additions & 1 deletion src/librustc/middle/trans/base.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
6 changes: 6 additions & 0 deletions src/librustc/middle/trans/common.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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> {
Expand Down
8 changes: 4 additions & 4 deletions src/librustc/middle/trans/debuginfo.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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,
Expand Down
4 changes: 2 additions & 2 deletions src/librustc/middle/trans/expr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -782,15 +782,15 @@ 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);
debug!("translating block function {} with type {}",
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) => {
Expand Down
Loading

0 comments on commit 9d45d63

Please sign in to comment.