librustc: Implement unboxed closures with mutable receivers

This commit is contained in:
Patrick Walton 2014-05-28 22:26:56 -07:00
parent 5ddc7b4a25
commit 02adaca4dc
77 changed files with 1905 additions and 384 deletions

View File

@ -749,6 +749,7 @@ pub trait DerefMut<Result>: Deref<Result> {
#[lang="fn"] #[lang="fn"]
pub trait Fn<Args,Result> { pub trait Fn<Args,Result> {
/// This is called when the call operator is used. /// This is called when the call operator is used.
#[rust_call_abi_hack]
fn call(&self, args: Args) -> Result; fn call(&self, args: Args) -> Result;
} }
@ -756,6 +757,7 @@ pub trait Fn<Args,Result> {
#[lang="fn_mut"] #[lang="fn_mut"]
pub trait FnMut<Args,Result> { pub trait FnMut<Args,Result> {
/// This is called when the call operator is used. /// This is called when the call operator is used.
#[rust_call_abi_hack]
fn call_mut(&mut self, args: Args) -> Result; fn call_mut(&mut self, args: Args) -> Result;
} }
@ -763,5 +765,7 @@ pub trait FnMut<Args,Result> {
#[lang="fn_once"] #[lang="fn_once"]
pub trait FnOnce<Args,Result> { pub trait FnOnce<Args,Result> {
/// This is called when the call operator is used. /// This is called when the call operator is used.
#[rust_call_abi_hack]
fn call_once(self, args: Args) -> Result; fn call_once(self, args: Args) -> Result;
} }

View File

@ -35,6 +35,7 @@ pub use ops::{BitAnd, BitOr, BitXor};
pub use ops::{Drop, Deref, DerefMut}; pub use ops::{Drop, Deref, DerefMut};
pub use ops::{Shl, Shr}; pub use ops::{Shl, Shr};
pub use ops::{Index, IndexMut}; pub use ops::{Index, IndexMut};
pub use ops::{Fn, FnMut, FnOnce};
pub use option::{Option, Some, None}; pub use option::{Option, Some, None};
pub use result::{Result, Ok, Err}; pub use result::{Result, Ok, Err};

View File

@ -67,6 +67,7 @@ static KNOWN_FEATURES: &'static [(&'static str, Status)] = &[
("quad_precision_float", Removed), ("quad_precision_float", Removed),
("rustc_diagnostic_macros", Active), ("rustc_diagnostic_macros", Active),
("unboxed_closures", Active),
// A temporary feature gate used to enable parser extensions needed // A temporary feature gate used to enable parser extensions needed
// to bootstrap fix for #5723. // to bootstrap fix for #5723.
@ -327,6 +328,12 @@ impl<'a> Visitor<()> for Context<'a> {
ast::ExprUnary(ast::UnBox, _) => { ast::ExprUnary(ast::UnBox, _) => {
self.gate_box(e.span); self.gate_box(e.span);
} }
ast::ExprUnboxedFn(..) => {
self.gate_feature("unboxed_closures",
e.span,
"unboxed closures are a work-in-progress \
feature with known bugs");
}
_ => {} _ => {}
} }
visit::walk_expr(self, e, ()); visit::walk_expr(self, e, ());

View File

@ -1451,6 +1451,9 @@ impl LintPass for Stability {
typeck::MethodStatic(def_id) => { typeck::MethodStatic(def_id) => {
def_id def_id
} }
typeck::MethodStaticUnboxedClosure(def_id) => {
def_id
}
typeck::MethodParam(typeck::MethodParam { typeck::MethodParam(typeck::MethodParam {
trait_id: trait_id, trait_id: trait_id,
method_num: index, method_num: index,

View File

@ -138,10 +138,11 @@ pub enum astencode_tag { // Reserves 0x40 -- 0x5f
tag_table_vtable_map = 0x50, tag_table_vtable_map = 0x50,
tag_table_adjustments = 0x51, tag_table_adjustments = 0x51,
tag_table_moves_map = 0x52, tag_table_moves_map = 0x52,
tag_table_capture_map = 0x53 tag_table_capture_map = 0x53,
tag_table_unboxed_closure_type = 0x54,
} }
static first_astencode_tag: uint = tag_ast as uint; static first_astencode_tag: uint = tag_ast as uint;
static last_astencode_tag: uint = tag_table_capture_map as uint; static last_astencode_tag: uint = tag_table_unboxed_closure_type as uint;
impl astencode_tag { impl astencode_tag {
pub fn from_uint(value : uint) -> Option<astencode_tag> { pub fn from_uint(value : uint) -> Option<astencode_tag> {
let is_a_tag = first_astencode_tag <= value && value <= last_astencode_tag; let is_a_tag = first_astencode_tag <= value && value <= last_astencode_tag;
@ -155,6 +156,10 @@ pub static tag_item_trait_method_sort: uint = 0x60;
pub static tag_item_impl_type_basename: uint = 0x61; pub static tag_item_impl_type_basename: uint = 0x61;
pub static tag_crate_triple: uint = 0x66;
pub static tag_dylib_dependency_formats: uint = 0x67;
// Language items are a top-level directory (for speed). Hierarchy: // Language items are a top-level directory (for speed). Hierarchy:
// //
// tag_lang_items // tag_lang_items
@ -199,10 +204,6 @@ pub static tag_plugin_registrar_fn: uint = 0x8b;
pub static tag_exported_macros: uint = 0x8c; pub static tag_exported_macros: uint = 0x8c;
pub static tag_macro_def: uint = 0x8d; pub static tag_macro_def: uint = 0x8d;
pub static tag_crate_triple: uint = 0x66;
pub static tag_dylib_dependency_formats: uint = 0x67;
pub static tag_method_argument_names: uint = 0x8e; pub static tag_method_argument_names: uint = 0x8e;
pub static tag_method_argument_name: uint = 0x8f; pub static tag_method_argument_name: uint = 0x8f;
@ -211,7 +212,6 @@ pub static tag_reachable_extern_fn_id: uint = 0x91;
pub static tag_items_data_item_stability: uint = 0x92; pub static tag_items_data_item_stability: uint = 0x92;
#[deriving(Clone, Show)] #[deriving(Clone, Show)]
pub struct LinkMeta { pub struct LinkMeta {
pub crate_name: String, pub crate_name: String,
@ -223,3 +223,7 @@ pub static tag_region_param_def_ident: uint = 0x91;
pub static tag_region_param_def_def_id: uint = 0x92; pub static tag_region_param_def_def_id: uint = 0x92;
pub static tag_region_param_def_space: uint = 0x93; pub static tag_region_param_def_space: uint = 0x93;
pub static tag_region_param_def_index: uint = 0x94; 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;

View File

@ -209,6 +209,18 @@ fn encode_variant_id(ebml_w: &mut Encoder, vid: DefId) {
ebml_w.end_tag(); ebml_w.end_tag();
} }
pub fn write_closure_type(ecx: &EncodeContext,
ebml_w: &mut Encoder,
closure_type: &ty::ClosureTy) {
let ty_str_ctxt = &tyencode::ctxt {
diag: ecx.diag,
ds: def_to_string,
tcx: ecx.tcx,
abbrevs: &ecx.type_abbrevs
};
tyencode::enc_closure_ty(ebml_w.writer, ty_str_ctxt, closure_type);
}
pub fn write_type(ecx: &EncodeContext, pub fn write_type(ecx: &EncodeContext,
ebml_w: &mut Encoder, ebml_w: &mut Encoder,
typ: ty::t) { typ: ty::t) {
@ -1618,6 +1630,26 @@ fn encode_macro_defs(ecx: &EncodeContext,
ebml_w.end_tag(); ebml_w.end_tag();
} }
fn encode_unboxed_closures<'a>(
ecx: &'a EncodeContext,
ebml_w: &'a mut Encoder) {
ebml_w.start_tag(tag_unboxed_closures);
for (unboxed_closure_id, unboxed_closure_type) in
ecx.tcx.unboxed_closure_types.borrow().iter() {
if unboxed_closure_id.krate != LOCAL_CRATE {
continue
}
ebml_w.start_tag(tag_unboxed_closure);
encode_def_id(ebml_w, *unboxed_closure_id);
ebml_w.start_tag(tag_unboxed_closure_type);
write_closure_type(ecx, ebml_w, unboxed_closure_type);
ebml_w.end_tag();
ebml_w.end_tag();
}
ebml_w.end_tag();
}
struct ImplVisitor<'a,'b,'c> { struct ImplVisitor<'a,'b,'c> {
ecx: &'a EncodeContext<'b>, ecx: &'a EncodeContext<'b>,
ebml_w: &'a mut Encoder<'c>, ebml_w: &'a mut Encoder<'c>,
@ -1787,6 +1819,7 @@ fn encode_metadata_inner(wr: &mut MemWriter, parms: EncodeParams, krate: &Crate)
native_lib_bytes: u64, native_lib_bytes: u64,
plugin_registrar_fn_bytes: u64, plugin_registrar_fn_bytes: u64,
macro_defs_bytes: u64, macro_defs_bytes: u64,
unboxed_closure_bytes: u64,
impl_bytes: u64, impl_bytes: u64,
misc_bytes: u64, misc_bytes: u64,
item_bytes: u64, item_bytes: u64,
@ -1801,6 +1834,7 @@ fn encode_metadata_inner(wr: &mut MemWriter, parms: EncodeParams, krate: &Crate)
native_lib_bytes: 0, native_lib_bytes: 0,
plugin_registrar_fn_bytes: 0, plugin_registrar_fn_bytes: 0,
macro_defs_bytes: 0, macro_defs_bytes: 0,
unboxed_closure_bytes: 0,
impl_bytes: 0, impl_bytes: 0,
misc_bytes: 0, misc_bytes: 0,
item_bytes: 0, item_bytes: 0,
@ -1873,6 +1907,11 @@ fn encode_metadata_inner(wr: &mut MemWriter, parms: EncodeParams, krate: &Crate)
encode_macro_defs(&ecx, krate, &mut ebml_w); encode_macro_defs(&ecx, krate, &mut ebml_w);
stats.macro_defs_bytes = ebml_w.writer.tell().unwrap() - i; stats.macro_defs_bytes = ebml_w.writer.tell().unwrap() - i;
// Encode the types of all unboxed closures in this crate.
i = ebml_w.writer.tell().unwrap();
encode_unboxed_closures(&ecx, &mut ebml_w);
stats.unboxed_closure_bytes = ebml_w.writer.tell().unwrap() - i;
// Encode the def IDs of impls, for coherence checking. // Encode the def IDs of impls, for coherence checking.
i = ebml_w.writer.tell().unwrap(); i = ebml_w.writer.tell().unwrap();
encode_impls(&ecx, krate, &mut ebml_w); encode_impls(&ecx, krate, &mut ebml_w);
@ -1911,6 +1950,7 @@ fn encode_metadata_inner(wr: &mut MemWriter, parms: EncodeParams, krate: &Crate)
println!(" native bytes: {}", stats.native_lib_bytes); println!(" native bytes: {}", stats.native_lib_bytes);
println!("plugin registrar bytes: {}", stats.plugin_registrar_fn_bytes); println!("plugin registrar bytes: {}", stats.plugin_registrar_fn_bytes);
println!(" macro def bytes: {}", stats.macro_defs_bytes); println!(" macro def bytes: {}", stats.macro_defs_bytes);
println!(" unboxed closure bytes: {}", stats.unboxed_closure_bytes);
println!(" impl bytes: {}", stats.impl_bytes); println!(" impl bytes: {}", stats.impl_bytes);
println!(" misc bytes: {}", stats.misc_bytes); println!(" misc bytes: {}", stats.misc_bytes);
println!(" item bytes: {}", stats.item_bytes); println!(" item bytes: {}", stats.item_bytes);

View File

@ -130,6 +130,16 @@ fn data_log_string(data: &[u8], pos: uint) -> String {
buf buf
} }
pub fn parse_ty_closure_data(data: &[u8],
crate_num: ast::CrateNum,
pos: uint,
tcx: &ty::ctxt,
conv: conv_did)
-> ty::ClosureTy {
let mut st = parse_state_from_data(data, crate_num, pos, tcx);
parse_closure_ty(&mut st, conv)
}
pub fn parse_ty_data(data: &[u8], crate_num: ast::CrateNum, pos: uint, tcx: &ty::ctxt, pub fn parse_ty_data(data: &[u8], crate_num: ast::CrateNum, pos: uint, tcx: &ty::ctxt,
conv: conv_did) -> ty::t { conv: conv_did) -> ty::t {
debug!("parse_ty_data {}", data_log_string(data, pos)); debug!("parse_ty_data {}", data_log_string(data, pos));
@ -420,6 +430,10 @@ fn parse_ty(st: &mut PState, conv: conv_did) -> ty::t {
assert_eq!(next(st), ']'); assert_eq!(next(st), ']');
return ty::mk_struct(st.tcx, did, substs); return ty::mk_struct(st.tcx, did, substs);
} }
'k' => {
let did = parse_def(st, NominalType, |x,y| conv(x,y));
return ty::mk_unboxed_closure(st.tcx, did);
}
'e' => { 'e' => {
return ty::mk_err(); return ty::mk_err();
} }
@ -502,12 +516,14 @@ fn parse_closure_ty(st: &mut PState, conv: conv_did) -> ty::ClosureTy {
let store = parse_trait_store(st, |x,y| conv(x,y)); let store = parse_trait_store(st, |x,y| conv(x,y));
let bounds = parse_bounds(st, |x,y| conv(x,y)); let bounds = parse_bounds(st, |x,y| conv(x,y));
let sig = parse_sig(st, |x,y| conv(x,y)); let sig = parse_sig(st, |x,y| conv(x,y));
let abi = parse_abi_set(st);
ty::ClosureTy { ty::ClosureTy {
fn_style: fn_style, fn_style: fn_style,
onceness: onceness, onceness: onceness,
store: store, store: store,
bounds: bounds.builtin_bounds, bounds: bounds.builtin_bounds,
sig: sig sig: sig,
abi: abi,
} }
} }

View File

@ -284,6 +284,9 @@ fn enc_sty(w: &mut MemWriter, cx: &ctxt, st: &ty::sty) {
enc_substs(w, cx, substs); enc_substs(w, cx, substs);
mywrite!(w, "]"); mywrite!(w, "]");
} }
ty::ty_unboxed_closure(def) => {
mywrite!(w, "k{}", (cx.ds)(def));
}
ty::ty_err => { ty::ty_err => {
mywrite!(w, "e"); mywrite!(w, "e");
} }
@ -316,7 +319,7 @@ pub fn enc_bare_fn_ty(w: &mut MemWriter, cx: &ctxt, ft: &ty::BareFnTy) {
enc_fn_sig(w, cx, &ft.sig); enc_fn_sig(w, cx, &ft.sig);
} }
fn enc_closure_ty(w: &mut MemWriter, cx: &ctxt, ft: &ty::ClosureTy) { pub fn enc_closure_ty(w: &mut MemWriter, cx: &ctxt, ft: &ty::ClosureTy) {
enc_fn_style(w, ft.fn_style); enc_fn_style(w, ft.fn_style);
enc_onceness(w, ft.onceness); enc_onceness(w, ft.onceness);
enc_trait_store(w, cx, ft.store); enc_trait_store(w, cx, ft.store);
@ -324,6 +327,7 @@ fn enc_closure_ty(w: &mut MemWriter, cx: &ctxt, ft: &ty::ClosureTy) {
trait_bounds: Vec::new()}; trait_bounds: Vec::new()};
enc_bounds(w, cx, &bounds); enc_bounds(w, cx, &bounds);
enc_fn_sig(w, cx, &ft.sig); enc_fn_sig(w, cx, &ft.sig);
enc_abi(w, ft.abi);
} }
fn enc_fn_sig(w: &mut MemWriter, cx: &ctxt, fsig: &ty::FnSig) { fn enc_fn_sig(w: &mut MemWriter, cx: &ctxt, fsig: &ty::FnSig) {

View File

@ -609,6 +609,9 @@ impl tr for MethodOrigin {
fn tr(&self, xcx: &ExtendedDecodeContext) -> MethodOrigin { fn tr(&self, xcx: &ExtendedDecodeContext) -> MethodOrigin {
match *self { match *self {
typeck::MethodStatic(did) => typeck::MethodStatic(did.tr(xcx)), typeck::MethodStatic(did) => typeck::MethodStatic(did.tr(xcx)),
typeck::MethodStaticUnboxedClosure(did) => {
typeck::MethodStaticUnboxedClosure(did.tr(xcx))
}
typeck::MethodParam(ref mp) => { typeck::MethodParam(ref mp) => {
typeck::MethodParam( typeck::MethodParam(
typeck::MethodParam { typeck::MethodParam {
@ -696,8 +699,18 @@ pub fn encode_vtable_origin(ecx: &e::EncodeContext,
}) })
}) })
} }
typeck::vtable_unboxed_closure(def_id) => {
ebml_w.emit_enum_variant("vtable_unboxed_closure",
2u,
1u,
|ebml_w| {
ebml_w.emit_enum_variant_arg(0u, |ebml_w| {
Ok(ebml_w.emit_def_id(def_id))
})
})
}
typeck::vtable_error => { typeck::vtable_error => {
ebml_w.emit_enum_variant("vtable_error", 2u, 3u, |_ebml_w| { ebml_w.emit_enum_variant("vtable_error", 3u, 3u, |_ebml_w| {
Ok(()) Ok(())
}) })
} }
@ -771,7 +784,8 @@ impl<'a> vtable_decoder_helpers for reader::Decoder<'a> {
self.read_enum("vtable_origin", |this| { self.read_enum("vtable_origin", |this| {
this.read_enum_variant(["vtable_static", this.read_enum_variant(["vtable_static",
"vtable_param", "vtable_param",
"vtable_error"], "vtable_error",
"vtable_unboxed_closure"],
|this, i| { |this, i| {
Ok(match i { Ok(match i {
0 => { 0 => {
@ -798,6 +812,13 @@ impl<'a> vtable_decoder_helpers for reader::Decoder<'a> {
) )
} }
2 => { 2 => {
typeck::vtable_unboxed_closure(
this.read_enum_variant_arg(0u, |this| {
Ok(this.read_def_id_noxcx(cdata))
}).unwrap()
)
}
3 => {
typeck::vtable_error typeck::vtable_error
} }
_ => fail!("bad enum variant") _ => fail!("bad enum variant")
@ -838,6 +859,9 @@ impl<'a> get_ty_str_ctxt for e::EncodeContext<'a> {
} }
trait ebml_writer_helpers { trait ebml_writer_helpers {
fn emit_closure_type(&mut self,
ecx: &e::EncodeContext,
closure_type: &ty::ClosureTy);
fn emit_ty(&mut self, ecx: &e::EncodeContext, ty: ty::t); fn emit_ty(&mut self, ecx: &e::EncodeContext, ty: ty::t);
fn emit_tys(&mut self, ecx: &e::EncodeContext, tys: &[ty::t]); fn emit_tys(&mut self, ecx: &e::EncodeContext, tys: &[ty::t]);
fn emit_type_param_def(&mut self, fn emit_type_param_def(&mut self,
@ -851,6 +875,14 @@ trait ebml_writer_helpers {
} }
impl<'a> ebml_writer_helpers for Encoder<'a> { impl<'a> ebml_writer_helpers for Encoder<'a> {
fn emit_closure_type(&mut self,
ecx: &e::EncodeContext,
closure_type: &ty::ClosureTy) {
self.emit_opaque(|this| {
Ok(e::write_closure_type(ecx, this, closure_type))
});
}
fn emit_ty(&mut self, ecx: &e::EncodeContext, ty: ty::t) { fn emit_ty(&mut self, ecx: &e::EncodeContext, ty: ty::t) {
self.emit_opaque(|this| Ok(e::write_type(ecx, this, ty))); self.emit_opaque(|this| Ok(e::write_type(ecx, this, ty)));
} }
@ -1127,6 +1159,18 @@ 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() {
ebml_w.tag(c::tag_table_unboxed_closure_type, |ebml_w| {
ebml_w.id(id);
ebml_w.tag(c::tag_table_val, |ebml_w| {
ebml_w.emit_closure_type(ecx, *unboxed_closure_type)
})
})
}
} }
trait doc_decoder_helpers { trait doc_decoder_helpers {
@ -1150,6 +1194,8 @@ trait ebml_decoder_decoder_helpers {
-> ty::Polytype; -> ty::Polytype;
fn read_substs(&mut self, xcx: &ExtendedDecodeContext) -> subst::Substs; fn read_substs(&mut self, xcx: &ExtendedDecodeContext) -> subst::Substs;
fn read_auto_adjustment(&mut self, xcx: &ExtendedDecodeContext) -> ty::AutoAdjustment; fn read_auto_adjustment(&mut self, xcx: &ExtendedDecodeContext) -> ty::AutoAdjustment;
fn read_unboxed_closure_type(&mut self, xcx: &ExtendedDecodeContext)
-> ty::ClosureTy;
fn convert_def_id(&mut self, fn convert_def_id(&mut self,
xcx: &ExtendedDecodeContext, xcx: &ExtendedDecodeContext,
source: DefIdSource, source: DefIdSource,
@ -1322,6 +1368,18 @@ impl<'a> ebml_decoder_decoder_helpers for reader::Decoder<'a> {
}).unwrap() }).unwrap()
} }
fn read_unboxed_closure_type(&mut self, xcx: &ExtendedDecodeContext)
-> ty::ClosureTy {
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()
}
fn convert_def_id(&mut self, fn convert_def_id(&mut self,
xcx: &ExtendedDecodeContext, xcx: &ExtendedDecodeContext,
source: tydecode::DefIdSource, source: tydecode::DefIdSource,
@ -1442,6 +1500,15 @@ fn decode_side_tables(xcx: &ExtendedDecodeContext,
let adj: ty::AutoAdjustment = val_dsr.read_auto_adjustment(xcx); let adj: ty::AutoAdjustment = val_dsr.read_auto_adjustment(xcx);
dcx.tcx.adjustments.borrow_mut().insert(id, adj); 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);
dcx.tcx
.unboxed_closure_types
.borrow_mut()
.insert(ast_util::local_def(id),
unboxed_closure_type);
}
_ => { _ => {
xcx.dcx.tcx.sess.bug( xcx.dcx.tcx.sess.bug(
format!("unknown tag found in side tables: {:x}", format!("unknown tag found in side tables: {:x}",

View File

@ -832,3 +832,4 @@ impl<'a> CheckLoanCtxt<'a> {
self.bccx.loan_path_to_string(loan_path)).as_slice()); self.bccx.loan_path_to_string(loan_path)).as_slice());
} }
} }

View File

@ -446,6 +446,7 @@ impl<'a> CFGBuilder<'a> {
ast::ExprMac(..) | ast::ExprMac(..) |
ast::ExprFnBlock(..) | ast::ExprFnBlock(..) |
ast::ExprProc(..) | ast::ExprProc(..) |
ast::ExprUnboxedFn(..) |
ast::ExprLit(..) | ast::ExprLit(..) |
ast::ExprPath(..) => { ast::ExprPath(..) => {
self.straightline(expr, pred, []) self.straightline(expr, pred, [])

View File

@ -42,7 +42,9 @@ impl<'a> Visitor<Context> for CheckLoopVisitor<'a> {
ast::ExprLoop(ref b, _) => { ast::ExprLoop(ref b, _) => {
self.visit_block(&**b, Loop); self.visit_block(&**b, Loop);
} }
ast::ExprFnBlock(_, ref b) | ast::ExprProc(_, ref b) => { ast::ExprFnBlock(_, ref b) |
ast::ExprProc(_, ref b) |
ast::ExprUnboxedFn(_, ref b) => {
self.visit_block(&**b, Closure); self.visit_block(&**b, Closure);
} }
ast::ExprBreak(_) => self.require_loop("break", cx, e.span), ast::ExprBreak(_) => self.require_loop("break", cx, e.span),

View File

@ -104,6 +104,7 @@ impl<'a> MarkSymbolVisitor<'a> {
None => self.check_def_id(def_id) None => self.check_def_id(def_id)
} }
} }
typeck::MethodStaticUnboxedClosure(_) => {}
typeck::MethodParam(typeck::MethodParam { typeck::MethodParam(typeck::MethodParam {
trait_id: trait_id, trait_id: trait_id,
method_num: index, method_num: index,

View File

@ -20,7 +20,7 @@ use middle::freevars;
use middle::pat_util; use middle::pat_util;
use middle::ty; use middle::ty;
use middle::typeck::{MethodCall, MethodObject, MethodOrigin, MethodParam}; use middle::typeck::{MethodCall, MethodObject, MethodOrigin, MethodParam};
use middle::typeck::{MethodStatic}; use middle::typeck::{MethodStatic, MethodStaticUnboxedClosure};
use middle::typeck; use middle::typeck;
use util::ppaux::Repr; use util::ppaux::Repr;
@ -160,6 +160,9 @@ impl OverloadedCallType {
MethodStatic(def_id) => { MethodStatic(def_id) => {
OverloadedCallType::from_method_id(tcx, def_id) OverloadedCallType::from_method_id(tcx, def_id)
} }
MethodStaticUnboxedClosure(def_id) => {
OverloadedCallType::from_method_id(tcx, def_id)
}
MethodParam(ref method_param) => { MethodParam(ref method_param) => {
OverloadedCallType::from_trait_id(tcx, method_param.trait_id) OverloadedCallType::from_trait_id(tcx, method_param.trait_id)
} }
@ -439,6 +442,7 @@ impl<'d,'t,TYPER:mc::Typer> ExprUseVisitor<'d,'t,TYPER> {
} }
ast::ExprFnBlock(..) | ast::ExprFnBlock(..) |
ast::ExprUnboxedFn(..) |
ast::ExprProc(..) => { ast::ExprProc(..) => {
self.walk_captures(expr) self.walk_captures(expr)
} }

View File

@ -16,7 +16,7 @@
use middle::def; use middle::def;
use middle::resolve; use middle::resolve;
use middle::ty; use middle::ty;
use util::nodemap::{NodeMap, NodeSet}; use util::nodemap::{DefIdSet, NodeMap, NodeSet};
use syntax::codemap::Span; use syntax::codemap::Span;
use syntax::{ast}; use syntax::{ast};
@ -39,8 +39,11 @@ pub struct freevar_entry {
pub def: def::Def, //< The variable being accessed free. pub def: def::Def, //< The variable being accessed free.
pub span: Span //< First span where it is accessed (there can be multiple) pub span: Span //< First span where it is accessed (there can be multiple)
} }
pub type freevar_map = NodeMap<Vec<freevar_entry>>; pub type freevar_map = NodeMap<Vec<freevar_entry>>;
pub type UnboxedClosureList = DefIdSet;
struct CollectFreevarsVisitor<'a> { struct CollectFreevarsVisitor<'a> {
seen: NodeSet, seen: NodeSet,
refs: Vec<freevar_entry>, refs: Vec<freevar_entry>,
@ -54,7 +57,8 @@ impl<'a> Visitor<int> for CollectFreevarsVisitor<'a> {
fn visit_expr(&mut self, expr: &ast::Expr, depth: int) { fn visit_expr(&mut self, expr: &ast::Expr, depth: int) {
match expr.node { match expr.node {
ast::ExprFnBlock(..) | ast::ExprProc(..) => { ast::ExprFnBlock(..) | ast::ExprProc(..) |
ast::ExprUnboxedFn(..) => {
visit::walk_expr(self, expr, depth + 1) visit::walk_expr(self, expr, depth + 1)
} }
ast::ExprPath(..) => { ast::ExprPath(..) => {
@ -125,8 +129,8 @@ impl<'a> Visitor<()> for AnnotateFreevarsVisitor<'a> {
// efficient as it fully recomputes the free variables at every // efficient as it fully recomputes the free variables at every
// node of interest rather than building up the free variables in // node of interest rather than building up the free variables in
// one pass. This could be improved upon if it turns out to matter. // one pass. This could be improved upon if it turns out to matter.
pub fn annotate_freevars(def_map: &resolve::DefMap, krate: &ast::Crate) -> pub fn annotate_freevars(def_map: &resolve::DefMap, krate: &ast::Crate)
freevar_map { -> freevar_map {
let mut visitor = AnnotateFreevarsVisitor { let mut visitor = AnnotateFreevarsVisitor {
def_map: def_map, def_map: def_map,
freevars: NodeMap::new(), freevars: NodeMap::new(),

View File

@ -216,6 +216,9 @@ fn with_appropriate_checker(cx: &Context,
ty::ty_bare_fn(_) => { ty::ty_bare_fn(_) => {
b(check_for_bare) b(check_for_bare)
} }
ty::ty_unboxed_closure(_) => {}
ref s => { ref s => {
cx.tcx.sess.bug(format!("expect fn type in kind checker, not \ cx.tcx.sess.bug(format!("expect fn type in kind checker, not \
{:?}", {:?}",
@ -321,7 +324,9 @@ fn check_bounds_on_type_parameters(cx: &mut Context, e: &Expr) {
Some(method) => { Some(method) => {
let is_object_call = match method.origin { let is_object_call = match method.origin {
typeck::MethodObject(..) => true, typeck::MethodObject(..) => true,
typeck::MethodStatic(..) | typeck::MethodParam(..) => false typeck::MethodStatic(..) |
typeck::MethodStaticUnboxedClosure(..) |
typeck::MethodParam(..) => false
}; };
(&method.substs.types, is_object_call) (&method.substs.types, is_object_call)
} }

View File

@ -448,7 +448,7 @@ fn visit_expr(ir: &mut IrMaps, expr: &Expr) {
} }
visit::walk_expr(ir, expr, ()); visit::walk_expr(ir, expr, ());
} }
ExprFnBlock(..) | ExprProc(..) => { ExprFnBlock(..) | ExprProc(..) | ExprUnboxedFn(..) => {
// Interesting control flow (for loops can contain labeled // Interesting control flow (for loops can contain labeled
// breaks or continues) // breaks or continues)
ir.add_live_node_for_node(expr.id, ExprNode(expr.span)); ir.add_live_node_for_node(expr.id, ExprNode(expr.span));
@ -941,8 +941,11 @@ impl<'a> Liveness<'a> {
self.propagate_through_expr(&**e, succ) self.propagate_through_expr(&**e, succ)
} }
ExprFnBlock(_, ref blk) | ExprProc(_, ref blk) => { ExprFnBlock(_, ref blk) |
debug!("{} is an ExprFnBlock or ExprProc", expr_to_string(expr)); ExprProc(_, ref blk) |
ExprUnboxedFn(_, ref blk) => {
debug!("{} is an ExprFnBlock, ExprProc, or ExprUnboxedFn",
expr_to_string(expr));
/* /*
The next-node for a break is the successor of the entire The next-node for a break is the successor of the entire
@ -1411,8 +1414,8 @@ fn check_expr(this: &mut Liveness, expr: &Expr) {
ExprCast(..) | ExprUnary(..) | ExprRet(..) | ExprBreak(..) | ExprCast(..) | ExprUnary(..) | ExprRet(..) | ExprBreak(..) |
ExprAgain(..) | ExprLit(_) | ExprBlock(..) | ExprAgain(..) | ExprLit(_) | ExprBlock(..) |
ExprMac(..) | ExprAddrOf(..) | ExprStruct(..) | ExprRepeat(..) | ExprMac(..) | ExprAddrOf(..) | ExprStruct(..) | ExprRepeat(..) |
ExprParen(..) | ExprFnBlock(..) | ExprProc(..) | ExprPath(..) | ExprParen(..) | ExprFnBlock(..) | ExprProc(..) | ExprUnboxedFn(..) |
ExprBox(..) => { ExprPath(..) | ExprBox(..) => {
visit::walk_expr(this, expr, ()); visit::walk_expr(this, expr, ());
} }
ExprForLoop(..) => fail!("non-desugared expr_for_loop") ExprForLoop(..) => fail!("non-desugared expr_for_loop")

View File

@ -473,7 +473,8 @@ impl<'t,TYPER:Typer> MemCategorizationContext<'t,TYPER> {
ast::ExprAddrOf(..) | ast::ExprCall(..) | ast::ExprAddrOf(..) | ast::ExprCall(..) |
ast::ExprAssign(..) | ast::ExprAssignOp(..) | ast::ExprAssign(..) | ast::ExprAssignOp(..) |
ast::ExprFnBlock(..) | ast::ExprProc(..) | ast::ExprRet(..) | ast::ExprFnBlock(..) | ast::ExprProc(..) |
ast::ExprUnboxedFn(..) | ast::ExprRet(..) |
ast::ExprUnary(..) | ast::ExprUnary(..) |
ast::ExprMethodCall(..) | ast::ExprCast(..) | ast::ExprVstore(..) | ast::ExprMethodCall(..) | ast::ExprCast(..) | ast::ExprVstore(..) |
ast::ExprVec(..) | ast::ExprTup(..) | ast::ExprIf(..) | ast::ExprVec(..) | ast::ExprTup(..) | ast::ExprIf(..) |
@ -578,6 +579,20 @@ impl<'t,TYPER:Typer> MemCategorizationContext<'t,TYPER> {
})) }))
} }
} }
ty::ty_unboxed_closure(_) => {
// FIXME #2152 allow mutation of moved upvars
Ok(Rc::new(cmt_ {
id: id,
span: span,
cat: cat_copied_upvar(CopiedUpvar {
upvar_id: var_id,
onceness: ast::Many,
capturing_proc: fn_node_id,
}),
mutbl: McImmutable,
ty: expr_ty
}))
}
_ => { _ => {
self.tcx().sess.span_bug( self.tcx().sess.span_bug(
span, span,

View File

@ -21,7 +21,7 @@ use lint;
use middle::resolve; use middle::resolve;
use middle::ty; use middle::ty;
use middle::typeck::{MethodCall, MethodMap, MethodOrigin, MethodParam}; use middle::typeck::{MethodCall, MethodMap, MethodOrigin, MethodParam};
use middle::typeck::{MethodStatic, MethodObject}; use middle::typeck::{MethodStatic, MethodStaticUnboxedClosure, MethodObject};
use util::nodemap::{NodeMap, NodeSet}; use util::nodemap::{NodeMap, NodeSet};
use syntax::ast; use syntax::ast;
@ -772,6 +772,7 @@ impl<'a> PrivacyVisitor<'a> {
MethodStatic(method_id) => { MethodStatic(method_id) => {
self.check_static_method(span, method_id, ident) self.check_static_method(span, method_id, ident)
} }
MethodStaticUnboxedClosure(_) => {}
// Trait methods are always all public. The only controlling factor // Trait methods are always all public. The only controlling factor
// is whether the trait itself is accessible or not. // is whether the trait itself is accessible or not.
MethodParam(MethodParam { trait_id: trait_id, .. }) | MethodParam(MethodParam { trait_id: trait_id, .. }) |

View File

@ -5254,7 +5254,8 @@ impl<'a> Resolver<'a> {
} }
ExprFnBlock(fn_decl, block) | ExprFnBlock(fn_decl, block) |
ExprProc(fn_decl, block) => { ExprProc(fn_decl, block) |
ExprUnboxedFn(fn_decl, block) => {
self.resolve_function(FunctionRibKind(expr.id, block.id), self.resolve_function(FunctionRibKind(expr.id, block.id),
Some(fn_decl), NoTypeParameters, Some(fn_decl), NoTypeParameters,
block); block);

View File

@ -842,7 +842,8 @@ impl <'l> DxrVisitor<'l> {
let method_map = self.analysis.ty_cx.method_map.borrow(); let method_map = self.analysis.ty_cx.method_map.borrow();
let method_callee = method_map.get(&typeck::MethodCall::expr(ex.id)); let method_callee = method_map.get(&typeck::MethodCall::expr(ex.id));
let (def_id, decl_id) = match method_callee.origin { let (def_id, decl_id) = match method_callee.origin {
typeck::MethodStatic(def_id) => { typeck::MethodStatic(def_id) |
typeck::MethodStaticUnboxedClosure(def_id) => {
// method invoked on an object with a concrete type (not a static method) // method invoked on an object with a concrete type (not a static method)
let decl_id = ty::trait_method_of_method(&self.analysis.ty_cx, def_id); let decl_id = ty::trait_method_of_method(&self.analysis.ty_cx, def_id);

View File

@ -317,6 +317,9 @@ impl<T> VecPerParamSpace<T> {
VecPerParamSpace::empty().with_vec(TypeSpace, types) VecPerParamSpace::empty().with_vec(TypeSpace, types)
} }
/// `t` is the type space.
/// `s` is the self space.
/// `f` is the fn space.
pub fn new(t: Vec<T>, s: Vec<T>, f: Vec<T>) -> VecPerParamSpace<T> { pub fn new(t: Vec<T>, s: Vec<T>, f: Vec<T>) -> VecPerParamSpace<T> {
let type_limit = t.len(); let type_limit = t.len();
let self_limit = t.len() + s.len(); let self_limit = t.len() + s.len();

View File

@ -163,6 +163,12 @@ fn represent_type_uncached(cx: &CrateContext, t: ty::t) -> Repr {
return Univariant(mk_struct(cx, ftys.as_slice(), packed), dtor) return Univariant(mk_struct(cx, ftys.as_slice(), packed), dtor)
} }
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),
false)
}
ty::ty_enum(def_id, ref substs) => { ty::ty_enum(def_id, ref substs) => {
let cases = get_cases(cx.tcx(), def_id, substs); let cases = get_cases(cx.tcx(), def_id, substs);
let hint = ty::lookup_repr_hint(cx.tcx(), def_id); let hint = ty::lookup_repr_hint(cx.tcx(), def_id);

View File

@ -29,17 +29,16 @@ use back::link::{mangle_exported_name};
use back::{link, abi}; use back::{link, abi};
use driver::config; use driver::config;
use driver::config::{NoDebugInfo, FullDebugInfo}; use driver::config::{NoDebugInfo, FullDebugInfo};
use driver::session::Session;
use driver::driver::{CrateAnalysis, CrateTranslation}; use driver::driver::{CrateAnalysis, CrateTranslation};
use llvm; use driver::session::Session;
use llvm::{ModuleRef, ValueRef, BasicBlockRef};
use llvm::{Vector};
use metadata::{csearch, encoder, loader};
use lint; use lint;
use llvm::{BasicBlockRef, ModuleRef, ValueRef, Vector, get_param};
use llvm;
use metadata::{csearch, encoder, loader};
use middle::astencode; use middle::astencode;
use middle::lang_items::{LangItem, ExchangeMallocFnLangItem, StartFnLangItem}; use middle::lang_items::{LangItem, ExchangeMallocFnLangItem, StartFnLangItem};
use middle::weak_lang_items;
use middle::subst; use middle::subst;
use middle::weak_lang_items;
use middle::subst::Subst; use middle::subst::Subst;
use middle::trans::_match; use middle::trans::_match;
use middle::trans::adt; use middle::trans::adt;
@ -82,7 +81,8 @@ use std::cell::{Cell, RefCell};
use std::rc::Rc; use std::rc::Rc;
use std::{i8, i16, i32, i64}; use std::{i8, i16, i32, i64};
use std::gc::Gc; use std::gc::Gc;
use syntax::abi::{X86, X86_64, Arm, Mips, Mipsel, Rust, RustIntrinsic}; use syntax::abi::{X86, X86_64, Arm, Mips, Mipsel, Rust, RustCall};
use syntax::abi::{RustIntrinsic, Abi};
use syntax::ast_util::{local_def, is_local}; use syntax::ast_util::{local_def, is_local};
use syntax::attr::AttrMetaMethods; use syntax::attr::AttrMetaMethods;
use syntax::attr; use syntax::attr;
@ -254,13 +254,32 @@ fn get_extern_rust_fn(ccx: &CrateContext, fn_ty: ty::t, name: &str, did: ast::De
} }
pub fn decl_rust_fn(ccx: &CrateContext, fn_ty: ty::t, name: &str) -> ValueRef { pub fn decl_rust_fn(ccx: &CrateContext, fn_ty: ty::t, name: &str) -> ValueRef {
let (inputs, output, has_env) = match ty::get(fn_ty).sty { let (inputs, output, abi, env) = match ty::get(fn_ty).sty {
ty::ty_bare_fn(ref f) => (f.sig.inputs.clone(), f.sig.output, false), ty::ty_bare_fn(ref f) => {
ty::ty_closure(ref f) => (f.sig.inputs.clone(), f.sig.output, true), (f.sig.inputs.clone(), f.sig.output, f.abi, None)
}
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();
(function_type.sig.inputs.clone(),
function_type.sig.output,
RustCall,
Some(llenvironment_type))
}
_ => fail!("expected closure or fn") _ => fail!("expected closure or fn")
}; };
let llfty = type_of_rust_fn(ccx, has_env, inputs.as_slice(), output); let llfty = type_of_rust_fn(ccx, env, inputs.as_slice(), output, abi);
debug!("decl_rust_fn(input count={},type={})",
inputs.len(),
ccx.tn.type_to_string(llfty));
let llfn = decl_fn(ccx, name, llvm::CCallConv, llfty, output); let llfn = decl_fn(ccx, name, llvm::CCallConv, llfty, output);
let attrs = get_fn_llvm_attributes(ccx, fn_ty); let attrs = get_fn_llvm_attributes(ccx, fn_ty);
for &(idx, attr) in attrs.iter() { for &(idx, attr) in attrs.iter() {
@ -674,6 +693,14 @@ pub fn iter_structural_ty<'r,
} }
}) })
} }
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() {
let llupvar = adt::trans_field_ptr(cx, &*repr, av, 0, i);
cx = f(cx, llupvar, upvar.ty);
}
}
ty::ty_vec(_, Some(n)) => { ty::ty_vec(_, Some(n)) => {
let unit_ty = ty::sequence_element_type(cx.tcx(), t); let unit_ty = ty::sequence_element_type(cx.tcx(), t);
let (base, len) = tvec::get_fixed_base_and_byte_len(cx, av, unit_ty, n); let (base, len) = tvec::get_fixed_base_and_byte_len(cx, av, unit_ty, n);
@ -870,7 +897,7 @@ pub fn trans_external_path(ccx: &CrateContext, did: ast::DefId, t: ty::t) -> Val
ty::ty_bare_fn(ref fn_ty) => { ty::ty_bare_fn(ref fn_ty) => {
match fn_ty.abi.for_target(ccx.sess().targ_cfg.os, match fn_ty.abi.for_target(ccx.sess().targ_cfg.os,
ccx.sess().targ_cfg.arch) { ccx.sess().targ_cfg.arch) {
Some(Rust) => { Some(Rust) | Some(RustCall) => {
get_extern_rust_fn(ccx, t, name.as_slice(), did) get_extern_rust_fn(ccx, t, name.as_slice(), did)
} }
Some(RustIntrinsic) => { Some(RustIntrinsic) => {
@ -1150,13 +1177,11 @@ pub fn arrayalloca(cx: &Block, ty: Type, v: ValueRef) -> ValueRef {
// slot where the return value of the function must go. // slot where the return value of the function must go.
pub fn make_return_pointer(fcx: &FunctionContext, output_type: ty::t) pub fn make_return_pointer(fcx: &FunctionContext, output_type: ty::t)
-> ValueRef { -> ValueRef {
unsafe { if type_of::return_uses_outptr(fcx.ccx, output_type) {
if type_of::return_uses_outptr(fcx.ccx, output_type) { get_param(fcx.llfn, 0)
llvm::LLVMGetParam(fcx.llfn, 0) } else {
} else { let lloutputtype = type_of::type_of(fcx.ccx, output_type);
let lloutputtype = type_of::type_of(fcx.ccx, output_type); AllocaFcx(fcx, lloutputtype, "__make_return_pointer")
AllocaFcx(fcx, lloutputtype, "__make_return_pointer")
}
} }
} }
@ -1213,9 +1238,7 @@ pub fn new_fn_ctxt<'a>(ccx: &'a CrateContext,
}; };
if has_env { if has_env {
fcx.llenv = Some(unsafe { fcx.llenv = Some(get_param(fcx.llfn, fcx.env_arg_pos() as c_uint))
llvm::LLVMGetParam(fcx.llfn, fcx.env_arg_pos() as c_uint)
});
} }
fcx fcx
@ -1280,16 +1303,85 @@ pub fn create_datums_for_fn_args(fcx: &FunctionContext,
-> Vec<RvalueDatum> { -> Vec<RvalueDatum> {
let _icx = push_ctxt("create_datums_for_fn_args"); let _icx = push_ctxt("create_datums_for_fn_args");
// Return an array wrapping the ValueRefs that we get from // Return an array wrapping the ValueRefs that we get from `get_param` for
// llvm::LLVMGetParam for each argument into datums. // each argument into datums.
arg_tys.iter().enumerate().map(|(i, &arg_ty)| { arg_tys.iter().enumerate().map(|(i, &arg_ty)| {
let llarg = unsafe { let llarg = get_param(fcx.llfn, fcx.arg_pos(i) as c_uint);
llvm::LLVMGetParam(fcx.llfn, fcx.arg_pos(i) as c_uint)
};
datum::Datum::new(llarg, arg_ty, arg_kind(fcx, arg_ty)) datum::Datum::new(llarg, arg_ty, arg_kind(fcx, arg_ty))
}).collect() }).collect()
} }
/// Creates rvalue datums for each of the incoming function arguments and
/// tuples the arguments. These will later be stored into appropriate lvalue
/// datums.
fn create_datums_for_fn_args_under_call_abi<
'a>(
mut bcx: &'a Block<'a>,
arg_scope: cleanup::CustomScopeIndex,
arg_tys: &[ty::t])
-> Vec<RvalueDatum> {
let mut result = Vec::new();
for (i, &arg_ty) in arg_tys.iter().enumerate() {
if i < arg_tys.len() - 1 {
// Regular argument.
let llarg = get_param(bcx.fcx.llfn, bcx.fcx.arg_pos(i) as c_uint);
result.push(datum::Datum::new(llarg, arg_ty, arg_kind(bcx.fcx,
arg_ty)));
continue
}
// This is the last argument. Tuple it.
match ty::get(arg_ty).sty {
ty::ty_tup(ref tupled_arg_tys) => {
let tuple_args_scope_id = cleanup::CustomScope(arg_scope);
let tuple =
unpack_datum!(bcx,
datum::lvalue_scratch_datum(bcx,
arg_ty,
"tupled_args",
false,
tuple_args_scope_id,
(),
|(),
mut bcx,
llval| {
for (j, &tupled_arg_ty) in
tupled_arg_tys.iter().enumerate() {
let llarg =
get_param(bcx.fcx.llfn,
bcx.fcx.arg_pos(i + j) as c_uint);
let lldest = GEPi(bcx, llval, [0, j]);
let datum = datum::Datum::new(
llarg,
tupled_arg_ty,
arg_kind(bcx.fcx, tupled_arg_ty));
bcx = datum.store_to(bcx, lldest);
}
bcx
}));
let tuple = unpack_datum!(bcx,
tuple.to_expr_datum()
.to_rvalue_datum(bcx,
"argtuple"));
result.push(tuple);
}
ty::ty_nil => {
let mode = datum::Rvalue::new(datum::ByValue);
result.push(datum::Datum::new(C_nil(bcx.ccx()),
ty::mk_nil(),
mode))
}
_ => {
bcx.tcx().sess.bug("last argument of a function with \
`rust-call` ABI isn't a tuple?!")
}
};
}
result
}
fn copy_args_to_allocas<'a>(fcx: &FunctionContext<'a>, fn copy_args_to_allocas<'a>(fcx: &FunctionContext<'a>,
arg_scope: cleanup::CustomScopeIndex, arg_scope: cleanup::CustomScopeIndex,
bcx: &'a Block<'a>, bcx: &'a Block<'a>,
@ -1322,6 +1414,59 @@ fn copy_args_to_allocas<'a>(fcx: &FunctionContext<'a>,
bcx bcx
} }
fn copy_unboxed_closure_args_to_allocas<'a>(
mut bcx: &'a Block<'a>,
arg_scope: cleanup::CustomScopeIndex,
args: &[ast::Arg],
arg_datums: Vec<RvalueDatum>,
monomorphized_arg_types: &[ty::t])
-> &'a Block<'a> {
let _icx = push_ctxt("copy_unboxed_closure_args_to_allocas");
let arg_scope_id = cleanup::CustomScope(arg_scope);
assert_eq!(arg_datums.len(), 1);
let arg_datum = arg_datums.move_iter().next().unwrap();
// Untuple the rest of the arguments.
let tuple_datum =
unpack_datum!(bcx,
arg_datum.to_lvalue_datum_in_scope(bcx,
"argtuple",
arg_scope_id));
let empty = Vec::new();
let untupled_arg_types = match ty::get(monomorphized_arg_types[0]).sty {
ty::ty_tup(ref types) => types.as_slice(),
ty::ty_nil => empty.as_slice(),
_ => {
bcx.tcx().sess.span_bug(args[0].pat.span,
"first arg to `rust-call` ABI function \
wasn't a tuple?!")
}
};
for j in range(0, args.len()) {
let tuple_element_type = untupled_arg_types[j];
let tuple_element_datum =
tuple_datum.get_element(tuple_element_type,
|llval| GEPi(bcx, llval, [0, j]));
let tuple_element_datum = tuple_element_datum.to_expr_datum();
let tuple_element_datum =
unpack_datum!(bcx,
tuple_element_datum.to_rvalue_datum(bcx,
"arg"));
bcx = _match::store_arg(bcx,
args[j].pat,
tuple_element_datum,
arg_scope_id);
if bcx.fcx.ccx.sess().opts.debuginfo == FullDebugInfo {
debuginfo::create_argument_metadata(bcx, &args[j]);
}
}
bcx
}
// Ties up the llstaticallocas -> llloadenv -> lltop edges, // Ties up the llstaticallocas -> llloadenv -> lltop edges,
// and builds the return block. // and builds the return block.
pub fn finish_fn<'a>(fcx: &'a FunctionContext<'a>, pub fn finish_fn<'a>(fcx: &'a FunctionContext<'a>,
@ -1379,6 +1524,12 @@ pub fn build_return_block(fcx: &FunctionContext, ret_cx: &Block, retty: ty::t) {
Ret(ret_cx, retval); Ret(ret_cx, retval);
} }
#[deriving(Clone, Eq, PartialEq)]
pub enum IsUnboxedClosureFlag {
NotUnboxedClosure,
IsUnboxedClosure,
}
// trans_closure: Builds an LLVM function out of a source function. // trans_closure: Builds an LLVM function out of a source function.
// If the function closes over its environment a closure will be // If the function closes over its environment a closure will be
// returned. // returned.
@ -1389,7 +1540,11 @@ pub fn trans_closure(ccx: &CrateContext,
param_substs: &param_substs, param_substs: &param_substs,
id: ast::NodeId, id: ast::NodeId,
_attributes: &[ast::Attribute], _attributes: &[ast::Attribute],
arg_types: Vec<ty::t>,
output_type: ty::t, output_type: ty::t,
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>| -> &'a Block<'a>) {
ccx.stats.n_closures.set(ccx.stats.n_closures.get() + 1); ccx.stats.n_closures.set(ccx.stats.n_closures.get() + 1);
@ -1399,11 +1554,6 @@ pub fn trans_closure(ccx: &CrateContext,
debug!("trans_closure(..., param_substs={})", debug!("trans_closure(..., param_substs={})",
param_substs.repr(ccx.tcx())); param_substs.repr(ccx.tcx()));
let has_env = match ty::get(ty::node_id_to_type(ccx.tcx(), id)).sty {
ty::ty_closure(_) => true,
_ => false
};
let arena = TypedArena::new(); let arena = TypedArena::new();
let fcx = new_fn_ctxt(ccx, let fcx = new_fn_ctxt(ccx,
llfndecl, llfndecl,
@ -1421,14 +1571,44 @@ pub fn trans_closure(ccx: &CrateContext,
let block_ty = node_id_type(bcx, body.id); let block_ty = node_id_type(bcx, body.id);
// Set up arguments to the function. // Set up arguments to the function.
let arg_tys = ty::ty_fn_args(node_id_type(bcx, id)); let monomorphized_arg_types =
let arg_datums = create_datums_for_fn_args(&fcx, arg_tys.as_slice()); arg_types.iter()
.map(|at| monomorphize_type(bcx, *at))
.collect::<Vec<_>>();
for monomorphized_arg_type in monomorphized_arg_types.iter() {
debug!("trans_closure: monomorphized_arg_type: {}",
ty_to_string(ccx.tcx(), *monomorphized_arg_type));
}
debug!("trans_closure: function lltype: {}",
bcx.fcx.ccx.tn.val_to_string(bcx.fcx.llfn));
bcx = copy_args_to_allocas(&fcx, let arg_datums = if abi != RustCall {
arg_scope, create_datums_for_fn_args(&fcx,
bcx, monomorphized_arg_types.as_slice())
decl.inputs.as_slice(), } else {
arg_datums); create_datums_for_fn_args_under_call_abi(
bcx,
arg_scope,
monomorphized_arg_types.as_slice())
};
bcx = match is_unboxed_closure {
NotUnboxedClosure => {
copy_args_to_allocas(&fcx,
arg_scope,
bcx,
decl.inputs.as_slice(),
arg_datums)
}
IsUnboxedClosure => {
copy_unboxed_closure_args_to_allocas(
bcx,
arg_scope,
decl.inputs.as_slice(),
arg_datums,
monomorphized_arg_types.as_slice())
}
};
bcx = maybe_load_env(bcx); bcx = maybe_load_env(bcx);
@ -1488,9 +1668,23 @@ pub fn trans_fn(ccx: &CrateContext,
let _s = StatRecorder::new(ccx, ccx.tcx.map.path_to_string(id).to_string()); let _s = StatRecorder::new(ccx, ccx.tcx.map.path_to_string(id).to_string());
debug!("trans_fn(param_substs={})", param_substs.repr(ccx.tcx())); debug!("trans_fn(param_substs={})", param_substs.repr(ccx.tcx()));
let _icx = push_ctxt("trans_fn"); let _icx = push_ctxt("trans_fn");
let output_type = ty::ty_fn_ret(ty::node_id_to_type(ccx.tcx(), id)); let fn_ty = ty::node_id_to_type(ccx.tcx(), id);
trans_closure(ccx, decl, body, llfndecl, let arg_types = ty::ty_fn_args(fn_ty);
param_substs, id, attrs, output_type, |bcx| bcx); let output_type = ty::ty_fn_ret(fn_ty);
let abi = ty::ty_fn_abi(fn_ty);
trans_closure(ccx,
decl,
body,
llfndecl,
param_substs,
id,
attrs,
arg_types,
output_type,
abi,
false,
NotUnboxedClosure,
|bcx| bcx);
} }
pub fn trans_enum_variant(ccx: &CrateContext, pub fn trans_enum_variant(ccx: &CrateContext,
@ -1657,7 +1851,7 @@ pub fn trans_item(ccx: &CrateContext, item: &ast::Item) {
let _icx = push_ctxt("trans_item"); let _icx = push_ctxt("trans_item");
match item.node { match item.node {
ast::ItemFn(ref decl, _fn_style, abi, ref generics, ref body) => { ast::ItemFn(ref decl, _fn_style, abi, ref generics, ref body) => {
if abi != Rust { if abi != Rust {
let llfndecl = get_item_val(ccx, item.id); let llfndecl = get_item_val(ccx, item.id);
foreign::trans_rust_fn_with_foreign_abi( foreign::trans_rust_fn_with_foreign_abi(
ccx, &**decl, &**body, item.attrs.as_slice(), llfndecl, item.id); ccx, &**decl, &**body, item.attrs.as_slice(), llfndecl, item.id);
@ -1792,7 +1986,7 @@ fn register_fn(ccx: &CrateContext,
-> ValueRef { -> ValueRef {
match ty::get(node_type).sty { match ty::get(node_type).sty {
ty::ty_bare_fn(ref f) => { ty::ty_bare_fn(ref f) => {
assert!(f.abi == Rust); assert!(f.abi == Rust || f.abi == RustCall);
} }
_ => fail!("expected bare rust fn") _ => fail!("expected bare rust fn")
}; };
@ -1802,15 +1996,30 @@ fn register_fn(ccx: &CrateContext,
llfn llfn
} }
pub fn get_fn_llvm_attributes(ccx: &CrateContext, fn_ty: ty::t) -> Vec<(uint, u64)> { pub fn get_fn_llvm_attributes(ccx: &CrateContext, fn_ty: ty::t)
-> Vec<(uint, u64)> {
use middle::ty::{BrAnon, ReLateBound}; use middle::ty::{BrAnon, ReLateBound};
let (fn_sig, has_env) = match ty::get(fn_ty).sty { let (fn_sig, abi, has_env) = match ty::get(fn_ty).sty {
ty::ty_closure(ref f) => (f.sig.clone(), true), ty::ty_closure(ref f) => (f.sig.clone(), f.abi, true),
ty::ty_bare_fn(ref f) => (f.sig.clone(), false), 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);
(function_type.sig.clone(), RustCall, true)
}
_ => fail!("expected closure or function.") _ => fail!("expected closure or function.")
}; };
// These have an odd calling convention, so we skip them for now.
//
// FIXME(pcwalton): We don't have to skip them; just untuple the result.
if abi == RustCall {
return Vec::new()
}
// Since index 0 is the return value of the llvm func, we start // Since index 0 is the return value of the llvm func, we start
// at either 1 or 2 depending on whether there's an env slot or not // at either 1 or 2 depending on whether there's an env slot or not
let mut first_arg_offset = if has_env { 2 } else { 1 }; let mut first_arg_offset = if has_env { 2 } else { 1 };
@ -1986,16 +2195,16 @@ pub fn create_entry_wrapper(ccx: &CrateContext,
vec!( vec!(
opaque_rust_main, opaque_rust_main,
llvm::LLVMGetParam(llfn, 0), get_param(llfn, 0),
llvm::LLVMGetParam(llfn, 1) get_param(llfn, 1)
) )
}; };
(start_fn, args) (start_fn, args)
} else { } else {
debug!("using user-defined start fn"); debug!("using user-defined start fn");
let args = vec!( let args = vec!(
llvm::LLVMGetParam(llfn, 0 as c_uint), get_param(llfn, 0 as c_uint),
llvm::LLVMGetParam(llfn, 1 as c_uint) get_param(llfn, 1 as c_uint)
); );
(rust_main, args) (rust_main, args)

View File

@ -19,18 +19,20 @@
use arena::TypedArena; use arena::TypedArena;
use back::abi; use back::abi;
use back::link; use back::link;
use llvm::{ValueRef, get_param};
use llvm; use llvm;
use llvm::ValueRef;
use metadata::csearch; use metadata::csearch;
use middle::def; use middle::def;
use middle::subst; use middle::subst;
use middle::subst::{Subst, VecPerParamSpace}; use middle::subst::{Subst, VecPerParamSpace};
use middle::trans::adt;
use middle::trans::base; use middle::trans::base;
use middle::trans::base::*; use middle::trans::base::*;
use middle::trans::build::*; use middle::trans::build::*;
use middle::trans::callee; use middle::trans::callee;
use middle::trans::cleanup; use middle::trans::cleanup;
use middle::trans::cleanup::CleanupMethods; use middle::trans::cleanup::CleanupMethods;
use middle::trans::closure;
use middle::trans::common; use middle::trans::common;
use middle::trans::common::*; use middle::trans::common::*;
use middle::trans::datum::*; use middle::trans::datum::*;
@ -74,7 +76,7 @@ pub enum CalleeData {
pub struct Callee<'a> { pub struct Callee<'a> {
pub bcx: &'a Block<'a>, pub bcx: &'a Block<'a>,
pub data: CalleeData pub data: CalleeData,
} }
fn trans<'a>(bcx: &'a Block<'a>, expr: &ast::Expr) -> Callee<'a> { fn trans<'a>(bcx: &'a Block<'a>, expr: &ast::Expr) -> Callee<'a> {
@ -97,12 +99,18 @@ fn trans<'a>(bcx: &'a Block<'a>, expr: &ast::Expr) -> Callee<'a> {
match ty::get(datum.ty).sty { match ty::get(datum.ty).sty {
ty::ty_bare_fn(..) => { ty::ty_bare_fn(..) => {
let llval = datum.to_llscalarish(bcx); let llval = datum.to_llscalarish(bcx);
return Callee {bcx: bcx, data: Fn(llval)}; return Callee {
bcx: bcx,
data: Fn(llval),
};
} }
ty::ty_closure(..) => { ty::ty_closure(..) => {
let datum = unpack_datum!( let datum = unpack_datum!(
bcx, datum.to_lvalue_datum(bcx, "callee", expr.id)); bcx, datum.to_lvalue_datum(bcx, "callee", expr.id));
return Callee {bcx: bcx, data: Closure(datum)}; return Callee {
bcx: bcx,
data: Closure(datum),
};
} }
_ => { _ => {
bcx.tcx().sess.span_bug( bcx.tcx().sess.span_bug(
@ -115,7 +123,10 @@ fn trans<'a>(bcx: &'a Block<'a>, expr: &ast::Expr) -> Callee<'a> {
} }
fn fn_callee<'a>(bcx: &'a Block<'a>, llfn: ValueRef) -> Callee<'a> { fn fn_callee<'a>(bcx: &'a Block<'a>, llfn: ValueRef) -> Callee<'a> {
return Callee {bcx: bcx, data: Fn(llfn)}; return Callee {
bcx: bcx,
data: Fn(llfn),
};
} }
fn trans_def<'a>(bcx: &'a Block<'a>, def: def::Def, ref_expr: &ast::Expr) fn trans_def<'a>(bcx: &'a Block<'a>, def: def::Def, ref_expr: &ast::Expr)
@ -206,9 +217,14 @@ fn trans_fn_ref_with_vtables_to_callee<'a>(bcx: &'a Block<'a>,
substs: subst::Substs, substs: subst::Substs,
vtables: typeck::vtable_res) vtables: typeck::vtable_res)
-> Callee<'a> { -> Callee<'a> {
Callee {bcx: bcx, Callee {
data: Fn(trans_fn_ref_with_vtables(bcx, def_id, ExprId(ref_id), bcx: bcx,
substs, vtables))} data: Fn(trans_fn_ref_with_vtables(bcx,
def_id,
ExprId(ref_id),
substs,
vtables)),
}
} }
fn resolve_default_method_vtables(bcx: &Block, fn resolve_default_method_vtables(bcx: &Block,
@ -304,9 +320,7 @@ pub fn trans_unboxing_shim(bcx: &Block,
let boxed_self_kind = arg_kind(&fcx, boxed_self_type); let boxed_self_kind = arg_kind(&fcx, boxed_self_type);
// Create a datum for self. // Create a datum for self.
let llboxedself = unsafe { let llboxedself = get_param(fcx.llfn, fcx.arg_pos(0) as u32);
llvm::LLVMGetParam(fcx.llfn, fcx.arg_pos(0) as u32)
};
let llboxedself = Datum::new(llboxedself, let llboxedself = Datum::new(llboxedself,
boxed_self_type, boxed_self_type,
boxed_self_kind); boxed_self_kind);
@ -340,9 +354,7 @@ pub fn trans_unboxing_shim(bcx: &Block,
// Now call the function. // Now call the function.
let mut llshimmedargs = vec!(llself.val); let mut llshimmedargs = vec!(llself.val);
for i in range(1, arg_types.len()) { for i in range(1, arg_types.len()) {
llshimmedargs.push(unsafe { llshimmedargs.push(get_param(fcx.llfn, fcx.arg_pos(i) as u32));
llvm::LLVMGetParam(fcx.llfn, fcx.arg_pos(i) as u32)
});
} }
bcx = trans_call_inner(bcx, bcx = trans_call_inner(bcx,
None, None,
@ -402,9 +414,6 @@ pub fn trans_fn_ref_with_vtables(
assert!(substs.types.all(|t| !ty::type_needs_infer(*t))); assert!(substs.types.all(|t| !ty::type_needs_infer(*t)));
// Polytype of the function item (may have type params)
let fn_tpt = ty::lookup_item_type(tcx, def_id);
// Load the info for the appropriate trait if necessary. // Load the info for the appropriate trait if necessary.
match ty::trait_of_method(tcx, def_id) { match ty::trait_of_method(tcx, def_id) {
None => {} None => {}
@ -465,6 +474,12 @@ pub fn trans_fn_ref_with_vtables(
} }
}; };
// If this is an unboxed closure, redirect to it.
match closure::get_or_create_declaration_if_unboxed_closure(ccx, def_id) {
None => {}
Some(llfn) => return llfn,
}
// Check whether this fn has an inlined copy and, if so, redirect // Check whether this fn has an inlined copy and, if so, redirect
// def_id to the local id of the inlined copy. // def_id to the local id of the inlined copy.
let def_id = { let def_id = {
@ -509,6 +524,9 @@ pub fn trans_fn_ref_with_vtables(
return val; return val;
} }
// Polytype of the function item (may have type params)
let fn_tpt = ty::lookup_item_type(tcx, def_id);
// Find the actual function pointer. // Find the actual function pointer.
let mut val = { let mut val = {
if def_id.krate == ast::LOCAL_CRATE { if def_id.krate == ast::LOCAL_CRATE {
@ -546,7 +564,10 @@ pub fn trans_fn_ref_with_vtables(
let llty = type_of::type_of_fn_from_ty(ccx, fn_tpt.ty); let llty = type_of::type_of_fn_from_ty(ccx, fn_tpt.ty);
let llptrty = llty.ptr_to(); let llptrty = llty.ptr_to();
if val_ty(val) != llptrty { if val_ty(val) != llptrty {
debug!("trans_fn_ref_with_vtables(): casting pointer!");
val = BitCast(bcx, val, llptrty); val = BitCast(bcx, val, llptrty);
} else {
debug!("trans_fn_ref_with_vtables(): not casting pointer!");
} }
val val
@ -660,7 +681,7 @@ pub fn trans_call_inner<'a>(
let (abi, ret_ty) = match ty::get(callee_ty).sty { let (abi, ret_ty) = match ty::get(callee_ty).sty {
ty::ty_bare_fn(ref f) => (f.abi, f.sig.output), ty::ty_bare_fn(ref f) => (f.abi, f.sig.output),
ty::ty_closure(ref f) => (synabi::Rust, f.sig.output), ty::ty_closure(ref f) => (f.abi, f.sig.output),
_ => fail!("expected bare rust fn or closure in trans_call_inner") _ => fail!("expected bare rust fn or closure in trans_call_inner")
}; };
@ -723,7 +744,7 @@ pub fn trans_call_inner<'a>(
// and done, either the return value of the function will have been // and done, either the return value of the function will have been
// written in opt_llretslot (if it is Some) or `llresult` will be // written in opt_llretslot (if it is Some) or `llresult` will be
// set appropriately (otherwise). // set appropriately (otherwise).
if abi == synabi::Rust { if abi == synabi::Rust || abi == synabi::RustCall {
let mut llargs = Vec::new(); let mut llargs = Vec::new();
// Push the out-pointer if we use an out-pointer for this // Push the out-pointer if we use an out-pointer for this
@ -742,9 +763,13 @@ pub fn trans_call_inner<'a>(
} }
// Push the arguments. // Push the arguments.
bcx = trans_args(bcx, args, callee_ty, &mut llargs, bcx = trans_args(bcx,
args,
callee_ty,
&mut llargs,
cleanup::CustomScope(arg_cleanup_scope), cleanup::CustomScope(arg_cleanup_scope),
llself.is_some()); llself.is_some(),
abi);
fcx.pop_custom_cleanup_scope(arg_cleanup_scope); fcx.pop_custom_cleanup_scope(arg_cleanup_scope);
@ -779,8 +804,13 @@ pub fn trans_call_inner<'a>(
ArgExprs(a) => a.iter().map(|x| expr_ty(bcx, &**x)).collect(), ArgExprs(a) => a.iter().map(|x| expr_ty(bcx, &**x)).collect(),
_ => fail!("expected arg exprs.") _ => fail!("expected arg exprs.")
}; };
bcx = trans_args(bcx, args, callee_ty, &mut llargs, bcx = trans_args(bcx,
cleanup::CustomScope(arg_cleanup_scope), false); args,
callee_ty,
&mut llargs,
cleanup::CustomScope(arg_cleanup_scope),
false,
abi);
fcx.pop_custom_cleanup_scope(arg_cleanup_scope); fcx.pop_custom_cleanup_scope(arg_cleanup_scope);
bcx = foreign::trans_native_call(bcx, callee_ty, bcx = foreign::trans_native_call(bcx, callee_ty,
llfn, opt_llretslot.unwrap(), llfn, opt_llretslot.unwrap(),
@ -821,15 +851,130 @@ pub enum CallArgs<'a> {
// is the left-hand-side and `rhs/rhs_id` is the datum/expr-id of // is the left-hand-side and `rhs/rhs_id` is the datum/expr-id of
// the right-hand-side (if any). // the right-hand-side (if any).
ArgOverloadedOp(Datum<Expr>, Option<(Datum<Expr>, ast::NodeId)>), ArgOverloadedOp(Datum<Expr>, Option<(Datum<Expr>, ast::NodeId)>),
// Supply value of arguments as a list of expressions that must be
// translated, for overloaded call operators.
ArgOverloadedCall(&'a [Gc<ast::Expr>]),
} }
pub fn trans_args<'a>(cx: &'a Block<'a>, fn trans_args_under_call_abi<'a>(
args: CallArgs, mut bcx: &'a Block<'a>,
fn_ty: ty::t, arg_exprs: &[Gc<ast::Expr>],
llargs: &mut Vec<ValueRef> , fn_ty: ty::t,
arg_cleanup_scope: cleanup::ScopeId, llargs: &mut Vec<ValueRef>,
ignore_self: bool) arg_cleanup_scope: cleanup::ScopeId,
-> &'a Block<'a> { ignore_self: bool)
-> &'a Block<'a> {
// Translate the `self` argument first.
let arg_tys = ty::ty_fn_args(fn_ty);
if !ignore_self {
let arg_datum = unpack_datum!(bcx, expr::trans(bcx, &*arg_exprs[0]));
llargs.push(unpack_result!(bcx, {
trans_arg_datum(bcx,
*arg_tys.get(0),
arg_datum,
arg_cleanup_scope,
DontAutorefArg)
}))
}
// Now untuple the rest of the arguments.
let tuple_expr = arg_exprs[1];
let tuple_type = node_id_type(bcx, tuple_expr.id);
match ty::get(tuple_type).sty {
ty::ty_tup(ref field_types) => {
let tuple_datum = unpack_datum!(bcx,
expr::trans(bcx, &*tuple_expr));
let tuple_lvalue_datum =
unpack_datum!(bcx,
tuple_datum.to_lvalue_datum(bcx,
"args",
tuple_expr.id));
let repr = adt::represent_type(bcx.ccx(), tuple_type);
let repr_ptr = &*repr;
for i in range(0, field_types.len()) {
let arg_datum = tuple_lvalue_datum.get_element(
*field_types.get(i),
|srcval| {
adt::trans_field_ptr(bcx, repr_ptr, srcval, 0, i)
});
let arg_datum = arg_datum.to_expr_datum();
let arg_datum =
unpack_datum!(bcx, arg_datum.to_rvalue_datum(bcx, "arg"));
let arg_datum =
unpack_datum!(bcx, arg_datum.to_appropriate_datum(bcx));
llargs.push(arg_datum.add_clean(bcx.fcx, arg_cleanup_scope));
}
}
ty::ty_nil => {}
_ => {
bcx.sess().span_bug(tuple_expr.span,
"argument to `.call()` wasn't a tuple?!")
}
};
bcx
}
fn trans_overloaded_call_args<'a>(
mut bcx: &'a Block<'a>,
arg_exprs: &[Gc<ast::Expr>],
fn_ty: ty::t,
llargs: &mut Vec<ValueRef>,
arg_cleanup_scope: cleanup::ScopeId,
ignore_self: bool)
-> &'a Block<'a> {
// Translate the `self` argument first.
let arg_tys = ty::ty_fn_args(fn_ty);
if !ignore_self {
let arg_datum = unpack_datum!(bcx, expr::trans(bcx, &*arg_exprs[0]));
llargs.push(unpack_result!(bcx, {
trans_arg_datum(bcx,
*arg_tys.get(0),
arg_datum,
arg_cleanup_scope,
DontAutorefArg)
}))
}
// Now untuple the rest of the arguments.
let tuple_type = *arg_tys.get(1);
match ty::get(tuple_type).sty {
ty::ty_tup(ref field_types) => {
for (i, &field_type) in field_types.iter().enumerate() {
let arg_datum =
unpack_datum!(bcx, expr::trans(bcx, &*arg_exprs[i + 1]));
llargs.push(unpack_result!(bcx, {
trans_arg_datum(bcx,
field_type,
arg_datum,
arg_cleanup_scope,
DontAutorefArg)
}))
}
}
ty::ty_nil => {}
_ => {
bcx.sess().span_bug(arg_exprs[0].span,
"argument to `.call()` wasn't a tuple?!")
}
};
bcx
}
pub fn trans_args<'a>(
cx: &'a Block<'a>,
args: CallArgs,
fn_ty: ty::t,
llargs: &mut Vec<ValueRef> ,
arg_cleanup_scope: cleanup::ScopeId,
ignore_self: bool,
abi: synabi::Abi)
-> &'a Block<'a> {
debug!("trans_args(abi={})", abi);
let _icx = push_ctxt("trans_args"); let _icx = push_ctxt("trans_args");
let arg_tys = ty::ty_fn_args(fn_ty); let arg_tys = ty::ty_fn_args(fn_ty);
let variadic = ty::fn_is_variadic(fn_ty); let variadic = ty::fn_is_variadic(fn_ty);
@ -841,6 +986,17 @@ pub fn trans_args<'a>(cx: &'a Block<'a>,
// to cast her view of the arguments to the caller's view. // to cast her view of the arguments to the caller's view.
match args { match args {
ArgExprs(arg_exprs) => { ArgExprs(arg_exprs) => {
if abi == synabi::RustCall {
// This is only used for direct calls to the `call`,
// `call_mut` or `call_once` functions.
return trans_args_under_call_abi(cx,
arg_exprs,
fn_ty,
llargs,
arg_cleanup_scope,
ignore_self)
}
let num_formal_args = arg_tys.len(); let num_formal_args = arg_tys.len();
for (i, arg_expr) in arg_exprs.iter().enumerate() { for (i, arg_expr) in arg_exprs.iter().enumerate() {
if i == 0 && ignore_self { if i == 0 && ignore_self {
@ -861,6 +1017,14 @@ pub fn trans_args<'a>(cx: &'a Block<'a>,
})); }));
} }
} }
ArgOverloadedCall(arg_exprs) => {
return trans_overloaded_call_args(cx,
arg_exprs,
fn_ty,
llargs,
arg_cleanup_scope,
ignore_self)
}
ArgOverloadedOp(lhs, rhs) => { ArgOverloadedOp(lhs, rhs) => {
assert!(!variadic); assert!(!variadic);

View File

@ -16,6 +16,7 @@ use llvm::ValueRef;
use middle::def; use middle::def;
use middle::freevars; use middle::freevars;
use middle::lang_items::ClosureExchangeMallocFnLangItem; use middle::lang_items::ClosureExchangeMallocFnLangItem;
use middle::trans::adt;
use middle::trans::base::*; use middle::trans::base::*;
use middle::trans::build::*; use middle::trans::build::*;
use middle::trans::common::*; use middle::trans::common::*;
@ -31,6 +32,7 @@ use util::ppaux::ty_to_string;
use arena::TypedArena; use arena::TypedArena;
use syntax::ast; use syntax::ast;
use syntax::ast_util;
// ___Good to know (tm)__________________________________________________ // ___Good to know (tm)__________________________________________________
// //
@ -285,7 +287,6 @@ fn load_environment<'a>(bcx: &'a Block<'a>,
let def_id = freevar.def.def_id(); let def_id = freevar.def.def_id();
bcx.fcx.llupvars.borrow_mut().insert(def_id.node, upvarptr); bcx.fcx.llupvars.borrow_mut().insert(def_id.node, upvarptr);
for &env_pointer_alloca in env_pointer_alloca.iter() { for &env_pointer_alloca in env_pointer_alloca.iter() {
debuginfo::create_captured_var_metadata( debuginfo::create_captured_var_metadata(
bcx, bcx,
@ -303,6 +304,26 @@ fn load_environment<'a>(bcx: &'a Block<'a>,
bcx bcx
} }
fn load_unboxed_closure_environment<'a>(
bcx: &'a Block<'a>,
freevars: &Vec<freevars::freevar_entry>)
-> &'a Block<'a> {
let _icx = push_ctxt("closure::load_environment");
if freevars.len() == 0 {
return bcx
}
let llenv = 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);
}
bcx
}
fn fill_fn_pair(bcx: &Block, pair: ValueRef, llfn: ValueRef, llenvptr: ValueRef) { fn fill_fn_pair(bcx: &Block, pair: ValueRef, llfn: ValueRef, llenvptr: ValueRef) {
Store(bcx, llfn, GEPi(bcx, pair, [0u, abi::fn_field_code])); Store(bcx, llfn, GEPi(bcx, pair, [0u, abi::fn_field_code]));
let llenvptr = PointerCast(bcx, llenvptr, Type::i8p(bcx.ccx())); let llenvptr = PointerCast(bcx, llenvptr, Type::i8p(bcx.ccx()));
@ -352,20 +373,149 @@ pub fn trans_expr_fn<'a>(
let freevar_mode = freevars::get_capture_mode(tcx, id); let freevar_mode = freevars::get_capture_mode(tcx, id);
let freevars: Vec<freevars::freevar_entry> = let freevars: Vec<freevars::freevar_entry> =
freevars::with_freevars( freevars::with_freevars(tcx,
tcx, id, id,
|fv| fv.iter().map(|&fv| fv).collect()); |fv| fv.iter().map(|&fv| fv).collect());
let ClosureResult {llbox, cdata_ty, bcx} = let ClosureResult {
build_closure(bcx, freevar_mode, &freevars, store); llbox,
trans_closure(ccx, decl, body, llfn, cdata_ty,
bcx.fcx.param_substs, id, bcx
[], ty::ty_fn_ret(fty), } = build_closure(bcx, freevar_mode, &freevars, store);
trans_closure(ccx,
decl,
body,
llfn,
bcx.fcx.param_substs,
id,
[],
ty::ty_fn_args(fty),
ty::ty_fn_ret(fty),
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); fill_fn_pair(bcx, dest_addr, llfn, llbox);
bcx bcx
} }
/// Returns the LLVM function declaration for an unboxed closure, creating it
/// if necessary. If the ID does not correspond to a closure ID, returns None.
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) {
// Not an unboxed closure.
return None
}
match ccx.unboxed_closure_vals.borrow().find(&closure_id) {
Some(llfn) => {
debug!("get_or_create_declaration_if_unboxed_closure(): found \
closure");
return Some(*llfn)
}
None => {}
}
let function_type = ty::mk_unboxed_closure(&ccx.tcx, closure_id);
let symbol = ccx.tcx.map.with_path(closure_id.node, |path| {
mangle_internal_name_by_path_and_seq(path, "unboxed_closure")
});
let llfn = decl_internal_rust_fn(ccx, function_type, symbol.as_slice());
// set an inline hint for all closures
set_inline_hint(llfn);
debug!("get_or_create_declaration_if_unboxed_closure(): inserting new \
closure {} (type {})",
closure_id,
ccx.tn.type_to_string(val_ty(llfn)));
ccx.unboxed_closure_vals.borrow_mut().insert(closure_id, llfn);
Some(llfn)
}
pub fn trans_unboxed_closure<'a>(
mut bcx: &'a Block<'a>,
decl: &ast::FnDecl,
body: &ast::Block,
id: ast::NodeId,
dest: expr::Dest)
-> &'a Block<'a> {
let _icx = push_ctxt("closure::trans_unboxed_closure");
debug!("trans_unboxed_closure()");
let closure_id = ast_util::local_def(id);
let llfn = get_or_create_declaration_if_unboxed_closure(
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 function_type = ty::mk_closure(bcx.tcx(), function_type);
let freevars: Vec<freevars::freevar_entry> =
freevars::with_freevars(bcx.tcx(),
id,
|fv| fv.iter().map(|&fv| fv).collect());
let freevars_ptr = &freevars;
trans_closure(bcx.ccx(),
decl,
body,
llfn,
bcx.fcx.param_substs,
id,
[],
ty::ty_fn_args(function_type),
ty::ty_fn_ret(function_type),
ty::ty_fn_abi(function_type),
true,
IsUnboxedClosure,
|bcx| load_unboxed_closure_environment(bcx, freevars_ptr));
// 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
// `Ignore`) and we must still generate the closure body.
let dest_addr = match dest {
expr::SaveIn(p) => p,
expr::Ignore => {
debug!("trans_unboxed_closure() ignoring result");
return bcx
}
};
let repr = adt::represent_type(bcx.ccx(), node_id_type(bcx, id));
// Create the closure.
adt::trans_start_init(bcx, &*repr, dest_addr, 0);
for freevar in freevars_ptr.iter() {
let datum = expr::trans_local_var(bcx, freevar.def);
let upvar_slot_dest = adt::trans_field_ptr(bcx,
&*repr,
dest_addr,
0,
0);
bcx = datum.store_to(bcx, upvar_slot_dest);
}
bcx
}
pub fn get_wrapper_for_bare_fn(ccx: &CrateContext, pub fn get_wrapper_for_bare_fn(ccx: &CrateContext,
closure_ty: ty::t, closure_ty: ty::t,
def: def::Def, def: def::Def,

View File

@ -71,7 +71,8 @@ pub fn type_is_immediate(ccx: &CrateContext, ty: ty::t) -> bool {
} }
match ty::get(ty).sty { match ty::get(ty).sty {
ty::ty_bot => true, ty::ty_bot => true,
ty::ty_struct(..) | ty::ty_enum(..) | ty::ty_tup(..) => { ty::ty_struct(..) | ty::ty_enum(..) | ty::ty_tup(..) |
ty::ty_unboxed_closure(..) => {
let llty = sizing_type_of(ccx, ty); let llty = sizing_type_of(ccx, ty);
llsize_of_alloc(ccx, llty) <= llsize_of_alloc(ccx, ccx.int_type) llsize_of_alloc(ccx, llty) <= llsize_of_alloc(ccx, ccx.int_type)
} }
@ -632,12 +633,6 @@ pub fn C_bytes(ccx: &CrateContext, bytes: &[u8]) -> ValueRef {
} }
} }
pub fn get_param(fndecl: ValueRef, param: uint) -> ValueRef {
unsafe {
llvm::LLVMGetParam(fndecl, param as c_uint)
}
}
pub fn const_get_elt(cx: &CrateContext, v: ValueRef, us: &[c_uint]) pub fn const_get_elt(cx: &CrateContext, v: ValueRef, us: &[c_uint])
-> ValueRef { -> ValueRef {
unsafe { unsafe {
@ -792,6 +787,9 @@ pub fn resolve_vtable_under_param_substs(tcx: &ty::ctxt,
typeck::vtable_param(n_param, n_bound) => { typeck::vtable_param(n_param, n_bound) => {
find_vtable(tcx, param_substs, n_param, n_bound) find_vtable(tcx, param_substs, n_param, n_bound)
} }
typeck::vtable_unboxed_closure(def_id) => {
typeck::vtable_unboxed_closure(def_id)
}
typeck::vtable_error => typeck::vtable_error typeck::vtable_error => typeck::vtable_error
} }
} }

View File

@ -117,6 +117,10 @@ pub struct CrateContext {
pub int_type: Type, pub int_type: Type,
pub opaque_vec_type: Type, pub opaque_vec_type: Type,
pub builder: BuilderRef_res, pub builder: BuilderRef_res,
/// Holds the LLVM values for closure IDs.
pub unboxed_closure_vals: RefCell<DefIdMap<ValueRef>>,
/// Set when at least one function uses GC. Needed so that /// Set when at least one function uses GC. Needed so that
/// decl_gc_metadata knows whether to link to the module metadata, which /// decl_gc_metadata knows whether to link to the module metadata, which
/// is not emitted by LLVM's GC pass when no functions use GC. /// is not emitted by LLVM's GC pass when no functions use GC.
@ -225,6 +229,7 @@ impl CrateContext {
int_type: Type::from_ref(ptr::mut_null()), int_type: Type::from_ref(ptr::mut_null()),
opaque_vec_type: Type::from_ref(ptr::mut_null()), opaque_vec_type: Type::from_ref(ptr::mut_null()),
builder: BuilderRef_res(llvm::LLVMCreateBuilderInContext(llcx)), builder: BuilderRef_res(llvm::LLVMCreateBuilderInContext(llcx)),
unboxed_closure_vals: RefCell::new(DefIdMap::new()),
uses_gc: false, uses_gc: false,
dbg_cx: dbg_cx, dbg_cx: dbg_cx,
eh_personality: RefCell::new(None), eh_personality: RefCell::new(None),

View File

@ -452,7 +452,8 @@ impl TypeMap {
onceness, onceness,
store, store,
ref bounds, ref bounds,
ref sig }) => { ref sig,
abi: _ }) => {
if fn_style == ast::UnsafeFn { if fn_style == ast::UnsafeFn {
unique_type_id.push_str("unsafe "); unique_type_id.push_str("unsafe ");
} }
@ -1150,7 +1151,8 @@ pub fn create_function_debug_context(cx: &CrateContext,
ast_map::NodeExpr(ref expr) => { ast_map::NodeExpr(ref expr) => {
match expr.node { match expr.node {
ast::ExprFnBlock(fn_decl, top_level_block) | ast::ExprFnBlock(fn_decl, top_level_block) |
ast::ExprProc(fn_decl, top_level_block) => { ast::ExprProc(fn_decl, top_level_block) |
ast::ExprUnboxedFn(fn_decl, top_level_block) => {
let name = format!("fn{}", token::gensym("fn")); let name = format!("fn{}", token::gensym("fn"));
let name = token::str_to_ident(name.as_slice()); let name = token::str_to_ident(name.as_slice());
(name, fn_decl, (name, fn_decl,
@ -3602,7 +3604,8 @@ fn populate_scope_map(cx: &CrateContext,
} }
ast::ExprFnBlock(ref decl, ref block) | ast::ExprFnBlock(ref decl, ref block) |
ast::ExprProc(ref decl, ref block) => { ast::ExprProc(ref decl, ref block) |
ast::ExprUnboxedFn(ref decl, ref block) => {
with_new_scope(cx, with_new_scope(cx,
block.span, block.span,
scope_stack, scope_stack,
@ -3877,6 +3880,9 @@ fn push_debuginfo_type_name(cx: &CrateContext,
push_debuginfo_type_name(cx, sig.output, true, output); push_debuginfo_type_name(cx, sig.output, true, output);
} }
}, },
ty::ty_unboxed_closure(_) => {
output.push_str("closure");
}
ty::ty_err | ty::ty_err |
ty::ty_infer(_) | ty::ty_infer(_) |
ty::ty_param(_) => { ty::ty_param(_) => {

View File

@ -783,12 +783,14 @@ fn trans_rvalue_dps_unadjusted<'a>(bcx: &'a Block<'a>,
expr_to_string(expr), expr_ty.repr(tcx)); expr_to_string(expr), expr_ty.repr(tcx));
closure::trans_expr_fn(bcx, store, &**decl, &**body, expr.id, dest) closure::trans_expr_fn(bcx, store, &**decl, &**body, expr.id, dest)
} }
ast::ExprUnboxedFn(decl, body) => {
closure::trans_unboxed_closure(bcx, &*decl, &*body, expr.id, dest)
}
ast::ExprCall(ref f, ref args) => { ast::ExprCall(ref f, ref args) => {
if bcx.tcx().is_method_call(expr.id) { if bcx.tcx().is_method_call(expr.id) {
let callee_datum = unpack_datum!(bcx, trans(bcx, &**f));
trans_overloaded_call(bcx, trans_overloaded_call(bcx,
expr, expr,
callee_datum, *f,
args.as_slice(), args.as_slice(),
Some(dest)) Some(dest))
} else { } else {
@ -1502,54 +1504,18 @@ fn trans_overloaded_op<'a, 'b>(
fn trans_overloaded_call<'a>( fn trans_overloaded_call<'a>(
mut bcx: &'a Block<'a>, mut bcx: &'a Block<'a>,
expr: &ast::Expr, expr: &ast::Expr,
callee: Datum<Expr>, callee: Gc<ast::Expr>,
args: &[Gc<ast::Expr>], args: &[Gc<ast::Expr>],
dest: Option<Dest>) dest: Option<Dest>)
-> &'a Block<'a> { -> &'a Block<'a> {
// Evaluate and tuple the arguments.
let tuple_type = ty::mk_tup(bcx.tcx(),
args.iter()
.map(|e| ty::expr_ty_adjusted(bcx.tcx(), &**e))
.collect());
let repr = adt::represent_type(bcx.ccx(), tuple_type);
let numbered_fields: Vec<(uint, Gc<ast::Expr>)> =
args.iter().enumerate().map(|(i, arg)| (i, *arg)).collect();
let argument_scope = bcx.fcx.push_custom_cleanup_scope();
let tuple_datum =
unpack_datum!(bcx,
lvalue_scratch_datum(bcx,
tuple_type,
"tupled_arguments",
false,
cleanup::CustomScope(
argument_scope),
(),
|(), bcx, addr| {
trans_adt(bcx,
&*repr,
0,
numbered_fields.as_slice(),
None,
SaveIn(addr))
}));
let method_call = MethodCall::expr(expr.id); let method_call = MethodCall::expr(expr.id);
let method_type = bcx.tcx() let method_type = bcx.tcx()
.method_map .method_map
.borrow() .borrow()
.get(&method_call) .get(&method_call)
.ty; .ty;
let callee_rvalue = unpack_datum!(bcx, let mut all_args = vec!(callee);
callee.to_rvalue_datum(bcx, "callee")); all_args.push_all(args);
let tuple_datum = tuple_datum.to_expr_datum();
let tuple_rvalue = unpack_datum!(bcx,
tuple_datum.to_rvalue_datum(bcx,
"tuple"));
let argument_values = [
callee_rvalue.add_clean(bcx.fcx,
cleanup::CustomScope(argument_scope)),
tuple_rvalue.add_clean(bcx.fcx, cleanup::CustomScope(argument_scope))
];
unpack_result!(bcx, unpack_result!(bcx,
callee::trans_call_inner(bcx, callee::trans_call_inner(bcx,
Some(expr_info(expr)), Some(expr_info(expr)),
@ -1562,10 +1528,9 @@ fn trans_overloaded_call<'a>(
None, None,
arg_cleanup_scope) arg_cleanup_scope)
}, },
callee::ArgVals(argument_values), callee::ArgOverloadedCall(
all_args.as_slice()),
dest)); dest));
bcx.fcx.pop_custom_cleanup_scope(argument_scope);
bcx bcx
} }

View File

@ -10,8 +10,8 @@
use back::{link}; use back::{link};
use llvm::{ValueRef, CallConv, Linkage, get_param};
use llvm; use llvm;
use llvm::{ValueRef, CallConv, Linkage};
use middle::weak_lang_items; use middle::weak_lang_items;
use middle::trans::base::push_ctxt; use middle::trans::base::push_ctxt;
use middle::trans::base; use middle::trans::base;
@ -27,7 +27,7 @@ use middle::ty;
use std::cmp; use std::cmp;
use libc::c_uint; use libc::c_uint;
use syntax::abi::{Cdecl, Aapcs, C, Win64, Abi}; use syntax::abi::{Cdecl, Aapcs, C, Win64, Abi};
use syntax::abi::{RustIntrinsic, Rust, Stdcall, Fastcall, System}; use syntax::abi::{RustIntrinsic, Rust, RustCall, Stdcall, Fastcall, System};
use syntax::codemap::Span; use syntax::codemap::Span;
use syntax::parse::token::{InternedString, special_idents}; use syntax::parse::token::{InternedString, special_idents};
use syntax::parse::token; use syntax::parse::token;
@ -84,6 +84,11 @@ pub fn llvm_calling_convention(ccx: &CrateContext,
ccx.sess().unimpl("foreign functions with Rust ABI"); ccx.sess().unimpl("foreign functions with Rust ABI");
} }
RustCall => {
// FIXME(#3678) Implement linking to foreign fns with Rust ABI
ccx.sess().unimpl("foreign functions with RustCall ABI");
}
// It's the ABI's job to select this, not us. // It's the ABI's job to select this, not us.
System => ccx.sess().bug("system abi should be selected elsewhere"), System => ccx.sess().bug("system abi should be selected elsewhere"),
@ -646,7 +651,7 @@ pub fn trans_rust_fn_with_foreign_abi(ccx: &CrateContext,
// If there is an out pointer on the foreign function // If there is an out pointer on the foreign function
let foreign_outptr = { let foreign_outptr = {
if tys.fn_ty.ret_ty.is_indirect() { if tys.fn_ty.ret_ty.is_indirect() {
Some(llvm::LLVMGetParam(llwrapfn, next_foreign_arg(false))) Some(get_param(llwrapfn, next_foreign_arg(false)))
} else { } else {
None None
} }
@ -708,7 +713,7 @@ pub fn trans_rust_fn_with_foreign_abi(ccx: &CrateContext,
// skip padding // skip padding
let foreign_index = next_foreign_arg(llforeign_arg_ty.pad.is_some()); let foreign_index = next_foreign_arg(llforeign_arg_ty.pad.is_some());
let mut llforeign_arg = llvm::LLVMGetParam(llwrapfn, foreign_index); let mut llforeign_arg = get_param(llwrapfn, foreign_index);
debug!("llforeign_arg {}{}: {}", "#", debug!("llforeign_arg {}{}: {}", "#",
i, ccx.tn.val_to_string(llforeign_arg)); i, ccx.tn.val_to_string(llforeign_arg));

View File

@ -15,8 +15,8 @@
use back::abi; use back::abi;
use back::link::*; use back::link::*;
use llvm::{ValueRef, True, get_param};
use llvm; use llvm;
use llvm::{ValueRef, True};
use middle::lang_items::{FreeFnLangItem, ExchangeFreeFnLangItem}; use middle::lang_items::{FreeFnLangItem, ExchangeFreeFnLangItem};
use middle::subst; use middle::subst;
use middle::trans::adt; use middle::trans::adt;
@ -353,6 +353,7 @@ fn make_drop_glue<'a>(bcx: &'a Block<'a>, v0: ValueRef, t: ty::t) -> &'a Block<'
} }
} }
} }
ty::ty_unboxed_closure(..) => iter_structural_ty(bcx, v0, t, drop_ty),
ty::ty_closure(ref f) if f.store == ty::UniqTraitStore => { ty::ty_closure(ref f) if f.store == ty::UniqTraitStore => {
let box_cell_v = GEPi(bcx, v0, [0u, abi::fn_field_box]); let box_cell_v = GEPi(bcx, v0, [0u, abi::fn_field_box]);
let env = Load(bcx, box_cell_v); let env = Load(bcx, box_cell_v);
@ -502,7 +503,7 @@ fn make_generic_glue(ccx: &CrateContext,
// llfn is expected be declared to take a parameter of the appropriate // llfn is expected be declared to take a parameter of the appropriate
// type, so we don't need to explicitly cast the function parameter. // type, so we don't need to explicitly cast the function parameter.
let llrawptr0 = unsafe { llvm::LLVMGetParam(llfn, fcx.arg_pos(0) as c_uint) }; let llrawptr0 = get_param(llfn, fcx.arg_pos(0) as c_uint);
let bcx = helper(bcx, llrawptr0, t); let bcx = helper(bcx, llrawptr0, t);
finish_fn(&fcx, bcx, ty::mk_nil()); finish_fn(&fcx, bcx, ty::mk_nil());

View File

@ -29,6 +29,7 @@ use middle::trans::machine;
use middle::trans::machine::llsize_of; use middle::trans::machine::llsize_of;
use middle::trans::type_::Type; use middle::trans::type_::Type;
use middle::ty; use middle::ty;
use syntax::abi::RustIntrinsic;
use syntax::ast; use syntax::ast;
use syntax::parse::token; use syntax::parse::token;
use util::ppaux::ty_to_string; use util::ppaux::ty_to_string;
@ -193,8 +194,13 @@ pub fn trans_intrinsic_call<'a>(mut bcx: &'a Block<'a>, node: ast::NodeId,
// Push the arguments. // Push the arguments.
let mut llargs = Vec::new(); let mut llargs = Vec::new();
bcx = callee::trans_args(bcx, args, callee_ty, &mut llargs, bcx = callee::trans_args(bcx,
cleanup::CustomScope(cleanup_scope), false); args,
callee_ty,
&mut llargs,
cleanup::CustomScope(cleanup_scope),
false,
RustIntrinsic);
fcx.pop_custom_cleanup_scope(cleanup_scope); fcx.pop_custom_cleanup_scope(cleanup_scope);

View File

@ -13,6 +13,7 @@ use back::abi;
use llvm; use llvm;
use llvm::ValueRef; use llvm::ValueRef;
use metadata::csearch; use metadata::csearch;
use middle::subst::VecPerParamSpace;
use middle::subst; use middle::subst;
use middle::trans::base::*; use middle::trans::base::*;
use middle::trans::build::*; use middle::trans::build::*;
@ -35,7 +36,7 @@ use util::ppaux::Repr;
use std::c_str::ToCStr; use std::c_str::ToCStr;
use std::gc::Gc; use std::gc::Gc;
use syntax::abi::Rust; use syntax::abi::{Rust, RustCall};
use syntax::parse::token; use syntax::parse::token;
use syntax::{ast, ast_map, visit}; use syntax::{ast, ast_map, visit};
use syntax::ast_util::PostExpansionMethod; use syntax::ast_util::PostExpansionMethod;
@ -104,10 +105,13 @@ pub fn trans_method_callee<'a>(
}; };
match origin { match origin {
typeck::MethodStatic(did) => { typeck::MethodStatic(did) |
typeck::MethodStaticUnboxedClosure(did) => {
Callee { Callee {
bcx: bcx, bcx: bcx,
data: Fn(callee::trans_fn_ref(bcx, did, MethodCall(method_call))) data: Fn(callee::trans_fn_ref(bcx,
did,
MethodCall(method_call))),
} }
} }
typeck::MethodParam(typeck::MethodParam { typeck::MethodParam(typeck::MethodParam {
@ -200,6 +204,9 @@ pub fn trans_static_method_callee(bcx: &Block,
let llty = type_of_fn_from_ty(ccx, callee_ty).ptr_to(); let llty = type_of_fn_from_ty(ccx, callee_ty).ptr_to();
PointerCast(bcx, llfn, llty) PointerCast(bcx, llfn, llty)
} }
typeck::vtable_unboxed_closure(_) => {
bcx.tcx().sess.bug("can't call a closure vtable in a static way");
}
_ => { _ => {
fail!("vtable_param left in monomorphized \ fail!("vtable_param left in monomorphized \
function's vtable substs"); function's vtable substs");
@ -225,12 +232,13 @@ fn method_with_name(ccx: &CrateContext,
*meth_did *meth_did
} }
fn trans_monomorphized_callee<'a>(bcx: &'a Block<'a>, fn trans_monomorphized_callee<'a>(
method_call: MethodCall, bcx: &'a Block<'a>,
trait_id: ast::DefId, method_call: MethodCall,
n_method: uint, trait_id: ast::DefId,
vtbl: typeck::vtable_origin) n_method: uint,
-> Callee<'a> { vtbl: typeck::vtable_origin)
-> Callee<'a> {
let _icx = push_ctxt("meth::trans_monomorphized_callee"); let _icx = push_ctxt("meth::trans_monomorphized_callee");
match vtbl { match vtbl {
typeck::vtable_static(impl_did, rcvr_substs, rcvr_origins) => { typeck::vtable_static(impl_did, rcvr_substs, rcvr_origins) => {
@ -253,6 +261,26 @@ fn trans_monomorphized_callee<'a>(bcx: &'a Block<'a>,
Callee { bcx: bcx, data: Fn(llfn) } Callee { bcx: bcx, data: Fn(llfn) }
} }
typeck::vtable_unboxed_closure(closure_def_id) => {
// The static region and type parameters are lies, but we're in
// trans so it doesn't matter.
//
// FIXME(pcwalton): Is this true in the case of type parameters?
let callee_substs = get_callee_substitutions_for_unboxed_closure(
bcx,
closure_def_id);
let llfn = trans_fn_ref_with_vtables(bcx,
closure_def_id,
MethodCall(method_call),
callee_substs,
VecPerParamSpace::empty());
Callee {
bcx: bcx,
data: Fn(llfn),
}
}
typeck::vtable_param(..) => { typeck::vtable_param(..) => {
bcx.tcx().sess.bug( bcx.tcx().sess.bug(
"vtable_param left in monomorphized function's vtable substs"); "vtable_param left in monomorphized function's vtable substs");
@ -385,8 +413,12 @@ pub fn trans_trait_callee_from_llval<'a>(bcx: &'a Block<'a>,
debug!("(translating trait callee) loading method"); debug!("(translating trait callee) loading method");
// Replace the self type (&Self or Box<Self>) with an opaque pointer. // Replace the self type (&Self or Box<Self>) with an opaque pointer.
let llcallee_ty = match ty::get(callee_ty).sty { let llcallee_ty = match ty::get(callee_ty).sty {
ty::ty_bare_fn(ref f) if f.abi == Rust => { ty::ty_bare_fn(ref f) if f.abi == Rust || f.abi == RustCall => {
type_of_rust_fn(ccx, true, f.sig.inputs.slice_from(1), f.sig.output) type_of_rust_fn(ccx,
Some(Type::i8p(ccx)),
f.sig.inputs.slice_from(1),
f.sig.output,
f.abi)
} }
_ => { _ => {
ccx.sess().bug("meth::trans_trait_callee given non-bare-rust-fn"); ccx.sess().bug("meth::trans_trait_callee given non-bare-rust-fn");
@ -409,6 +441,26 @@ pub fn trans_trait_callee_from_llval<'a>(bcx: &'a Block<'a>,
}; };
} }
/// Creates the self type and (fake) callee substitutions for an unboxed
/// closure with the given def ID. The static region and type parameters are
/// lies, but we're in trans so it doesn't matter.
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);
subst::Substs::erased(
VecPerParamSpace::new(Vec::new(),
vec![
ty::mk_rptr(bcx.tcx(),
ty::ReStatic,
ty::mt {
ty: self_ty,
mutbl: ast::MutMutable,
})
],
Vec::new()))
}
/// Creates a returns a dynamic vtable for the given type and vtable origin. /// Creates a returns a dynamic vtable for the given type and vtable origin.
/// This is used only for objects. /// This is used only for objects.
fn get_vtable(bcx: &Block, fn get_vtable(bcx: &Block,
@ -436,6 +488,21 @@ fn get_vtable(bcx: &Block,
typeck::vtable_static(id, substs, sub_vtables) => { typeck::vtable_static(id, substs, sub_vtables) => {
emit_vtable_methods(bcx, id, substs, sub_vtables).move_iter() emit_vtable_methods(bcx, id, substs, sub_vtables).move_iter()
} }
typeck::vtable_unboxed_closure(closure_def_id) => {
let callee_substs =
get_callee_substitutions_for_unboxed_closure(
bcx,
closure_def_id);
let llfn = trans_fn_ref_with_vtables(
bcx,
closure_def_id,
ExprId(0),
callee_substs,
VecPerParamSpace::empty());
(vec!(llfn)).move_iter()
}
_ => ccx.sess().bug("get_vtable: expected a static origin"), _ => ccx.sess().bug("get_vtable: expected a static origin"),
} }
}); });

View File

@ -254,6 +254,13 @@ pub fn make_vtable_id(_ccx: &CrateContext,
} }
} }
&typeck::vtable_unboxed_closure(def_id) => {
MonoId {
def: def_id,
params: subst::VecPerParamSpace::empty(),
}
}
// can't this be checked at the callee? // can't this be checked at the callee?
_ => fail!("make_vtable_id needs vtable_static") _ => fail!("make_vtable_id needs vtable_static")
} }

View File

@ -9,8 +9,7 @@
// except according to those terms. // except according to those terms.
use back::link::mangle_internal_name_by_path_and_seq; use back::link::mangle_internal_name_by_path_and_seq;
use llvm; use llvm::{ValueRef, get_param};
use llvm::{ValueRef};
use middle::trans::adt; use middle::trans::adt;
use middle::trans::base::*; use middle::trans::base::*;
use middle::trans::build::*; use middle::trans::build::*;
@ -316,14 +315,10 @@ impl<'a, 'b> Reflector<'a, 'b> {
None, &arena); None, &arena);
let bcx = init_function(&fcx, false, ty::mk_u64()); let bcx = init_function(&fcx, false, ty::mk_u64());
let arg = unsafe { // we know the return type of llfdecl is an int here, so
// // no need for a special check to see if the return type
// we know the return type of llfdecl is an int here, so // is immediate.
// no need for a special check to see if the return type let arg = get_param(llfdecl, fcx.arg_pos(0u) as c_uint);
// is immediate.
//
llvm::LLVMGetParam(llfdecl, fcx.arg_pos(0u) as c_uint)
};
let arg = BitCast(bcx, arg, llptrty); let arg = BitCast(bcx, arg, llptrty);
let ret = adt::trans_get_discr(bcx, &*repr, arg, Some(Type::i64(ccx))); let ret = adt::trans_get_discr(bcx, &*repr, arg, Some(Type::i64(ccx)));
Store(bcx, ret, fcx.llretptr.get().unwrap()); Store(bcx, ret, fcx.llretptr.get().unwrap());
@ -366,6 +361,7 @@ impl<'a, 'b> Reflector<'a, 'b> {
// Miscellaneous extra types // Miscellaneous extra types
ty::ty_infer(_) => self.leaf("infer"), ty::ty_infer(_) => self.leaf("infer"),
ty::ty_err => self.leaf("err"), ty::ty_err => self.leaf("err"),
ty::ty_unboxed_closure(..) => self.leaf("err"),
ty::ty_param(ref p) => { ty::ty_param(ref p) => {
let extra = vec!(self.c_uint(p.idx)); let extra = vec!(self.c_uint(p.idx));
self.visit("param", extra.as_slice()) self.visit("param", extra.as_slice())

View File

@ -39,10 +39,56 @@ pub fn type_of_explicit_arg(ccx: &CrateContext, arg_ty: ty::t) -> Type {
} }
} }
pub fn type_of_rust_fn(cx: &CrateContext, has_env: bool, /// Yields the types of the "real" arguments for this function. For most
inputs: &[ty::t], output: ty::t) -> Type { /// functions, these are simply the types of the arguments. For functions with
/// the `RustCall` ABI, however, this untuples the arguments of the function.
fn untuple_arguments_if_necessary(ccx: &CrateContext,
inputs: &[ty::t],
abi: abi::Abi)
-> Vec<ty::t> {
if abi != abi::RustCall {
return inputs.iter().map(|x| (*x).clone()).collect()
}
if inputs.len() == 0 {
return Vec::new()
}
let mut result = Vec::new();
for (i, &arg_prior_to_tuple) in inputs.iter().enumerate() {
if i < inputs.len() - 1 {
result.push(arg_prior_to_tuple);
}
}
match ty::get(inputs[inputs.len() - 1]).sty {
ty::ty_tup(ref tupled_arguments) => {
debug!("untuple_arguments_if_necessary(): untupling arguments");
for &tupled_argument in tupled_arguments.iter() {
result.push(tupled_argument);
}
}
ty::ty_nil => {}
_ => {
ccx.tcx().sess.bug("argument to function with \"rust-call\" ABI \
is neither a tuple nor unit")
}
}
result
}
pub fn type_of_rust_fn(cx: &CrateContext,
llenvironment_type: Option<Type>,
inputs: &[ty::t],
output: ty::t,
abi: abi::Abi)
-> Type {
let mut atys: Vec<Type> = Vec::new(); let mut atys: Vec<Type> = Vec::new();
// First, munge the inputs, if this has the `rust-call` ABI.
let inputs = untuple_arguments_if_necessary(cx, inputs, abi);
// Arg 0: Output pointer. // Arg 0: Output pointer.
// (if the output type is non-immediate) // (if the output type is non-immediate)
let use_out_pointer = return_uses_outptr(cx, output); let use_out_pointer = return_uses_outptr(cx, output);
@ -52,8 +98,9 @@ pub fn type_of_rust_fn(cx: &CrateContext, has_env: bool,
} }
// Arg 1: Environment // Arg 1: Environment
if has_env { match llenvironment_type {
atys.push(Type::i8p(cx)); None => {}
Some(llenvironment_type) => atys.push(llenvironment_type),
} }
// ... then explicit args. // ... then explicit args.
@ -72,16 +119,19 @@ pub fn type_of_rust_fn(cx: &CrateContext, has_env: bool,
pub fn type_of_fn_from_ty(cx: &CrateContext, fty: ty::t) -> Type { pub fn type_of_fn_from_ty(cx: &CrateContext, fty: ty::t) -> Type {
match ty::get(fty).sty { match ty::get(fty).sty {
ty::ty_closure(ref f) => { ty::ty_closure(ref f) => {
type_of_rust_fn(cx, true, f.sig.inputs.as_slice(), f.sig.output) type_of_rust_fn(cx,
Some(Type::i8p(cx)),
f.sig.inputs.as_slice(),
f.sig.output,
f.abi)
} }
ty::ty_bare_fn(ref f) => { ty::ty_bare_fn(ref f) => {
if f.abi == abi::Rust { if f.abi == abi::Rust || f.abi == abi::RustCall {
type_of_rust_fn(cx, type_of_rust_fn(cx,
false, None,
f.sig.inputs.as_slice(), f.sig.inputs.as_slice(),
f.sig.output) f.sig.output,
} else if f.abi == abi::RustIntrinsic { f.abi)
cx.sess().bug("type_of_fn_from_ty given intrinsic")
} else { } else {
foreign::lltype_for_foreign_fn(cx, fty) foreign::lltype_for_foreign_fn(cx, fty)
} }
@ -142,7 +192,7 @@ pub fn sizing_type_of(cx: &CrateContext, t: ty::t) -> Type {
Type::array(&sizing_type_of(cx, mt.ty), size as u64) Type::array(&sizing_type_of(cx, mt.ty), size as u64)
} }
ty::ty_tup(..) | ty::ty_enum(..) => { ty::ty_tup(..) | ty::ty_enum(..) | ty::ty_unboxed_closure(..) => {
let repr = adt::represent_type(cx, t); let repr = adt::represent_type(cx, t);
adt::sizing_type_of(cx, &*repr) adt::sizing_type_of(cx, &*repr)
} }
@ -223,6 +273,13 @@ pub fn type_of(cx: &CrateContext, t: ty::t) -> Type {
let name = llvm_type_name(cx, an_enum, did, tps); let name = llvm_type_name(cx, an_enum, did, tps);
adt::incomplete_type_of(cx, &*repr, name.as_slice()) adt::incomplete_type_of(cx, &*repr, name.as_slice())
} }
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);
let name = llvm_type_name(cx, an_unboxed_closure, did, []);
adt::incomplete_type_of(cx, &*repr, name.as_slice())
}
ty::ty_box(typ) => { ty::ty_box(typ) => {
Type::at_box(cx, type_of(cx, typ)).ptr_to() Type::at_box(cx, type_of(cx, typ)).ptr_to()
} }
@ -299,7 +356,8 @@ pub fn type_of(cx: &CrateContext, t: ty::t) -> Type {
// If this was an enum or struct, fill in the type now. // If this was an enum or struct, fill in the type now.
match ty::get(t).sty { match ty::get(t).sty {
ty::ty_enum(..) | ty::ty_struct(..) if !ty::type_is_simd(cx.tcx(), t) => { ty::ty_enum(..) | ty::ty_struct(..) | ty::ty_unboxed_closure(..)
if !ty::type_is_simd(cx.tcx(), t) => {
let repr = adt::represent_type(cx, t); let repr = adt::represent_type(cx, t);
adt::finish_type_of(cx, &*repr, &mut llty); adt::finish_type_of(cx, &*repr, &mut llty);
} }
@ -310,7 +368,11 @@ pub fn type_of(cx: &CrateContext, t: ty::t) -> Type {
} }
// Want refinements! (Or case classes, I guess // Want refinements! (Or case classes, I guess
pub enum named_ty { a_struct, an_enum } pub enum named_ty {
a_struct,
an_enum,
an_unboxed_closure,
}
pub fn llvm_type_name(cx: &CrateContext, pub fn llvm_type_name(cx: &CrateContext,
what: named_ty, what: named_ty,
@ -319,8 +381,9 @@ pub fn llvm_type_name(cx: &CrateContext,
-> String -> String
{ {
let name = match what { let name = match what {
a_struct => { "struct" } a_struct => "struct",
an_enum => { "enum" } an_enum => "enum",
an_unboxed_closure => return "closure".to_string(),
}; };
let base = ty::item_path_str(cx.tcx(), did); let base = ty::item_path_str(cx.tcx(), did);

View File

@ -18,7 +18,7 @@ use lint;
use middle::const_eval; use middle::const_eval;
use middle::def; use middle::def;
use middle::dependency_format; use middle::dependency_format;
use middle::lang_items::OpaqueStructLangItem; use middle::lang_items::{FnMutTraitLangItem, OpaqueStructLangItem};
use middle::lang_items::{TyDescStructLangItem, TyVisitorTraitLangItem}; use middle::lang_items::{TyDescStructLangItem, TyVisitorTraitLangItem};
use middle::freevars; use middle::freevars;
use middle::resolve; use middle::resolve;
@ -370,6 +370,10 @@ pub struct ctxt {
pub dependency_formats: RefCell<dependency_format::Dependencies>, pub dependency_formats: RefCell<dependency_format::Dependencies>,
/// 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 node_lint_levels: RefCell<HashMap<(ast::NodeId, lint::LintId), pub node_lint_levels: RefCell<HashMap<(ast::NodeId, lint::LintId),
lint::LevelSource>>, lint::LevelSource>>,
@ -454,6 +458,7 @@ pub struct ClosureTy {
pub store: TraitStore, pub store: TraitStore,
pub bounds: BuiltinBounds, pub bounds: BuiltinBounds,
pub sig: FnSig, pub sig: FnSig,
pub abi: abi::Abi,
} }
/** /**
@ -736,6 +741,7 @@ pub enum sty {
ty_closure(Box<ClosureTy>), ty_closure(Box<ClosureTy>),
ty_trait(Box<TyTrait>), ty_trait(Box<TyTrait>),
ty_struct(DefId, Substs), ty_struct(DefId, Substs),
ty_unboxed_closure(DefId),
ty_tup(Vec<t>), ty_tup(Vec<t>),
ty_param(ParamTy), // type parameter ty_param(ParamTy), // type parameter
@ -1054,7 +1060,7 @@ pub fn mk_ctxt(s: Session,
region_maps: middle::region::RegionMaps, region_maps: middle::region::RegionMaps,
lang_items: middle::lang_items::LanguageItems, lang_items: middle::lang_items::LanguageItems,
stability: stability::Index) stability: stability::Index)
-> ctxt { -> ctxt {
ctxt { ctxt {
named_region_map: named_region_map, named_region_map: named_region_map,
item_variance_map: RefCell::new(DefIdMap::new()), item_variance_map: RefCell::new(DefIdMap::new()),
@ -1106,6 +1112,7 @@ pub fn mk_ctxt(s: Session,
method_map: RefCell::new(FnvHashMap::new()), method_map: RefCell::new(FnvHashMap::new()),
vtable_map: RefCell::new(FnvHashMap::new()), vtable_map: RefCell::new(FnvHashMap::new()),
dependency_formats: RefCell::new(HashMap::new()), dependency_formats: RefCell::new(HashMap::new()),
unboxed_closure_types: RefCell::new(DefIdMap::new()),
node_lint_levels: RefCell::new(HashMap::new()), node_lint_levels: RefCell::new(HashMap::new()),
transmute_restrictions: RefCell::new(Vec::new()), transmute_restrictions: RefCell::new(Vec::new()),
stability: RefCell::new(stability) stability: RefCell::new(stability)
@ -1164,7 +1171,7 @@ pub fn mk_t(cx: &ctxt, st: sty) -> t {
} }
match &st { match &st {
&ty_nil | &ty_bool | &ty_char | &ty_int(_) | &ty_float(_) | &ty_uint(_) | &ty_nil | &ty_bool | &ty_char | &ty_int(_) | &ty_float(_) | &ty_uint(_) |
&ty_str => {} &ty_str | &ty_unboxed_closure(_) => {}
// You might think that we could just return ty_err for // You might think that we could just return ty_err for
// any type containing ty_err as a component, and get // any type containing ty_err as a component, and get
// rid of the has_ty_err flag -- likewise for ty_bot (with // rid of the has_ty_err flag -- likewise for ty_bot (with
@ -1429,6 +1436,10 @@ pub fn mk_struct(cx: &ctxt, struct_id: ast::DefId, substs: Substs) -> t {
mk_t(cx, ty_struct(struct_id, substs)) 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_var(cx: &ctxt, v: TyVid) -> t { mk_infer(cx, TyVar(v)) } pub fn mk_var(cx: &ctxt, v: TyVid) -> t { mk_infer(cx, TyVar(v)) }
pub fn mk_int_var(cx: &ctxt, v: IntVid) -> t { mk_infer(cx, IntVar(v)) } pub fn mk_int_var(cx: &ctxt, v: IntVid) -> t { mk_infer(cx, IntVar(v)) }
@ -1459,7 +1470,7 @@ pub fn maybe_walk_ty(ty: t, f: |t| -> bool) {
} }
match get(ty).sty { match get(ty).sty {
ty_nil | ty_bot | ty_bool | ty_char | ty_int(_) | ty_uint(_) | ty_float(_) | ty_nil | ty_bot | ty_bool | ty_char | ty_int(_) | ty_uint(_) | ty_float(_) |
ty_str | ty_infer(_) | ty_param(_) | 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_box(ty) | ty_uniq(ty) => maybe_walk_ty(ty, f),
ty_ptr(ref tm) | ty_rptr(_, ref tm) | ty_vec(ref tm, _) => { ty_ptr(ref tm) | ty_rptr(_, ref tm) | ty_vec(ref tm, _) => {
@ -1567,7 +1578,7 @@ pub fn type_is_vec(ty: t) -> bool {
pub fn type_is_structural(ty: t) -> bool { pub fn type_is_structural(ty: t) -> bool {
match get(ty).sty { match get(ty).sty {
ty_struct(..) | ty_tup(_) | ty_enum(..) | ty_closure(_) | ty_struct(..) | ty_tup(_) | ty_enum(..) | ty_closure(_) |
ty_vec(_, Some(_)) => true, ty_vec(_, Some(_)) | ty_unboxed_closure(_) => true,
_ => type_is_slice(ty) | type_is_trait(ty) _ => type_is_slice(ty) | type_is_trait(ty)
} }
} }
@ -2082,6 +2093,12 @@ pub fn type_contents(cx: &ctxt, ty: t) -> TypeContents {
apply_lang_items(cx, did, res) apply_lang_items(cx, did, res)
} }
ty_unboxed_closure(did) => {
let upvars = unboxed_closure_upvars(cx, did);
TypeContents::union(upvars.as_slice(),
|f| tc_ty(cx, f.ty, cache))
}
ty_tup(ref tys) => { ty_tup(ref tys) => {
TypeContents::union(tys.as_slice(), TypeContents::union(tys.as_slice(),
|ty| tc_ty(cx, *ty, cache)) |ty| tc_ty(cx, *ty, cache))
@ -2323,6 +2340,11 @@ pub fn is_instantiable(cx: &ctxt, r_ty: t) -> bool {
r r
} }
ty_unboxed_closure(did) => {
let upvars = unboxed_closure_upvars(cx, did);
upvars.iter().any(|f| type_requires(cx, seen, r_ty, f.ty))
}
ty_tup(ref ts) => { ty_tup(ref ts) => {
ts.iter().any(|t| type_requires(cx, seen, r_ty, *t)) ts.iter().any(|t| type_requires(cx, seen, r_ty, *t))
} }
@ -2427,6 +2449,7 @@ pub fn is_type_representable(cx: &ctxt, sp: Span, ty: t) -> Representability {
seen.pop(); seen.pop();
r r
} }
ty_enum(did, ref substs) => { ty_enum(did, ref substs) => {
seen.push(did); seen.push(did);
let vs = enum_variants(cx, did); let vs = enum_variants(cx, did);
@ -2445,6 +2468,14 @@ pub fn is_type_representable(cx: &ctxt, sp: Span, ty: t) -> Representability {
r r
} }
ty_unboxed_closure(did) => {
let upvars = unboxed_closure_upvars(cx, did);
find_nonrepresentable(cx,
sp,
seen,
upvars.iter().map(|f| f.ty))
}
_ => Representable, _ => Representable,
} }
} }
@ -2655,6 +2686,15 @@ pub fn ty_fn_sig(fty: t) -> FnSig {
} }
} }
/// Returns the ABI of the given function.
pub fn ty_fn_abi(fty: t) -> abi::Abi {
match get(fty).sty {
ty_bare_fn(ref f) => f.abi,
ty_closure(ref f) => f.abi,
_ => fail!("ty_fn_abi() called on non-fn type"),
}
}
// Type accessors for substructures of types // Type accessors for substructures of types
pub fn ty_fn_args(fty: t) -> Vec<t> { pub fn ty_fn_args(fty: t) -> Vec<t> {
match get(fty).sty { match get(fty).sty {
@ -2669,6 +2709,11 @@ pub fn ty_fn_args(fty: t) -> Vec<t> {
pub fn ty_closure_store(fty: t) -> TraitStore { pub fn ty_closure_store(fty: t) -> TraitStore {
match get(fty).sty { match get(fty).sty {
ty_closure(ref f) => f.store, ty_closure(ref f) => f.store,
ty_unboxed_closure(_) => {
// Close enough for the purposes of all the callers of this
// function (which is soon to be deprecated anyhow).
UniqTraitStore
}
ref s => { ref s => {
fail!("ty_closure_store() called on non-closure type: {:?}", s) fail!("ty_closure_store() called on non-closure type: {:?}", s)
} }
@ -2816,11 +2861,14 @@ pub fn adjust_ty(cx: &ctxt,
ty::ty_bare_fn(ref b) => { ty::ty_bare_fn(ref b) => {
ty::mk_closure( ty::mk_closure(
cx, cx,
ty::ClosureTy {fn_style: b.fn_style, ty::ClosureTy {
onceness: ast::Many, fn_style: b.fn_style,
store: store, onceness: ast::Many,
bounds: ty::all_builtin_bounds(), store: store,
sig: b.sig.clone()}) bounds: ty::all_builtin_bounds(),
sig: b.sig.clone(),
abi: b.abi,
})
} }
ref b => { ref b => {
cx.sess.bug( cx.sess.bug(
@ -2990,6 +3038,14 @@ pub fn method_call_type_param_defs(tcx: &ctxt, origin: typeck::MethodOrigin)
typeck::MethodStatic(did) => { typeck::MethodStatic(did) => {
ty::lookup_item_type(tcx, did).generics.types.clone() ty::lookup_item_type(tcx, did).generics.types.clone()
} }
typeck::MethodStaticUnboxedClosure(_) => {
match tcx.lang_items.require(FnMutTraitLangItem) {
Ok(def_id) => {
lookup_trait_def(tcx, def_id).generics.types.clone()
}
Err(s) => tcx.sess.fatal(s.as_slice()),
}
}
typeck::MethodParam(typeck::MethodParam{trait_id: trt_id, typeck::MethodParam(typeck::MethodParam{trait_id: trt_id,
method_num: n_mth, ..}) | method_num: n_mth, ..}) |
typeck::MethodObject(typeck::MethodObject{trait_id: trt_id, typeck::MethodObject(typeck::MethodObject{trait_id: trt_id,
@ -3104,6 +3160,7 @@ pub fn expr_kind(tcx: &ctxt, expr: &ast::Expr) -> ExprKind {
ast::ExprMatch(..) | ast::ExprMatch(..) |
ast::ExprFnBlock(..) | ast::ExprFnBlock(..) |
ast::ExprProc(..) | ast::ExprProc(..) |
ast::ExprUnboxedFn(..) |
ast::ExprBlock(..) | ast::ExprBlock(..) |
ast::ExprRepeat(..) | ast::ExprRepeat(..) |
ast::ExprVstore(_, ast::ExprVstoreSlice) | ast::ExprVstore(_, ast::ExprVstoreSlice) |
@ -3250,6 +3307,7 @@ pub fn ty_sort_string(cx: &ctxt, t: t) -> String {
ty_struct(id, _) => { ty_struct(id, _) => {
format!("struct {}", item_path_str(cx, id)) format!("struct {}", item_path_str(cx, id))
} }
ty_unboxed_closure(_) => "closure".to_string(),
ty_tup(_) => "tuple".to_string(), ty_tup(_) => "tuple".to_string(),
ty_infer(TyVar(_)) => "inferred type".to_string(), ty_infer(TyVar(_)) => "inferred type".to_string(),
ty_infer(IntVar(_)) => "integral variable".to_string(), ty_infer(IntVar(_)) => "integral variable".to_string(),
@ -3617,7 +3675,8 @@ pub fn ty_to_def_id(ty: t) -> Option<ast::DefId> {
match get(ty).sty { match get(ty).sty {
ty_trait(box TyTrait { def_id: id, .. }) | ty_trait(box TyTrait { def_id: id, .. }) |
ty_struct(id, _) | ty_struct(id, _) |
ty_enum(id, _) => Some(id), ty_enum(id, _) |
ty_unboxed_closure(id) => Some(id),
_ => None _ => None
} }
} }
@ -4046,6 +4105,34 @@ pub fn struct_fields(cx: &ctxt, did: ast::DefId, substs: &Substs)
}).collect() }).collect()
} }
pub struct UnboxedClosureUpvar {
pub def: def::Def,
pub span: Span,
pub ty: t,
}
// Returns a list of `UnboxedClosureUpvar`s for each upvar.
pub fn unboxed_closure_upvars(tcx: &ctxt, closure_id: ast::DefId)
-> Vec<UnboxedClosureUpvar> {
if closure_id.krate == ast::LOCAL_CRATE {
match tcx.freevars.borrow().find(&closure_id.node) {
None => tcx.sess.bug("no freevars for unboxed closure?!"),
Some(ref freevars) => {
freevars.iter().map(|freevar| {
let freevar_def_id = freevar.def.def_id();
UnboxedClosureUpvar {
def: freevar.def,
span: freevar.span,
ty: node_id_to_type(tcx, freevar_def_id.node),
}
}).collect()
}
}
} else {
tcx.sess.bug("unimplemented cross-crate closure upvars")
}
}
pub fn is_binopable(cx: &ctxt, ty: t, op: ast::BinOp) -> bool { pub fn is_binopable(cx: &ctxt, ty: t, op: ast::BinOp) -> bool {
static tycat_other: int = 0; static tycat_other: int = 0;
static tycat_bool: int = 1; static tycat_bool: int = 1;
@ -4623,6 +4710,10 @@ pub fn hash_crate_independent(tcx: &ctxt, t: t, svh: &Svh) -> u64 {
} }
ty_infer(_) => unreachable!(), ty_infer(_) => unreachable!(),
ty_err => byte!(23), ty_err => byte!(23),
ty_unboxed_closure(d) => {
byte!(24);
did(&mut state, d);
}
} }
}); });

View File

@ -220,6 +220,9 @@ impl TypeFoldable for typeck::vtable_origin {
typeck::vtable_param(n, b) => { typeck::vtable_param(n, b) => {
typeck::vtable_param(n, b) typeck::vtable_param(n, b)
} }
typeck::vtable_unboxed_closure(def_id) => {
typeck::vtable_unboxed_closure(def_id)
}
typeck::vtable_error => { typeck::vtable_error => {
typeck::vtable_error typeck::vtable_error
} }
@ -326,6 +329,7 @@ pub fn super_fold_closure_ty<T:TypeFolder>(this: &mut T,
fn_style: fty.fn_style, fn_style: fty.fn_style,
onceness: fty.onceness, onceness: fty.onceness,
bounds: fty.bounds, bounds: fty.bounds,
abi: fty.abi,
} }
} }
@ -388,6 +392,9 @@ pub fn super_fold_sty<T:TypeFolder>(this: &mut T,
ty::ty_struct(did, ref substs) => { ty::ty_struct(did, ref substs) => {
ty::ty_struct(did, substs.fold_with(this)) ty::ty_struct(did, substs.fold_with(this))
} }
ty::ty_unboxed_closure(did) => {
ty::ty_unboxed_closure(did)
}
ty::ty_nil | ty::ty_bot | ty::ty_bool | ty::ty_char | ty::ty_str | ty::ty_nil | ty::ty_bot | ty::ty_bool | ty::ty_char | ty::ty_str |
ty::ty_int(_) | ty::ty_uint(_) | ty::ty_float(_) | ty::ty_int(_) | ty::ty_uint(_) | ty::ty_float(_) |
ty::ty_err | ty::ty_infer(_) | ty::ty_err | ty::ty_infer(_) |

View File

@ -762,6 +762,7 @@ pub fn ast_ty_to_ty<AC:AstConv, RS:RegionScope>(
bounds, bounds,
store, store,
&*f.decl, &*f.decl,
abi::Rust,
None); None);
ty::mk_closure(tcx, fn_decl) ty::mk_closure(tcx, fn_decl)
} }
@ -780,6 +781,7 @@ pub fn ast_ty_to_ty<AC:AstConv, RS:RegionScope>(
bounds, bounds,
ty::UniqTraitStore, ty::UniqTraitStore,
&*f.decl, &*f.decl,
abi::Rust,
None); None);
ty::mk_closure(tcx, fn_decl) ty::mk_closure(tcx, fn_decl)
} }
@ -879,9 +881,9 @@ pub fn ast_ty_to_ty<AC:AstConv, RS:RegionScope>(
} }
ast::TyInfer => { ast::TyInfer => {
// TyInfer also appears as the type of arguments or return // TyInfer also appears as the type of arguments or return
// values in a ExprFnBlock or ExprProc, or as the type of // values in a ExprFnBlock, ExprProc, or ExprUnboxedFn, or as
// local variables. Both of these cases are handled specially // the type of local variables. Both of these cases are
// and will not descend into this routine. // handled specially and will not descend into this routine.
this.ty_infer(ast_ty.span) this.ty_infer(ast_ty.span)
} }
} }
@ -911,7 +913,8 @@ pub fn ty_of_method<AC:AstConv>(
fn_style: ast::FnStyle, fn_style: ast::FnStyle,
untransformed_self_ty: ty::t, untransformed_self_ty: ty::t,
explicit_self: ast::ExplicitSelf, explicit_self: ast::ExplicitSelf,
decl: &ast::FnDecl) decl: &ast::FnDecl,
abi: abi::Abi)
-> (ty::BareFnTy, ty::ExplicitSelfCategory) { -> (ty::BareFnTy, ty::ExplicitSelfCategory) {
let self_info = Some(SelfInfo { let self_info = Some(SelfInfo {
untransformed_self_ty: untransformed_self_ty, untransformed_self_ty: untransformed_self_ty,
@ -921,7 +924,7 @@ pub fn ty_of_method<AC:AstConv>(
ty_of_method_or_bare_fn(this, ty_of_method_or_bare_fn(this,
id, id,
fn_style, fn_style,
abi::Rust, abi,
self_info, self_info,
decl); decl);
(bare_fn_ty, optional_explicit_self_category.unwrap()) (bare_fn_ty, optional_explicit_self_category.unwrap())
@ -1083,6 +1086,7 @@ pub fn ty_of_closure<AC:AstConv>(
bounds: ty::BuiltinBounds, bounds: ty::BuiltinBounds,
store: ty::TraitStore, store: ty::TraitStore,
decl: &ast::FnDecl, decl: &ast::FnDecl,
abi: abi::Abi,
expected_sig: Option<ty::FnSig>) expected_sig: Option<ty::FnSig>)
-> ty::ClosureTy -> ty::ClosureTy
{ {
@ -1117,6 +1121,7 @@ pub fn ty_of_closure<AC:AstConv>(
onceness: onceness, onceness: onceness,
store: store, store: store,
bounds: bounds, bounds: bounds,
abi: abi,
sig: ty::FnSig {binder_id: id, sig: ty::FnSig {binder_id: id,
inputs: input_tys, inputs: input_tys,
output: output_ty, output: output_ty,

View File

@ -87,10 +87,11 @@ use middle::ty;
use middle::typeck::astconv::AstConv; use middle::typeck::astconv::AstConv;
use middle::typeck::check::{FnCtxt, PreferMutLvalue, impl_self_ty}; use middle::typeck::check::{FnCtxt, PreferMutLvalue, impl_self_ty};
use middle::typeck::check; use middle::typeck::check;
use middle::typeck::infer::MiscVariable;
use middle::typeck::infer; use middle::typeck::infer;
use middle::typeck::MethodCallee; use middle::typeck::MethodCallee;
use middle::typeck::{MethodOrigin, MethodParam}; use middle::typeck::{MethodOrigin, MethodParam};
use middle::typeck::{MethodStatic, MethodObject}; use middle::typeck::{MethodStatic, MethodStaticUnboxedClosure, MethodObject};
use middle::typeck::{param_index}; use middle::typeck::{param_index};
use middle::typeck::check::regionmanip::replace_late_bound_regions_in_fn_sig; use middle::typeck::check::regionmanip::replace_late_bound_regions_in_fn_sig;
use middle::typeck::TypeAndSubsts; use middle::typeck::TypeAndSubsts;
@ -341,7 +342,7 @@ struct Candidate {
#[deriving(Clone)] #[deriving(Clone)]
pub enum RcvrMatchCondition { pub enum RcvrMatchCondition {
RcvrMatchesIfObject(ast::DefId), RcvrMatchesIfObject(ast::DefId),
RcvrMatchesIfSubtype(ty::t) RcvrMatchesIfSubtype(ty::t),
} }
impl<'a> LookupContext<'a> { impl<'a> LookupContext<'a> {
@ -441,7 +442,9 @@ impl<'a> LookupContext<'a> {
} }
_ => {} _ => {}
}, },
ty_enum(did, _) | ty_struct(did, _) => { ty_enum(did, _) |
ty_struct(did, _) |
ty_unboxed_closure(did) => {
if self.check_traits == CheckTraitsAndInherentMethods { if self.check_traits == CheckTraitsAndInherentMethods {
self.push_inherent_impl_candidates_for_type(did); self.push_inherent_impl_candidates_for_type(did);
} }
@ -465,6 +468,10 @@ impl<'a> LookupContext<'a> {
ty_param(p) => { ty_param(p) => {
self.push_inherent_candidates_from_param(self_ty, restrict_to, p); self.push_inherent_candidates_from_param(self_ty, restrict_to, p);
} }
ty_unboxed_closure(closure_did) => {
self.push_unboxed_closure_call_candidates_if_applicable(
closure_did);
}
_ => { /* No bound methods in these types */ } _ => { /* No bound methods in these types */ }
} }
@ -497,11 +504,89 @@ impl<'a> LookupContext<'a> {
let opt_applicable_traits = self.fcx.ccx.trait_map.find(&expr_id); let opt_applicable_traits = self.fcx.ccx.trait_map.find(&expr_id);
for applicable_traits in opt_applicable_traits.move_iter() { for applicable_traits in opt_applicable_traits.move_iter() {
for trait_did in applicable_traits.iter() { for trait_did in applicable_traits.iter() {
debug!("push_extension_candidates() found trait: {}",
if trait_did.krate == ast::LOCAL_CRATE {
self.fcx.ccx.tcx.map.node_to_string(trait_did.node)
} else {
"(external)".to_string()
});
self.push_extension_candidate(*trait_did); self.push_extension_candidate(*trait_did);
} }
} }
} }
fn push_unboxed_closure_call_candidate_if_applicable(
&mut self,
trait_did: DefId,
closure_did: DefId,
closure_function_type: &ClosureTy) {
let method =
ty::trait_methods(self.tcx(), trait_did).get(0).clone();
let vcx = self.fcx.vtable_context();
let region_params =
vec!(vcx.infcx.next_region_var(MiscVariable(self.span)));
// Get the tupled type of the arguments.
let arguments_type = *closure_function_type.sig.inputs.get(0);
let return_type = closure_function_type.sig.output;
let unboxed_closure_type = ty::mk_unboxed_closure(self.tcx(),
closure_did);
self.extension_candidates.push(Candidate {
rcvr_match_condition:
RcvrMatchesIfSubtype(unboxed_closure_type),
rcvr_substs: subst::Substs::new_trait(
vec![arguments_type, return_type],
region_params,
*vcx.infcx.next_ty_vars(1).get(0)),
method_ty: method,
origin: MethodStaticUnboxedClosure(closure_did),
});
}
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,
};
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.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
}
None => {}
}
self.tcx().sess.bug("didn't find unboxed closure type in tcx map or \
inherited map, so there")
}
fn push_inherent_candidates_from_object(&mut self, fn push_inherent_candidates_from_object(&mut self,
did: DefId, did: DefId,
substs: &subst::Substs) { substs: &subst::Substs) {
@ -926,7 +1011,8 @@ impl<'a> LookupContext<'a> {
ty_infer(FloatVar(_)) | ty_infer(FloatVar(_)) |
ty_param(..) | ty_nil | ty_bot | ty_bool | ty_param(..) | ty_nil | ty_bot | ty_bool |
ty_char | ty_int(..) | ty_uint(..) | ty_char | ty_int(..) | ty_uint(..) |
ty_float(..) | ty_enum(..) | ty_ptr(..) | ty_struct(..) | ty_tup(..) | ty_float(..) | ty_enum(..) | ty_ptr(..) | ty_struct(..) |
ty_unboxed_closure(..) | ty_tup(..) |
ty_str | ty_vec(..) | ty_trait(..) | ty_closure(..) => { ty_str | ty_vec(..) | ty_trait(..) | ty_closure(..) => {
self.search_for_some_kind_of_autorefd_method( self.search_for_some_kind_of_autorefd_method(
AutoPtr, autoderefs, [MutImmutable, MutMutable], AutoPtr, autoderefs, [MutImmutable, MutMutable],
@ -1212,7 +1298,9 @@ impl<'a> LookupContext<'a> {
*/ */
match candidate.origin { match candidate.origin {
MethodStatic(..) | MethodParam(..) => { MethodStatic(..) |
MethodParam(..) |
MethodStaticUnboxedClosure(..) => {
return; // not a call to a trait instance return; // not a call to a trait instance
} }
MethodObject(..) => {} MethodObject(..) => {}
@ -1268,6 +1356,7 @@ impl<'a> LookupContext<'a> {
MethodStatic(method_id) => { MethodStatic(method_id) => {
bad = self.tcx().destructors.borrow().contains(&method_id); bad = self.tcx().destructors.borrow().contains(&method_id);
} }
MethodStaticUnboxedClosure(_) => bad = false,
// FIXME: does this properly enforce this on everything now // FIXME: does this properly enforce this on everything now
// that self has been merged in? -sully // that self has been merged in? -sully
MethodParam(MethodParam { trait_id: trait_id, .. }) | MethodParam(MethodParam { trait_id: trait_id, .. }) |
@ -1409,6 +1498,9 @@ impl<'a> LookupContext<'a> {
}; };
self.report_static_candidate(idx, did) self.report_static_candidate(idx, did)
} }
MethodStaticUnboxedClosure(did) => {
self.report_static_candidate(idx, did)
}
MethodParam(ref mp) => { MethodParam(ref mp) => {
self.report_param_candidate(idx, (*mp).trait_id) self.report_param_candidate(idx, (*mp).trait_id)
} }

View File

@ -114,7 +114,7 @@ use lint;
use util::common::{block_query, indenter, loop_query}; use util::common::{block_query, indenter, loop_query};
use util::ppaux; use util::ppaux;
use util::ppaux::{UserString, Repr}; use util::ppaux::{UserString, Repr};
use util::nodemap::{FnvHashMap, NodeMap}; use util::nodemap::{DefIdMap, FnvHashMap, NodeMap};
use std::cell::{Cell, RefCell}; use std::cell::{Cell, RefCell};
use std::collections::HashMap; use std::collections::HashMap;
@ -167,6 +167,7 @@ pub struct Inherited<'a> {
method_map: MethodMap, method_map: MethodMap,
vtable_map: vtable_map, vtable_map: vtable_map,
upvar_borrow_map: RefCell<ty::UpvarBorrowMap>, upvar_borrow_map: RefCell<ty::UpvarBorrowMap>,
unboxed_closure_types: RefCell<DefIdMap<ty::ClosureTy>>,
} }
/// When type-checking an expression, we propagate downward /// When type-checking an expression, we propagate downward
@ -273,6 +274,7 @@ impl<'a> Inherited<'a> {
method_map: RefCell::new(FnvHashMap::new()), method_map: RefCell::new(FnvHashMap::new()),
vtable_map: RefCell::new(FnvHashMap::new()), vtable_map: RefCell::new(FnvHashMap::new()),
upvar_borrow_map: RefCell::new(HashMap::new()), upvar_borrow_map: RefCell::new(HashMap::new()),
unboxed_closure_types: RefCell::new(DefIdMap::new()),
} }
} }
} }
@ -1251,7 +1253,8 @@ impl<'a> FnCtxt<'a> {
pub fn vtable_context<'a>(&'a self) -> VtableContext<'a> { pub fn vtable_context<'a>(&'a self) -> VtableContext<'a> {
VtableContext { VtableContext {
infcx: self.infcx(), infcx: self.infcx(),
param_env: &self.inh.param_env param_env: &self.inh.param_env,
unboxed_closure_types: &self.inh.unboxed_closure_types,
} }
} }
} }
@ -1861,7 +1864,8 @@ fn check_argument_types(fcx: &FnCtxt,
for (i, arg) in args.iter().take(t).enumerate() { for (i, arg) in args.iter().take(t).enumerate() {
let is_block = match arg.node { let is_block = match arg.node {
ast::ExprFnBlock(..) | ast::ExprFnBlock(..) |
ast::ExprProc(..) => true, ast::ExprProc(..) |
ast::ExprUnboxedFn(..) => true,
_ => false _ => false
}; };
@ -2514,6 +2518,47 @@ fn check_expr_with_unifier(fcx: &FnCtxt,
}) })
} }
fn check_unboxed_closure(fcx: &FnCtxt,
expr: &ast::Expr,
decl: &ast::FnDecl,
body: ast::P<ast::Block>) {
// The `RegionTraitStore` is a lie, but we ignore it so it doesn't
// matter.
//
// FIXME(pcwalton): Refactor this API.
let mut fn_ty = astconv::ty_of_closure(
fcx,
expr.id,
ast::NormalFn,
ast::Many,
ty::empty_builtin_bounds(),
ty::RegionTraitStore(ty::ReStatic, ast::MutImmutable),
decl,
abi::RustCall,
None);
let closure_type = ty::mk_unboxed_closure(fcx.ccx.tcx,
local_def(expr.id));
fcx.write_ty(expr.id, closure_type);
check_fn(fcx.ccx,
ast::NormalFn,
&fn_ty.sig,
decl,
expr.id,
&*body,
fcx.inh);
// Tuple up the arguments and insert the resulting function type into
// the `unboxed_closure_types` table.
fn_ty.sig.inputs = vec![ty::mk_tup(fcx.tcx(), fn_ty.sig.inputs)];
fcx.inh
.unboxed_closure_types
.borrow_mut()
.insert(local_def(expr.id), fn_ty);
}
fn check_expr_fn(fcx: &FnCtxt, fn check_expr_fn(fcx: &FnCtxt,
expr: &ast::Expr, expr: &ast::Expr,
store: ty::TraitStore, store: ty::TraitStore,
@ -2577,6 +2622,7 @@ fn check_expr_with_unifier(fcx: &FnCtxt,
expected_bounds, expected_bounds,
store, store,
decl, decl,
abi::Rust,
expected_sig); expected_sig);
let fty_sig = fn_ty.sig.clone(); let fty_sig = fn_ty.sig.clone();
let fty = ty::mk_closure(tcx, fn_ty); let fty = ty::mk_closure(tcx, fn_ty);
@ -2593,8 +2639,13 @@ fn check_expr_with_unifier(fcx: &FnCtxt,
ty::UniqTraitStore => (ast::NormalFn, expr.id) ty::UniqTraitStore => (ast::NormalFn, expr.id)
}; };
check_fn(fcx.ccx, inherited_style, &fty_sig, check_fn(fcx.ccx,
&*decl, id, &*body, fcx.inh); inherited_style,
&fty_sig,
decl,
id,
&*body,
fcx.inh);
} }
@ -3241,6 +3292,12 @@ fn check_expr_with_unifier(fcx: &FnCtxt,
body.clone(), body.clone(),
expected); expected);
} }
ast::ExprUnboxedFn(ref decl, ref body) => {
check_unboxed_closure(fcx,
expr,
&**decl,
*body);
}
ast::ExprProc(ref decl, ref body) => { ast::ExprProc(ref decl, ref body) => {
check_expr_fn(fcx, check_expr_fn(fcx,
expr, expr,

View File

@ -587,7 +587,9 @@ fn visit_expr(rcx: &mut Rcx, expr: &ast::Expr) {
visit::walk_expr(rcx, expr, ()); visit::walk_expr(rcx, expr, ());
} }
ast::ExprFnBlock(_, ref body) | ast::ExprProc(_, ref body) => { ast::ExprFnBlock(_, ref body) |
ast::ExprProc(_, ref body) |
ast::ExprUnboxedFn(_, ref body) => {
check_expr_fn_block(rcx, expr, &**body); check_expr_fn_block(rcx, expr, &**body);
} }

View File

@ -15,21 +15,23 @@ use middle::ty_fold::TypeFolder;
use middle::typeck::astconv::AstConv; use middle::typeck::astconv::AstConv;
use middle::typeck::check::{FnCtxt, impl_self_ty}; use middle::typeck::check::{FnCtxt, impl_self_ty};
use middle::typeck::check::{structurally_resolved_type}; use middle::typeck::check::{structurally_resolved_type};
use middle::typeck::check::regionmanip;
use middle::typeck::check::writeback; use middle::typeck::check::writeback;
use middle::typeck::infer::fixup_err_to_string; use middle::typeck::infer::fixup_err_to_string;
use middle::typeck::infer::{resolve_and_force_all_but_regions, resolve_type}; use middle::typeck::infer::{resolve_and_force_all_but_regions, resolve_type};
use middle::typeck::infer; use middle::typeck::infer;
use middle::typeck::{vtable_origin, vtable_res, vtable_param_res}; use middle::typeck::{MethodCall, TypeAndSubsts};
use middle::typeck::{vtable_static, vtable_param, vtable_error}; use middle::typeck::{param_index, vtable_error, vtable_origin, vtable_param};
use middle::typeck::{param_index}; use middle::typeck::{vtable_param_res, vtable_res, vtable_static};
use middle::typeck::MethodCall; use middle::typeck::{vtable_unboxed_closure};
use middle::typeck::TypeAndSubsts;
use middle::subst; use middle::subst;
use middle::subst::{Subst, VecPerParamSpace}; use middle::subst::{Subst, VecPerParamSpace};
use util::common::indenter; use util::common::indenter;
use util::nodemap::DefIdMap;
use util::ppaux; use util::ppaux;
use util::ppaux::Repr; use util::ppaux::Repr;
use std::cell::RefCell;
use std::rc::Rc; use std::rc::Rc;
use std::collections::HashSet; use std::collections::HashSet;
use syntax::ast; use syntax::ast;
@ -69,6 +71,7 @@ use syntax::visit::Visitor;
pub struct VtableContext<'a> { pub struct VtableContext<'a> {
pub infcx: &'a infer::InferCtxt<'a>, pub infcx: &'a infer::InferCtxt<'a>,
pub param_env: &'a ty::ParameterEnvironment, pub param_env: &'a ty::ParameterEnvironment,
pub unboxed_closure_types: &'a RefCell<DefIdMap<ty::ClosureTy>>,
} }
impl<'a> VtableContext<'a> { impl<'a> VtableContext<'a> {
@ -248,10 +251,13 @@ fn lookup_vtable(vcx: &VtableContext,
ty::ty_param(ParamTy {space, idx: n, ..}) => { ty::ty_param(ParamTy {space, idx: n, ..}) => {
let env_bounds = &vcx.param_env.bounds; let env_bounds = &vcx.param_env.bounds;
let type_param_bounds = &env_bounds.get(space, n).trait_bounds; let type_param_bounds = &env_bounds.get(space, n).trait_bounds;
lookup_vtable_from_bounds(vcx, span, lookup_vtable_from_bounds(vcx,
span,
type_param_bounds.as_slice(), type_param_bounds.as_slice(),
param_index { space: space, param_index {
index: n }, space: space,
index: n,
},
trait_ref.clone()) trait_ref.clone())
} }
@ -297,6 +303,75 @@ fn lookup_vtable_from_bounds(vcx: &VtableContext,
ret ret
} }
fn search_for_unboxed_closure_vtable(vcx: &VtableContext,
span: Span,
ty: ty::t,
trait_ref: Rc<ty::TraitRef>)
-> 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,
_ => return None,
};
let fn_traits = [
tcx.lang_items.fn_trait(),
tcx.lang_items.fn_mut_trait(),
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 => {}
_ => 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(),
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(),
None => {
tcx.sess.span_bug(span,
"didn't find unboxed closure type \
in tcx map or inh map")
}
}
}
};
// FIXME(pcwalton): This is a bogus thing to do, but
// it'll do for now until we get the new trait-bound
// region skolemization working.
let (_, new_signature) =
regionmanip::replace_late_bound_regions_in_fn_sig(
tcx,
&closure_type.sig,
|br| {
vcx.infcx.next_region_var(infer::LateBoundRegion(span,
br))
});
let arguments_tuple = *new_signature.inputs.get(0);
let corresponding_trait_ref = Rc::new(ty::TraitRef {
def_id: trait_ref.def_id,
substs: subst::Substs::new_trait(
vec![arguments_tuple, new_signature.output],
Vec::new(),
ty)
});
relate_trait_refs(vcx, span, corresponding_trait_ref, trait_ref);
return Some(vtable_unboxed_closure(closure_def_id))
}
None
}
fn search_for_vtable(vcx: &VtableContext, fn search_for_vtable(vcx: &VtableContext,
span: Span, span: Span,
ty: ty::t, ty: ty::t,
@ -306,6 +381,18 @@ fn search_for_vtable(vcx: &VtableContext,
debug!("nrc - search_for_vtable"); debug!("nrc - search_for_vtable");
let tcx = vcx.tcx(); let tcx = vcx.tcx();
// First, check to see whether this is a call to the `call` method of an
// unboxed closure. If so, and the arguments match, we're done.
match search_for_unboxed_closure_vtable(vcx,
span,
ty,
trait_ref.clone()) {
Some(vtable_origin) => return Some(vtable_origin),
None => {}
}
// Nope. Continue.
let mut found = Vec::new(); let mut found = Vec::new();
let mut impls_seen = HashSet::new(); let mut impls_seen = HashSet::new();
@ -799,7 +886,12 @@ pub fn resolve_impl(tcx: &ty::ctxt,
debug!("impl_trait_ref={}", impl_trait_ref.repr(tcx)); debug!("impl_trait_ref={}", impl_trait_ref.repr(tcx));
let infcx = &infer::new_infer_ctxt(tcx); let infcx = &infer::new_infer_ctxt(tcx);
let vcx = VtableContext { infcx: infcx, param_env: &param_env }; let unboxed_closure_types = RefCell::new(DefIdMap::new());
let vcx = VtableContext {
infcx: infcx,
param_env: &param_env,
unboxed_closure_types: &unboxed_closure_types,
};
// Resolve the vtables for the trait reference on the impl. This // Resolve the vtables for the trait reference on the impl. This
// serves many purposes, best explained by example. Imagine we have: // serves many purposes, best explained by example. Imagine we have:
@ -847,9 +939,11 @@ pub fn resolve_impl(tcx: &ty::ctxt,
pub fn trans_resolve_method(tcx: &ty::ctxt, id: ast::NodeId, pub fn trans_resolve_method(tcx: &ty::ctxt, id: ast::NodeId,
substs: &subst::Substs) -> vtable_res { substs: &subst::Substs) -> vtable_res {
let generics = ty::lookup_item_type(tcx, ast_util::local_def(id)).generics; let generics = ty::lookup_item_type(tcx, ast_util::local_def(id)).generics;
let unboxed_closure_types = RefCell::new(DefIdMap::new());
let vcx = VtableContext { let vcx = VtableContext {
infcx: &infer::new_infer_ctxt(tcx), infcx: &infer::new_infer_ctxt(tcx),
param_env: &ty::construct_parameter_environment(tcx, &ty::Generics::empty(), id) param_env: &ty::construct_parameter_environment(tcx, &ty::Generics::empty(), id),
unboxed_closure_types: &unboxed_closure_types,
}; };
lookup_vtables(&vcx, lookup_vtables(&vcx,

View File

@ -30,7 +30,7 @@ use util::ppaux::Repr;
use std::cell::Cell; use std::cell::Cell;
use syntax::ast; use syntax::ast;
use syntax::codemap::Span; use syntax::codemap::{DUMMY_SP, Span};
use syntax::print::pprust::pat_to_string; use syntax::print::pprust::pat_to_string;
use syntax::visit; use syntax::visit;
use syntax::visit::Visitor; use syntax::visit::Visitor;
@ -43,6 +43,7 @@ pub fn resolve_type_vars_in_expr(fcx: &FnCtxt, e: &ast::Expr) {
let mut wbcx = WritebackCx::new(fcx); let mut wbcx = WritebackCx::new(fcx);
wbcx.visit_expr(e, ()); wbcx.visit_expr(e, ());
wbcx.visit_upvar_borrow_map(); wbcx.visit_upvar_borrow_map();
wbcx.visit_unboxed_closure_types();
} }
pub fn resolve_type_vars_in_fn(fcx: &FnCtxt, pub fn resolve_type_vars_in_fn(fcx: &FnCtxt,
@ -61,6 +62,7 @@ pub fn resolve_type_vars_in_fn(fcx: &FnCtxt,
} }
} }
wbcx.visit_upvar_borrow_map(); wbcx.visit_upvar_borrow_map();
wbcx.visit_unboxed_closure_types();
} }
pub fn resolve_impl_res(infcx: &infer::InferCtxt, pub fn resolve_impl_res(infcx: &infer::InferCtxt,
@ -130,7 +132,9 @@ impl<'cx> Visitor<()> for WritebackCx<'cx> {
MethodCall::expr(e.id)); MethodCall::expr(e.id));
match e.node { match e.node {
ast::ExprFnBlock(ref decl, _) | ast::ExprProc(ref decl, _) => { ast::ExprFnBlock(ref decl, _) |
ast::ExprProc(ref decl, _) |
ast::ExprUnboxedFn(ref decl, _) => {
for input in decl.inputs.iter() { for input in decl.inputs.iter() {
let _ = self.visit_node_id(ResolvingExpr(e.span), let _ = self.visit_node_id(ResolvingExpr(e.span),
input.id); input.id);
@ -201,6 +205,26 @@ impl<'cx> WritebackCx<'cx> {
} }
} }
fn visit_unboxed_closure_types(&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,
ResolvingUnboxedClosure(*def_id));
self.fcx
.tcx()
.unboxed_closure_types
.borrow_mut()
.insert(*def_id, closure_ty);
}
}
fn visit_node_id(&self, reason: ResolveReason, id: ast::NodeId) { fn visit_node_id(&self, reason: ResolveReason, id: ast::NodeId) {
// Resolve any borrowings for the node with id `id` // Resolve any borrowings for the node with id `id`
self.visit_adjustments(reason, id); self.visit_adjustments(reason, id);
@ -332,6 +356,7 @@ enum ResolveReason {
ResolvingPattern(Span), ResolvingPattern(Span),
ResolvingUpvar(ty::UpvarId), ResolvingUpvar(ty::UpvarId),
ResolvingImplRes(Span), ResolvingImplRes(Span),
ResolvingUnboxedClosure(ast::DefId),
} }
impl ResolveReason { impl ResolveReason {
@ -344,6 +369,13 @@ impl ResolveReason {
ty::expr_span(tcx, upvar_id.closure_expr_id) ty::expr_span(tcx, upvar_id.closure_expr_id)
} }
ResolvingImplRes(s) => s, ResolvingImplRes(s) => s,
ResolvingUnboxedClosure(did) => {
if did.krate == ast::LOCAL_CRATE {
ty::expr_span(tcx, did.node)
} else {
DUMMY_SP
}
}
} }
} }
} }
@ -441,6 +473,13 @@ impl<'cx> Resolver<'cx> {
"cannot determine a type for impl \ "cannot determine a type for impl \
supertrait"); supertrait");
} }
ResolvingUnboxedClosure(_) => {
let span = self.reason.span(self.tcx);
self.tcx.sess.span_err(span,
"cannot determine a type for this \
unboxed closure")
}
} }
} }
} }

View File

@ -25,7 +25,8 @@ use middle::ty::{t, ty_bool, ty_char, ty_bot, ty_box, ty_enum, ty_err};
use middle::ty::{ty_str, ty_vec, ty_float, ty_infer, ty_int, ty_nil}; use middle::ty::{ty_str, ty_vec, ty_float, ty_infer, ty_int, ty_nil};
use middle::ty::{ty_param, Polytype, ty_ptr}; use middle::ty::{ty_param, Polytype, ty_ptr};
use middle::ty::{ty_rptr, ty_struct, ty_trait, ty_tup}; use middle::ty::{ty_rptr, ty_struct, ty_trait, ty_tup};
use middle::ty::{ty_uint, ty_uniq, ty_bare_fn, ty_closure}; use middle::ty::{ty_uint, ty_unboxed_closure, ty_uniq, ty_bare_fn};
use middle::ty::{ty_closure};
use middle::ty::type_is_ty_var; use middle::ty::type_is_ty_var;
use middle::subst::Subst; use middle::subst::Subst;
use middle::ty; use middle::ty;
@ -75,7 +76,7 @@ fn get_base_type(inference_context: &InferCtxt,
} }
match get(resolved_type).sty { match get(resolved_type).sty {
ty_enum(..) | ty_struct(..) => { ty_enum(..) | ty_struct(..) | ty_unboxed_closure(..) => {
debug!("(getting base type) found base type"); debug!("(getting base type) found base type");
Some(resolved_type) Some(resolved_type)
} }
@ -111,7 +112,8 @@ fn type_is_defined_in_local_crate(tcx: &ty::ctxt, original_type: t) -> bool {
ty::walk_ty(original_type, |t| { ty::walk_ty(original_type, |t| {
match get(t).sty { match get(t).sty {
ty_enum(def_id, _) | ty_enum(def_id, _) |
ty_struct(def_id, _) => { ty_struct(def_id, _) |
ty_unboxed_closure(def_id) => {
if def_id.krate == ast::LOCAL_CRATE { if def_id.krate == ast::LOCAL_CRATE {
found_nominal = true; found_nominal = true;
} }
@ -154,7 +156,8 @@ fn get_base_type_def_id(inference_context: &InferCtxt,
Some(base_type) => { Some(base_type) => {
match get(base_type).sty { match get(base_type).sty {
ty_enum(def_id, _) | ty_enum(def_id, _) |
ty_struct(def_id, _) => { ty_struct(def_id, _) |
ty_unboxed_closure(def_id) => {
Some(def_id) Some(def_id)
} }
ty_rptr(_, ty::mt {ty, ..}) | ty_uniq(ty) => match ty::get(ty).sty { ty_rptr(_, ty::mt {ty, ..}) | ty_uniq(ty) => match ty::get(ty).sty {
@ -691,7 +694,8 @@ impl<'a> CoherenceChecker<'a> {
let self_type = self.get_self_type_for_implementation(impl_did); let self_type = self.get_self_type_for_implementation(impl_did);
match ty::get(self_type.ty).sty { match ty::get(self_type.ty).sty {
ty::ty_enum(type_def_id, _) | ty::ty_enum(type_def_id, _) |
ty::ty_struct(type_def_id, _) => { ty::ty_struct(type_def_id, _) |
ty::ty_unboxed_closure(type_def_id) => {
tcx.destructor_for_type.borrow_mut().insert(type_def_id, tcx.destructor_for_type.borrow_mut().insert(type_def_id,
method_def_id); method_def_id);
tcx.destructors.borrow_mut().insert(method_def_id); tcx.destructors.borrow_mut().insert(method_def_id);

View File

@ -208,9 +208,16 @@ pub fn ensure_trait_methods(ccx: &CrateCtxt,
let ty_method = Rc::new(match m { let ty_method = Rc::new(match m {
&ast::Required(ref m) => { &ast::Required(ref m) => {
ty_method_of_trait_method( ty_method_of_trait_method(
ccx, trait_id, &trait_def.generics, ccx,
&m.id, &m.ident, &m.explicit_self, trait_id,
&m.generics, &m.fn_style, &*m.decl) &trait_def.generics,
&m.id,
&m.ident,
&m.explicit_self,
m.abi,
&m.generics,
&m.fn_style,
&*m.decl)
} }
&ast::Provided(ref m) => { &ast::Provided(ref m) => {
@ -221,6 +228,7 @@ pub fn ensure_trait_methods(ccx: &CrateCtxt,
&m.id, &m.id,
&m.pe_ident(), &m.pe_ident(),
m.pe_explicit_self(), m.pe_explicit_self(),
m.pe_abi(),
m.pe_generics(), m.pe_generics(),
&m.pe_fn_style(), &m.pe_fn_style(),
&*m.pe_fn_decl()) &*m.pe_fn_decl())
@ -272,25 +280,25 @@ pub fn ensure_trait_methods(ccx: &CrateCtxt,
m_id: &ast::NodeId, m_id: &ast::NodeId,
m_ident: &ast::Ident, m_ident: &ast::Ident,
m_explicit_self: &ast::ExplicitSelf, m_explicit_self: &ast::ExplicitSelf,
m_abi: abi::Abi,
m_generics: &ast::Generics, m_generics: &ast::Generics,
m_fn_style: &ast::FnStyle, m_fn_style: &ast::FnStyle,
m_decl: &ast::FnDecl) -> ty::Method m_decl: &ast::FnDecl)
{ -> ty::Method {
let trait_self_ty = ty::mk_param(this.tcx, let trait_self_ty = ty::mk_self_type(this.tcx, local_def(trait_id));
subst::SelfSpace,
0,
local_def(trait_id));
let ty_generics = ty_generics_for_fn_or_method(
this,
m_generics,
(*trait_generics).clone());
let (fty, explicit_self_category) = let (fty, explicit_self_category) =
astconv::ty_of_method(this, astconv::ty_of_method(this,
*m_id, *m_id,
*m_fn_style, *m_fn_style,
trait_self_ty, trait_self_ty,
*m_explicit_self, *m_explicit_self,
m_decl); m_decl,
m_abi);
let ty_generics =
ty_generics_for_fn_or_method(this,
m_generics,
(*trait_generics).clone());
ty::Method::new( ty::Method::new(
*m_ident, *m_ident,
ty_generics, ty_generics,
@ -381,15 +389,29 @@ fn convert_methods(ccx: &CrateCtxt,
untransformed_rcvr_ty: ty::t, untransformed_rcvr_ty: ty::t,
rcvr_ty_generics: &ty::Generics, rcvr_ty_generics: &ty::Generics,
rcvr_visibility: ast::Visibility) rcvr_visibility: ast::Visibility)
-> ty::Method -> ty::Method {
{ // FIXME(pcwalton): Hack until we have syntax in stage0 for snapshots.
let real_abi = match container {
ty::TraitContainer(trait_id) => {
if ccx.tcx.lang_items.fn_trait() == Some(trait_id) ||
ccx.tcx.lang_items.fn_mut_trait() == Some(trait_id) ||
ccx.tcx.lang_items.fn_once_trait() == Some(trait_id) {
abi::RustCall
} else {
m.pe_abi()
}
}
_ => m.pe_abi(),
};
let (fty, explicit_self_category) = let (fty, explicit_self_category) =
astconv::ty_of_method(ccx, astconv::ty_of_method(ccx,
m.id, m.id,
m.pe_fn_style(), m.pe_fn_style(),
untransformed_rcvr_ty, untransformed_rcvr_ty,
*m.pe_explicit_self(), *m.pe_explicit_self(),
&*m.pe_fn_decl()); &*m.pe_fn_decl(),
real_abi);
// if the method specifies a visibility, use that, otherwise // if the method specifies a visibility, use that, otherwise
// inherit the visibility from the impl (so `foo` in `pub impl // inherit the visibility from the impl (so `foo` in `pub impl

View File

@ -223,12 +223,14 @@ pub trait Combine {
let onceness = if_ok!(self.oncenesses(a.onceness, b.onceness)); let onceness = if_ok!(self.oncenesses(a.onceness, b.onceness));
let bounds = if_ok!(self.bounds(a.bounds, b.bounds)); let bounds = if_ok!(self.bounds(a.bounds, b.bounds));
let sig = if_ok!(self.fn_sigs(&a.sig, &b.sig)); let sig = if_ok!(self.fn_sigs(&a.sig, &b.sig));
let abi = if_ok!(self.abi(a.abi, b.abi));
Ok(ty::ClosureTy { Ok(ty::ClosureTy {
fn_style: fn_style, fn_style: fn_style,
onceness: onceness, onceness: onceness,
store: store, store: store,
bounds: bounds, bounds: bounds,
sig: sig sig: sig,
abi: abi,
}) })
} }
@ -490,6 +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)) Ok(ty::mk_struct(tcx, a_id, substs))
} }
(&ty::ty_unboxed_closure(a_id), &ty::ty_unboxed_closure(b_id))
if a_id == b_id => {
Ok(ty::mk_unboxed_closure(tcx, a_id))
}
(&ty::ty_box(a_inner), &ty::ty_box(b_inner)) => { (&ty::ty_box(a_inner), &ty::ty_box(b_inner)) => {
this.tys(a_inner, b_inner).and_then(|typ| Ok(ty::mk_box(tcx, typ))) this.tys(a_inner, b_inner).and_then(|typ| Ok(ty::mk_box(tcx, typ)))
} }

View File

@ -97,6 +97,9 @@ pub enum MethodOrigin {
// fully statically resolved method // fully statically resolved method
MethodStatic(ast::DefId), MethodStatic(ast::DefId),
// fully statically resolved unboxed closure invocation
MethodStaticUnboxedClosure(ast::DefId),
// method invoked on a type parameter with a bounded trait // method invoked on a type parameter with a bounded trait
MethodParam(MethodParam), MethodParam(MethodParam),
@ -232,6 +235,12 @@ pub enum vtable_origin {
*/ */
vtable_param(param_index, uint), vtable_param(param_index, uint),
/*
Vtable automatically generated for an unboxed closure. The def ID is the
ID of the closure expression.
*/
vtable_unboxed_closure(ast::DefId),
/* /*
Asked to determine the vtable for ty_err. This is the value used Asked to determine the vtable for ty_err. This is the value used
for the vtables of `Self` in a virtual call like `foo.bar()` for the vtables of `Self` in a virtual call like `foo.bar()`
@ -256,6 +265,10 @@ impl Repr for vtable_origin {
format!("vtable_param({:?}, {:?})", x, y) format!("vtable_param({:?}, {:?})", x, y)
} }
vtable_unboxed_closure(def_id) => {
format!("vtable_unboxed_closure({})", def_id)
}
vtable_error => { vtable_error => {
format!("vtable_error") format!("vtable_error")
} }

View File

@ -715,7 +715,7 @@ impl<'a> ConstraintContext<'a> {
match ty::get(ty).sty { match ty::get(ty).sty {
ty::ty_nil | ty::ty_bot | ty::ty_bool | ty::ty_nil | ty::ty_bot | ty::ty_bool |
ty::ty_char | ty::ty_int(_) | ty::ty_uint(_) | ty::ty_char | ty::ty_int(_) | ty::ty_uint(_) |
ty::ty_float(_) | ty::ty_str => { ty::ty_float(_) | ty::ty_str | ty::ty_unboxed_closure(..) => {
/* leaf type -- noop */ /* leaf type -- noop */
} }

View File

@ -21,6 +21,7 @@ use middle::ty::{ty_bool, ty_char, ty_bot, ty_box, ty_struct, ty_enum};
use middle::ty::{ty_err, ty_str, ty_vec, ty_float, ty_bare_fn, ty_closure}; use middle::ty::{ty_err, ty_str, ty_vec, ty_float, ty_bare_fn, ty_closure};
use middle::ty::{ty_nil, ty_param, ty_ptr, ty_rptr, ty_tup}; use middle::ty::{ty_nil, ty_param, ty_ptr, ty_rptr, ty_tup};
use middle::ty::{ty_uniq, ty_trait, ty_int, ty_uint, ty_infer}; use middle::ty::{ty_uniq, ty_trait, ty_int, ty_uint, ty_infer};
use middle::ty::{ty_unboxed_closure};
use middle::ty; use middle::ty;
use middle::typeck; use middle::typeck;
use middle::typeck::infer; use middle::typeck::infer;
@ -414,6 +415,7 @@ pub fn ty_to_string(cx: &ctxt, typ: t) -> String {
bound_str) bound_str)
} }
ty_str => "str".to_string(), ty_str => "str".to_string(),
ty_unboxed_closure(..) => "closure".to_string(),
ty_vec(ref mt, sz) => { ty_vec(ref mt, sz) => {
match sz { match sz {
Some(n) => { Some(n) => {
@ -878,6 +880,9 @@ impl Repr for typeck::MethodOrigin {
&typeck::MethodStatic(def_id) => { &typeck::MethodStatic(def_id) => {
format!("MethodStatic({})", def_id.repr(tcx)) format!("MethodStatic({})", def_id.repr(tcx))
} }
&typeck::MethodStaticUnboxedClosure(def_id) => {
format!("MethodStaticUnboxedClosure({})", def_id.repr(tcx))
}
&typeck::MethodParam(ref p) => { &typeck::MethodParam(ref p) => {
p.repr(tcx) p.repr(tcx)
} }

View File

@ -239,6 +239,7 @@ mod svh_visitor {
SawExprWhile, SawExprWhile,
SawExprMatch, SawExprMatch,
SawExprFnBlock, SawExprFnBlock,
SawExprUnboxedFn,
SawExprProc, SawExprProc,
SawExprBlock, SawExprBlock,
SawExprAssign, SawExprAssign,
@ -270,6 +271,7 @@ mod svh_visitor {
ExprLoop(_, id) => SawExprLoop(id.map(content)), ExprLoop(_, id) => SawExprLoop(id.map(content)),
ExprMatch(..) => SawExprMatch, ExprMatch(..) => SawExprMatch,
ExprFnBlock(..) => SawExprFnBlock, ExprFnBlock(..) => SawExprFnBlock,
ExprUnboxedFn(..) => SawExprUnboxedFn,
ExprProc(..) => SawExprProc, ExprProc(..) => SawExprProc,
ExprBlock(..) => SawExprBlock, ExprBlock(..) => SawExprBlock,
ExprAssign(..) => SawExprAssign, ExprAssign(..) => SawExprAssign,

View File

@ -1944,6 +1944,14 @@ pub fn mk_section_iter(llof: ObjectFileRef) -> SectionIter {
} }
} }
/// Safe wrapper around `LLVMGetParam`, because segfaults are no fun.
pub fn get_param(llfn: ValueRef, index: c_uint) -> ValueRef {
unsafe {
assert!(index < LLVMCountParams(llfn));
LLVMGetParam(llfn, index)
}
}
// FIXME #15460 - create a public function that actually calls our // FIXME #15460 - create a public function that actually calls our
// static LLVM symbols. Otherwise the linker will just throw llvm // static LLVM symbols. Otherwise the linker will just throw llvm
// away. We're just calling lots of stuff until we transitively get // away. We're just calling lots of stuff until we transitively get

View File

@ -1301,6 +1301,8 @@ impl Clean<Type> for ty::t {
} }
} }
ty::ty_unboxed_closure(..) => Primitive(Unit), // FIXME(pcwalton)
ty::ty_infer(..) => fail!("ty_infer"), ty::ty_infer(..) => fail!("ty_infer"),
ty::ty_err => fail!("ty_err"), ty::ty_err => fail!("ty_err"),
} }

View File

@ -30,6 +30,7 @@ pub enum Abi {
C, C,
System, System,
RustIntrinsic, RustIntrinsic,
RustCall,
} }
#[allow(non_camel_case_types)] #[allow(non_camel_case_types)]
@ -85,6 +86,7 @@ static AbiDatas: &'static [AbiData] = &[
AbiData {abi: C, name: "C", abi_arch: AllArch}, AbiData {abi: C, name: "C", abi_arch: AllArch},
AbiData {abi: System, name: "system", abi_arch: AllArch}, AbiData {abi: System, name: "system", abi_arch: AllArch},
AbiData {abi: RustIntrinsic, name: "rust-intrinsic", abi_arch: RustArch}, AbiData {abi: RustIntrinsic, name: "rust-intrinsic", abi_arch: RustArch},
AbiData {abi: RustCall, name: "rust-call", abi_arch: RustArch},
]; ];
/// Returns the ABI with the given name (if any). /// Returns the ABI with the given name (if any).

View File

@ -503,6 +503,7 @@ pub enum Expr_ {
ExprMatch(Gc<Expr>, Vec<Arm>), ExprMatch(Gc<Expr>, Vec<Arm>),
ExprFnBlock(P<FnDecl>, P<Block>), ExprFnBlock(P<FnDecl>, P<Block>),
ExprProc(P<FnDecl>, P<Block>), ExprProc(P<FnDecl>, P<Block>),
ExprUnboxedFn(P<FnDecl>, P<Block>),
ExprBlock(P<Block>), ExprBlock(P<Block>),
ExprAssign(Gc<Expr>, Gc<Expr>), ExprAssign(Gc<Expr>, Gc<Expr>),
@ -690,6 +691,7 @@ pub struct TypeMethod {
pub ident: Ident, pub ident: Ident,
pub attrs: Vec<Attribute>, pub attrs: Vec<Attribute>,
pub fn_style: FnStyle, pub fn_style: FnStyle,
pub abi: Abi,
pub decl: P<FnDecl>, pub decl: P<FnDecl>,
pub generics: Generics, pub generics: Generics,
pub explicit_self: ExplicitSelf, pub explicit_self: ExplicitSelf,
@ -966,13 +968,20 @@ pub struct Method {
pub attrs: Vec<Attribute>, pub attrs: Vec<Attribute>,
pub id: NodeId, pub id: NodeId,
pub span: Span, pub span: Span,
pub node: Method_ pub node: Method_,
} }
#[deriving(PartialEq, Eq, Encodable, Decodable, Hash, Show)] #[deriving(PartialEq, Eq, Encodable, Decodable, Hash, Show)]
pub enum Method_ { pub enum Method_ {
/// Represents a method declaration /// Represents a method declaration
MethDecl(Ident, Generics, ExplicitSelf, FnStyle, P<FnDecl>, P<Block>, Visibility), MethDecl(Ident,
Generics,
Abi,
ExplicitSelf,
FnStyle,
P<FnDecl>,
P<Block>,
Visibility),
/// Represents a macro in method position /// Represents a macro in method position
MethMac(Mac), MethMac(Mac),
} }

View File

@ -320,13 +320,15 @@ impl Map {
} }
NodeForeignItem(i) => PathName(i.ident.name), NodeForeignItem(i) => PathName(i.ident.name),
NodeMethod(m) => match m.node { NodeMethod(m) => match m.node {
MethDecl(ident, _, _, _, _, _, _) => PathName(ident.name), MethDecl(ident, _, _, _, _, _, _, _) => PathName(ident.name),
MethMac(_) => fail!("no path elem for {:?}", node) MethMac(_) => fail!("no path elem for {:?}", node)
}, },
NodeTraitMethod(tm) => match *tm { NodeTraitMethod(tm) => match *tm {
Required(ref m) => PathName(m.ident.name), Required(ref m) => PathName(m.ident.name),
Provided(m) => match m.node { Provided(m) => match m.node {
MethDecl(ident, _, _, _, _, _, _) => PathName(ident.name), MethDecl(ident, _, _, _, _, _, _, _) => {
PathName(ident.name)
}
MethMac(_) => fail!("no path elem for {:?}", node), MethMac(_) => fail!("no path elem for {:?}", node),
} }
}, },
@ -709,7 +711,7 @@ fn node_id_to_string(map: &Map, id: NodeId) -> String {
format!("foreign item {} (id={})", path_str, id) format!("foreign item {} (id={})", path_str, id)
} }
Some(NodeMethod(m)) => match m.node { Some(NodeMethod(m)) => match m.node {
MethDecl(ident, _, _, _, _, _, _) => MethDecl(ident, _, _, _, _, _, _, _) =>
format!("method {} in {} (id={})", format!("method {} in {} (id={})",
token::get_ident(ident), token::get_ident(ident),
map.path_to_string(id), id), map.path_to_string(id), id),

View File

@ -8,6 +8,7 @@
// option. This file may not be copied, modified, or distributed // option. This file may not be copied, modified, or distributed
// except according to those terms. // except according to those terms.
use abi::Abi;
use ast::*; use ast::*;
use ast; use ast;
use ast_util; use ast_util;
@ -249,7 +250,14 @@ pub fn trait_method_to_ty_method(method: &TraitMethod) -> TypeMethod {
Required(ref m) => (*m).clone(), Required(ref m) => (*m).clone(),
Provided(m) => { Provided(m) => {
match m.node { match m.node {
MethDecl(ident, ref generics, explicit_self, fn_style, decl, _, vis) => { MethDecl(ident,
ref generics,
abi,
explicit_self,
fn_style,
decl,
_,
vis) => {
TypeMethod { TypeMethod {
ident: ident, ident: ident,
attrs: m.attrs.clone(), attrs: m.attrs.clone(),
@ -260,6 +268,7 @@ pub fn trait_method_to_ty_method(method: &TraitMethod) -> TypeMethod {
id: m.id, id: m.id,
span: m.span, span: m.span,
vis: vis, vis: vis,
abi: abi,
} }
}, },
MethMac(_) => fail!("expected non-macro method declaration") MethMac(_) => fail!("expected non-macro method declaration")
@ -749,6 +758,7 @@ pub fn static_has_significant_address(mutbl: ast::Mutability,
pub trait PostExpansionMethod { pub trait PostExpansionMethod {
fn pe_ident(&self) -> ast::Ident; fn pe_ident(&self) -> ast::Ident;
fn pe_generics<'a>(&'a self) -> &'a ast::Generics; fn pe_generics<'a>(&'a self) -> &'a ast::Generics;
fn pe_abi(&self) -> Abi;
fn pe_explicit_self<'a>(&'a self) -> &'a ast::ExplicitSelf; fn pe_explicit_self<'a>(&'a self) -> &'a ast::ExplicitSelf;
fn pe_fn_style(&self) -> ast::FnStyle; fn pe_fn_style(&self) -> ast::FnStyle;
fn pe_fn_decl(&self) -> P<ast::FnDecl>; fn pe_fn_decl(&self) -> P<ast::FnDecl>;
@ -797,25 +807,28 @@ macro_rules! mf_method{
// PRE // PRE
impl PostExpansionMethod for Method { impl PostExpansionMethod for Method {
fn pe_ident(&self) -> ast::Ident { fn pe_ident(&self) -> ast::Ident {
mf_method_body!(self,MethDecl(ident,_,_,_,_,_,_),ident) mf_method_body!(self, MethDecl(ident,_,_,_,_,_,_,_),ident)
} }
fn pe_generics<'a>(&'a self) -> &'a ast::Generics { fn pe_generics<'a>(&'a self) -> &'a ast::Generics {
mf_method_body!(self,MethDecl(_,ref generics,_,_,_,_,_),generics) mf_method_body!(self, MethDecl(_,ref generics,_,_,_,_,_,_),generics)
}
fn pe_abi(&self) -> Abi {
mf_method_body!(self, MethDecl(_,_,abi,_,_,_,_,_),abi)
} }
fn pe_explicit_self<'a>(&'a self) -> &'a ast::ExplicitSelf { fn pe_explicit_self<'a>(&'a self) -> &'a ast::ExplicitSelf {
mf_method_body!(self,MethDecl(_,_,ref explicit_self,_,_,_,_),explicit_self) mf_method_body!(self, MethDecl(_,_,_,ref explicit_self,_,_,_,_),explicit_self)
} }
fn pe_fn_style(&self) -> ast::FnStyle{ fn pe_fn_style(&self) -> ast::FnStyle{
mf_method_body!(self,MethDecl(_,_,_,fn_style,_,_,_),fn_style) mf_method_body!(self, MethDecl(_,_,_,_,fn_style,_,_,_),fn_style)
} }
fn pe_fn_decl(&self) -> P<ast::FnDecl> { fn pe_fn_decl(&self) -> P<ast::FnDecl> {
mf_method_body!(self,MethDecl(_,_,_,_,decl,_,_),decl) mf_method_body!(self, MethDecl(_,_,_,_,_,decl,_,_),decl)
} }
fn pe_body(&self) -> P<ast::Block> { fn pe_body(&self) -> P<ast::Block> {
mf_method_body!(self,MethDecl(_,_,_,_,_,body,_),body) mf_method_body!(self, MethDecl(_,_,_,_,_,_,body,_),body)
} }
fn pe_vis(&self) -> ast::Visibility { fn pe_vis(&self) -> ast::Visibility {
mf_method_body!(self,MethDecl(_,_,_,_,_,_,vis),vis) mf_method_body!(self, MethDecl(_,_,_,_,_,_,_,vis),vis)
} }
} }

View File

@ -183,6 +183,8 @@
use std::cell::RefCell; use std::cell::RefCell;
use std::gc::{Gc, GC}; use std::gc::{Gc, GC};
use abi::Abi;
use abi;
use ast; use ast;
use ast::{P, EnumDef, Expr, Ident, Generics, StructDef}; use ast::{P, EnumDef, Expr, Ident, Generics, StructDef};
use ast_util; use ast_util;
@ -477,9 +479,13 @@ impl<'a> TraitDef<'a> {
nonself_args.as_slice()) nonself_args.as_slice())
}; };
method_def.create_method(cx, self, method_def.create_method(cx,
type_ident, generics, self,
explicit_self, tys, type_ident,
generics,
abi::Rust,
explicit_self,
tys,
body) body)
}).collect(); }).collect();
@ -513,9 +519,13 @@ impl<'a> TraitDef<'a> {
nonself_args.as_slice()) nonself_args.as_slice())
}; };
method_def.create_method(cx, self, method_def.create_method(cx,
type_ident, generics, self,
explicit_self, tys, type_ident,
generics,
abi::Rust,
explicit_self,
tys,
body) body)
}).collect(); }).collect();
@ -622,9 +632,11 @@ impl<'a> MethodDef<'a> {
trait_: &TraitDef, trait_: &TraitDef,
type_ident: Ident, type_ident: Ident,
generics: &Generics, generics: &Generics,
abi: Abi,
explicit_self: ast::ExplicitSelf, explicit_self: ast::ExplicitSelf,
arg_types: Vec<(Ident, P<ast::Ty>)> , arg_types: Vec<(Ident, P<ast::Ty>)> ,
body: Gc<Expr>) -> Gc<ast::Method> { body: Gc<Expr>)
-> Gc<ast::Method> {
// create the generics that aren't for Self // create the generics that aren't for Self
let fn_generics = self.generics.to_generics(cx, trait_.span, type_ident, generics); let fn_generics = self.generics.to_generics(cx, trait_.span, type_ident, generics);
@ -653,6 +665,7 @@ impl<'a> MethodDef<'a> {
span: trait_.span, span: trait_.span,
node: ast::MethDecl(method_ident, node: ast::MethDecl(method_ident,
fn_generics, fn_generics,
abi,
explicit_self, explicit_self,
ast::NormalFn, ast::NormalFn,
fn_decl, fn_decl,

View File

@ -910,7 +910,14 @@ impl<'a> Folder for PatIdentRenamer<'a> {
fn expand_method(m: &ast::Method, fld: &mut MacroExpander) -> SmallVector<Gc<ast::Method>> { fn expand_method(m: &ast::Method, fld: &mut MacroExpander) -> SmallVector<Gc<ast::Method>> {
let id = fld.new_id(m.id); let id = fld.new_id(m.id);
match m.node { match m.node {
ast::MethDecl(ident, ref generics, ref explicit_self, fn_style, decl, body, vis) => { ast::MethDecl(ident,
ref generics,
abi,
ref explicit_self,
fn_style,
decl,
body,
vis) => {
let (rewritten_fn_decl, rewritten_body) let (rewritten_fn_decl, rewritten_body)
= expand_and_rename_fn_decl_and_block(&*decl,body,fld); = expand_and_rename_fn_decl_and_block(&*decl,body,fld);
SmallVector::one(box(GC) ast::Method { SmallVector::one(box(GC) ast::Method {
@ -919,6 +926,7 @@ fn expand_method(m: &ast::Method, fld: &mut MacroExpander) -> SmallVector<Gc<ast
span: fld.new_span(m.span), span: fld.new_span(m.span),
node: ast::MethDecl(fld.fold_ident(ident), node: ast::MethDecl(fld.fold_ident(ident),
fold_generics(generics, fld), fold_generics(generics, fld),
abi,
fld.fold_explicit_self(explicit_self), fld.fold_explicit_self(explicit_self),
fn_style, fn_style,
rewritten_fn_decl, rewritten_fn_decl,

View File

@ -727,6 +727,7 @@ pub fn noop_fold_type_method<T: Folder>(m: &TypeMethod, fld: &mut T) -> TypeMeth
ident: fld.fold_ident(m.ident), ident: fld.fold_ident(m.ident),
attrs: m.attrs.iter().map(|a| fld.fold_attribute(*a)).collect(), attrs: m.attrs.iter().map(|a| fld.fold_attribute(*a)).collect(),
fn_style: m.fn_style, fn_style: m.fn_style,
abi: m.abi,
decl: fld.fold_fn_decl(&*m.decl), decl: fld.fold_fn_decl(&*m.decl),
generics: fold_generics(&m.generics, fld), generics: fold_generics(&m.generics, fld),
explicit_self: fld.fold_explicit_self(&m.explicit_self), explicit_self: fld.fold_explicit_self(&m.explicit_self),
@ -818,9 +819,17 @@ pub fn noop_fold_method<T: Folder>(m: &Method, folder: &mut T) -> SmallVector<Gc
id: id, id: id,
span: folder.new_span(m.span), span: folder.new_span(m.span),
node: match m.node { node: match m.node {
MethDecl(ident, ref generics, ref explicit_self, fn_style, decl, body, vis) => { MethDecl(ident,
ref generics,
abi,
ref explicit_self,
fn_style,
decl,
body,
vis) => {
MethDecl(folder.fold_ident(ident), MethDecl(folder.fold_ident(ident),
fold_generics(generics, folder), fold_generics(generics, folder),
abi,
folder.fold_explicit_self(explicit_self), folder.fold_explicit_self(explicit_self),
fn_style, fn_style,
folder.fold_fn_decl(&*decl), folder.fold_fn_decl(&*decl),
@ -948,7 +957,11 @@ pub fn noop_fold_expr<T: Folder>(e: Gc<Expr>, folder: &mut T) -> Gc<Expr> {
ExprProc(folder.fold_fn_decl(&**decl), ExprProc(folder.fold_fn_decl(&**decl),
folder.fold_block(body.clone())) folder.fold_block(body.clone()))
} }
ExprBlock(ref blk) => ExprBlock(folder.fold_block(blk.clone())), ExprUnboxedFn(ref decl, ref body) => {
ExprUnboxedFn(folder.fold_fn_decl(&**decl),
folder.fold_block(*body))
}
ExprBlock(ref blk) => ExprBlock(folder.fold_block(*blk)),
ExprAssign(el, er) => { ExprAssign(el, er) => {
ExprAssign(folder.fold_expr(el), folder.fold_expr(er)) ExprAssign(folder.fold_expr(el), folder.fold_expr(er))
} }

View File

@ -25,7 +25,7 @@ use ast::{ExprBreak, ExprCall, ExprCast};
use ast::{ExprField, ExprFnBlock, ExprIf, ExprIndex}; use ast::{ExprField, ExprFnBlock, ExprIf, ExprIndex};
use ast::{ExprLit, ExprLoop, ExprMac}; use ast::{ExprLit, ExprLoop, ExprMac};
use ast::{ExprMethodCall, ExprParen, ExprPath, ExprProc}; use ast::{ExprMethodCall, ExprParen, ExprPath, ExprProc};
use ast::{ExprRepeat, ExprRet, ExprStruct, ExprTup, ExprUnary}; use ast::{ExprRepeat, ExprRet, ExprStruct, ExprTup, ExprUnary, ExprUnboxedFn};
use ast::{ExprVec, ExprVstore, ExprVstoreSlice}; use ast::{ExprVec, ExprVstore, ExprVstoreSlice};
use ast::{ExprVstoreMutSlice, ExprWhile, ExprForLoop, Field, FnDecl}; use ast::{ExprVstoreMutSlice, ExprWhile, ExprForLoop, Field, FnDecl};
use ast::{ExprVstoreUniq, Once, Many}; use ast::{ExprVstoreUniq, Once, Many};
@ -59,6 +59,7 @@ use ast::Visibility;
use ast; use ast;
use ast_util::{as_prec, ident_to_path, lit_is_str, operator_prec}; use ast_util::{as_prec, ident_to_path, lit_is_str, operator_prec};
use ast_util; use ast_util;
use attr;
use codemap::{Span, BytePos, Spanned, spanned, mk_sp}; use codemap::{Span, BytePos, Spanned, spanned, mk_sp};
use codemap; use codemap;
use parse; use parse;
@ -1217,6 +1218,16 @@ impl<'a> Parser<'a> {
// NB: at the moment, trait methods are public by default; this // NB: at the moment, trait methods are public by default; this
// could change. // could change.
let vis = p.parse_visibility(); let vis = p.parse_visibility();
let abi = if p.eat_keyword(keywords::Extern) {
p.parse_opt_abi().unwrap_or(abi::C)
} else if attr::contains_name(attrs.as_slice(),
"rust_call_abi_hack") {
// FIXME(stage0, pcwalton): Remove this awful hack after a
// snapshot, and change to `extern "rust-call" fn`.
abi::RustCall
} else {
abi::Rust
};
let style = p.parse_fn_style(); let style = p.parse_fn_style();
let ident = p.parse_ident(); let ident = p.parse_ident();
@ -1239,6 +1250,7 @@ impl<'a> Parser<'a> {
fn_style: style, fn_style: style,
decl: d, decl: d,
generics: generics, generics: generics,
abi: abi,
explicit_self: explicit_self, explicit_self: explicit_self,
id: ast::DUMMY_NODE_ID, id: ast::DUMMY_NODE_ID,
span: mk_sp(lo, hi), span: mk_sp(lo, hi),
@ -1254,7 +1266,14 @@ impl<'a> Parser<'a> {
attrs: attrs, attrs: attrs,
id: ast::DUMMY_NODE_ID, id: ast::DUMMY_NODE_ID,
span: mk_sp(lo, hi), span: mk_sp(lo, hi),
node: ast::MethDecl(ident, generics, explicit_self, style, d, body, vis) node: ast::MethDecl(ident,
generics,
abi,
explicit_self,
style,
d,
body,
vis)
}) })
} }
@ -2620,51 +2639,11 @@ impl<'a> Parser<'a> {
self.mk_expr(lo, hi, ExprIf(cond, thn, els)) self.mk_expr(lo, hi, ExprIf(cond, thn, els))
} }
/// `|args| { ... }` or `{ ...}` like in `do` expressions // `|args| expr`
pub fn parse_lambda_block_expr(&mut self) -> Gc<Expr> {
self.parse_lambda_expr_(
|p| {
match p.token {
token::BINOP(token::OR) | token::OROR => {
p.parse_fn_block_decl()
}
_ => {
// No argument list - `do foo {`
P(FnDecl {
inputs: Vec::new(),
output: P(Ty {
id: ast::DUMMY_NODE_ID,
node: TyInfer,
span: p.span
}),
cf: Return,
variadic: false
})
}
}
},
|p| {
let blk = p.parse_block();
p.mk_expr(blk.span.lo, blk.span.hi, ExprBlock(blk))
})
}
/// `|args| expr`
pub fn parse_lambda_expr(&mut self) -> Gc<Expr> { pub fn parse_lambda_expr(&mut self) -> Gc<Expr> {
self.parse_lambda_expr_(|p| p.parse_fn_block_decl(),
|p| p.parse_expr())
}
/// parse something of the form |args| expr
/// this is used both in parsing a lambda expr
/// and in parsing a block expr as e.g. in for...
pub fn parse_lambda_expr_(&mut self,
parse_decl: |&mut Parser| -> P<FnDecl>,
parse_body: |&mut Parser| -> Gc<Expr>)
-> Gc<Expr> {
let lo = self.span.lo; let lo = self.span.lo;
let decl = parse_decl(self); let (decl, is_unboxed) = self.parse_fn_block_decl();
let body = parse_body(self); let body = self.parse_expr();
let fakeblock = P(ast::Block { let fakeblock = P(ast::Block {
view_items: Vec::new(), view_items: Vec::new(),
stmts: Vec::new(), stmts: Vec::new(),
@ -2674,7 +2653,11 @@ impl<'a> Parser<'a> {
span: body.span, span: body.span,
}); });
return self.mk_expr(lo, body.span.hi, ExprFnBlock(decl, fakeblock)); if is_unboxed {
self.mk_expr(lo, body.span.hi, ExprUnboxedFn(decl, fakeblock))
} else {
self.mk_expr(lo, body.span.hi, ExprFnBlock(decl, fakeblock))
}
} }
pub fn parse_else_expr(&mut self) -> Gc<Expr> { pub fn parse_else_expr(&mut self) -> Gc<Expr> {
@ -3955,18 +3938,30 @@ impl<'a> Parser<'a> {
(spanned(lo, hi, explicit_self), fn_decl) (spanned(lo, hi, explicit_self), fn_decl)
} }
/// Parse the |arg, arg| header on a lambda // parse the |arg, arg| header on a lambda
fn parse_fn_block_decl(&mut self) -> P<FnDecl> { fn parse_fn_block_decl(&mut self) -> (P<FnDecl>, bool) {
let inputs_captures = { let (is_unboxed, inputs_captures) = {
if self.eat(&token::OROR) { if self.eat(&token::OROR) {
Vec::new() (false, Vec::new())
} else { } else {
self.parse_unspanned_seq( self.expect(&token::BINOP(token::OR));
&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 args = self.parse_seq_to_before_end(
&token::BINOP(token::OR), &token::BINOP(token::OR),
seq_sep_trailing_disallowed(token::COMMA), seq_sep_trailing_disallowed(token::COMMA),
|p| p.parse_fn_block_arg() |p| p.parse_fn_block_arg()
) );
self.bump();
(is_unboxed, args)
} }
}; };
let output = if self.eat(&token::RARROW) { let output = if self.eat(&token::RARROW) {
@ -3979,12 +3974,12 @@ impl<'a> Parser<'a> {
}) })
}; };
P(FnDecl { (P(FnDecl {
inputs: inputs_captures, inputs: inputs_captures,
output: output, output: output,
cf: Return, cf: Return,
variadic: false variadic: false
}) }), is_unboxed)
} }
/// Parses the `(arg, arg) -> return_type` header on a procedure. /// Parses the `(arg, arg) -> return_type` header on a procedure.
@ -4079,6 +4074,11 @@ impl<'a> Parser<'a> {
(ast::MethMac(m), self.span.hi, attrs) (ast::MethMac(m), self.span.hi, attrs)
} else { } else {
let visa = self.parse_visibility(); let visa = self.parse_visibility();
let abi = if self.eat_keyword(keywords::Extern) {
self.parse_opt_abi().unwrap_or(abi::C)
} else {
abi::Rust
};
let fn_style = self.parse_fn_style(); let fn_style = self.parse_fn_style();
let ident = self.parse_ident(); let ident = self.parse_ident();
let generics = self.parse_generics(); let generics = self.parse_generics();
@ -4087,7 +4087,14 @@ impl<'a> Parser<'a> {
}); });
let (inner_attrs, body) = self.parse_inner_attrs_and_block(); let (inner_attrs, body) = self.parse_inner_attrs_and_block();
let new_attrs = attrs.append(inner_attrs.as_slice()); let new_attrs = attrs.append(inner_attrs.as_slice());
(ast::MethDecl(ident, generics, explicit_self, fn_style, decl, body, visa), (ast::MethDecl(ident,
generics,
abi,
explicit_self,
fn_style,
decl,
body,
visa),
body.span.hi, new_attrs) body.span.hi, new_attrs)
} }
}; };

View File

@ -188,7 +188,7 @@ pub fn method_to_string(p: &ast::Method) -> String {
} }
pub fn fn_block_to_string(p: &ast::FnDecl) -> String { pub fn fn_block_to_string(p: &ast::FnDecl) -> String {
to_string(|s| s.print_fn_block_args(p)) to_string(|s| s.print_fn_block_args(p, false))
} }
pub fn path_to_string(p: &ast::Path) -> String { pub fn path_to_string(p: &ast::Path) -> String {
@ -259,7 +259,8 @@ fn needs_parentheses(expr: &ast::Expr) -> bool {
match expr.node { match expr.node {
ast::ExprAssign(..) | ast::ExprBinary(..) | ast::ExprAssign(..) | ast::ExprBinary(..) |
ast::ExprFnBlock(..) | ast::ExprProc(..) | ast::ExprFnBlock(..) | ast::ExprProc(..) |
ast::ExprAssignOp(..) | ast::ExprCast(..) => true, ast::ExprUnboxedFn(..) | ast::ExprAssignOp(..) |
ast::ExprCast(..) => true,
_ => false, _ => false,
} }
} }
@ -1004,9 +1005,20 @@ impl<'a> State<'a> {
try!(self.maybe_print_comment(meth.span.lo)); try!(self.maybe_print_comment(meth.span.lo));
try!(self.print_outer_attributes(meth.attrs.as_slice())); try!(self.print_outer_attributes(meth.attrs.as_slice()));
match meth.node { match meth.node {
ast::MethDecl(ident, ref generics, ref explicit_self, fn_style, decl, body, vis) => { ast::MethDecl(ident,
try!(self.print_fn(&*decl, Some(fn_style), abi::Rust, ref generics,
ident, generics, Some(explicit_self.node), abi,
ref explicit_self,
fn_style,
decl,
body,
vis) => {
try!(self.print_fn(&*decl,
Some(fn_style),
abi,
ident,
generics,
Some(explicit_self.node),
vis)); vis));
try!(word(&mut self.s, " ")); try!(word(&mut self.s, " "));
self.print_block_with_attrs(&*body, meth.attrs.as_slice()) self.print_block_with_attrs(&*body, meth.attrs.as_slice())
@ -1446,7 +1458,37 @@ impl<'a> State<'a> {
// we are inside. // we are inside.
// //
// if !decl.inputs.is_empty() { // if !decl.inputs.is_empty() {
try!(self.print_fn_block_args(&**decl)); try!(self.print_fn_block_args(&**decl, false));
try!(space(&mut self.s));
// }
if !body.stmts.is_empty() || !body.expr.is_some() {
try!(self.print_block_unclosed(&**body));
} else {
// we extract the block, so as not to create another set of boxes
match body.expr.unwrap().node {
ast::ExprBlock(blk) => {
try!(self.print_block_unclosed(&*blk));
}
_ => {
// this is a bare expression
try!(self.print_expr(&*body.expr.unwrap()));
try!(self.end()); // need to close a box
}
}
}
// a box will be closed by print_expr, but we didn't want an overall
// wrapper so we closed the corresponding opening. so create an
// empty box to satisfy the close.
try!(self.ibox(0));
}
ast::ExprUnboxedFn(ref decl, ref body) => {
// in do/for blocks we don't want to show an empty
// argument list, but at this point we don't know which
// we are inside.
//
// if !decl.inputs.is_empty() {
try!(self.print_fn_block_args(&**decl, true));
try!(space(&mut self.s)); try!(space(&mut self.s));
// } // }
@ -1939,8 +1981,13 @@ impl<'a> State<'a> {
} }
pub fn print_fn_block_args(&mut self, pub fn print_fn_block_args(&mut self,
decl: &ast::FnDecl) -> IoResult<()> { decl: &ast::FnDecl,
is_unboxed: bool)
-> IoResult<()> {
try!(word(&mut self.s, "|")); try!(word(&mut self.s, "|"));
if is_unboxed {
try!(self.word_space("&mut:"));
}
try!(self.print_fn_args(decl, None)); try!(self.print_fn_args(decl, None));
try!(word(&mut self.s, "|")); try!(word(&mut self.s, "|"));

View File

@ -562,7 +562,7 @@ pub fn walk_method_helper<E: Clone, V: Visitor<E>>(visitor: &mut V,
method: &Method, method: &Method,
env: E) { env: E) {
match method.node { match method.node {
MethDecl(ident, ref generics, _, _, decl, body, _) => { MethDecl(ident, ref generics, _, _, _, decl, body, _) => {
visitor.visit_ident(method.span, ident, env.clone()); visitor.visit_ident(method.span, ident, env.clone());
visitor.visit_fn(&FkMethod(ident, generics, method), visitor.visit_fn(&FkMethod(ident, generics, method),
&*decl, &*decl,
@ -594,7 +594,7 @@ pub fn walk_fn<E: Clone, V: Visitor<E>>(visitor: &mut V,
FkMethod(_, generics, method) => { FkMethod(_, generics, method) => {
visitor.visit_generics(generics, env.clone()); visitor.visit_generics(generics, env.clone());
match method.node { match method.node {
MethDecl(_, _, ref explicit_self, _, _, _, _) => MethDecl(_, _, _, ref explicit_self, _, _, _, _) =>
visitor.visit_explicit_self(explicit_self, env.clone()), visitor.visit_explicit_self(explicit_self, env.clone()),
MethMac(ref mac) => MethMac(ref mac) =>
visitor.visit_mac(mac, env.clone()) visitor.visit_mac(mac, env.clone())
@ -790,6 +790,14 @@ pub fn walk_expr<E: Clone, V: Visitor<E>>(visitor: &mut V, expression: &Expr, en
expression.id, expression.id,
env.clone()) env.clone())
} }
ExprUnboxedFn(ref function_declaration, ref body) => {
visitor.visit_fn(&FkFnBlock,
&**function_declaration,
&**body,
expression.span,
expression.id,
env.clone())
}
ExprProc(ref function_declaration, ref body) => { ExprProc(ref function_declaration, ref body) => {
visitor.visit_fn(&FkFnBlock, visitor.visit_fn(&FkFnBlock,
&**function_declaration, &**function_declaration,

View File

@ -18,7 +18,7 @@ struct SFn {
} }
impl Fn<(int,),int> for SFn { impl Fn<(int,),int> for SFn {
fn call(&self, (z,): (int,)) -> int { extern "rust-call" fn call(&self, (z,): (int,)) -> int {
self.x * self.y * z self.x * self.y * z
} }
} }
@ -29,7 +29,7 @@ struct SFnMut {
} }
impl FnMut<(int,),int> for SFnMut { impl FnMut<(int,),int> for SFnMut {
fn call_mut(&mut self, (z,): (int,)) -> int { extern "rust-call" fn call_mut(&mut self, (z,): (int,)) -> int {
self.x * self.y * z self.x * self.y * z
} }
} }
@ -39,7 +39,7 @@ struct SFnOnce {
} }
impl FnOnce<(String,),uint> for SFnOnce { impl FnOnce<(String,),uint> for SFnOnce {
fn call_once(self, (z,): (String,)) -> uint { extern "rust-call" fn call_once(self, (z,): (String,)) -> uint {
self.x.len() + z.len() self.x.len() + z.len()
} }
} }

View File

@ -18,7 +18,7 @@ struct S {
} }
impl FnMut<(int,),int> for S { impl FnMut<(int,),int> for S {
fn call_mut(&mut self, (z,): (int,)) -> int { extern "rust-call" fn call_mut(&mut self, (z,): (int,)) -> int {
self.x * self.y * z self.x * self.y * z
} }
} }

View File

@ -18,7 +18,7 @@ struct S {
} }
impl FnMut<int,int> for S { impl FnMut<int,int> for S {
fn call_mut(&mut self, z: int) -> int { extern "rust-call" fn call_mut(&mut self, z: int) -> int {
self.x + self.y + z self.x + self.y + z
} }
} }

View File

@ -0,0 +1,19 @@
// Copyright 2012 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_closures)]
use std::ops::FnMut;
pub fn main() {
let mut f = |&mut: x: int, y: int| -> int { x + y };
let z = f.call_mut((1u, 2)); //~ ERROR mismatched types
println!("{}", z);
}

View File

@ -0,0 +1,25 @@
// Copyright 2012 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_closures)]
use std::ops::FnMut;
fn call_it<F:FnMut<(int,int),int>>(y: int, mut f: F) -> int {
f.call_mut((2, y))
}
pub fn main() {
let f = |&mut: x: uint, y: int| -> int { (x as int) + y };
let z = call_it(3, f); //~ ERROR expected core::ops::FnMut
//~^ ERROR expected core::ops::FnMut
println!("{}", z);
}

View File

@ -16,7 +16,7 @@ use std::ops::FnMut;
struct S; struct S;
impl FnMut<(int,),int> for S { impl FnMut<(int,),int> for S {
fn call_mut(&mut self, (x,): (int,)) -> int { extern "rust-call" fn call_mut(&mut self, (x,): (int,)) -> int {
x * x x * x
} }
} }

View File

@ -15,7 +15,7 @@ trait Foo {}
struct Bar; struct Bar;
impl<'a> std::ops::Fn<(&'a Foo,), ()> for Bar { impl<'a> std::ops::Fn<(&'a Foo,), ()> for Bar {
fn call(&self, _: (&'a Foo,)) {} extern "rust-call" fn call(&self, _: (&'a Foo,)) {}
} }
struct Baz; struct Baz;

View File

@ -34,7 +34,7 @@ impl Alloy {
} }
impl<'a, 'b> Fn<(&'b mut Response,),()> for SendFile<'a> { impl<'a, 'b> Fn<(&'b mut Response,),()> for SendFile<'a> {
fn call(&self, (_res,): (&'b mut Response,)) {} extern "rust-call" fn call(&self, (_res,): (&'b mut Response,)) {}
} }
impl<Rq: Request, Rs: Response> Ingot<Rq, Rs> for HelloWorld { impl<Rq: Request, Rs: Response> Ingot<Rq, Rs> for HelloWorld {

View File

@ -8,7 +8,7 @@
// option. This file may not be copied, modified, or distributed // option. This file may not be copied, modified, or distributed
// except according to those terms. // except according to those terms.
#![feature(overloaded_calls)] #![feature(lang_items, overloaded_calls)]
use std::ops::{Fn, FnMut, FnOnce}; use std::ops::{Fn, FnMut, FnOnce};
@ -18,7 +18,7 @@ struct S1 {
} }
impl FnMut<(int,),int> for S1 { impl FnMut<(int,),int> for S1 {
fn call_mut(&mut self, (z,): (int,)) -> int { extern "rust-call" fn call_mut(&mut self, (z,): (int,)) -> int {
self.x * self.y * z self.x * self.y * z
} }
} }
@ -29,7 +29,7 @@ struct S2 {
} }
impl Fn<(int,),int> for S2 { impl Fn<(int,),int> for S2 {
fn call(&self, (z,): (int,)) -> int { extern "rust-call" fn call(&self, (z,): (int,)) -> int {
self.x * self.y * z self.x * self.y * z
} }
} }
@ -40,7 +40,7 @@ struct S3 {
} }
impl FnOnce<(int,int),int> for S3 { impl FnOnce<(int,int),int> for S3 {
fn call_once(self, (z,zz): (int,int)) -> int { extern "rust-call" fn call_once(self, (z,zz): (int,int)) -> int {
self.x * self.y * z * zz self.x * self.y * z * zz
} }
} }
@ -50,21 +50,21 @@ fn main() {
x: 3, x: 3,
y: 3, y: 3,
}; };
let ans = s(3); let ans = s.call_mut((3,));
assert_eq!(ans, 27);
assert_eq!(ans, 27);
let s = S2 { let s = S2 {
x: 3, x: 3,
y: 3, y: 3,
}; };
let ans = s(3); let ans = s.call((3,));
assert_eq!(ans, 27); assert_eq!(ans, 27);
let s = S3 { let s = S3 {
x: 3, x: 3,
y: 3, y: 3,
}; };
let ans = s(3, 1); let ans = s.call_once((3, 1));
assert_eq!(ans, 27); assert_eq!(ans, 27);
} }

View File

@ -18,7 +18,7 @@ struct S {
} }
impl FnMut<(),int> for S { impl FnMut<(),int> for S {
fn call_mut(&mut self, (): ()) -> int { extern "rust-call" fn call_mut(&mut self, (): ()) -> int {
self.x * self.y self.x * self.y
} }
} }

View File

@ -0,0 +1,25 @@
// Copyright 2012 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_closures)]
use std::ops::FnMut;
fn make_adder(x: int) -> Box<FnMut<(int,),int>> {
(box |&mut: y: int| -> int { x + y }) as Box<FnMut<(int,),int>>
}
pub fn main() {
let mut adder = make_adder(3);
let z = adder.call_mut((2,));
println!("{}", z);
assert_eq!(z, 5);
}

View File

@ -0,0 +1,25 @@
// Copyright 2012 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_closures)]
use std::ops::FnMut;
fn call_it<F:FnMut<(int,int),int>>(y: int, mut f: F) -> int {
f.call_mut((2, y))
}
pub fn main() {
let f = |&mut: x: int, y: int| -> int { x + y };
let z = call_it(3, f);
println!("{}", z);
assert_eq!(z, 5);
}

View File

@ -0,0 +1,19 @@
// Copyright 2012 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_closures)]
use std::ops::FnMut;
pub fn main() {
let mut f = |&mut: x: int, y: int| -> int { x + y };
let z = f.call_mut((1, 2));
assert_eq!(z, 3);
}