mirror of
https://github.com/rust-lang/rust.git
synced 2025-02-03 18:43:38 +00:00
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:
parent
9d45d63d0d
commit
8d27232141
@ -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");
|
||||
|
@ -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;
|
||||
|
@ -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();
|
||||
|
@ -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();
|
||||
|
@ -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");
|
||||
|
@ -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(
|
||||
|
@ -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)
|
||||
|
@ -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),
|
||||
|
@ -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,
|
||||
|
@ -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 \
|
||||
|
@ -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));
|
||||
|
||||
|
@ -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),
|
||||
|
@ -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);
|
||||
|
@ -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),
|
||||
|
@ -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.")
|
||||
|
@ -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);
|
||||
|
@ -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)
|
||||
}
|
||||
|
@ -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 |
|
||||
|
@ -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) => {
|
||||
|
@ -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![
|
||||
|
@ -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);
|
||||
|
@ -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 => {}
|
||||
}
|
||||
})
|
||||
|
@ -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(_) |
|
||||
|
@ -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()
|
||||
|
@ -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 \
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
})
|
||||
}
|
||||
_ => ()
|
||||
}
|
||||
|
||||
|
@ -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: ¶m_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,
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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)) => {
|
||||
|
@ -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);
|
||||
|
@ -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.
|
||||
|
@ -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))
|
||||
}
|
||||
|
@ -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.
|
||||
|
@ -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 {
|
||||
|
@ -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,
|
||||
|
29
src/test/compile-fail/borrowck-unboxed-closures.rs
Normal file
29
src/test/compile-fail/borrowck-unboxed-closures.rs
Normal file
@ -0,0 +1,29 @@
|
||||
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
#![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() {}
|
||||
|
24
src/test/compile-fail/regionck-unboxed-closure-lifetimes.rs
Normal file
24
src/test/compile-fail/regionck-unboxed-closure-lifetimes.rs
Normal 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
|
||||
}
|
||||
}
|
||||
|
22
src/test/compile-fail/unboxed-closures-wrong-trait.rs
Normal file
22
src/test/compile-fail/unboxed-closures-wrong-trait.rs
Normal 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
|
||||
}
|
||||
|
31
src/test/run-pass/unboxed-closures-all-traits.rs
Normal file
31
src/test/run-pass/unboxed-closures-all-traits.rs
Normal 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);
|
||||
}
|
||||
|
127
src/test/run-pass/unboxed-closures-drop.rs
Normal file
127
src/test/run-pass/unboxed-closures-drop.rs
Normal 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();
|
||||
}
|
||||
|
34
src/test/run-pass/unboxed-closures-single-word-env.rs
Normal file
34
src/test/run-pass/unboxed-closures-single-word-env.rs
Normal 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);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user