librustc: Tie up loose ends in unboxed closures.

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]
This commit is contained in:
Patrick Walton 2014-07-29 22:08:39 -07:00
parent 9d45d63d0d
commit 8d27232141
43 changed files with 834 additions and 297 deletions

View File

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

View File

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

View File

@ -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);
@ -1629,8 +1641,10 @@ 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
}
@ -1638,8 +1652,9 @@ fn encode_unboxed_closures<'a>(
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();

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -45,8 +45,8 @@ use middle::trans::adt;
use middle::trans::build::*;
use middle::trans::builder::{Builder, noname};
use middle::trans::callee;
use middle::trans::cleanup::{CleanupMethods, ScopeId};
use middle::trans::cleanup;
use middle::trans::cleanup::CleanupMethods;
use middle::trans::common::*;
use middle::trans::consts;
use middle::trans::controlflow;
@ -252,6 +252,31 @@ fn get_extern_rust_fn(ccx: &CrateContext, fn_ty: ty::t, name: &str, did: ast::De
f
}
pub fn self_type_for_unboxed_closure(ccx: &CrateContext,
closure_id: ast::DefId)
-> ty::t {
let unboxed_closure_type = ty::mk_unboxed_closure(ccx.tcx(),
closure_id,
ty::ReStatic);
let unboxed_closures = ccx.tcx.unboxed_closures.borrow();
let unboxed_closure = unboxed_closures.get(&closure_id);
match unboxed_closure.kind {
ty::FnUnboxedClosureKind => {
ty::mk_imm_rptr(&ccx.tcx, ty::ReStatic, unboxed_closure_type)
}
ty::FnMutUnboxedClosureKind => {
ty::mk_mut_rptr(&ccx.tcx, ty::ReStatic, unboxed_closure_type)
}
ty::FnOnceUnboxedClosureKind => unboxed_closure_type,
}
}
pub fn kind_for_unboxed_closure(ccx: &CrateContext, closure_id: ast::DefId)
-> ty::UnboxedClosureKind {
let unboxed_closures = ccx.tcx.unboxed_closures.borrow();
unboxed_closures.get(&closure_id).kind
}
pub fn decl_rust_fn(ccx: &CrateContext, fn_ty: ty::t, name: &str) -> ValueRef {
let (inputs, output, abi, env) = match ty::get(fn_ty).sty {
ty::ty_bare_fn(ref f) => {
@ -260,12 +285,12 @@ pub fn decl_rust_fn(ccx: &CrateContext, fn_ty: ty::t, name: &str) -> ValueRef {
ty::ty_closure(ref f) => {
(f.sig.inputs.clone(), f.sig.output, f.abi, Some(Type::i8p(ccx)))
}
ty::ty_unboxed_closure(closure_did) => {
let unboxed_closure_types = ccx.tcx
.unboxed_closure_types
.borrow();
let function_type = unboxed_closure_types.get(&closure_did);
let llenvironment_type = type_of(ccx, fn_ty).ptr_to();
ty::ty_unboxed_closure(closure_did, _) => {
let unboxed_closures = ccx.tcx.unboxed_closures.borrow();
let unboxed_closure = unboxed_closures.get(&closure_did);
let function_type = unboxed_closure.closure_type.clone();
let self_type = self_type_for_unboxed_closure(ccx, closure_did);
let llenvironment_type = type_of_explicit_arg(ccx, self_type);
(function_type.sig.inputs.clone(),
function_type.sig.output,
RustCall,
@ -691,7 +716,7 @@ pub fn iter_structural_ty<'r,
}
})
}
ty::ty_unboxed_closure(def_id) => {
ty::ty_unboxed_closure(def_id, _) => {
let repr = adt::represent_type(cx.ccx(), t);
let upvars = ty::unboxed_closure_upvars(cx.tcx(), def_id);
for (i, upvar) in upvars.iter().enumerate() {
@ -1308,7 +1333,7 @@ fn has_nested_returns(tcx: &ty::ctxt, id: ast::NodeId) -> bool {
match e.node {
ast::ExprFnBlock(_, _, blk) |
ast::ExprProc(_, blk) |
ast::ExprUnboxedFn(_, _, blk) => {
ast::ExprUnboxedFn(_, _, _, blk) => {
let mut explicit = CheckForNestedReturnsVisitor { found: false };
let mut implicit = CheckForNestedReturnsVisitor { found: false };
visit::walk_expr(&mut explicit, &*e, false);
@ -1460,6 +1485,8 @@ pub fn create_datums_for_fn_args(fcx: &FunctionContext,
/// Creates rvalue datums for each of the incoming function arguments and
/// tuples the arguments. These will later be stored into appropriate lvalue
/// datums.
///
/// FIXME(pcwalton): Reduce the amount of code bloat this is responsible for.
fn create_datums_for_fn_args_under_call_abi<
'a>(
mut bcx: &'a Block<'a>,
@ -1708,7 +1735,8 @@ pub fn trans_closure(ccx: &CrateContext,
abi: Abi,
has_env: bool,
is_unboxed_closure: IsUnboxedClosureFlag,
maybe_load_env: <'a> |&'a Block<'a>| -> &'a Block<'a>) {
maybe_load_env: <'a>|&'a Block<'a>, ScopeId|
-> &'a Block<'a>) {
ccx.stats.n_closures.set(ccx.stats.n_closures.get() + 1);
let _icx = push_ctxt("trans_closure");
@ -1773,7 +1801,7 @@ pub fn trans_closure(ccx: &CrateContext,
}
};
bcx = maybe_load_env(bcx);
bcx = maybe_load_env(bcx, cleanup::CustomScope(arg_scope));
// Up until here, IR instructions for this function have explicitly not been annotated with
// source code location, so we don't step into call setup code. From here on, source location
@ -1854,7 +1882,7 @@ pub fn trans_fn(ccx: &CrateContext,
abi,
false,
NotUnboxedClosure,
|bcx| bcx);
|bcx, _| bcx);
}
pub fn trans_enum_variant(ccx: &CrateContext,
@ -2188,11 +2216,11 @@ pub fn get_fn_llvm_attributes(ccx: &CrateContext, fn_ty: ty::t)
let (fn_sig, abi, has_env) = match ty::get(fn_ty).sty {
ty::ty_closure(ref f) => (f.sig.clone(), f.abi, true),
ty::ty_bare_fn(ref f) => (f.sig.clone(), f.abi, false),
ty::ty_unboxed_closure(closure_did) => {
let unboxed_closure_types = ccx.tcx
.unboxed_closure_types
.borrow();
let function_type = unboxed_closure_types.get(&closure_did);
ty::ty_unboxed_closure(closure_did, _) => {
let unboxed_closures = ccx.tcx.unboxed_closures.borrow();
let function_type = unboxed_closures.get(&closure_did)
.closure_type
.clone();
(function_type.sig.clone(), RustCall, true)
}
_ => fail!("expected closure or function.")

View File

@ -19,6 +19,7 @@ use middle::lang_items::ClosureExchangeMallocFnLangItem;
use middle::trans::adt;
use middle::trans::base::*;
use middle::trans::build::*;
use middle::trans::cleanup::{CleanupMethods, ScopeId};
use middle::trans::common::*;
use middle::trans::datum::{Datum, DatumBlock, Expr, Lvalue, rvalue_scratch_datum};
use middle::trans::debuginfo;
@ -306,7 +307,9 @@ fn load_environment<'a>(bcx: &'a Block<'a>,
fn load_unboxed_closure_environment<'a>(
bcx: &'a Block<'a>,
freevars: &Vec<freevars::freevar_entry>)
arg_scope_id: ScopeId,
freevars: &Vec<freevars::freevar_entry>,
closure_id: ast::DefId)
-> &'a Block<'a> {
let _icx = push_ctxt("closure::load_environment");
@ -314,11 +317,31 @@ fn load_unboxed_closure_environment<'a>(
return bcx
}
let llenv = bcx.fcx.llenv.unwrap();
// Special case for small by-value selfs.
let self_type = self_type_for_unboxed_closure(bcx.ccx(), closure_id);
let kind = kind_for_unboxed_closure(bcx.ccx(), closure_id);
let llenv = if kind == ty::FnOnceUnboxedClosureKind &&
!arg_is_indirect(bcx.ccx(), self_type) {
let datum = rvalue_scratch_datum(bcx,
self_type,
"unboxed_closure_env");
store_ty(bcx, bcx.fcx.llenv.unwrap(), datum.val, self_type);
assert!(freevars.len() <= 1);
datum.val
} else {
bcx.fcx.llenv.unwrap()
};
for (i, freevar) in freevars.iter().enumerate() {
let upvar_ptr = GEPi(bcx, llenv, [0, i]);
let def_id = freevar.def.def_id();
bcx.fcx.llupvars.borrow_mut().insert(def_id.node, upvar_ptr);
if kind == ty::FnOnceUnboxedClosureKind {
bcx.fcx.schedule_drop_mem(arg_scope_id,
upvar_ptr,
node_id_type(bcx, def_id.node))
}
}
bcx
@ -394,7 +417,7 @@ pub fn trans_expr_fn<'a>(
ty::ty_fn_abi(fty),
true,
NotUnboxedClosure,
|bcx| load_environment(bcx, cdata_ty, &freevars, store));
|bcx, _| load_environment(bcx, cdata_ty, &freevars, store));
fill_fn_pair(bcx, dest_addr, llfn, llbox);
bcx
}
@ -404,7 +427,7 @@ pub fn trans_expr_fn<'a>(
pub fn get_or_create_declaration_if_unboxed_closure(ccx: &CrateContext,
closure_id: ast::DefId)
-> Option<ValueRef> {
if !ccx.tcx.unboxed_closure_types.borrow().contains_key(&closure_id) {
if !ccx.tcx.unboxed_closures.borrow().contains_key(&closure_id) {
// Not an unboxed closure.
return None
}
@ -418,7 +441,9 @@ pub fn get_or_create_declaration_if_unboxed_closure(ccx: &CrateContext,
None => {}
}
let function_type = ty::mk_unboxed_closure(&ccx.tcx, closure_id);
let function_type = ty::mk_unboxed_closure(&ccx.tcx,
closure_id,
ty::ReStatic);
let symbol = ccx.tcx.map.with_path(closure_id.node, |path| {
mangle_internal_name_by_path_and_seq(path, "unboxed_closure")
});
@ -453,19 +478,10 @@ pub fn trans_unboxed_closure<'a>(
bcx.ccx(),
closure_id).unwrap();
// Untuple the arguments.
let unboxed_closure_types = bcx.tcx().unboxed_closure_types.borrow();
let /*mut*/ function_type = (*unboxed_closure_types.get(&closure_id)).clone();
/*function_type.sig.inputs =
match ty::get(*function_type.sig.inputs.get(0)).sty {
ty::ty_tup(ref tuple_types) => {
tuple_types.iter().map(|x| (*x).clone()).collect()
}
_ => {
bcx.tcx().sess.span_bug(body.span,
"unboxed closure wasn't a tuple?!")
}
};*/
let unboxed_closures = bcx.tcx().unboxed_closures.borrow();
let function_type = unboxed_closures.get(&closure_id)
.closure_type
.clone();
let function_type = ty::mk_closure(bcx.tcx(), function_type);
let freevars: Vec<freevars::freevar_entry> =
@ -486,7 +502,12 @@ pub fn trans_unboxed_closure<'a>(
ty::ty_fn_abi(function_type),
true,
IsUnboxedClosure,
|bcx| load_unboxed_closure_environment(bcx, freevars_ptr));
|bcx, arg_scope| {
load_unboxed_closure_environment(bcx,
arg_scope,
freevars_ptr,
closure_id)
});
// Don't hoist this to the top of the function. It's perfectly legitimate
// to have a zero-size unboxed closure (in which case dest will be
@ -502,13 +523,13 @@ pub fn trans_unboxed_closure<'a>(
let repr = adt::represent_type(bcx.ccx(), node_id_type(bcx, id));
// Create the closure.
for freevar in freevars_ptr.iter() {
for (i, freevar) in freevars_ptr.iter().enumerate() {
let datum = expr::trans_local_var(bcx, freevar.def);
let upvar_slot_dest = adt::trans_field_ptr(bcx,
&*repr,
dest_addr,
0,
0);
i);
bcx = datum.store_to(bcx, upvar_slot_dest);
}
adt::trans_set_discr(bcx, &*repr, dest_addr, 0);

View File

@ -32,7 +32,7 @@ use middle::trans::type_of;
use middle::ty;
use middle::typeck;
use util::ppaux::Repr;
use util::nodemap::NodeMap;
use util::nodemap::{DefIdMap, NodeMap};
use arena::TypedArena;
use std::collections::HashMap;
@ -514,6 +514,11 @@ impl<'a> mc::Typer for Block<'a> {
self.tcx().region_maps.temporary_scope(rvalue_id)
}
fn unboxed_closures<'a>(&'a self)
-> &'a RefCell<DefIdMap<ty::UnboxedClosure>> {
&self.tcx().unboxed_closures
}
fn upvar_borrow(&self, upvar_id: ty::UpvarId) -> ty::UpvarBorrow {
self.tcx().upvar_borrow_map.borrow().get_copy(&upvar_id)
}

View File

@ -1152,7 +1152,7 @@ pub fn create_function_debug_context(cx: &CrateContext,
match expr.node {
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,
@ -3620,7 +3620,7 @@ fn populate_scope_map(cx: &CrateContext,
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,
@ -3895,7 +3895,7 @@ fn push_debuginfo_type_name(cx: &CrateContext,
push_debuginfo_type_name(cx, sig.output, true, output);
}
},
ty::ty_unboxed_closure(_) => {
ty::ty_unboxed_closure(..) => {
output.push_str("closure");
}
ty::ty_err |

View File

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

@ -446,7 +446,7 @@ pub fn trans_trait_callee_from_llval<'a>(bcx: &'a Block<'a>,
fn get_callee_substitutions_for_unboxed_closure(bcx: &Block,
def_id: ast::DefId)
-> subst::Substs {
let self_ty = ty::mk_unboxed_closure(bcx.tcx(), def_id);
let self_ty = ty::mk_unboxed_closure(bcx.tcx(), def_id, ty::ReStatic);
subst::Substs::erased(
VecPerParamSpace::new(Vec::new(),
vec![

View File

@ -273,7 +273,7 @@ pub fn type_of(cx: &CrateContext, t: ty::t) -> Type {
let name = llvm_type_name(cx, an_enum, did, tps);
adt::incomplete_type_of(cx, &*repr, name.as_slice())
}
ty::ty_unboxed_closure(did) => {
ty::ty_unboxed_closure(did, _) => {
// Only create the named struct, but don't fill it in. We
// fill it in *after* placing it into the type cache.
let repr = adt::represent_type(cx, t);

View File

@ -373,7 +373,7 @@ pub struct ctxt {
/// Records the type of each unboxed closure. The def ID is the ID of the
/// expression defining the unboxed closure.
pub unboxed_closure_types: RefCell<DefIdMap<ClosureTy>>,
pub unboxed_closures: RefCell<DefIdMap<UnboxedClosure>>,
pub node_lint_levels: RefCell<HashMap<(ast::NodeId, lint::LintId),
lint::LevelSource>>,
@ -745,7 +745,7 @@ pub enum sty {
ty_closure(Box<ClosureTy>),
ty_trait(Box<TyTrait>),
ty_struct(DefId, Substs),
ty_unboxed_closure(DefId),
ty_unboxed_closure(DefId, Region),
ty_tup(Vec<t>),
ty_param(ParamTy), // type parameter
@ -1056,6 +1056,21 @@ pub type type_cache = RefCell<DefIdMap<Polytype>>;
pub type node_type_table = RefCell<HashMap<uint,t>>;
/// Records information about each unboxed closure.
pub struct UnboxedClosure {
/// The type of the unboxed closure.
pub closure_type: ClosureTy,
/// The kind of unboxed closure this is.
pub kind: UnboxedClosureKind,
}
#[deriving(PartialEq, Eq)]
pub enum UnboxedClosureKind {
FnUnboxedClosureKind,
FnMutUnboxedClosureKind,
FnOnceUnboxedClosureKind,
}
pub fn mk_ctxt(s: Session,
dm: resolve::DefMap,
named_region_map: resolve_lifetime::NamedRegionMap,
@ -1117,7 +1132,7 @@ pub fn mk_ctxt(s: Session,
method_map: RefCell::new(FnvHashMap::new()),
vtable_map: RefCell::new(FnvHashMap::new()),
dependency_formats: RefCell::new(HashMap::new()),
unboxed_closure_types: RefCell::new(DefIdMap::new()),
unboxed_closures: RefCell::new(DefIdMap::new()),
node_lint_levels: RefCell::new(HashMap::new()),
transmute_restrictions: RefCell::new(Vec::new()),
stability: RefCell::new(stability),
@ -1177,7 +1192,7 @@ pub fn mk_t(cx: &ctxt, st: sty) -> t {
}
match &st {
&ty_nil | &ty_bool | &ty_char | &ty_int(_) | &ty_float(_) | &ty_uint(_) |
&ty_str | &ty_unboxed_closure(_) => {}
&ty_str => {}
// You might think that we could just return ty_err for
// any type containing ty_err as a component, and get
// rid of the has_ty_err flag -- likewise for ty_bot (with
@ -1194,6 +1209,7 @@ pub fn mk_t(cx: &ctxt, st: sty) -> t {
flags |= has_params as uint;
}
}
&ty_unboxed_closure(_, ref region) => flags |= rflags(*region),
&ty_infer(_) => flags |= needs_infer as uint,
&ty_enum(_, ref substs) | &ty_struct(_, ref substs) => {
flags |= sflags(substs);
@ -1442,8 +1458,9 @@ pub fn mk_struct(cx: &ctxt, struct_id: ast::DefId, substs: Substs) -> t {
mk_t(cx, ty_struct(struct_id, substs))
}
pub fn mk_unboxed_closure(cx: &ctxt, closure_id: ast::DefId) -> t {
mk_t(cx, ty_unboxed_closure(closure_id))
pub fn mk_unboxed_closure(cx: &ctxt, closure_id: ast::DefId, region: Region)
-> t {
mk_t(cx, ty_unboxed_closure(closure_id, region))
}
pub fn mk_var(cx: &ctxt, v: TyVid) -> t { mk_infer(cx, TyVar(v)) }
@ -1476,8 +1493,8 @@ pub fn maybe_walk_ty(ty: t, f: |t| -> bool) {
}
match get(ty).sty {
ty_nil | ty_bot | ty_bool | ty_char | ty_int(_) | ty_uint(_) | ty_float(_) |
ty_str | ty_infer(_) | ty_param(_) | ty_unboxed_closure(_) | ty_err => {
}
ty_str | ty_infer(_) | ty_param(_) | ty_unboxed_closure(..) |
ty_err => {}
ty_box(ty) | ty_uniq(ty) => maybe_walk_ty(ty, f),
ty_ptr(ref tm) | ty_rptr(_, ref tm) | ty_vec(ref tm, _) => {
maybe_walk_ty(tm.ty, f);
@ -1584,7 +1601,7 @@ pub fn type_is_vec(ty: t) -> bool {
pub fn type_is_structural(ty: t) -> bool {
match get(ty).sty {
ty_struct(..) | ty_tup(_) | ty_enum(..) | ty_closure(_) |
ty_vec(_, Some(_)) | ty_unboxed_closure(_) => true,
ty_vec(_, Some(_)) | ty_unboxed_closure(..) => true,
_ => type_is_slice(ty) | type_is_trait(ty)
}
}
@ -2099,10 +2116,13 @@ pub fn type_contents(cx: &ctxt, ty: t) -> TypeContents {
apply_lang_items(cx, did, res)
}
ty_unboxed_closure(did) => {
ty_unboxed_closure(did, r) => {
// FIXME(#14449): `borrowed_contents` below assumes `&mut`
// unboxed closure.
let upvars = unboxed_closure_upvars(cx, did);
TypeContents::union(upvars.as_slice(),
|f| tc_ty(cx, f.ty, cache))
|f| tc_ty(cx, f.ty, cache)) |
borrowed_contents(r, MutMutable)
}
ty_tup(ref tys) => {
@ -2349,7 +2369,7 @@ pub fn is_instantiable(cx: &ctxt, r_ty: t) -> bool {
r
}
ty_unboxed_closure(did) => {
ty_unboxed_closure(did, _) => {
let upvars = unboxed_closure_upvars(cx, did);
upvars.iter().any(|f| type_requires(cx, seen, r_ty, f.ty))
}
@ -2477,7 +2497,7 @@ pub fn is_type_representable(cx: &ctxt, sp: Span, ty: t) -> Representability {
r
}
ty_unboxed_closure(did) => {
ty_unboxed_closure(did, _) => {
let upvars = unboxed_closure_upvars(cx, did);
find_nonrepresentable(cx,
sp,
@ -2718,7 +2738,7 @@ pub fn ty_fn_args(fty: t) -> Vec<t> {
pub fn ty_closure_store(fty: t) -> TraitStore {
match get(fty).sty {
ty_closure(ref f) => f.store,
ty_unboxed_closure(_) => {
ty_unboxed_closure(..) => {
// Close enough for the purposes of all the callers of this
// function (which is soon to be deprecated anyhow).
UniqTraitStore
@ -3318,7 +3338,7 @@ pub fn ty_sort_string(cx: &ctxt, t: t) -> String {
ty_struct(id, _) => {
format!("struct {}", item_path_str(cx, id))
}
ty_unboxed_closure(_) => "closure".to_string(),
ty_unboxed_closure(..) => "closure".to_string(),
ty_tup(_) => "tuple".to_string(),
ty_infer(TyVar(_)) => "inferred type".to_string(),
ty_infer(IntVar(_)) => "integral variable".to_string(),
@ -3687,7 +3707,7 @@ pub fn ty_to_def_id(ty: t) -> Option<ast::DefId> {
ty_trait(box TyTrait { def_id: id, .. }) |
ty_struct(id, _) |
ty_enum(id, _) |
ty_unboxed_closure(id) => Some(id),
ty_unboxed_closure(id, _) => Some(id),
_ => None
}
}
@ -4717,9 +4737,10 @@ pub fn hash_crate_independent(tcx: &ctxt, t: t, svh: &Svh) -> u64 {
}
ty_infer(_) => unreachable!(),
ty_err => byte!(23),
ty_unboxed_closure(d) => {
ty_unboxed_closure(d, r) => {
byte!(24);
did(&mut state, d);
region(&mut state, r);
}
}
});
@ -4873,6 +4894,11 @@ impl mc::Typer for ty::ctxt {
-> freevars::CaptureMode {
self.capture_modes.borrow().get_copy(&closure_expr_id)
}
fn unboxed_closures<'a>(&'a self)
-> &'a RefCell<DefIdMap<UnboxedClosure>> {
&self.unboxed_closures
}
}
/// The category of explicit self.
@ -4914,6 +4940,7 @@ pub fn accumulate_lifetimes_in_type(accumulator: &mut Vec<ty::Region>,
UniqTraitStore => {}
}
}
ty_unboxed_closure(_, ref region) => accumulator.push(*region),
ty_nil |
ty_bot |
ty_bool |
@ -4930,7 +4957,6 @@ pub fn accumulate_lifetimes_in_type(accumulator: &mut Vec<ty::Region>,
ty_tup(_) |
ty_param(_) |
ty_infer(_) |
ty_unboxed_closure(_) |
ty_err => {}
}
})

View File

@ -392,8 +392,8 @@ pub fn super_fold_sty<T:TypeFolder>(this: &mut T,
ty::ty_struct(did, ref substs) => {
ty::ty_struct(did, substs.fold_with(this))
}
ty::ty_unboxed_closure(did) => {
ty::ty_unboxed_closure(did)
ty::ty_unboxed_closure(did, ref region) => {
ty::ty_unboxed_closure(did, region.fold_with(this))
}
ty::ty_nil | ty::ty_bot | ty::ty_bool | ty::ty_char | ty::ty_str |
ty::ty_int(_) | ty::ty_uint(_) | ty::ty_float(_) |

View File

@ -51,7 +51,8 @@
use middle::const_eval;
use middle::def;
use middle::lang_items::FnMutTraitLangItem;
use middle::lang_items::{FnTraitLangItem, FnMutTraitLangItem};
use middle::lang_items::{FnOnceTraitLangItem};
use middle::subst::{FnSpace, TypeSpace, SelfSpace, Subst, Substs};
use middle::subst::{VecPerParamSpace};
use middle::ty;
@ -544,16 +545,17 @@ fn ast_ty_to_mt<AC:AstConv, RS:RegionScope>(this: &AC,
pub fn trait_ref_for_unboxed_function<AC:AstConv,
RS:RegionScope>(
this: &AC,
rscope: &RS,
unboxed_function: &ast::UnboxedFnTy,
self_ty: Option<ty::t>)
-> ty::TraitRef
{
let fn_mut_trait_did = this.tcx()
.lang_items
.require(FnMutTraitLangItem)
.unwrap();
this: &AC,
rscope: &RS,
unboxed_function: &ast::UnboxedFnTy,
self_ty: Option<ty::t>)
-> ty::TraitRef {
let lang_item = match unboxed_function.kind {
ast::FnUnboxedClosureKind => FnTraitLangItem,
ast::FnMutUnboxedClosureKind => FnMutTraitLangItem,
ast::FnOnceUnboxedClosureKind => FnOnceTraitLangItem,
};
let trait_did = this.tcx().lang_items.require(lang_item).unwrap();
let input_types =
unboxed_function.decl
.inputs
@ -574,7 +576,7 @@ pub fn trait_ref_for_unboxed_function<AC:AstConv,
}
ty::TraitRef {
def_id: fn_mut_trait_did,
def_id: trait_did,
substs: substs,
}
}
@ -810,7 +812,7 @@ pub fn ast_ty_to_ty<AC:AstConv, RS:RegionScope>(
None);
ty::mk_closure(tcx, fn_decl)
}
ast::TyUnboxedFn(_) => {
ast::TyUnboxedFn(..) => {
tcx.sess.span_err(ast_ty.span,
"cannot use unboxed functions here");
ty::mk_err()

View File

@ -444,7 +444,7 @@ impl<'a> LookupContext<'a> {
},
ty_enum(did, _) |
ty_struct(did, _) |
ty_unboxed_closure(did) => {
ty_unboxed_closure(did, _) => {
if self.check_traits == CheckTraitsAndInherentMethods {
self.push_inherent_impl_candidates_for_type(did);
}
@ -468,7 +468,7 @@ impl<'a> LookupContext<'a> {
ty_param(p) => {
self.push_inherent_candidates_from_param(self_ty, restrict_to, p);
}
ty_unboxed_closure(closure_did) => {
ty_unboxed_closure(closure_did, _) => {
self.push_unboxed_closure_call_candidates_if_applicable(
closure_did);
}
@ -531,8 +531,11 @@ impl<'a> LookupContext<'a> {
let arguments_type = *closure_function_type.sig.inputs.get(0);
let return_type = closure_function_type.sig.output;
let closure_region =
vcx.infcx.next_region_var(MiscVariable(self.span));
let unboxed_closure_type = ty::mk_unboxed_closure(self.tcx(),
closure_did);
closure_did,
closure_region);
self.extension_candidates.push(Candidate {
rcvr_match_condition:
RcvrMatchesIfSubtype(unboxed_closure_type),
@ -548,39 +551,38 @@ impl<'a> LookupContext<'a> {
fn push_unboxed_closure_call_candidates_if_applicable(
&mut self,
closure_did: DefId) {
// FIXME(pcwalton): Try `Fn` and `FnOnce` too.
let trait_did = match self.tcx().lang_items.fn_mut_trait() {
Some(trait_did) => trait_did,
None => return,
};
let trait_dids = [
self.tcx().lang_items.fn_trait(),
self.tcx().lang_items.fn_mut_trait(),
self.tcx().lang_items.fn_once_trait()
];
for optional_trait_did in trait_dids.iter() {
let trait_did = match *optional_trait_did {
Some(trait_did) => trait_did,
None => continue,
};
match self.tcx()
.unboxed_closure_types
.borrow()
.find(&closure_did) {
None => {} // Fall through to try inherited.
Some(closure_function_type) => {
self.push_unboxed_closure_call_candidate_if_applicable(
trait_did,
closure_did,
closure_function_type);
return
match self.tcx().unboxed_closures.borrow().find(&closure_did) {
None => {} // Fall through to try inherited.
Some(closure) => {
self.push_unboxed_closure_call_candidate_if_applicable(
trait_did,
closure_did,
&closure.closure_type);
return
}
}
}
match self.fcx
.inh
.unboxed_closure_types
.borrow()
.find(&closure_did) {
Some(closure_function_type) => {
self.push_unboxed_closure_call_candidate_if_applicable(
trait_did,
closure_did,
closure_function_type);
return
match self.fcx.inh.unboxed_closures.borrow().find(&closure_did) {
Some(closure) => {
self.push_unboxed_closure_call_candidate_if_applicable(
trait_did,
closure_did,
&closure.closure_type);
return
}
None => {}
}
None => {}
}
self.tcx().sess.bug("didn't find unboxed closure type in tcx map or \

View File

@ -168,7 +168,7 @@ pub struct Inherited<'a> {
method_map: MethodMap,
vtable_map: vtable_map,
upvar_borrow_map: RefCell<ty::UpvarBorrowMap>,
unboxed_closure_types: RefCell<DefIdMap<ty::ClosureTy>>,
unboxed_closures: RefCell<DefIdMap<ty::UnboxedClosure>>,
}
/// When type-checking an expression, we propagate downward
@ -275,7 +275,7 @@ impl<'a> Inherited<'a> {
method_map: RefCell::new(FnvHashMap::new()),
vtable_map: RefCell::new(FnvHashMap::new()),
upvar_borrow_map: RefCell::new(HashMap::new()),
unboxed_closure_types: RefCell::new(DefIdMap::new()),
unboxed_closures: RefCell::new(DefIdMap::new()),
}
}
}
@ -1271,7 +1271,7 @@ impl<'a> FnCtxt<'a> {
VtableContext {
infcx: self.infcx(),
param_env: &self.inh.param_env,
unboxed_closure_types: &self.inh.unboxed_closure_types,
unboxed_closures: &self.inh.unboxed_closures,
}
}
}
@ -2618,6 +2618,7 @@ fn check_expr_with_unifier(fcx: &FnCtxt,
fn check_unboxed_closure(fcx: &FnCtxt,
expr: &ast::Expr,
kind: ast::UnboxedClosureKind,
decl: &ast::FnDecl,
body: ast::P<ast::Block>) {
// The `RegionTraitStore` is a lie, but we ignore it so it doesn't
@ -2635,8 +2636,16 @@ fn check_expr_with_unifier(fcx: &FnCtxt,
abi::RustCall,
None);
let region = match fcx.infcx().anon_regions(expr.span, 1) {
Err(_) => {
fcx.ccx.tcx.sess.span_bug(expr.span,
"can't make anon regions here?!")
}
Ok(regions) => *regions.get(0),
};
let closure_type = ty::mk_unboxed_closure(fcx.ccx.tcx,
local_def(expr.id));
local_def(expr.id),
region);
fcx.write_ty(expr.id, closure_type);
check_fn(fcx.ccx,
@ -2648,13 +2657,24 @@ fn check_expr_with_unifier(fcx: &FnCtxt,
fcx.inh);
// Tuple up the arguments and insert the resulting function type into
// the `unboxed_closure_types` table.
// the `unboxed_closures` table.
fn_ty.sig.inputs = vec![ty::mk_tup(fcx.tcx(), fn_ty.sig.inputs)];
let kind = match kind {
ast::FnUnboxedClosureKind => ty::FnUnboxedClosureKind,
ast::FnMutUnboxedClosureKind => ty::FnMutUnboxedClosureKind,
ast::FnOnceUnboxedClosureKind => ty::FnOnceUnboxedClosureKind,
};
let unboxed_closure = ty::UnboxedClosure {
closure_type: fn_ty,
kind: kind,
};
fcx.inh
.unboxed_closure_types
.unboxed_closures
.borrow_mut()
.insert(local_def(expr.id), fn_ty);
.insert(local_def(expr.id), unboxed_closure);
}
fn check_expr_fn(fcx: &FnCtxt,
@ -3402,9 +3422,10 @@ fn check_expr_with_unifier(fcx: &FnCtxt,
body.clone(),
expected);
}
ast::ExprUnboxedFn(_, ref decl, ref body) => {
ast::ExprUnboxedFn(_, kind, ref decl, ref body) => {
check_unboxed_closure(fcx,
expr,
kind,
&**decl,
*body);
}

View File

@ -132,7 +132,7 @@ use middle::typeck::infer::resolve_type;
use middle::typeck::infer;
use middle::typeck::MethodCall;
use middle::pat_util;
use util::nodemap::NodeMap;
use util::nodemap::{DefIdMap, NodeMap};
use util::ppaux::{ty_to_string, region_to_string, Repr};
use syntax::ast;
@ -295,6 +295,11 @@ impl<'fcx> mc::Typer for Rcx<'fcx> {
-> freevars::CaptureMode {
self.tcx().capture_modes.borrow().get_copy(&closure_expr_id)
}
fn unboxed_closures<'a>(&'a self)
-> &'a RefCell<DefIdMap<ty::UnboxedClosure>> {
&self.fcx.inh.unboxed_closures
}
}
pub fn regionck_expr(fcx: &FnCtxt, e: &ast::Expr) {
@ -594,7 +599,7 @@ fn visit_expr(rcx: &mut Rcx, expr: &ast::Expr) {
ast::ExprFnBlock(_, _, ref body) |
ast::ExprProc(_, ref body) |
ast::ExprUnboxedFn(_, _, ref body) => {
ast::ExprUnboxedFn(_, _, _, ref body) => {
check_expr_fn_block(rcx, expr, &**body);
}
@ -660,6 +665,17 @@ fn check_expr_fn_block(rcx: &mut Rcx,
}
});
}
ty::ty_unboxed_closure(_, region) => {
freevars::with_freevars(tcx, expr.id, |freevars| {
// No free variables means that there is no environment and
// hence the closure has static lifetime. Otherwise, the
// closure must not outlive the variables it closes over
// by-reference.
if !freevars.is_empty() {
constrain_free_variables(rcx, region, expr, freevars);
}
})
}
_ => ()
}

View File

@ -71,7 +71,7 @@ use syntax::visit::Visitor;
pub struct VtableContext<'a> {
pub infcx: &'a infer::InferCtxt<'a>,
pub param_env: &'a ty::ParameterEnvironment,
pub unboxed_closure_types: &'a RefCell<DefIdMap<ty::ClosureTy>>,
pub unboxed_closures: &'a RefCell<DefIdMap<ty::UnboxedClosure>>,
}
impl<'a> VtableContext<'a> {
@ -309,31 +309,42 @@ fn search_for_unboxed_closure_vtable(vcx: &VtableContext,
-> Option<vtable_origin> {
let tcx = vcx.tcx();
let closure_def_id = match ty::get(ty).sty {
ty::ty_unboxed_closure(closure_def_id) => closure_def_id,
ty::ty_unboxed_closure(closure_def_id, _) => closure_def_id,
_ => return None,
};
let fn_traits = [
tcx.lang_items.fn_trait(),
tcx.lang_items.fn_mut_trait(),
tcx.lang_items.fn_once_trait()
(ty::FnUnboxedClosureKind, tcx.lang_items.fn_trait()),
(ty::FnMutUnboxedClosureKind, tcx.lang_items.fn_mut_trait()),
(ty::FnOnceUnboxedClosureKind, tcx.lang_items.fn_once_trait()),
];
for fn_trait in fn_traits.iter() {
match *fn_trait {
Some(ref fn_trait) if *fn_trait == trait_ref.def_id => {}
for tuple in fn_traits.iter() {
let kind = match tuple {
&(kind, Some(ref fn_trait)) if *fn_trait == trait_ref.def_id => {
kind
}
_ => continue,
};
// Check to see whether the argument and return types match.
let unboxed_closure_types = tcx.unboxed_closure_types.borrow();
let closure_type = match unboxed_closure_types.find(&closure_def_id) {
Some(closure_type) => (*closure_type).clone(),
let unboxed_closures = tcx.unboxed_closures.borrow();
let closure_type = match unboxed_closures.find(&closure_def_id) {
Some(closure) => {
if closure.kind != kind {
continue
}
closure.closure_type.clone()
}
None => {
// Try the inherited unboxed closure type map.
let unboxed_closure_types = vcx.unboxed_closure_types
.borrow();
match unboxed_closure_types.find(&closure_def_id) {
Some(closure_type) => (*closure_type).clone(),
let unboxed_closures = vcx.unboxed_closures.borrow();
match unboxed_closures.find(&closure_def_id) {
Some(closure) => {
if closure.kind != kind {
continue
}
closure.closure_type.clone()
}
None => {
tcx.sess.span_bug(span,
"didn't find unboxed closure type \
@ -881,11 +892,11 @@ pub fn resolve_impl(tcx: &ty::ctxt,
debug!("impl_trait_ref={}", impl_trait_ref.repr(tcx));
let infcx = &infer::new_infer_ctxt(tcx);
let unboxed_closure_types = RefCell::new(DefIdMap::new());
let unboxed_closures = RefCell::new(DefIdMap::new());
let vcx = VtableContext {
infcx: infcx,
param_env: &param_env,
unboxed_closure_types: &unboxed_closure_types,
unboxed_closures: &unboxed_closures,
};
// Resolve the vtables for the trait reference on the impl. This
@ -934,11 +945,11 @@ pub fn resolve_impl(tcx: &ty::ctxt,
pub fn trans_resolve_method(tcx: &ty::ctxt, id: ast::NodeId,
substs: &subst::Substs) -> vtable_res {
let generics = ty::lookup_item_type(tcx, ast_util::local_def(id)).generics;
let unboxed_closure_types = RefCell::new(DefIdMap::new());
let unboxed_closures = RefCell::new(DefIdMap::new());
let vcx = VtableContext {
infcx: &infer::new_infer_ctxt(tcx),
param_env: &ty::construct_parameter_environment(tcx, &ty::Generics::empty(), id),
unboxed_closure_types: &unboxed_closure_types,
unboxed_closures: &unboxed_closures,
};
lookup_vtables(&vcx,

View File

@ -43,7 +43,7 @@ pub fn resolve_type_vars_in_expr(fcx: &FnCtxt, e: &ast::Expr) {
let mut wbcx = WritebackCx::new(fcx);
wbcx.visit_expr(e, ());
wbcx.visit_upvar_borrow_map();
wbcx.visit_unboxed_closure_types();
wbcx.visit_unboxed_closures();
}
pub fn resolve_type_vars_in_fn(fcx: &FnCtxt,
@ -62,7 +62,7 @@ pub fn resolve_type_vars_in_fn(fcx: &FnCtxt,
}
}
wbcx.visit_upvar_borrow_map();
wbcx.visit_unboxed_closure_types();
wbcx.visit_unboxed_closures();
}
pub fn resolve_impl_res(infcx: &infer::InferCtxt,
@ -134,7 +134,7 @@ impl<'cx> Visitor<()> for WritebackCx<'cx> {
match e.node {
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);
@ -211,23 +211,27 @@ impl<'cx> WritebackCx<'cx> {
}
}
fn visit_unboxed_closure_types(&self) {
fn visit_unboxed_closures(&self) {
if self.fcx.writeback_errors.get() {
return
}
for (def_id, closure_ty) in self.fcx
.inh
.unboxed_closure_types
.borrow()
.iter() {
let closure_ty = self.resolve(closure_ty,
for (def_id, unboxed_closure) in self.fcx
.inh
.unboxed_closures
.borrow()
.iter() {
let closure_ty = self.resolve(&unboxed_closure.closure_type,
ResolvingUnboxedClosure(*def_id));
let unboxed_closure = ty::UnboxedClosure {
closure_type: closure_ty,
kind: unboxed_closure.kind,
};
self.fcx
.tcx()
.unboxed_closure_types
.unboxed_closures
.borrow_mut()
.insert(*def_id, closure_ty);
.insert(*def_id, unboxed_closure);
}
}

View File

@ -109,7 +109,7 @@ fn type_is_defined_in_local_crate(tcx: &ty::ctxt, original_type: t) -> bool {
match get(t).sty {
ty_enum(def_id, _) |
ty_struct(def_id, _) |
ty_unboxed_closure(def_id) => {
ty_unboxed_closure(def_id, _) => {
if def_id.krate == ast::LOCAL_CRATE {
found_nominal = true;
}
@ -153,7 +153,7 @@ fn get_base_type_def_id(inference_context: &InferCtxt,
match get(base_type).sty {
ty_enum(def_id, _) |
ty_struct(def_id, _) |
ty_unboxed_closure(def_id) => {
ty_unboxed_closure(def_id, _) => {
Some(def_id)
}
ty_rptr(_, ty::mt {ty, ..}) | ty_uniq(ty) => match ty::get(ty).sty {
@ -687,7 +687,7 @@ impl<'a> CoherenceChecker<'a> {
match ty::get(self_type.ty).sty {
ty::ty_enum(type_def_id, _) |
ty::ty_struct(type_def_id, _) |
ty::ty_unboxed_closure(type_def_id) => {
ty::ty_unboxed_closure(type_def_id, _) => {
tcx.destructor_for_type.borrow_mut().insert(type_def_id,
method_def_id);
tcx.destructors.borrow_mut().insert(method_def_id);

View File

@ -492,9 +492,11 @@ pub fn super_tys<C:Combine>(this: &C, a: ty::t, b: ty::t) -> cres<ty::t> {
Ok(ty::mk_struct(tcx, a_id, substs))
}
(&ty::ty_unboxed_closure(a_id), &ty::ty_unboxed_closure(b_id))
(&ty::ty_unboxed_closure(a_id, a_region),
&ty::ty_unboxed_closure(b_id, b_region))
if a_id == b_id => {
Ok(ty::mk_unboxed_closure(tcx, a_id))
let region = if_ok!(this.regions(a_region, b_region));
Ok(ty::mk_unboxed_closure(tcx, a_id, region))
}
(&ty::ty_box(a_inner), &ty::ty_box(b_inner)) => {

View File

@ -722,10 +722,15 @@ impl<'a> ConstraintContext<'a> {
match ty::get(ty).sty {
ty::ty_nil | ty::ty_bot | ty::ty_bool |
ty::ty_char | ty::ty_int(_) | ty::ty_uint(_) |
ty::ty_float(_) | ty::ty_str | ty::ty_unboxed_closure(..) => {
ty::ty_float(_) | ty::ty_str => {
/* leaf type -- noop */
}
ty::ty_unboxed_closure(_, region) => {
let contra = self.contravariant(variance);
self.add_constraints_from_region(region, contra);
}
ty::ty_rptr(region, ref mt) => {
let contra = self.contravariant(variance);
self.add_constraints_from_region(region, contra);

View File

@ -528,7 +528,7 @@ pub enum Expr_ {
ExprMatch(Gc<Expr>, Vec<Arm>),
ExprFnBlock(CaptureClause, P<FnDecl>, P<Block>),
ExprProc(P<FnDecl>, P<Block>),
ExprUnboxedFn(CaptureClause, P<FnDecl>, P<Block>),
ExprUnboxedFn(CaptureClause, UnboxedClosureKind, P<FnDecl>, P<Block>),
ExprBlock(P<Block>),
ExprAssign(Gc<Expr>, Gc<Expr>),
@ -900,6 +900,7 @@ pub struct BareFnTy {
#[deriving(Clone, PartialEq, Eq, Encodable, Decodable, Hash, Show)]
pub struct UnboxedFnTy {
pub kind: UnboxedClosureKind,
pub decl: P<FnDecl>,
}
@ -1297,6 +1298,13 @@ pub enum ForeignItem_ {
ForeignItemStatic(P<Ty>, /* is_mutbl */ bool),
}
#[deriving(Clone, PartialEq, Eq, Encodable, Decodable, Hash, Show)]
pub enum UnboxedClosureKind {
FnUnboxedClosureKind,
FnMutUnboxedClosureKind,
FnOnceUnboxedClosureKind,
}
/// The data we save and restore about an inlined item or method. This is not
/// part of the AST that we parse from a file, but it becomes part of the tree
/// that we trans.

View File

@ -368,6 +368,7 @@ pub fn noop_fold_ty<T: Folder>(t: P<Ty>, fld: &mut T) -> P<Ty> {
TyUnboxedFn(ref f) => {
TyUnboxedFn(box(GC) UnboxedFnTy {
decl: fld.fold_fn_decl(&*f.decl),
kind: f.kind,
})
}
TyTup(ref tys) => TyTup(tys.iter().map(|&ty| fld.fold_ty(ty)).collect()),
@ -641,6 +642,7 @@ pub fn noop_fold_ty_param_bound<T: Folder>(tpb: &TyParamBound, fld: &mut T)
UnboxedFnTyParamBound(ref unboxed_function_type) => {
UnboxedFnTyParamBound(UnboxedFnTy {
decl: fld.fold_fn_decl(&*unboxed_function_type.decl),
kind: unboxed_function_type.kind,
})
}
OtherRegionTyParamBound(s) => OtherRegionTyParamBound(s)
@ -1103,8 +1105,9 @@ pub fn noop_fold_expr<T: Folder>(e: Gc<Expr>, folder: &mut T) -> Gc<Expr> {
ExprProc(folder.fold_fn_decl(&**decl),
folder.fold_block(body.clone()))
}
ExprUnboxedFn(capture_clause, ref decl, ref body) => {
ExprUnboxedFn(capture_clause, kind, ref decl, ref body) => {
ExprUnboxedFn(capture_clause,
kind,
folder.fold_fn_decl(&**decl),
folder.fold_block(*body))
}

View File

@ -30,6 +30,8 @@ use ast::{ExprRepeat, ExprRet, ExprStruct, ExprTup, ExprUnary, ExprUnboxedFn};
use ast::{ExprVec, ExprVstore, ExprVstoreSlice};
use ast::{ExprVstoreMutSlice, ExprWhile, ExprForLoop, Field, FnDecl};
use ast::{ExprVstoreUniq, Once, Many};
use ast::{FnUnboxedClosureKind, FnMutUnboxedClosureKind};
use ast::{FnOnceUnboxedClosureKind};
use ast::{ForeignItem, ForeignItemStatic, ForeignItemFn, ForeignMod};
use ast::{Ident, NormalFn, Inherited, Item, Item_, ItemStatic};
use ast::{ItemEnum, ItemFn, ItemForeignMod, ItemImpl};
@ -53,7 +55,8 @@ use ast::{TypeField, TyFixedLengthVec, TyClosure, TyProc, TyBareFn};
use ast::{TyTypeof, TyInfer, TypeMethod};
use ast::{TyNil, TyParam, TyParamBound, TyParen, TyPath, TyPtr, TyRptr};
use ast::{TyTup, TyU32, TyUnboxedFn, TyUniq, TyVec, UnUniq};
use ast::{UnboxedFnTy, UnboxedFnTyParamBound, UnnamedField, UnsafeBlock};
use ast::{UnboxedClosureKind, UnboxedFnTy, UnboxedFnTyParamBound};
use ast::{UnnamedField, UnsafeBlock};
use ast::{UnsafeFn, ViewItem, ViewItem_, ViewItemExternCrate, ViewItemUse};
use ast::{ViewPath, ViewPathGlob, ViewPathList, ViewPathSimple};
use ast::Visibility;
@ -1087,6 +1090,34 @@ impl<'a> Parser<'a> {
})
}
/// Parses an optional unboxed closure kind (`&:`, `&mut:`, or `:`).
pub fn parse_optional_unboxed_closure_kind(&mut self)
-> Option<UnboxedClosureKind> {
if self.token == token::BINOP(token::AND) &&
self.look_ahead(1, |t| {
token::is_keyword(keywords::Mut, t)
}) &&
self.look_ahead(2, |t| *t == token::COLON) {
self.bump();
self.bump();
self.bump();
return Some(FnMutUnboxedClosureKind)
}
if self.token == token::BINOP(token::AND) &&
self.look_ahead(1, |t| *t == token::COLON) {
self.bump();
self.bump();
return Some(FnUnboxedClosureKind)
}
if self.eat(&token::COLON) {
return Some(FnOnceUnboxedClosureKind)
}
return None
}
/// Parse a TyClosure type
pub fn parse_ty_closure(&mut self) -> Ty_ {
/*
@ -1115,27 +1146,19 @@ impl<'a> Parser<'a> {
Vec::new()
};
let (is_unboxed, inputs) = if self.eat(&token::OROR) {
(false, Vec::new())
let (optional_unboxed_closure_kind, inputs) = if self.eat(&token::OROR) {
(None, Vec::new())
} else {
self.expect_or();
let is_unboxed = self.token == token::BINOP(token::AND) &&
self.look_ahead(1, |t| {
token::is_keyword(keywords::Mut, t)
}) &&
self.look_ahead(2, |t| *t == token::COLON);
if is_unboxed {
self.bump();
self.bump();
self.bump();
}
let optional_unboxed_closure_kind =
self.parse_optional_unboxed_closure_kind();
let inputs = self.parse_seq_to_before_or(
&token::COMMA,
|p| p.parse_arg_general(false));
self.expect_or();
(is_unboxed, inputs)
(optional_unboxed_closure_kind, inputs)
};
let (region, bounds) = {
@ -1155,18 +1178,22 @@ impl<'a> Parser<'a> {
variadic: false
});
if is_unboxed {
TyUnboxedFn(box(GC) UnboxedFnTy {
decl: decl,
})
} else {
TyClosure(box(GC) ClosureTy {
fn_style: fn_style,
onceness: onceness,
bounds: bounds,
decl: decl,
lifetimes: lifetime_defs,
}, region)
match optional_unboxed_closure_kind {
Some(unboxed_closure_kind) => {
TyUnboxedFn(box(GC) UnboxedFnTy {
kind: unboxed_closure_kind,
decl: decl,
})
}
None => {
TyClosure(box(GC) ClosureTy {
fn_style: fn_style,
onceness: onceness,
bounds: bounds,
decl: decl,
lifetimes: lifetime_defs,
}, region)
}
}
}
@ -2703,7 +2730,8 @@ impl<'a> Parser<'a> {
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 (decl, optional_unboxed_closure_kind) =
self.parse_fn_block_decl();
let body = self.parse_expr();
let fakeblock = P(ast::Block {
view_items: Vec::new(),
@ -2714,14 +2742,20 @@ impl<'a> Parser<'a> {
span: body.span,
});
if is_unboxed {
self.mk_expr(lo,
body.span.hi,
ExprUnboxedFn(capture_clause, decl, fakeblock))
} else {
self.mk_expr(lo,
body.span.hi,
ExprFnBlock(capture_clause, decl, fakeblock))
match optional_unboxed_closure_kind {
Some(unboxed_closure_kind) => {
self.mk_expr(lo,
body.span.hi,
ExprUnboxedFn(capture_clause,
unboxed_closure_kind,
decl,
fakeblock))
}
None => {
self.mk_expr(lo,
body.span.hi,
ExprFnBlock(capture_clause, decl, fakeblock))
}
}
}
@ -3553,28 +3587,22 @@ impl<'a> Parser<'a> {
}
fn parse_unboxed_function_type(&mut self) -> UnboxedFnTy {
let inputs = if self.eat(&token::OROR) {
Vec::new()
} else {
self.expect_or();
let (optional_unboxed_closure_kind, inputs) =
if self.eat(&token::OROR) {
(None, Vec::new())
} else {
self.expect_or();
if self.token == token::BINOP(token::AND) &&
self.look_ahead(1, |t| {
token::is_keyword(keywords::Mut, t)
}) &&
self.look_ahead(2, |t| *t == token::COLON) {
self.bump();
self.bump();
self.bump();
}
let optional_unboxed_closure_kind =
self.parse_optional_unboxed_closure_kind();
let inputs = self.parse_seq_to_before_or(&token::COMMA,
|p| {
p.parse_arg_general(false)
});
self.expect_or();
inputs
};
let inputs = self.parse_seq_to_before_or(&token::COMMA,
|p| {
p.parse_arg_general(false)
});
self.expect_or();
(optional_unboxed_closure_kind, inputs)
};
let (return_style, output) = self.parse_ret_ty();
UnboxedFnTy {
@ -3583,7 +3611,11 @@ impl<'a> Parser<'a> {
output: output,
cf: return_style,
variadic: false,
})
}),
kind: match optional_unboxed_closure_kind {
Some(kind) => kind,
None => FnMutUnboxedClosureKind,
},
}
}
@ -4026,29 +4058,22 @@ impl<'a> Parser<'a> {
}
// parse the |arg, arg| header on a lambda
fn parse_fn_block_decl(&mut self) -> (P<FnDecl>, bool) {
let (is_unboxed, inputs_captures) = {
fn parse_fn_block_decl(&mut self)
-> (P<FnDecl>, Option<UnboxedClosureKind>) {
let (optional_unboxed_closure_kind, inputs_captures) = {
if self.eat(&token::OROR) {
(false, Vec::new())
(None, Vec::new())
} else {
self.expect(&token::BINOP(token::OR));
let is_unboxed = self.token == token::BINOP(token::AND) &&
self.look_ahead(1, |t| {
token::is_keyword(keywords::Mut, t)
}) &&
self.look_ahead(2, |t| *t == token::COLON);
if is_unboxed {
self.bump();
self.bump();
self.bump();
}
let optional_unboxed_closure_kind =
self.parse_optional_unboxed_closure_kind();
let args = self.parse_seq_to_before_end(
&token::BINOP(token::OR),
seq_sep_trailing_disallowed(token::COMMA),
|p| p.parse_fn_block_arg()
);
self.bump();
(is_unboxed, args)
(optional_unboxed_closure_kind, args)
}
};
let output = if self.eat(&token::RARROW) {
@ -4066,7 +4091,7 @@ impl<'a> Parser<'a> {
output: output,
cf: Return,
variadic: false
}), is_unboxed)
}), optional_unboxed_closure_kind)
}
/// Parses the `(arg, arg) -> return_type` header on a procedure.

View File

@ -9,8 +9,10 @@
// except according to those terms.
use abi;
use ast::{P, StaticRegionTyParamBound, OtherRegionTyParamBound};
use ast::{TraitTyParamBound, UnboxedFnTyParamBound, Required, Provided};
use ast::{FnMutUnboxedClosureKind, FnOnceUnboxedClosureKind};
use ast::{FnUnboxedClosureKind, P, OtherRegionTyParamBound};
use ast::{StaticRegionTyParamBound, TraitTyParamBound, UnboxedClosureKind};
use ast::{UnboxedFnTyParamBound, Required, Provided};
use ast;
use ast_util;
use owned_slice::OwnedSlice;
@ -228,7 +230,7 @@ pub fn method_to_string(p: &ast::Method) -> String {
}
pub fn fn_block_to_string(p: &ast::FnDecl) -> String {
$to_string(|s| s.print_fn_block_args(p, false))
$to_string(|s| s.print_fn_block_args(p, None))
}
pub fn path_to_string(p: &ast::Path) -> String {
@ -594,7 +596,7 @@ impl<'a> State<'a> {
&None,
Some(&generics),
None,
false));
None));
}
ast::TyClosure(f, ref region) => {
let generics = ast::Generics {
@ -611,7 +613,7 @@ impl<'a> State<'a> {
&f.bounds,
Some(&generics),
None,
false));
None));
}
ast::TyProc(ref f) => {
let generics = ast::Generics {
@ -628,7 +630,7 @@ impl<'a> State<'a> {
&f.bounds,
Some(&generics),
None,
false));
None));
}
ast::TyUnboxedFn(f) => {
try!(self.print_ty_fn(None,
@ -641,7 +643,7 @@ impl<'a> State<'a> {
&None,
None,
None,
true));
Some(f.kind)));
}
ast::TyPath(ref path, ref bounds, _) => {
try!(self.print_bounded_path(path, bounds));
@ -1054,7 +1056,7 @@ impl<'a> State<'a> {
&None,
Some(&m.generics),
Some(m.explicit_self.node),
false));
None));
word(&mut self.s, ";")
}
@ -1481,7 +1483,7 @@ impl<'a> State<'a> {
// we are inside.
//
// if !decl.inputs.is_empty() {
try!(self.print_fn_block_args(&**decl, false));
try!(self.print_fn_block_args(&**decl, None));
try!(space(&mut self.s));
// }
@ -1505,7 +1507,7 @@ impl<'a> State<'a> {
// empty box to satisfy the close.
try!(self.ibox(0));
}
ast::ExprUnboxedFn(capture_clause, ref decl, ref body) => {
ast::ExprUnboxedFn(capture_clause, kind, ref decl, ref body) => {
try!(self.print_capture_clause(capture_clause));
// in do/for blocks we don't want to show an empty
@ -1513,7 +1515,7 @@ impl<'a> State<'a> {
// we are inside.
//
// if !decl.inputs.is_empty() {
try!(self.print_fn_block_args(&**decl, true));
try!(self.print_fn_block_args(&**decl, Some(kind)));
try!(space(&mut self.s));
// }
@ -2052,13 +2054,17 @@ impl<'a> State<'a> {
}
}
pub fn print_fn_block_args(&mut self,
decl: &ast::FnDecl,
is_unboxed: bool)
-> IoResult<()> {
pub fn print_fn_block_args(
&mut self,
decl: &ast::FnDecl,
unboxed_closure_kind: Option<UnboxedClosureKind>)
-> IoResult<()> {
try!(word(&mut self.s, "|"));
if is_unboxed {
try!(self.word_space("&mut:"));
match unboxed_closure_kind {
None => {}
Some(FnUnboxedClosureKind) => try!(self.word_space("&:")),
Some(FnMutUnboxedClosureKind) => try!(self.word_space("&mut:")),
Some(FnOnceUnboxedClosureKind) => try!(self.word_space(":")),
}
try!(self.print_fn_args(decl, None));
try!(word(&mut self.s, "|"));
@ -2148,7 +2154,7 @@ impl<'a> State<'a> {
&None,
None,
None,
true)
Some(unboxed_function_type.kind))
}
OtherRegionTyParamBound(_) => Ok(())
})
@ -2366,7 +2372,8 @@ impl<'a> State<'a> {
opt_bounds: &Option<OwnedSlice<ast::TyParamBound>>,
generics: Option<&ast::Generics>,
opt_explicit_self: Option<ast::ExplicitSelf_>,
is_unboxed: bool)
opt_unboxed_closure_kind:
Option<ast::UnboxedClosureKind>)
-> IoResult<()> {
try!(self.ibox(indent_unit));
@ -2383,7 +2390,7 @@ impl<'a> State<'a> {
try!(self.print_fn_style(fn_style));
try!(self.print_opt_abi_and_extern_if_nondefault(opt_abi));
try!(self.print_onceness(onceness));
if !is_unboxed {
if opt_unboxed_closure_kind.is_none() {
try!(word(&mut self.s, "fn"));
}
}
@ -2399,20 +2406,30 @@ impl<'a> State<'a> {
match generics { Some(g) => try!(self.print_generics(g)), _ => () }
try!(zerobreak(&mut self.s));
if is_unboxed || opt_sigil == Some('&') {
if opt_unboxed_closure_kind.is_some() || opt_sigil == Some('&') {
try!(word(&mut self.s, "|"));
} else {
try!(self.popen());
}
if is_unboxed {
try!(word(&mut self.s, "&mut"));
try!(self.word_space(":"));
match opt_unboxed_closure_kind {
Some(ast::FnUnboxedClosureKind) => {
try!(word(&mut self.s, "&"));
try!(self.word_space(":"));
}
Some(ast::FnMutUnboxedClosureKind) => {
try!(word(&mut self.s, "&mut"));
try!(self.word_space(":"));
}
Some(ast::FnOnceUnboxedClosureKind) => {
try!(self.word_space(":"));
}
None => {}
}
try!(self.print_fn_args(decl, opt_explicit_self));
if is_unboxed || opt_sigil == Some('&') {
if opt_unboxed_closure_kind.is_some() || opt_sigil == Some('&') {
try!(word(&mut self.s, "|"));
} else {
if decl.variadic {

View File

@ -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,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.
#![feature(overloaded_calls)]
fn a<F:|&: int, int| -> int>(mut f: F) {
let g = &mut f;
f(1, 2); //~ ERROR cannot borrow `f` as immutable
//~^ ERROR cannot borrow `f` as immutable
}
fn b<F:|&mut: int, int| -> int>(f: F) {
f(1, 2); //~ ERROR cannot borrow immutable argument
}
fn c<F:|: int, int| -> int>(f: F) {
f(1, 2);
f(1, 2); //~ ERROR use of moved value
}
fn main() {}

View File

@ -0,0 +1,24 @@
// 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.
#![feature(unboxed_closure_sugar, unboxed_closures, overloaded_calls)]
use std::ops::FnMut;
fn main() {
let mut f;
{
let c = 1;
let c_ref = &c;
f = |&mut: a: int, b: int| { a + b + *c_ref };
//~^ ERROR cannot infer an appropriate lifetime
}
}

View File

@ -0,0 +1,22 @@
// 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.
#![feature(lang_items, overloaded_calls, unboxed_closures)]
fn c<F:|: int, int| -> int>(f: F) -> int {
f(5, 6)
}
fn main() {
let z: int = 7;
assert_eq!(c(|&: x: int, y| x + y + z), 10);
//~^ ERROR failed to find an implementation
}

View File

@ -0,0 +1,31 @@
// 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.
#![feature(lang_items, overloaded_calls, unboxed_closures)]
fn a<F:|&: int, int| -> int>(f: F) -> int {
f(1, 2)
}
fn b<F:|&mut: int, int| -> int>(mut f: F) -> int {
f(3, 4)
}
fn c<F:|: int, int| -> int>(f: F) -> int {
f(5, 6)
}
fn main() {
let z: int = 7;
assert_eq!(a(|&: x: int, y| x + y + z), 10);
assert_eq!(b(|&mut: x: int, y| x + y + z), 14);
assert_eq!(c(|: x: int, y| x + y + z), 18);
}

View File

@ -0,0 +1,127 @@
// 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.
// A battery of tests to ensure destructors of unboxed closure environments
// run at the right times.
#![feature(overloaded_calls, unboxed_closures)]
static mut DROP_COUNT: uint = 0;
fn drop_count() -> uint {
unsafe {
DROP_COUNT
}
}
struct Droppable {
x: int,
}
impl Droppable {
fn new() -> Droppable {
Droppable {
x: 1
}
}
}
impl Drop for Droppable {
fn drop(&mut self) {
unsafe {
DROP_COUNT += 1
}
}
}
fn a<F:|&: int, int| -> int>(f: F) -> int {
f(1, 2)
}
fn b<F:|&mut: int, int| -> int>(mut f: F) -> int {
f(3, 4)
}
fn c<F:|: int, int| -> int>(f: F) -> int {
f(5, 6)
}
fn test_fn() {
{
a(|&: a: int, b| { a + b });
}
assert_eq!(drop_count(), 0);
{
let z = &Droppable::new();
a(|&: a: int, b| { z; a + b });
assert_eq!(drop_count(), 0);
}
assert_eq!(drop_count(), 1);
{
let z = &Droppable::new();
let zz = &Droppable::new();
a(|&: a: int, b| { z; zz; a + b });
assert_eq!(drop_count(), 1);
}
assert_eq!(drop_count(), 3);
}
fn test_fn_mut() {
{
b(|&mut: a: int, b| { a + b });
}
assert_eq!(drop_count(), 3);
{
let z = &Droppable::new();
b(|&mut: a: int, b| { z; a + b });
assert_eq!(drop_count(), 3);
}
assert_eq!(drop_count(), 4);
{
let z = &Droppable::new();
let zz = &Droppable::new();
b(|&mut: a: int, b| { z; zz; a + b });
assert_eq!(drop_count(), 4);
}
assert_eq!(drop_count(), 6);
}
fn test_fn_once() {
{
c(|: a: int, b| { a + b });
}
assert_eq!(drop_count(), 6);
{
let z = Droppable::new();
c(|: a: int, b| { z; a + b });
assert_eq!(drop_count(), 7);
}
assert_eq!(drop_count(), 7);
{
let z = Droppable::new();
let zz = Droppable::new();
c(|: a: int, b| { z; zz; a + b });
assert_eq!(drop_count(), 9);
}
assert_eq!(drop_count(), 9);
}
fn main() {
test_fn();
test_fn_mut();
test_fn_once();
}

View File

@ -0,0 +1,34 @@
// 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.
// Ensures that single-word environments work right in unboxed closures.
// These take a different path in codegen.
#![feature(overloaded_calls, unboxed_closures)]
fn a<F:|&: int, int| -> int>(f: F) -> int {
f(1, 2)
}
fn b<F:|&mut: int, int| -> int>(mut f: F) -> int {
f(3, 4)
}
fn c<F:|: int, int| -> int>(f: F) -> int {
f(5, 6)
}
fn main() {
let z = 10;
assert_eq!(a(|&: x: int, y| x + y + z), 13);
assert_eq!(b(|&mut: x: int, y| x + y + z), 17);
assert_eq!(c(|: x: int, y| x + y + z), 21);
}