Skip to content

Commit

Permalink
auto merge of #16122 : pcwalton/rust/lifetimes-in-unboxed-closures, r…
Browse files Browse the repository at this point in the history
…=pnkfelix

This patch primarily does two things: (1) it prevents lifetimes from
leaking out of unboxed closures; (2) it allows unboxed closure type
notation, call notation, and construction notation to construct closures
matching any of the three traits.

This breaks code that looked like:

    let mut f;
    {
        let x = &5i;
        f = |&mut:| *x + 10;
    }

Change this code to avoid having a reference escape. For example:

    {
        let x = &5i;
        let mut f; // <-- move here to avoid dangling reference
        f = |&mut:| *x + 10;
    }

I believe this is enough to consider unboxed closures essentially
implemented. Further issues (for example, higher-rank lifetimes) should
be filed as followups.

Closes #14449.

[breaking-change]

r? @pnkfelix
  • Loading branch information
bors committed Aug 14, 2014
2 parents 56b86aa + 8d27232 commit 404978e
Show file tree
Hide file tree
Showing 43 changed files with 835 additions and 298 deletions.
2 changes: 1 addition & 1 deletion src/librustc/front/feature_gate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -314,7 +314,7 @@ impl<'a> Visitor<()> for Context<'a> {

},
ast::TyBox(_) => { self.gate_box(t.span); }
ast::TyUnboxedFn(_) => {
ast::TyUnboxedFn(..) => {
self.gate_feature("unboxed_closure_sugar",
t.span,
"unboxed closure trait sugar is experimental");
Expand Down
12 changes: 7 additions & 5 deletions src/librustc/metadata/common.rs
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,7 @@ pub enum astencode_tag { // Reserves 0x40 -- 0x5f
tag_table_adjustments = 0x51,
tag_table_moves_map = 0x52,
tag_table_capture_map = 0x53,
tag_table_unboxed_closure_type = 0x54,
tag_table_unboxed_closures = 0x54,
tag_table_upvar_borrow_map = 0x55,
tag_table_capture_modes = 0x56,
}
Expand Down Expand Up @@ -229,9 +229,11 @@ pub static tag_region_param_def_index: uint = 0x94;
pub static tag_unboxed_closures: uint = 0x95;
pub static tag_unboxed_closure: uint = 0x96;
pub static tag_unboxed_closure_type: uint = 0x97;
pub static tag_unboxed_closure_kind: uint = 0x98;

pub static tag_struct_fields: uint = 0x98;
pub static tag_struct_field: uint = 0x99;
pub static tag_struct_field_id: uint = 0x9a;
pub static tag_struct_fields: uint = 0x99;
pub static tag_struct_field: uint = 0x9a;
pub static tag_struct_field_id: uint = 0x9b;

pub static tag_attribute_is_sugared_doc: uint = 0x9c;

pub static tag_attribute_is_sugared_doc: uint = 0x9b;
21 changes: 18 additions & 3 deletions src/librustc/metadata/encoder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -630,6 +630,18 @@ fn encode_visibility(rbml_w: &mut Encoder, visibility: Visibility) {
rbml_w.end_tag();
}

fn encode_unboxed_closure_kind(rbml_w: &mut Encoder,
kind: ty::UnboxedClosureKind) {
rbml_w.start_tag(tag_unboxed_closure_kind);
let ch = match kind {
ty::FnUnboxedClosureKind => 'f',
ty::FnMutUnboxedClosureKind => 'm',
ty::FnOnceUnboxedClosureKind => 'o',
};
rbml_w.wr_str(ch.to_string().as_slice());
rbml_w.end_tag();
}

fn encode_explicit_self(rbml_w: &mut Encoder,
explicit_self: &ty::ExplicitSelfCategory) {
rbml_w.start_tag(tag_item_trait_method_explicit_self);
Expand Down Expand Up @@ -1629,17 +1641,20 @@ fn encode_unboxed_closures<'a>(
ecx: &'a EncodeContext,
rbml_w: &'a mut Encoder) {
rbml_w.start_tag(tag_unboxed_closures);
for (unboxed_closure_id, unboxed_closure_type) in
ecx.tcx.unboxed_closure_types.borrow().iter() {
for (unboxed_closure_id, unboxed_closure) in ecx.tcx
.unboxed_closures
.borrow()
.iter() {
if unboxed_closure_id.krate != LOCAL_CRATE {
continue
}

rbml_w.start_tag(tag_unboxed_closure);
encode_def_id(rbml_w, *unboxed_closure_id);
rbml_w.start_tag(tag_unboxed_closure_type);
write_closure_type(ecx, rbml_w, unboxed_closure_type);
write_closure_type(ecx, rbml_w, &unboxed_closure.closure_type);
rbml_w.end_tag();
encode_unboxed_closure_kind(rbml_w, unboxed_closure.kind);
rbml_w.end_tag();
}
rbml_w.end_tag();
Expand Down
3 changes: 2 additions & 1 deletion src/librustc/metadata/tydecode.rs
Original file line number Diff line number Diff line change
Expand Up @@ -432,7 +432,8 @@ fn parse_ty(st: &mut PState, conv: conv_did) -> ty::t {
}
'k' => {
let did = parse_def(st, NominalType, |x,y| conv(x,y));
return ty::mk_unboxed_closure(st.tcx, did);
let region = parse_region(st, conv);
return ty::mk_unboxed_closure(st.tcx, did, region);
}
'e' => {
return ty::mk_err();
Expand Down
3 changes: 2 additions & 1 deletion src/librustc/metadata/tyencode.rs
Original file line number Diff line number Diff line change
Expand Up @@ -285,8 +285,9 @@ fn enc_sty(w: &mut SeekableMemWriter, cx: &ctxt, st: &ty::sty) {
enc_substs(w, cx, substs);
mywrite!(w, "]");
}
ty::ty_unboxed_closure(def) => {
ty::ty_unboxed_closure(def, region) => {
mywrite!(w, "k{}", (cx.ds)(def));
enc_region(w, cx, region);
}
ty::ty_err => {
mywrite!(w, "e");
Expand Down
81 changes: 62 additions & 19 deletions src/librustc/middle/astencode.rs
Original file line number Diff line number Diff line change
Expand Up @@ -689,10 +689,35 @@ pub fn encode_vtable_param_res(ecx: &e::EncodeContext,
}).unwrap()
}

pub fn encode_unboxed_closure_kind(ebml_w: &mut Encoder,
kind: ty::UnboxedClosureKind) {
ebml_w.emit_enum("UnboxedClosureKind", |ebml_w| {
match kind {
ty::FnUnboxedClosureKind => {
ebml_w.emit_enum_variant("FnUnboxedClosureKind", 0, 3, |_| {
Ok(())
})
}
ty::FnMutUnboxedClosureKind => {
ebml_w.emit_enum_variant("FnMutUnboxedClosureKind", 1, 3, |_| {
Ok(())
})
}
ty::FnOnceUnboxedClosureKind => {
ebml_w.emit_enum_variant("FnOnceUnboxedClosureKind",
2,
3,
|_| {
Ok(())
})
}
}
}).unwrap()
}

pub fn encode_vtable_origin(ecx: &e::EncodeContext,
rbml_w: &mut Encoder,
vtable_origin: &typeck::vtable_origin) {
rbml_w: &mut Encoder,
vtable_origin: &typeck::vtable_origin) {
rbml_w.emit_enum("vtable_origin", |rbml_w| {
match *vtable_origin {
typeck::vtable_static(def_id, ref substs, ref vtable_res) => {
Expand Down Expand Up @@ -1210,14 +1235,15 @@ fn encode_side_tables_for_id(ecx: &e::EncodeContext,
})
}

for unboxed_closure_type in tcx.unboxed_closure_types
.borrow()
.find(&ast_util::local_def(id))
.iter() {
rbml_w.tag(c::tag_table_unboxed_closure_type, |rbml_w| {
for unboxed_closure in tcx.unboxed_closures
.borrow()
.find(&ast_util::local_def(id))
.iter() {
rbml_w.tag(c::tag_table_unboxed_closures, |rbml_w| {
rbml_w.id(id);
rbml_w.tag(c::tag_table_val, |rbml_w| {
rbml_w.emit_closure_type(ecx, *unboxed_closure_type)
rbml_w.emit_closure_type(ecx, &unboxed_closure.closure_type);
encode_unboxed_closure_kind(rbml_w, unboxed_closure.kind)
})
})
}
Expand All @@ -1244,8 +1270,8 @@ trait rbml_decoder_decoder_helpers {
-> ty::Polytype;
fn read_substs(&mut self, xcx: &ExtendedDecodeContext) -> subst::Substs;
fn read_auto_adjustment(&mut self, xcx: &ExtendedDecodeContext) -> ty::AutoAdjustment;
fn read_unboxed_closure_type(&mut self, xcx: &ExtendedDecodeContext)
-> ty::ClosureTy;
fn read_unboxed_closure(&mut self, xcx: &ExtendedDecodeContext)
-> ty::UnboxedClosure;
fn convert_def_id(&mut self,
xcx: &ExtendedDecodeContext,
source: DefIdSource,
Expand Down Expand Up @@ -1418,16 +1444,33 @@ impl<'a> rbml_decoder_decoder_helpers for reader::Decoder<'a> {
}).unwrap()
}

fn read_unboxed_closure_type(&mut self, xcx: &ExtendedDecodeContext)
-> ty::ClosureTy {
self.read_opaque(|this, doc| {
fn read_unboxed_closure(&mut self, xcx: &ExtendedDecodeContext)
-> ty::UnboxedClosure {
let closure_type = self.read_opaque(|this, doc| {
Ok(tydecode::parse_ty_closure_data(
doc.data,
xcx.dcx.cdata.cnum,
doc.start,
xcx.dcx.tcx,
|s, a| this.convert_def_id(xcx, s, a)))
}).unwrap()
}).unwrap();
let variants = [
"FnUnboxedClosureKind",
"FnMutUnboxedClosureKind",
"FnOnceUnboxedClosureKind"
];
let kind = self.read_enum_variant(variants, |_, i| {
Ok(match i {
0 => ty::FnUnboxedClosureKind,
1 => ty::FnMutUnboxedClosureKind,
2 => ty::FnOnceUnboxedClosureKind,
_ => fail!("bad enum variant for ty::UnboxedClosureKind"),
})
}).unwrap();
ty::UnboxedClosure {
closure_type: closure_type,
kind: kind,
}
}

fn convert_def_id(&mut self,
Expand Down Expand Up @@ -1566,14 +1609,14 @@ fn decode_side_tables(xcx: &ExtendedDecodeContext,
let adj: ty::AutoAdjustment = val_dsr.read_auto_adjustment(xcx);
dcx.tcx.adjustments.borrow_mut().insert(id, adj);
}
c::tag_table_unboxed_closure_type => {
let unboxed_closure_type =
val_dsr.read_unboxed_closure_type(xcx);
c::tag_table_unboxed_closures => {
let unboxed_closure =
val_dsr.read_unboxed_closure(xcx);
dcx.tcx
.unboxed_closure_types
.unboxed_closures
.borrow_mut()
.insert(ast_util::local_def(id),
unboxed_closure_type);
unboxed_closure);
}
_ => {
xcx.dcx.tcx.sess.bug(
Expand Down
5 changes: 3 additions & 2 deletions src/librustc/middle/borrowck/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -290,8 +290,9 @@ pub fn closure_to_block(closure_id: ast::NodeId,
tcx: &ty::ctxt) -> 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::ExprProc(_, block) |
ast::ExprFnBlock(_, _, block) |
ast::ExprUnboxedFn(_, _, _, block) => { block.id }
_ => fail!("encountered non-closure id: {}", closure_id)
},
_ => fail!("encountered non-expr id: {}", closure_id)
Expand Down
2 changes: 1 addition & 1 deletion src/librustc/middle/check_loop.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ impl<'a> Visitor<Context> for CheckLoopVisitor<'a> {
}
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
2 changes: 1 addition & 1 deletion src/librustc/middle/freevars.rs
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ impl<'a> Visitor<int> for CollectFreevarsVisitor<'a> {
self.capture_mode_map.insert(expr.id, capture_mode);
visit::walk_expr(self, expr, depth + 1)
}
ast::ExprUnboxedFn(capture_clause, _, _) => {
ast::ExprUnboxedFn(capture_clause, _, _, _) => {
let capture_mode = match capture_clause {
ast::CaptureByValue => CaptureByValue,
ast::CaptureByRef => CaptureByRef,
Expand Down
2 changes: 1 addition & 1 deletion src/librustc/middle/kind.rs
Original file line number Diff line number Diff line change
Expand Up @@ -225,7 +225,7 @@ fn with_appropriate_checker(cx: &Context,
b(check_for_bare)
}

ty::ty_unboxed_closure(_) => {}
ty::ty_unboxed_closure(..) => {}

ref s => {
cx.tcx.sess.bug(format!("expect fn type in kind checker, not \
Expand Down
2 changes: 1 addition & 1 deletion src/librustc/middle/liveness.rs
Original file line number Diff line number Diff line change
Expand Up @@ -967,7 +967,7 @@ impl<'a> Liveness<'a> {

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
17 changes: 14 additions & 3 deletions src/librustc/middle/mem_categorization.rs
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ use middle::def;
use middle::freevars;
use middle::ty;
use middle::typeck;
use util::nodemap::NodeMap;
use util::nodemap::{DefIdMap, NodeMap};
use util::ppaux::{ty_to_string, Repr};

use syntax::ast::{MutImmutable, MutMutable};
Expand Down Expand Up @@ -273,6 +273,8 @@ pub trait Typer {
fn upvar_borrow(&self, upvar_id: ty::UpvarId) -> ty::UpvarBorrow;
fn capture_mode(&self, closure_expr_id: ast::NodeId)
-> freevars::CaptureMode;
fn unboxed_closures<'a>(&'a self)
-> &'a RefCell<DefIdMap<ty::UnboxedClosure>>;
}

impl MutabilityCategory {
Expand Down Expand Up @@ -598,13 +600,22 @@ impl<'t,TYPER:Typer> MemCategorizationContext<'t,TYPER> {
}))
}
}
ty::ty_unboxed_closure(_) => {
ty::ty_unboxed_closure(closure_id, _) => {
let unboxed_closures = self.typer
.unboxed_closures()
.borrow();
let kind = unboxed_closures.get(&closure_id).kind;
let onceness = match kind {
ty::FnUnboxedClosureKind |
ty::FnMutUnboxedClosureKind => ast::Many,
ty::FnOnceUnboxedClosureKind => ast::Once,
};
Ok(Rc::new(cmt_ {
id: id,
span: span,
cat: cat_copied_upvar(CopiedUpvar {
upvar_id: var_id,
onceness: ast::Many,
onceness: onceness,
capturing_proc: fn_node_id,
}),
mutbl: MutabilityCategory::from_def(&def),
Expand Down
2 changes: 1 addition & 1 deletion src/librustc/middle/resolve.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5289,7 +5289,7 @@ impl<'a> Resolver<'a> {

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/trans/adt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -170,7 +170,7 @@ fn represent_type_uncached(cx: &CrateContext, t: ty::t) -> Repr {

return Univariant(mk_struct(cx, ftys.as_slice(), packed), dtor)
}
ty::ty_unboxed_closure(def_id) => {
ty::ty_unboxed_closure(def_id, _) => {
let upvars = ty::unboxed_closure_upvars(cx.tcx(), def_id);
let upvar_types = upvars.iter().map(|u| u.ty).collect::<Vec<_>>();
return Univariant(mk_struct(cx, upvar_types.as_slice(), false),
Expand Down
Loading

0 comments on commit 404978e

Please sign in to comment.