mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-22 23:04:33 +00:00
librustc: Implement unboxed closures with mutable receivers
This commit is contained in:
parent
5ddc7b4a25
commit
02adaca4dc
@ -749,6 +749,7 @@ pub trait DerefMut<Result>: Deref<Result> {
|
||||
#[lang="fn"]
|
||||
pub trait Fn<Args,Result> {
|
||||
/// This is called when the call operator is used.
|
||||
#[rust_call_abi_hack]
|
||||
fn call(&self, args: Args) -> Result;
|
||||
}
|
||||
|
||||
@ -756,6 +757,7 @@ pub trait Fn<Args,Result> {
|
||||
#[lang="fn_mut"]
|
||||
pub trait FnMut<Args,Result> {
|
||||
/// This is called when the call operator is used.
|
||||
#[rust_call_abi_hack]
|
||||
fn call_mut(&mut self, args: Args) -> Result;
|
||||
}
|
||||
|
||||
@ -763,5 +765,7 @@ pub trait FnMut<Args,Result> {
|
||||
#[lang="fn_once"]
|
||||
pub trait FnOnce<Args,Result> {
|
||||
/// This is called when the call operator is used.
|
||||
#[rust_call_abi_hack]
|
||||
fn call_once(self, args: Args) -> Result;
|
||||
}
|
||||
|
||||
|
@ -35,6 +35,7 @@ pub use ops::{BitAnd, BitOr, BitXor};
|
||||
pub use ops::{Drop, Deref, DerefMut};
|
||||
pub use ops::{Shl, Shr};
|
||||
pub use ops::{Index, IndexMut};
|
||||
pub use ops::{Fn, FnMut, FnOnce};
|
||||
pub use option::{Option, Some, None};
|
||||
pub use result::{Result, Ok, Err};
|
||||
|
||||
|
@ -67,6 +67,7 @@ static KNOWN_FEATURES: &'static [(&'static str, Status)] = &[
|
||||
("quad_precision_float", Removed),
|
||||
|
||||
("rustc_diagnostic_macros", Active),
|
||||
("unboxed_closures", Active),
|
||||
|
||||
// A temporary feature gate used to enable parser extensions needed
|
||||
// to bootstrap fix for #5723.
|
||||
@ -327,6 +328,12 @@ impl<'a> Visitor<()> for Context<'a> {
|
||||
ast::ExprUnary(ast::UnBox, _) => {
|
||||
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, ());
|
||||
|
@ -1451,6 +1451,9 @@ impl LintPass for Stability {
|
||||
typeck::MethodStatic(def_id) => {
|
||||
def_id
|
||||
}
|
||||
typeck::MethodStaticUnboxedClosure(def_id) => {
|
||||
def_id
|
||||
}
|
||||
typeck::MethodParam(typeck::MethodParam {
|
||||
trait_id: trait_id,
|
||||
method_num: index,
|
||||
|
@ -138,10 +138,11 @@ pub enum astencode_tag { // Reserves 0x40 -- 0x5f
|
||||
tag_table_vtable_map = 0x50,
|
||||
tag_table_adjustments = 0x51,
|
||||
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 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 {
|
||||
pub fn from_uint(value : uint) -> Option<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_crate_triple: uint = 0x66;
|
||||
|
||||
pub static tag_dylib_dependency_formats: uint = 0x67;
|
||||
|
||||
// Language items are a top-level directory (for speed). Hierarchy:
|
||||
//
|
||||
// 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_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_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;
|
||||
|
||||
|
||||
#[deriving(Clone, Show)]
|
||||
pub struct LinkMeta {
|
||||
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_space: uint = 0x93;
|
||||
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;
|
||||
|
@ -209,6 +209,18 @@ fn encode_variant_id(ebml_w: &mut Encoder, vid: DefId) {
|
||||
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,
|
||||
ebml_w: &mut Encoder,
|
||||
typ: ty::t) {
|
||||
@ -1618,6 +1630,26 @@ fn encode_macro_defs(ecx: &EncodeContext,
|
||||
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> {
|
||||
ecx: &'a EncodeContext<'b>,
|
||||
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,
|
||||
plugin_registrar_fn_bytes: u64,
|
||||
macro_defs_bytes: u64,
|
||||
unboxed_closure_bytes: u64,
|
||||
impl_bytes: u64,
|
||||
misc_bytes: u64,
|
||||
item_bytes: u64,
|
||||
@ -1801,6 +1834,7 @@ fn encode_metadata_inner(wr: &mut MemWriter, parms: EncodeParams, krate: &Crate)
|
||||
native_lib_bytes: 0,
|
||||
plugin_registrar_fn_bytes: 0,
|
||||
macro_defs_bytes: 0,
|
||||
unboxed_closure_bytes: 0,
|
||||
impl_bytes: 0,
|
||||
misc_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);
|
||||
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.
|
||||
i = ebml_w.writer.tell().unwrap();
|
||||
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!("plugin registrar bytes: {}", stats.plugin_registrar_fn_bytes);
|
||||
println!(" macro def bytes: {}", stats.macro_defs_bytes);
|
||||
println!(" unboxed closure bytes: {}", stats.unboxed_closure_bytes);
|
||||
println!(" impl bytes: {}", stats.impl_bytes);
|
||||
println!(" misc bytes: {}", stats.misc_bytes);
|
||||
println!(" item bytes: {}", stats.item_bytes);
|
||||
|
@ -130,6 +130,16 @@ fn data_log_string(data: &[u8], pos: uint) -> String {
|
||||
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,
|
||||
conv: conv_did) -> ty::t {
|
||||
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), ']');
|
||||
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' => {
|
||||
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 bounds = parse_bounds(st, |x,y| conv(x,y));
|
||||
let sig = parse_sig(st, |x,y| conv(x,y));
|
||||
let abi = parse_abi_set(st);
|
||||
ty::ClosureTy {
|
||||
fn_style: fn_style,
|
||||
onceness: onceness,
|
||||
store: store,
|
||||
bounds: bounds.builtin_bounds,
|
||||
sig: sig
|
||||
sig: sig,
|
||||
abi: abi,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -284,6 +284,9 @@ fn enc_sty(w: &mut MemWriter, cx: &ctxt, st: &ty::sty) {
|
||||
enc_substs(w, cx, substs);
|
||||
mywrite!(w, "]");
|
||||
}
|
||||
ty::ty_unboxed_closure(def) => {
|
||||
mywrite!(w, "k{}", (cx.ds)(def));
|
||||
}
|
||||
ty::ty_err => {
|
||||
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);
|
||||
}
|
||||
|
||||
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_onceness(w, ft.onceness);
|
||||
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()};
|
||||
enc_bounds(w, cx, &bounds);
|
||||
enc_fn_sig(w, cx, &ft.sig);
|
||||
enc_abi(w, ft.abi);
|
||||
}
|
||||
|
||||
fn enc_fn_sig(w: &mut MemWriter, cx: &ctxt, fsig: &ty::FnSig) {
|
||||
|
@ -609,6 +609,9 @@ impl tr for MethodOrigin {
|
||||
fn tr(&self, xcx: &ExtendedDecodeContext) -> MethodOrigin {
|
||||
match *self {
|
||||
typeck::MethodStatic(did) => typeck::MethodStatic(did.tr(xcx)),
|
||||
typeck::MethodStaticUnboxedClosure(did) => {
|
||||
typeck::MethodStaticUnboxedClosure(did.tr(xcx))
|
||||
}
|
||||
typeck::MethodParam(ref mp) => {
|
||||
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 => {
|
||||
ebml_w.emit_enum_variant("vtable_error", 2u, 3u, |_ebml_w| {
|
||||
ebml_w.emit_enum_variant("vtable_error", 3u, 3u, |_ebml_w| {
|
||||
Ok(())
|
||||
})
|
||||
}
|
||||
@ -771,7 +784,8 @@ impl<'a> vtable_decoder_helpers for reader::Decoder<'a> {
|
||||
self.read_enum("vtable_origin", |this| {
|
||||
this.read_enum_variant(["vtable_static",
|
||||
"vtable_param",
|
||||
"vtable_error"],
|
||||
"vtable_error",
|
||||
"vtable_unboxed_closure"],
|
||||
|this, i| {
|
||||
Ok(match i {
|
||||
0 => {
|
||||
@ -798,6 +812,13 @@ impl<'a> vtable_decoder_helpers for reader::Decoder<'a> {
|
||||
)
|
||||
}
|
||||
2 => {
|
||||
typeck::vtable_unboxed_closure(
|
||||
this.read_enum_variant_arg(0u, |this| {
|
||||
Ok(this.read_def_id_noxcx(cdata))
|
||||
}).unwrap()
|
||||
)
|
||||
}
|
||||
3 => {
|
||||
typeck::vtable_error
|
||||
}
|
||||
_ => fail!("bad enum variant")
|
||||
@ -838,6 +859,9 @@ impl<'a> get_ty_str_ctxt for e::EncodeContext<'a> {
|
||||
}
|
||||
|
||||
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_tys(&mut self, ecx: &e::EncodeContext, tys: &[ty::t]);
|
||||
fn emit_type_param_def(&mut self,
|
||||
@ -851,6 +875,14 @@ trait ebml_writer_helpers {
|
||||
}
|
||||
|
||||
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) {
|
||||
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 {
|
||||
@ -1150,6 +1194,8 @@ trait ebml_decoder_decoder_helpers {
|
||||
-> ty::Polytype;
|
||||
fn read_substs(&mut self, xcx: &ExtendedDecodeContext) -> subst::Substs;
|
||||
fn read_auto_adjustment(&mut self, xcx: &ExtendedDecodeContext) -> ty::AutoAdjustment;
|
||||
fn read_unboxed_closure_type(&mut self, xcx: &ExtendedDecodeContext)
|
||||
-> ty::ClosureTy;
|
||||
fn convert_def_id(&mut self,
|
||||
xcx: &ExtendedDecodeContext,
|
||||
source: DefIdSource,
|
||||
@ -1322,6 +1368,18 @@ impl<'a> ebml_decoder_decoder_helpers for reader::Decoder<'a> {
|
||||
}).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,
|
||||
xcx: &ExtendedDecodeContext,
|
||||
source: tydecode::DefIdSource,
|
||||
@ -1442,6 +1500,15 @@ fn decode_side_tables(xcx: &ExtendedDecodeContext,
|
||||
let adj: ty::AutoAdjustment = val_dsr.read_auto_adjustment(xcx);
|
||||
dcx.tcx.adjustments.borrow_mut().insert(id, adj);
|
||||
}
|
||||
c::tag_table_unboxed_closure_type => {
|
||||
let unboxed_closure_type =
|
||||
val_dsr.read_unboxed_closure_type(xcx);
|
||||
dcx.tcx
|
||||
.unboxed_closure_types
|
||||
.borrow_mut()
|
||||
.insert(ast_util::local_def(id),
|
||||
unboxed_closure_type);
|
||||
}
|
||||
_ => {
|
||||
xcx.dcx.tcx.sess.bug(
|
||||
format!("unknown tag found in side tables: {:x}",
|
||||
|
@ -832,3 +832,4 @@ impl<'a> CheckLoanCtxt<'a> {
|
||||
self.bccx.loan_path_to_string(loan_path)).as_slice());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -446,6 +446,7 @@ impl<'a> CFGBuilder<'a> {
|
||||
ast::ExprMac(..) |
|
||||
ast::ExprFnBlock(..) |
|
||||
ast::ExprProc(..) |
|
||||
ast::ExprUnboxedFn(..) |
|
||||
ast::ExprLit(..) |
|
||||
ast::ExprPath(..) => {
|
||||
self.straightline(expr, pred, [])
|
||||
|
@ -42,7 +42,9 @@ impl<'a> Visitor<Context> for CheckLoopVisitor<'a> {
|
||||
ast::ExprLoop(ref b, _) => {
|
||||
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);
|
||||
}
|
||||
ast::ExprBreak(_) => self.require_loop("break", cx, e.span),
|
||||
|
@ -104,6 +104,7 @@ impl<'a> MarkSymbolVisitor<'a> {
|
||||
None => self.check_def_id(def_id)
|
||||
}
|
||||
}
|
||||
typeck::MethodStaticUnboxedClosure(_) => {}
|
||||
typeck::MethodParam(typeck::MethodParam {
|
||||
trait_id: trait_id,
|
||||
method_num: index,
|
||||
|
@ -20,7 +20,7 @@ use middle::freevars;
|
||||
use middle::pat_util;
|
||||
use middle::ty;
|
||||
use middle::typeck::{MethodCall, MethodObject, MethodOrigin, MethodParam};
|
||||
use middle::typeck::{MethodStatic};
|
||||
use middle::typeck::{MethodStatic, MethodStaticUnboxedClosure};
|
||||
use middle::typeck;
|
||||
use util::ppaux::Repr;
|
||||
|
||||
@ -160,6 +160,9 @@ impl OverloadedCallType {
|
||||
MethodStatic(def_id) => {
|
||||
OverloadedCallType::from_method_id(tcx, def_id)
|
||||
}
|
||||
MethodStaticUnboxedClosure(def_id) => {
|
||||
OverloadedCallType::from_method_id(tcx, def_id)
|
||||
}
|
||||
MethodParam(ref method_param) => {
|
||||
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::ExprUnboxedFn(..) |
|
||||
ast::ExprProc(..) => {
|
||||
self.walk_captures(expr)
|
||||
}
|
||||
|
@ -16,7 +16,7 @@
|
||||
use middle::def;
|
||||
use middle::resolve;
|
||||
use middle::ty;
|
||||
use util::nodemap::{NodeMap, NodeSet};
|
||||
use util::nodemap::{DefIdSet, NodeMap, NodeSet};
|
||||
|
||||
use syntax::codemap::Span;
|
||||
use syntax::{ast};
|
||||
@ -39,8 +39,11 @@ pub struct freevar_entry {
|
||||
pub def: def::Def, //< The variable being accessed free.
|
||||
pub span: Span //< First span where it is accessed (there can be multiple)
|
||||
}
|
||||
|
||||
pub type freevar_map = NodeMap<Vec<freevar_entry>>;
|
||||
|
||||
pub type UnboxedClosureList = DefIdSet;
|
||||
|
||||
struct CollectFreevarsVisitor<'a> {
|
||||
seen: NodeSet,
|
||||
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) {
|
||||
match expr.node {
|
||||
ast::ExprFnBlock(..) | ast::ExprProc(..) => {
|
||||
ast::ExprFnBlock(..) | ast::ExprProc(..) |
|
||||
ast::ExprUnboxedFn(..) => {
|
||||
visit::walk_expr(self, expr, depth + 1)
|
||||
}
|
||||
ast::ExprPath(..) => {
|
||||
@ -125,8 +129,8 @@ impl<'a> Visitor<()> for AnnotateFreevarsVisitor<'a> {
|
||||
// efficient as it fully recomputes the free variables at every
|
||||
// node of interest rather than building up the free variables in
|
||||
// one pass. This could be improved upon if it turns out to matter.
|
||||
pub fn annotate_freevars(def_map: &resolve::DefMap, krate: &ast::Crate) ->
|
||||
freevar_map {
|
||||
pub fn annotate_freevars(def_map: &resolve::DefMap, krate: &ast::Crate)
|
||||
-> freevar_map {
|
||||
let mut visitor = AnnotateFreevarsVisitor {
|
||||
def_map: def_map,
|
||||
freevars: NodeMap::new(),
|
||||
|
@ -216,6 +216,9 @@ fn with_appropriate_checker(cx: &Context,
|
||||
ty::ty_bare_fn(_) => {
|
||||
b(check_for_bare)
|
||||
}
|
||||
|
||||
ty::ty_unboxed_closure(_) => {}
|
||||
|
||||
ref s => {
|
||||
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) => {
|
||||
let is_object_call = match method.origin {
|
||||
typeck::MethodObject(..) => true,
|
||||
typeck::MethodStatic(..) | typeck::MethodParam(..) => false
|
||||
typeck::MethodStatic(..) |
|
||||
typeck::MethodStaticUnboxedClosure(..) |
|
||||
typeck::MethodParam(..) => false
|
||||
};
|
||||
(&method.substs.types, is_object_call)
|
||||
}
|
||||
|
@ -448,7 +448,7 @@ fn visit_expr(ir: &mut IrMaps, expr: &Expr) {
|
||||
}
|
||||
visit::walk_expr(ir, expr, ());
|
||||
}
|
||||
ExprFnBlock(..) | ExprProc(..) => {
|
||||
ExprFnBlock(..) | ExprProc(..) | ExprUnboxedFn(..) => {
|
||||
// Interesting control flow (for loops can contain labeled
|
||||
// breaks or continues)
|
||||
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)
|
||||
}
|
||||
|
||||
ExprFnBlock(_, ref blk) | ExprProc(_, ref blk) => {
|
||||
debug!("{} is an ExprFnBlock or ExprProc", expr_to_string(expr));
|
||||
ExprFnBlock(_, ref blk) |
|
||||
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
|
||||
@ -1411,8 +1414,8 @@ fn check_expr(this: &mut Liveness, expr: &Expr) {
|
||||
ExprCast(..) | ExprUnary(..) | ExprRet(..) | ExprBreak(..) |
|
||||
ExprAgain(..) | ExprLit(_) | ExprBlock(..) |
|
||||
ExprMac(..) | ExprAddrOf(..) | ExprStruct(..) | ExprRepeat(..) |
|
||||
ExprParen(..) | ExprFnBlock(..) | ExprProc(..) | ExprPath(..) |
|
||||
ExprBox(..) => {
|
||||
ExprParen(..) | ExprFnBlock(..) | ExprProc(..) | ExprUnboxedFn(..) |
|
||||
ExprPath(..) | ExprBox(..) => {
|
||||
visit::walk_expr(this, expr, ());
|
||||
}
|
||||
ExprForLoop(..) => fail!("non-desugared expr_for_loop")
|
||||
|
@ -473,7 +473,8 @@ impl<'t,TYPER:Typer> MemCategorizationContext<'t,TYPER> {
|
||||
|
||||
ast::ExprAddrOf(..) | ast::ExprCall(..) |
|
||||
ast::ExprAssign(..) | ast::ExprAssignOp(..) |
|
||||
ast::ExprFnBlock(..) | ast::ExprProc(..) | ast::ExprRet(..) |
|
||||
ast::ExprFnBlock(..) | ast::ExprProc(..) |
|
||||
ast::ExprUnboxedFn(..) | ast::ExprRet(..) |
|
||||
ast::ExprUnary(..) |
|
||||
ast::ExprMethodCall(..) | ast::ExprCast(..) | ast::ExprVstore(..) |
|
||||
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(
|
||||
span,
|
||||
|
@ -21,7 +21,7 @@ use lint;
|
||||
use middle::resolve;
|
||||
use middle::ty;
|
||||
use middle::typeck::{MethodCall, MethodMap, MethodOrigin, MethodParam};
|
||||
use middle::typeck::{MethodStatic, MethodObject};
|
||||
use middle::typeck::{MethodStatic, MethodStaticUnboxedClosure, MethodObject};
|
||||
use util::nodemap::{NodeMap, NodeSet};
|
||||
|
||||
use syntax::ast;
|
||||
@ -772,6 +772,7 @@ impl<'a> PrivacyVisitor<'a> {
|
||||
MethodStatic(method_id) => {
|
||||
self.check_static_method(span, method_id, ident)
|
||||
}
|
||||
MethodStaticUnboxedClosure(_) => {}
|
||||
// Trait methods are always all public. The only controlling factor
|
||||
// is whether the trait itself is accessible or not.
|
||||
MethodParam(MethodParam { trait_id: trait_id, .. }) |
|
||||
|
@ -5254,7 +5254,8 @@ impl<'a> Resolver<'a> {
|
||||
}
|
||||
|
||||
ExprFnBlock(fn_decl, block) |
|
||||
ExprProc(fn_decl, block) => {
|
||||
ExprProc(fn_decl, block) |
|
||||
ExprUnboxedFn(fn_decl, block) => {
|
||||
self.resolve_function(FunctionRibKind(expr.id, block.id),
|
||||
Some(fn_decl), NoTypeParameters,
|
||||
block);
|
||||
|
@ -842,7 +842,8 @@ impl <'l> DxrVisitor<'l> {
|
||||
let method_map = self.analysis.ty_cx.method_map.borrow();
|
||||
let method_callee = method_map.get(&typeck::MethodCall::expr(ex.id));
|
||||
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)
|
||||
let decl_id = ty::trait_method_of_method(&self.analysis.ty_cx, def_id);
|
||||
|
||||
|
@ -317,6 +317,9 @@ impl<T> VecPerParamSpace<T> {
|
||||
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> {
|
||||
let type_limit = t.len();
|
||||
let self_limit = t.len() + s.len();
|
||||
|
@ -163,6 +163,12 @@ fn represent_type_uncached(cx: &CrateContext, t: ty::t) -> Repr {
|
||||
|
||||
return Univariant(mk_struct(cx, ftys.as_slice(), packed), dtor)
|
||||
}
|
||||
ty::ty_unboxed_closure(def_id) => {
|
||||
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) => {
|
||||
let cases = get_cases(cx.tcx(), def_id, substs);
|
||||
let hint = ty::lookup_repr_hint(cx.tcx(), def_id);
|
||||
|
@ -29,17 +29,16 @@ use back::link::{mangle_exported_name};
|
||||
use back::{link, abi};
|
||||
use driver::config;
|
||||
use driver::config::{NoDebugInfo, FullDebugInfo};
|
||||
use driver::session::Session;
|
||||
use driver::driver::{CrateAnalysis, CrateTranslation};
|
||||
use llvm;
|
||||
use llvm::{ModuleRef, ValueRef, BasicBlockRef};
|
||||
use llvm::{Vector};
|
||||
use metadata::{csearch, encoder, loader};
|
||||
use driver::session::Session;
|
||||
use lint;
|
||||
use llvm::{BasicBlockRef, ModuleRef, ValueRef, Vector, get_param};
|
||||
use llvm;
|
||||
use metadata::{csearch, encoder, loader};
|
||||
use middle::astencode;
|
||||
use middle::lang_items::{LangItem, ExchangeMallocFnLangItem, StartFnLangItem};
|
||||
use middle::weak_lang_items;
|
||||
use middle::subst;
|
||||
use middle::weak_lang_items;
|
||||
use middle::subst::Subst;
|
||||
use middle::trans::_match;
|
||||
use middle::trans::adt;
|
||||
@ -82,7 +81,8 @@ use std::cell::{Cell, RefCell};
|
||||
use std::rc::Rc;
|
||||
use std::{i8, i16, i32, i64};
|
||||
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::attr::AttrMetaMethods;
|
||||
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 {
|
||||
let (inputs, output, has_env) = match ty::get(fn_ty).sty {
|
||||
ty::ty_bare_fn(ref f) => (f.sig.inputs.clone(), f.sig.output, false),
|
||||
ty::ty_closure(ref f) => (f.sig.inputs.clone(), f.sig.output, true),
|
||||
let (inputs, output, abi, env) = match ty::get(fn_ty).sty {
|
||||
ty::ty_bare_fn(ref f) => {
|
||||
(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")
|
||||
};
|
||||
|
||||
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 attrs = get_fn_llvm_attributes(ccx, fn_ty);
|
||||
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)) => {
|
||||
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);
|
||||
@ -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) => {
|
||||
match fn_ty.abi.for_target(ccx.sess().targ_cfg.os,
|
||||
ccx.sess().targ_cfg.arch) {
|
||||
Some(Rust) => {
|
||||
Some(Rust) | Some(RustCall) => {
|
||||
get_extern_rust_fn(ccx, t, name.as_slice(), did)
|
||||
}
|
||||
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.
|
||||
pub fn make_return_pointer(fcx: &FunctionContext, output_type: ty::t)
|
||||
-> ValueRef {
|
||||
unsafe {
|
||||
if type_of::return_uses_outptr(fcx.ccx, output_type) {
|
||||
llvm::LLVMGetParam(fcx.llfn, 0)
|
||||
} else {
|
||||
let lloutputtype = type_of::type_of(fcx.ccx, output_type);
|
||||
AllocaFcx(fcx, lloutputtype, "__make_return_pointer")
|
||||
}
|
||||
if type_of::return_uses_outptr(fcx.ccx, output_type) {
|
||||
get_param(fcx.llfn, 0)
|
||||
} else {
|
||||
let lloutputtype = type_of::type_of(fcx.ccx, output_type);
|
||||
AllocaFcx(fcx, lloutputtype, "__make_return_pointer")
|
||||
}
|
||||
}
|
||||
|
||||
@ -1213,9 +1238,7 @@ pub fn new_fn_ctxt<'a>(ccx: &'a CrateContext,
|
||||
};
|
||||
|
||||
if has_env {
|
||||
fcx.llenv = Some(unsafe {
|
||||
llvm::LLVMGetParam(fcx.llfn, fcx.env_arg_pos() as c_uint)
|
||||
});
|
||||
fcx.llenv = Some(get_param(fcx.llfn, fcx.env_arg_pos() as c_uint))
|
||||
}
|
||||
|
||||
fcx
|
||||
@ -1280,16 +1303,85 @@ pub fn create_datums_for_fn_args(fcx: &FunctionContext,
|
||||
-> Vec<RvalueDatum> {
|
||||
let _icx = push_ctxt("create_datums_for_fn_args");
|
||||
|
||||
// Return an array wrapping the ValueRefs that we get from
|
||||
// llvm::LLVMGetParam for each argument into datums.
|
||||
// Return an array wrapping the ValueRefs that we get from `get_param` for
|
||||
// each argument into datums.
|
||||
arg_tys.iter().enumerate().map(|(i, &arg_ty)| {
|
||||
let llarg = unsafe {
|
||||
llvm::LLVMGetParam(fcx.llfn, fcx.arg_pos(i) as c_uint)
|
||||
};
|
||||
let llarg = get_param(fcx.llfn, fcx.arg_pos(i) as c_uint);
|
||||
datum::Datum::new(llarg, arg_ty, arg_kind(fcx, arg_ty))
|
||||
}).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>,
|
||||
arg_scope: cleanup::CustomScopeIndex,
|
||||
bcx: &'a Block<'a>,
|
||||
@ -1322,6 +1414,59 @@ fn copy_args_to_allocas<'a>(fcx: &FunctionContext<'a>,
|
||||
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,
|
||||
// and builds the return block.
|
||||
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);
|
||||
}
|
||||
|
||||
#[deriving(Clone, Eq, PartialEq)]
|
||||
pub enum IsUnboxedClosureFlag {
|
||||
NotUnboxedClosure,
|
||||
IsUnboxedClosure,
|
||||
}
|
||||
|
||||
// trans_closure: Builds an LLVM function out of a source function.
|
||||
// If the function closes over its environment a closure will be
|
||||
// returned.
|
||||
@ -1389,7 +1540,11 @@ pub fn trans_closure(ccx: &CrateContext,
|
||||
param_substs: ¶m_substs,
|
||||
id: ast::NodeId,
|
||||
_attributes: &[ast::Attribute],
|
||||
arg_types: Vec<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>) {
|
||||
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={})",
|
||||
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 fcx = new_fn_ctxt(ccx,
|
||||
llfndecl,
|
||||
@ -1421,14 +1571,44 @@ pub fn trans_closure(ccx: &CrateContext,
|
||||
let block_ty = node_id_type(bcx, body.id);
|
||||
|
||||
// Set up arguments to the function.
|
||||
let arg_tys = ty::ty_fn_args(node_id_type(bcx, id));
|
||||
let arg_datums = create_datums_for_fn_args(&fcx, arg_tys.as_slice());
|
||||
let monomorphized_arg_types =
|
||||
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,
|
||||
arg_scope,
|
||||
bcx,
|
||||
decl.inputs.as_slice(),
|
||||
arg_datums);
|
||||
let arg_datums = if abi != RustCall {
|
||||
create_datums_for_fn_args(&fcx,
|
||||
monomorphized_arg_types.as_slice())
|
||||
} else {
|
||||
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);
|
||||
|
||||
@ -1488,9 +1668,23 @@ pub fn trans_fn(ccx: &CrateContext,
|
||||
let _s = StatRecorder::new(ccx, ccx.tcx.map.path_to_string(id).to_string());
|
||||
debug!("trans_fn(param_substs={})", param_substs.repr(ccx.tcx()));
|
||||
let _icx = push_ctxt("trans_fn");
|
||||
let output_type = ty::ty_fn_ret(ty::node_id_to_type(ccx.tcx(), id));
|
||||
trans_closure(ccx, decl, body, llfndecl,
|
||||
param_substs, id, attrs, output_type, |bcx| bcx);
|
||||
let fn_ty = ty::node_id_to_type(ccx.tcx(), id);
|
||||
let arg_types = ty::ty_fn_args(fn_ty);
|
||||
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,
|
||||
@ -1657,7 +1851,7 @@ pub fn trans_item(ccx: &CrateContext, item: &ast::Item) {
|
||||
let _icx = push_ctxt("trans_item");
|
||||
match item.node {
|
||||
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);
|
||||
foreign::trans_rust_fn_with_foreign_abi(
|
||||
ccx, &**decl, &**body, item.attrs.as_slice(), llfndecl, item.id);
|
||||
@ -1792,7 +1986,7 @@ fn register_fn(ccx: &CrateContext,
|
||||
-> ValueRef {
|
||||
match ty::get(node_type).sty {
|
||||
ty::ty_bare_fn(ref f) => {
|
||||
assert!(f.abi == Rust);
|
||||
assert!(f.abi == Rust || f.abi == RustCall);
|
||||
}
|
||||
_ => fail!("expected bare rust fn")
|
||||
};
|
||||
@ -1802,15 +1996,30 @@ fn register_fn(ccx: &CrateContext,
|
||||
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};
|
||||
|
||||
let (fn_sig, has_env) = match ty::get(fn_ty).sty {
|
||||
ty::ty_closure(ref f) => (f.sig.clone(), true),
|
||||
ty::ty_bare_fn(ref f) => (f.sig.clone(), false),
|
||||
let (fn_sig, abi, has_env) = match ty::get(fn_ty).sty {
|
||||
ty::ty_closure(ref f) => (f.sig.clone(), f.abi, true),
|
||||
ty::ty_bare_fn(ref f) => (f.sig.clone(), f.abi, false),
|
||||
ty::ty_unboxed_closure(closure_did) => {
|
||||
let unboxed_closure_types = ccx.tcx
|
||||
.unboxed_closure_types
|
||||
.borrow();
|
||||
let function_type = unboxed_closure_types.get(&closure_did);
|
||||
(function_type.sig.clone(), RustCall, true)
|
||||
}
|
||||
_ => 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
|
||||
// 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 };
|
||||
@ -1986,16 +2195,16 @@ pub fn create_entry_wrapper(ccx: &CrateContext,
|
||||
|
||||
vec!(
|
||||
opaque_rust_main,
|
||||
llvm::LLVMGetParam(llfn, 0),
|
||||
llvm::LLVMGetParam(llfn, 1)
|
||||
get_param(llfn, 0),
|
||||
get_param(llfn, 1)
|
||||
)
|
||||
};
|
||||
(start_fn, args)
|
||||
} else {
|
||||
debug!("using user-defined start fn");
|
||||
let args = vec!(
|
||||
llvm::LLVMGetParam(llfn, 0 as c_uint),
|
||||
llvm::LLVMGetParam(llfn, 1 as c_uint)
|
||||
get_param(llfn, 0 as c_uint),
|
||||
get_param(llfn, 1 as c_uint)
|
||||
);
|
||||
|
||||
(rust_main, args)
|
||||
|
@ -19,18 +19,20 @@
|
||||
use arena::TypedArena;
|
||||
use back::abi;
|
||||
use back::link;
|
||||
use llvm::{ValueRef, get_param};
|
||||
use llvm;
|
||||
use llvm::ValueRef;
|
||||
use metadata::csearch;
|
||||
use middle::def;
|
||||
use middle::subst;
|
||||
use middle::subst::{Subst, VecPerParamSpace};
|
||||
use middle::trans::adt;
|
||||
use middle::trans::base;
|
||||
use middle::trans::base::*;
|
||||
use middle::trans::build::*;
|
||||
use middle::trans::callee;
|
||||
use middle::trans::cleanup;
|
||||
use middle::trans::cleanup::CleanupMethods;
|
||||
use middle::trans::closure;
|
||||
use middle::trans::common;
|
||||
use middle::trans::common::*;
|
||||
use middle::trans::datum::*;
|
||||
@ -74,7 +76,7 @@ pub enum CalleeData {
|
||||
|
||||
pub struct Callee<'a> {
|
||||
pub bcx: &'a Block<'a>,
|
||||
pub data: CalleeData
|
||||
pub data: CalleeData,
|
||||
}
|
||||
|
||||
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 {
|
||||
ty::ty_bare_fn(..) => {
|
||||
let llval = datum.to_llscalarish(bcx);
|
||||
return Callee {bcx: bcx, data: Fn(llval)};
|
||||
return Callee {
|
||||
bcx: bcx,
|
||||
data: Fn(llval),
|
||||
};
|
||||
}
|
||||
ty::ty_closure(..) => {
|
||||
let datum = unpack_datum!(
|
||||
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(
|
||||
@ -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> {
|
||||
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)
|
||||
@ -206,9 +217,14 @@ fn trans_fn_ref_with_vtables_to_callee<'a>(bcx: &'a Block<'a>,
|
||||
substs: subst::Substs,
|
||||
vtables: typeck::vtable_res)
|
||||
-> Callee<'a> {
|
||||
Callee {bcx: bcx,
|
||||
data: Fn(trans_fn_ref_with_vtables(bcx, def_id, ExprId(ref_id),
|
||||
substs, vtables))}
|
||||
Callee {
|
||||
bcx: bcx,
|
||||
data: Fn(trans_fn_ref_with_vtables(bcx,
|
||||
def_id,
|
||||
ExprId(ref_id),
|
||||
substs,
|
||||
vtables)),
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
// Create a datum for self.
|
||||
let llboxedself = unsafe {
|
||||
llvm::LLVMGetParam(fcx.llfn, fcx.arg_pos(0) as u32)
|
||||
};
|
||||
let llboxedself = get_param(fcx.llfn, fcx.arg_pos(0) as u32);
|
||||
let llboxedself = Datum::new(llboxedself,
|
||||
boxed_self_type,
|
||||
boxed_self_kind);
|
||||
@ -340,9 +354,7 @@ pub fn trans_unboxing_shim(bcx: &Block,
|
||||
// Now call the function.
|
||||
let mut llshimmedargs = vec!(llself.val);
|
||||
for i in range(1, arg_types.len()) {
|
||||
llshimmedargs.push(unsafe {
|
||||
llvm::LLVMGetParam(fcx.llfn, fcx.arg_pos(i) as u32)
|
||||
});
|
||||
llshimmedargs.push(get_param(fcx.llfn, fcx.arg_pos(i) as u32));
|
||||
}
|
||||
bcx = trans_call_inner(bcx,
|
||||
None,
|
||||
@ -402,9 +414,6 @@ pub fn trans_fn_ref_with_vtables(
|
||||
|
||||
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.
|
||||
match ty::trait_of_method(tcx, def_id) {
|
||||
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
|
||||
// def_id to the local id of the inlined copy.
|
||||
let def_id = {
|
||||
@ -509,6 +524,9 @@ pub fn trans_fn_ref_with_vtables(
|
||||
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.
|
||||
let mut val = {
|
||||
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 llptrty = llty.ptr_to();
|
||||
if val_ty(val) != llptrty {
|
||||
debug!("trans_fn_ref_with_vtables(): casting pointer!");
|
||||
val = BitCast(bcx, val, llptrty);
|
||||
} else {
|
||||
debug!("trans_fn_ref_with_vtables(): not casting pointer!");
|
||||
}
|
||||
|
||||
val
|
||||
@ -660,7 +681,7 @@ pub fn trans_call_inner<'a>(
|
||||
|
||||
let (abi, ret_ty) = match ty::get(callee_ty).sty {
|
||||
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")
|
||||
};
|
||||
|
||||
@ -723,7 +744,7 @@ pub fn trans_call_inner<'a>(
|
||||
// and done, either the return value of the function will have been
|
||||
// written in opt_llretslot (if it is Some) or `llresult` will be
|
||||
// set appropriately (otherwise).
|
||||
if abi == synabi::Rust {
|
||||
if abi == synabi::Rust || abi == synabi::RustCall {
|
||||
let mut llargs = Vec::new();
|
||||
|
||||
// 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.
|
||||
bcx = trans_args(bcx, args, callee_ty, &mut llargs,
|
||||
bcx = trans_args(bcx,
|
||||
args,
|
||||
callee_ty,
|
||||
&mut llargs,
|
||||
cleanup::CustomScope(arg_cleanup_scope),
|
||||
llself.is_some());
|
||||
llself.is_some(),
|
||||
abi);
|
||||
|
||||
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(),
|
||||
_ => fail!("expected arg exprs.")
|
||||
};
|
||||
bcx = trans_args(bcx, args, callee_ty, &mut llargs,
|
||||
cleanup::CustomScope(arg_cleanup_scope), false);
|
||||
bcx = trans_args(bcx,
|
||||
args,
|
||||
callee_ty,
|
||||
&mut llargs,
|
||||
cleanup::CustomScope(arg_cleanup_scope),
|
||||
false,
|
||||
abi);
|
||||
fcx.pop_custom_cleanup_scope(arg_cleanup_scope);
|
||||
bcx = foreign::trans_native_call(bcx, callee_ty,
|
||||
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
|
||||
// the right-hand-side (if any).
|
||||
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>,
|
||||
args: CallArgs,
|
||||
fn_ty: ty::t,
|
||||
llargs: &mut Vec<ValueRef> ,
|
||||
arg_cleanup_scope: cleanup::ScopeId,
|
||||
ignore_self: bool)
|
||||
-> &'a Block<'a> {
|
||||
fn trans_args_under_call_abi<'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_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 arg_tys = ty::ty_fn_args(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.
|
||||
match args {
|
||||
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();
|
||||
for (i, arg_expr) in arg_exprs.iter().enumerate() {
|
||||
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) => {
|
||||
assert!(!variadic);
|
||||
|
||||
|
@ -16,6 +16,7 @@ use llvm::ValueRef;
|
||||
use middle::def;
|
||||
use middle::freevars;
|
||||
use middle::lang_items::ClosureExchangeMallocFnLangItem;
|
||||
use middle::trans::adt;
|
||||
use middle::trans::base::*;
|
||||
use middle::trans::build::*;
|
||||
use middle::trans::common::*;
|
||||
@ -31,6 +32,7 @@ use util::ppaux::ty_to_string;
|
||||
|
||||
use arena::TypedArena;
|
||||
use syntax::ast;
|
||||
use syntax::ast_util;
|
||||
|
||||
// ___Good to know (tm)__________________________________________________
|
||||
//
|
||||
@ -285,7 +287,6 @@ fn load_environment<'a>(bcx: &'a Block<'a>,
|
||||
let def_id = freevar.def.def_id();
|
||||
|
||||
bcx.fcx.llupvars.borrow_mut().insert(def_id.node, upvarptr);
|
||||
|
||||
for &env_pointer_alloca in env_pointer_alloca.iter() {
|
||||
debuginfo::create_captured_var_metadata(
|
||||
bcx,
|
||||
@ -303,6 +304,26 @@ fn load_environment<'a>(bcx: &'a Block<'a>,
|
||||
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) {
|
||||
Store(bcx, llfn, GEPi(bcx, pair, [0u, abi::fn_field_code]));
|
||||
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 freevars: Vec<freevars::freevar_entry> =
|
||||
freevars::with_freevars(
|
||||
tcx, id,
|
||||
|fv| fv.iter().map(|&fv| fv).collect());
|
||||
freevars::with_freevars(tcx,
|
||||
id,
|
||||
|fv| fv.iter().map(|&fv| fv).collect());
|
||||
|
||||
let ClosureResult {llbox, cdata_ty, bcx} =
|
||||
build_closure(bcx, freevar_mode, &freevars, store);
|
||||
trans_closure(ccx, decl, body, llfn,
|
||||
bcx.fcx.param_substs, id,
|
||||
[], ty::ty_fn_ret(fty),
|
||||
let ClosureResult {
|
||||
llbox,
|
||||
cdata_ty,
|
||||
bcx
|
||||
} = 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));
|
||||
fill_fn_pair(bcx, dest_addr, llfn, llbox);
|
||||
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,
|
||||
closure_ty: ty::t,
|
||||
def: def::Def,
|
||||
|
@ -71,7 +71,8 @@ pub fn type_is_immediate(ccx: &CrateContext, ty: ty::t) -> bool {
|
||||
}
|
||||
match ty::get(ty).sty {
|
||||
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);
|
||||
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])
|
||||
-> ValueRef {
|
||||
unsafe {
|
||||
@ -792,6 +787,9 @@ pub fn resolve_vtable_under_param_substs(tcx: &ty::ctxt,
|
||||
typeck::vtable_param(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
|
||||
}
|
||||
}
|
||||
|
@ -117,6 +117,10 @@ pub struct CrateContext {
|
||||
pub int_type: Type,
|
||||
pub opaque_vec_type: Type,
|
||||
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
|
||||
/// 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.
|
||||
@ -225,6 +229,7 @@ impl CrateContext {
|
||||
int_type: Type::from_ref(ptr::mut_null()),
|
||||
opaque_vec_type: Type::from_ref(ptr::mut_null()),
|
||||
builder: BuilderRef_res(llvm::LLVMCreateBuilderInContext(llcx)),
|
||||
unboxed_closure_vals: RefCell::new(DefIdMap::new()),
|
||||
uses_gc: false,
|
||||
dbg_cx: dbg_cx,
|
||||
eh_personality: RefCell::new(None),
|
||||
|
@ -452,7 +452,8 @@ impl TypeMap {
|
||||
onceness,
|
||||
store,
|
||||
ref bounds,
|
||||
ref sig }) => {
|
||||
ref sig,
|
||||
abi: _ }) => {
|
||||
if fn_style == ast::UnsafeFn {
|
||||
unique_type_id.push_str("unsafe ");
|
||||
}
|
||||
@ -1150,7 +1151,8 @@ pub fn create_function_debug_context(cx: &CrateContext,
|
||||
ast_map::NodeExpr(ref expr) => {
|
||||
match expr.node {
|
||||
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 = token::str_to_ident(name.as_slice());
|
||||
(name, fn_decl,
|
||||
@ -3602,7 +3604,8 @@ fn populate_scope_map(cx: &CrateContext,
|
||||
}
|
||||
|
||||
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,
|
||||
block.span,
|
||||
scope_stack,
|
||||
@ -3877,6 +3880,9 @@ fn push_debuginfo_type_name(cx: &CrateContext,
|
||||
push_debuginfo_type_name(cx, sig.output, true, output);
|
||||
}
|
||||
},
|
||||
ty::ty_unboxed_closure(_) => {
|
||||
output.push_str("closure");
|
||||
}
|
||||
ty::ty_err |
|
||||
ty::ty_infer(_) |
|
||||
ty::ty_param(_) => {
|
||||
|
@ -783,12 +783,14 @@ fn trans_rvalue_dps_unadjusted<'a>(bcx: &'a Block<'a>,
|
||||
expr_to_string(expr), expr_ty.repr(tcx));
|
||||
closure::trans_expr_fn(bcx, store, &**decl, &**body, expr.id, dest)
|
||||
}
|
||||
ast::ExprUnboxedFn(decl, body) => {
|
||||
closure::trans_unboxed_closure(bcx, &*decl, &*body, expr.id, dest)
|
||||
}
|
||||
ast::ExprCall(ref f, ref args) => {
|
||||
if bcx.tcx().is_method_call(expr.id) {
|
||||
let callee_datum = unpack_datum!(bcx, trans(bcx, &**f));
|
||||
trans_overloaded_call(bcx,
|
||||
expr,
|
||||
callee_datum,
|
||||
*f,
|
||||
args.as_slice(),
|
||||
Some(dest))
|
||||
} else {
|
||||
@ -1502,54 +1504,18 @@ fn trans_overloaded_op<'a, 'b>(
|
||||
fn trans_overloaded_call<'a>(
|
||||
mut bcx: &'a Block<'a>,
|
||||
expr: &ast::Expr,
|
||||
callee: Datum<Expr>,
|
||||
callee: Gc<ast::Expr>,
|
||||
args: &[Gc<ast::Expr>],
|
||||
dest: Option<Dest>)
|
||||
-> &'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_type = bcx.tcx()
|
||||
.method_map
|
||||
.borrow()
|
||||
.get(&method_call)
|
||||
.ty;
|
||||
let callee_rvalue = unpack_datum!(bcx,
|
||||
callee.to_rvalue_datum(bcx, "callee"));
|
||||
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))
|
||||
];
|
||||
let mut all_args = vec!(callee);
|
||||
all_args.push_all(args);
|
||||
unpack_result!(bcx,
|
||||
callee::trans_call_inner(bcx,
|
||||
Some(expr_info(expr)),
|
||||
@ -1562,10 +1528,9 @@ fn trans_overloaded_call<'a>(
|
||||
None,
|
||||
arg_cleanup_scope)
|
||||
},
|
||||
callee::ArgVals(argument_values),
|
||||
callee::ArgOverloadedCall(
|
||||
all_args.as_slice()),
|
||||
dest));
|
||||
|
||||
bcx.fcx.pop_custom_cleanup_scope(argument_scope);
|
||||
bcx
|
||||
}
|
||||
|
||||
|
@ -10,8 +10,8 @@
|
||||
|
||||
|
||||
use back::{link};
|
||||
use llvm::{ValueRef, CallConv, Linkage, get_param};
|
||||
use llvm;
|
||||
use llvm::{ValueRef, CallConv, Linkage};
|
||||
use middle::weak_lang_items;
|
||||
use middle::trans::base::push_ctxt;
|
||||
use middle::trans::base;
|
||||
@ -27,7 +27,7 @@ use middle::ty;
|
||||
use std::cmp;
|
||||
use libc::c_uint;
|
||||
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::parse::token::{InternedString, special_idents};
|
||||
use syntax::parse::token;
|
||||
@ -84,6 +84,11 @@ pub fn llvm_calling_convention(ccx: &CrateContext,
|
||||
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.
|
||||
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
|
||||
let foreign_outptr = {
|
||||
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 {
|
||||
None
|
||||
}
|
||||
@ -708,7 +713,7 @@ pub fn trans_rust_fn_with_foreign_abi(ccx: &CrateContext,
|
||||
|
||||
// skip padding
|
||||
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 {}{}: {}", "#",
|
||||
i, ccx.tn.val_to_string(llforeign_arg));
|
||||
|
@ -15,8 +15,8 @@
|
||||
|
||||
use back::abi;
|
||||
use back::link::*;
|
||||
use llvm::{ValueRef, True, get_param};
|
||||
use llvm;
|
||||
use llvm::{ValueRef, True};
|
||||
use middle::lang_items::{FreeFnLangItem, ExchangeFreeFnLangItem};
|
||||
use middle::subst;
|
||||
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 => {
|
||||
let box_cell_v = GEPi(bcx, v0, [0u, abi::fn_field_box]);
|
||||
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
|
||||
// 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);
|
||||
finish_fn(&fcx, bcx, ty::mk_nil());
|
||||
|
||||
|
@ -29,6 +29,7 @@ use middle::trans::machine;
|
||||
use middle::trans::machine::llsize_of;
|
||||
use middle::trans::type_::Type;
|
||||
use middle::ty;
|
||||
use syntax::abi::RustIntrinsic;
|
||||
use syntax::ast;
|
||||
use syntax::parse::token;
|
||||
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.
|
||||
let mut llargs = Vec::new();
|
||||
bcx = callee::trans_args(bcx, args, callee_ty, &mut llargs,
|
||||
cleanup::CustomScope(cleanup_scope), false);
|
||||
bcx = callee::trans_args(bcx,
|
||||
args,
|
||||
callee_ty,
|
||||
&mut llargs,
|
||||
cleanup::CustomScope(cleanup_scope),
|
||||
false,
|
||||
RustIntrinsic);
|
||||
|
||||
fcx.pop_custom_cleanup_scope(cleanup_scope);
|
||||
|
||||
|
@ -13,6 +13,7 @@ use back::abi;
|
||||
use llvm;
|
||||
use llvm::ValueRef;
|
||||
use metadata::csearch;
|
||||
use middle::subst::VecPerParamSpace;
|
||||
use middle::subst;
|
||||
use middle::trans::base::*;
|
||||
use middle::trans::build::*;
|
||||
@ -35,7 +36,7 @@ use util::ppaux::Repr;
|
||||
|
||||
use std::c_str::ToCStr;
|
||||
use std::gc::Gc;
|
||||
use syntax::abi::Rust;
|
||||
use syntax::abi::{Rust, RustCall};
|
||||
use syntax::parse::token;
|
||||
use syntax::{ast, ast_map, visit};
|
||||
use syntax::ast_util::PostExpansionMethod;
|
||||
@ -104,10 +105,13 @@ pub fn trans_method_callee<'a>(
|
||||
};
|
||||
|
||||
match origin {
|
||||
typeck::MethodStatic(did) => {
|
||||
typeck::MethodStatic(did) |
|
||||
typeck::MethodStaticUnboxedClosure(did) => {
|
||||
Callee {
|
||||
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 {
|
||||
@ -200,6 +204,9 @@ pub fn trans_static_method_callee(bcx: &Block,
|
||||
let llty = type_of_fn_from_ty(ccx, callee_ty).ptr_to();
|
||||
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 \
|
||||
function's vtable substs");
|
||||
@ -225,12 +232,13 @@ fn method_with_name(ccx: &CrateContext,
|
||||
*meth_did
|
||||
}
|
||||
|
||||
fn trans_monomorphized_callee<'a>(bcx: &'a Block<'a>,
|
||||
method_call: MethodCall,
|
||||
trait_id: ast::DefId,
|
||||
n_method: uint,
|
||||
vtbl: typeck::vtable_origin)
|
||||
-> Callee<'a> {
|
||||
fn trans_monomorphized_callee<'a>(
|
||||
bcx: &'a Block<'a>,
|
||||
method_call: MethodCall,
|
||||
trait_id: ast::DefId,
|
||||
n_method: uint,
|
||||
vtbl: typeck::vtable_origin)
|
||||
-> Callee<'a> {
|
||||
let _icx = push_ctxt("meth::trans_monomorphized_callee");
|
||||
match vtbl {
|
||||
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) }
|
||||
}
|
||||
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(..) => {
|
||||
bcx.tcx().sess.bug(
|
||||
"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");
|
||||
// Replace the self type (&Self or Box<Self>) with an opaque pointer.
|
||||
let llcallee_ty = match ty::get(callee_ty).sty {
|
||||
ty::ty_bare_fn(ref f) if f.abi == Rust => {
|
||||
type_of_rust_fn(ccx, true, f.sig.inputs.slice_from(1), f.sig.output)
|
||||
ty::ty_bare_fn(ref f) if f.abi == Rust || f.abi == RustCall => {
|
||||
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");
|
||||
@ -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.
|
||||
/// This is used only for objects.
|
||||
fn get_vtable(bcx: &Block,
|
||||
@ -436,6 +488,21 @@ fn get_vtable(bcx: &Block,
|
||||
typeck::vtable_static(id, substs, sub_vtables) => {
|
||||
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"),
|
||||
}
|
||||
});
|
||||
|
@ -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?
|
||||
_ => fail!("make_vtable_id needs vtable_static")
|
||||
}
|
||||
|
@ -9,8 +9,7 @@
|
||||
// except according to those terms.
|
||||
|
||||
use back::link::mangle_internal_name_by_path_and_seq;
|
||||
use llvm;
|
||||
use llvm::{ValueRef};
|
||||
use llvm::{ValueRef, get_param};
|
||||
use middle::trans::adt;
|
||||
use middle::trans::base::*;
|
||||
use middle::trans::build::*;
|
||||
@ -316,14 +315,10 @@ impl<'a, 'b> Reflector<'a, 'b> {
|
||||
None, &arena);
|
||||
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
|
||||
// is immediate.
|
||||
//
|
||||
llvm::LLVMGetParam(llfdecl, fcx.arg_pos(0u) as c_uint)
|
||||
};
|
||||
// we know the return type of llfdecl is an int here, so
|
||||
// no need for a special check to see if the return type
|
||||
// is immediate.
|
||||
let arg = get_param(llfdecl, fcx.arg_pos(0u) as c_uint);
|
||||
let arg = BitCast(bcx, arg, llptrty);
|
||||
let ret = adt::trans_get_discr(bcx, &*repr, arg, Some(Type::i64(ccx)));
|
||||
Store(bcx, ret, fcx.llretptr.get().unwrap());
|
||||
@ -366,6 +361,7 @@ impl<'a, 'b> Reflector<'a, 'b> {
|
||||
// Miscellaneous extra types
|
||||
ty::ty_infer(_) => self.leaf("infer"),
|
||||
ty::ty_err => self.leaf("err"),
|
||||
ty::ty_unboxed_closure(..) => self.leaf("err"),
|
||||
ty::ty_param(ref p) => {
|
||||
let extra = vec!(self.c_uint(p.idx));
|
||||
self.visit("param", extra.as_slice())
|
||||
|
@ -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,
|
||||
inputs: &[ty::t], output: ty::t) -> Type {
|
||||
/// Yields the types of the "real" arguments for this function. For most
|
||||
/// 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();
|
||||
|
||||
// First, munge the inputs, if this has the `rust-call` ABI.
|
||||
let inputs = untuple_arguments_if_necessary(cx, inputs, abi);
|
||||
|
||||
// Arg 0: Output pointer.
|
||||
// (if the output type is non-immediate)
|
||||
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
|
||||
if has_env {
|
||||
atys.push(Type::i8p(cx));
|
||||
match llenvironment_type {
|
||||
None => {}
|
||||
Some(llenvironment_type) => atys.push(llenvironment_type),
|
||||
}
|
||||
|
||||
// ... 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 {
|
||||
match ty::get(fty).sty {
|
||||
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) => {
|
||||
if f.abi == abi::Rust {
|
||||
if f.abi == abi::Rust || f.abi == abi::RustCall {
|
||||
type_of_rust_fn(cx,
|
||||
false,
|
||||
None,
|
||||
f.sig.inputs.as_slice(),
|
||||
f.sig.output)
|
||||
} else if f.abi == abi::RustIntrinsic {
|
||||
cx.sess().bug("type_of_fn_from_ty given intrinsic")
|
||||
f.sig.output,
|
||||
f.abi)
|
||||
} else {
|
||||
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)
|
||||
}
|
||||
|
||||
ty::ty_tup(..) | ty::ty_enum(..) => {
|
||||
ty::ty_tup(..) | ty::ty_enum(..) | ty::ty_unboxed_closure(..) => {
|
||||
let repr = adt::represent_type(cx, t);
|
||||
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);
|
||||
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) => {
|
||||
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.
|
||||
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);
|
||||
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
|
||||
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,
|
||||
what: named_ty,
|
||||
@ -319,8 +381,9 @@ pub fn llvm_type_name(cx: &CrateContext,
|
||||
-> String
|
||||
{
|
||||
let name = match what {
|
||||
a_struct => { "struct" }
|
||||
an_enum => { "enum" }
|
||||
a_struct => "struct",
|
||||
an_enum => "enum",
|
||||
an_unboxed_closure => return "closure".to_string(),
|
||||
};
|
||||
|
||||
let base = ty::item_path_str(cx.tcx(), did);
|
||||
|
@ -18,7 +18,7 @@ use lint;
|
||||
use middle::const_eval;
|
||||
use middle::def;
|
||||
use middle::dependency_format;
|
||||
use middle::lang_items::OpaqueStructLangItem;
|
||||
use middle::lang_items::{FnMutTraitLangItem, OpaqueStructLangItem};
|
||||
use middle::lang_items::{TyDescStructLangItem, TyVisitorTraitLangItem};
|
||||
use middle::freevars;
|
||||
use middle::resolve;
|
||||
@ -370,6 +370,10 @@ pub struct ctxt {
|
||||
|
||||
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),
|
||||
lint::LevelSource>>,
|
||||
|
||||
@ -454,6 +458,7 @@ pub struct ClosureTy {
|
||||
pub store: TraitStore,
|
||||
pub bounds: BuiltinBounds,
|
||||
pub sig: FnSig,
|
||||
pub abi: abi::Abi,
|
||||
}
|
||||
|
||||
/**
|
||||
@ -736,6 +741,7 @@ pub enum sty {
|
||||
ty_closure(Box<ClosureTy>),
|
||||
ty_trait(Box<TyTrait>),
|
||||
ty_struct(DefId, Substs),
|
||||
ty_unboxed_closure(DefId),
|
||||
ty_tup(Vec<t>),
|
||||
|
||||
ty_param(ParamTy), // type parameter
|
||||
@ -1054,7 +1060,7 @@ pub fn mk_ctxt(s: Session,
|
||||
region_maps: middle::region::RegionMaps,
|
||||
lang_items: middle::lang_items::LanguageItems,
|
||||
stability: stability::Index)
|
||||
-> ctxt {
|
||||
-> ctxt {
|
||||
ctxt {
|
||||
named_region_map: named_region_map,
|
||||
item_variance_map: RefCell::new(DefIdMap::new()),
|
||||
@ -1106,6 +1112,7 @@ pub fn mk_ctxt(s: Session,
|
||||
method_map: RefCell::new(FnvHashMap::new()),
|
||||
vtable_map: RefCell::new(FnvHashMap::new()),
|
||||
dependency_formats: RefCell::new(HashMap::new()),
|
||||
unboxed_closure_types: RefCell::new(DefIdMap::new()),
|
||||
node_lint_levels: RefCell::new(HashMap::new()),
|
||||
transmute_restrictions: RefCell::new(Vec::new()),
|
||||
stability: RefCell::new(stability)
|
||||
@ -1164,7 +1171,7 @@ pub fn mk_t(cx: &ctxt, st: sty) -> t {
|
||||
}
|
||||
match &st {
|
||||
&ty_nil | &ty_bool | &ty_char | &ty_int(_) | &ty_float(_) | &ty_uint(_) |
|
||||
&ty_str => {}
|
||||
&ty_str | &ty_unboxed_closure(_) => {}
|
||||
// You might think that we could just return ty_err for
|
||||
// any type containing ty_err as a component, and get
|
||||
// rid of the has_ty_err flag -- likewise for ty_bot (with
|
||||
@ -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))
|
||||
}
|
||||
|
||||
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_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 {
|
||||
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_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 {
|
||||
match get(ty).sty {
|
||||
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)
|
||||
}
|
||||
}
|
||||
@ -2082,6 +2093,12 @@ pub fn type_contents(cx: &ctxt, ty: t) -> TypeContents {
|
||||
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) => {
|
||||
TypeContents::union(tys.as_slice(),
|
||||
|ty| tc_ty(cx, *ty, cache))
|
||||
@ -2323,6 +2340,11 @@ pub fn is_instantiable(cx: &ctxt, r_ty: t) -> bool {
|
||||
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) => {
|
||||
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();
|
||||
r
|
||||
}
|
||||
|
||||
ty_enum(did, ref substs) => {
|
||||
seen.push(did);
|
||||
let vs = enum_variants(cx, did);
|
||||
@ -2445,6 +2468,14 @@ pub fn is_type_representable(cx: &ctxt, sp: Span, ty: t) -> Representability {
|
||||
r
|
||||
}
|
||||
|
||||
ty_unboxed_closure(did) => {
|
||||
let upvars = unboxed_closure_upvars(cx, did);
|
||||
find_nonrepresentable(cx,
|
||||
sp,
|
||||
seen,
|
||||
upvars.iter().map(|f| f.ty))
|
||||
}
|
||||
|
||||
_ => 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
|
||||
pub fn ty_fn_args(fty: t) -> Vec<t> {
|
||||
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 {
|
||||
match get(fty).sty {
|
||||
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 => {
|
||||
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::mk_closure(
|
||||
cx,
|
||||
ty::ClosureTy {fn_style: b.fn_style,
|
||||
onceness: ast::Many,
|
||||
store: store,
|
||||
bounds: ty::all_builtin_bounds(),
|
||||
sig: b.sig.clone()})
|
||||
ty::ClosureTy {
|
||||
fn_style: b.fn_style,
|
||||
onceness: ast::Many,
|
||||
store: store,
|
||||
bounds: ty::all_builtin_bounds(),
|
||||
sig: b.sig.clone(),
|
||||
abi: b.abi,
|
||||
})
|
||||
}
|
||||
ref b => {
|
||||
cx.sess.bug(
|
||||
@ -2990,6 +3038,14 @@ pub fn method_call_type_param_defs(tcx: &ctxt, origin: typeck::MethodOrigin)
|
||||
typeck::MethodStatic(did) => {
|
||||
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,
|
||||
method_num: n_mth, ..}) |
|
||||
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::ExprFnBlock(..) |
|
||||
ast::ExprProc(..) |
|
||||
ast::ExprUnboxedFn(..) |
|
||||
ast::ExprBlock(..) |
|
||||
ast::ExprRepeat(..) |
|
||||
ast::ExprVstore(_, ast::ExprVstoreSlice) |
|
||||
@ -3250,6 +3307,7 @@ pub fn ty_sort_string(cx: &ctxt, t: t) -> String {
|
||||
ty_struct(id, _) => {
|
||||
format!("struct {}", item_path_str(cx, id))
|
||||
}
|
||||
ty_unboxed_closure(_) => "closure".to_string(),
|
||||
ty_tup(_) => "tuple".to_string(),
|
||||
ty_infer(TyVar(_)) => "inferred type".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 {
|
||||
ty_trait(box TyTrait { def_id: id, .. }) |
|
||||
ty_struct(id, _) |
|
||||
ty_enum(id, _) => Some(id),
|
||||
ty_enum(id, _) |
|
||||
ty_unboxed_closure(id) => Some(id),
|
||||
_ => None
|
||||
}
|
||||
}
|
||||
@ -4046,6 +4105,34 @@ pub fn struct_fields(cx: &ctxt, did: ast::DefId, substs: &Substs)
|
||||
}).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 {
|
||||
static tycat_other: int = 0;
|
||||
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_err => byte!(23),
|
||||
ty_unboxed_closure(d) => {
|
||||
byte!(24);
|
||||
did(&mut state, d);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -220,6 +220,9 @@ impl TypeFoldable for typeck::vtable_origin {
|
||||
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
|
||||
}
|
||||
@ -326,6 +329,7 @@ pub fn super_fold_closure_ty<T:TypeFolder>(this: &mut T,
|
||||
fn_style: fty.fn_style,
|
||||
onceness: fty.onceness,
|
||||
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, 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_int(_) | ty::ty_uint(_) | ty::ty_float(_) |
|
||||
ty::ty_err | ty::ty_infer(_) |
|
||||
|
@ -762,6 +762,7 @@ pub fn ast_ty_to_ty<AC:AstConv, RS:RegionScope>(
|
||||
bounds,
|
||||
store,
|
||||
&*f.decl,
|
||||
abi::Rust,
|
||||
None);
|
||||
ty::mk_closure(tcx, fn_decl)
|
||||
}
|
||||
@ -780,6 +781,7 @@ pub fn ast_ty_to_ty<AC:AstConv, RS:RegionScope>(
|
||||
bounds,
|
||||
ty::UniqTraitStore,
|
||||
&*f.decl,
|
||||
abi::Rust,
|
||||
None);
|
||||
ty::mk_closure(tcx, fn_decl)
|
||||
}
|
||||
@ -879,9 +881,9 @@ pub fn ast_ty_to_ty<AC:AstConv, RS:RegionScope>(
|
||||
}
|
||||
ast::TyInfer => {
|
||||
// TyInfer also appears as the type of arguments or return
|
||||
// values in a ExprFnBlock or ExprProc, or as the type of
|
||||
// local variables. Both of these cases are handled specially
|
||||
// and will not descend into this routine.
|
||||
// values in a ExprFnBlock, ExprProc, or ExprUnboxedFn, or as
|
||||
// the type of local variables. Both of these cases are
|
||||
// handled specially and will not descend into this routine.
|
||||
this.ty_infer(ast_ty.span)
|
||||
}
|
||||
}
|
||||
@ -911,7 +913,8 @@ pub fn ty_of_method<AC:AstConv>(
|
||||
fn_style: ast::FnStyle,
|
||||
untransformed_self_ty: ty::t,
|
||||
explicit_self: ast::ExplicitSelf,
|
||||
decl: &ast::FnDecl)
|
||||
decl: &ast::FnDecl,
|
||||
abi: abi::Abi)
|
||||
-> (ty::BareFnTy, ty::ExplicitSelfCategory) {
|
||||
let self_info = Some(SelfInfo {
|
||||
untransformed_self_ty: untransformed_self_ty,
|
||||
@ -921,7 +924,7 @@ pub fn ty_of_method<AC:AstConv>(
|
||||
ty_of_method_or_bare_fn(this,
|
||||
id,
|
||||
fn_style,
|
||||
abi::Rust,
|
||||
abi,
|
||||
self_info,
|
||||
decl);
|
||||
(bare_fn_ty, optional_explicit_self_category.unwrap())
|
||||
@ -1083,6 +1086,7 @@ pub fn ty_of_closure<AC:AstConv>(
|
||||
bounds: ty::BuiltinBounds,
|
||||
store: ty::TraitStore,
|
||||
decl: &ast::FnDecl,
|
||||
abi: abi::Abi,
|
||||
expected_sig: Option<ty::FnSig>)
|
||||
-> ty::ClosureTy
|
||||
{
|
||||
@ -1117,6 +1121,7 @@ pub fn ty_of_closure<AC:AstConv>(
|
||||
onceness: onceness,
|
||||
store: store,
|
||||
bounds: bounds,
|
||||
abi: abi,
|
||||
sig: ty::FnSig {binder_id: id,
|
||||
inputs: input_tys,
|
||||
output: output_ty,
|
||||
|
@ -87,10 +87,11 @@ use middle::ty;
|
||||
use middle::typeck::astconv::AstConv;
|
||||
use middle::typeck::check::{FnCtxt, PreferMutLvalue, impl_self_ty};
|
||||
use middle::typeck::check;
|
||||
use middle::typeck::infer::MiscVariable;
|
||||
use middle::typeck::infer;
|
||||
use middle::typeck::MethodCallee;
|
||||
use middle::typeck::{MethodOrigin, MethodParam};
|
||||
use middle::typeck::{MethodStatic, MethodObject};
|
||||
use middle::typeck::{MethodStatic, MethodStaticUnboxedClosure, MethodObject};
|
||||
use middle::typeck::{param_index};
|
||||
use middle::typeck::check::regionmanip::replace_late_bound_regions_in_fn_sig;
|
||||
use middle::typeck::TypeAndSubsts;
|
||||
@ -341,7 +342,7 @@ struct Candidate {
|
||||
#[deriving(Clone)]
|
||||
pub enum RcvrMatchCondition {
|
||||
RcvrMatchesIfObject(ast::DefId),
|
||||
RcvrMatchesIfSubtype(ty::t)
|
||||
RcvrMatchesIfSubtype(ty::t),
|
||||
}
|
||||
|
||||
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 {
|
||||
self.push_inherent_impl_candidates_for_type(did);
|
||||
}
|
||||
@ -465,6 +468,10 @@ impl<'a> LookupContext<'a> {
|
||||
ty_param(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 */ }
|
||||
}
|
||||
|
||||
@ -497,11 +504,89 @@ impl<'a> LookupContext<'a> {
|
||||
let opt_applicable_traits = self.fcx.ccx.trait_map.find(&expr_id);
|
||||
for applicable_traits in opt_applicable_traits.move_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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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,
|
||||
did: DefId,
|
||||
substs: &subst::Substs) {
|
||||
@ -926,7 +1011,8 @@ impl<'a> LookupContext<'a> {
|
||||
ty_infer(FloatVar(_)) |
|
||||
ty_param(..) | ty_nil | ty_bot | ty_bool |
|
||||
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(..) => {
|
||||
self.search_for_some_kind_of_autorefd_method(
|
||||
AutoPtr, autoderefs, [MutImmutable, MutMutable],
|
||||
@ -1212,7 +1298,9 @@ impl<'a> LookupContext<'a> {
|
||||
*/
|
||||
|
||||
match candidate.origin {
|
||||
MethodStatic(..) | MethodParam(..) => {
|
||||
MethodStatic(..) |
|
||||
MethodParam(..) |
|
||||
MethodStaticUnboxedClosure(..) => {
|
||||
return; // not a call to a trait instance
|
||||
}
|
||||
MethodObject(..) => {}
|
||||
@ -1268,6 +1356,7 @@ impl<'a> LookupContext<'a> {
|
||||
MethodStatic(method_id) => {
|
||||
bad = self.tcx().destructors.borrow().contains(&method_id);
|
||||
}
|
||||
MethodStaticUnboxedClosure(_) => bad = false,
|
||||
// FIXME: does this properly enforce this on everything now
|
||||
// that self has been merged in? -sully
|
||||
MethodParam(MethodParam { trait_id: trait_id, .. }) |
|
||||
@ -1409,6 +1498,9 @@ impl<'a> LookupContext<'a> {
|
||||
};
|
||||
self.report_static_candidate(idx, did)
|
||||
}
|
||||
MethodStaticUnboxedClosure(did) => {
|
||||
self.report_static_candidate(idx, did)
|
||||
}
|
||||
MethodParam(ref mp) => {
|
||||
self.report_param_candidate(idx, (*mp).trait_id)
|
||||
}
|
||||
|
@ -114,7 +114,7 @@ use lint;
|
||||
use util::common::{block_query, indenter, loop_query};
|
||||
use util::ppaux;
|
||||
use util::ppaux::{UserString, Repr};
|
||||
use util::nodemap::{FnvHashMap, NodeMap};
|
||||
use util::nodemap::{DefIdMap, FnvHashMap, NodeMap};
|
||||
|
||||
use std::cell::{Cell, RefCell};
|
||||
use std::collections::HashMap;
|
||||
@ -167,6 +167,7 @@ pub struct Inherited<'a> {
|
||||
method_map: MethodMap,
|
||||
vtable_map: vtable_map,
|
||||
upvar_borrow_map: RefCell<ty::UpvarBorrowMap>,
|
||||
unboxed_closure_types: RefCell<DefIdMap<ty::ClosureTy>>,
|
||||
}
|
||||
|
||||
/// When type-checking an expression, we propagate downward
|
||||
@ -273,6 +274,7 @@ impl<'a> Inherited<'a> {
|
||||
method_map: RefCell::new(FnvHashMap::new()),
|
||||
vtable_map: RefCell::new(FnvHashMap::new()),
|
||||
upvar_borrow_map: RefCell::new(HashMap::new()),
|
||||
unboxed_closure_types: RefCell::new(DefIdMap::new()),
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1251,7 +1253,8 @@ impl<'a> FnCtxt<'a> {
|
||||
pub fn vtable_context<'a>(&'a self) -> VtableContext<'a> {
|
||||
VtableContext {
|
||||
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() {
|
||||
let is_block = match arg.node {
|
||||
ast::ExprFnBlock(..) |
|
||||
ast::ExprProc(..) => true,
|
||||
ast::ExprProc(..) |
|
||||
ast::ExprUnboxedFn(..) => true,
|
||||
_ => 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,
|
||||
expr: &ast::Expr,
|
||||
store: ty::TraitStore,
|
||||
@ -2577,6 +2622,7 @@ fn check_expr_with_unifier(fcx: &FnCtxt,
|
||||
expected_bounds,
|
||||
store,
|
||||
decl,
|
||||
abi::Rust,
|
||||
expected_sig);
|
||||
let fty_sig = fn_ty.sig.clone();
|
||||
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)
|
||||
};
|
||||
|
||||
check_fn(fcx.ccx, inherited_style, &fty_sig,
|
||||
&*decl, id, &*body, fcx.inh);
|
||||
check_fn(fcx.ccx,
|
||||
inherited_style,
|
||||
&fty_sig,
|
||||
decl,
|
||||
id,
|
||||
&*body,
|
||||
fcx.inh);
|
||||
}
|
||||
|
||||
|
||||
@ -3241,6 +3292,12 @@ fn check_expr_with_unifier(fcx: &FnCtxt,
|
||||
body.clone(),
|
||||
expected);
|
||||
}
|
||||
ast::ExprUnboxedFn(ref decl, ref body) => {
|
||||
check_unboxed_closure(fcx,
|
||||
expr,
|
||||
&**decl,
|
||||
*body);
|
||||
}
|
||||
ast::ExprProc(ref decl, ref body) => {
|
||||
check_expr_fn(fcx,
|
||||
expr,
|
||||
|
@ -587,7 +587,9 @@ fn visit_expr(rcx: &mut Rcx, expr: &ast::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);
|
||||
}
|
||||
|
||||
|
@ -15,21 +15,23 @@ use middle::ty_fold::TypeFolder;
|
||||
use middle::typeck::astconv::AstConv;
|
||||
use middle::typeck::check::{FnCtxt, impl_self_ty};
|
||||
use middle::typeck::check::{structurally_resolved_type};
|
||||
use middle::typeck::check::regionmanip;
|
||||
use middle::typeck::check::writeback;
|
||||
use middle::typeck::infer::fixup_err_to_string;
|
||||
use middle::typeck::infer::{resolve_and_force_all_but_regions, resolve_type};
|
||||
use middle::typeck::infer;
|
||||
use middle::typeck::{vtable_origin, vtable_res, vtable_param_res};
|
||||
use middle::typeck::{vtable_static, vtable_param, vtable_error};
|
||||
use middle::typeck::{param_index};
|
||||
use middle::typeck::MethodCall;
|
||||
use middle::typeck::TypeAndSubsts;
|
||||
use middle::typeck::{MethodCall, TypeAndSubsts};
|
||||
use middle::typeck::{param_index, vtable_error, vtable_origin, vtable_param};
|
||||
use middle::typeck::{vtable_param_res, vtable_res, vtable_static};
|
||||
use middle::typeck::{vtable_unboxed_closure};
|
||||
use middle::subst;
|
||||
use middle::subst::{Subst, VecPerParamSpace};
|
||||
use util::common::indenter;
|
||||
use util::nodemap::DefIdMap;
|
||||
use util::ppaux;
|
||||
use util::ppaux::Repr;
|
||||
|
||||
use std::cell::RefCell;
|
||||
use std::rc::Rc;
|
||||
use std::collections::HashSet;
|
||||
use syntax::ast;
|
||||
@ -69,6 +71,7 @@ use syntax::visit::Visitor;
|
||||
pub struct VtableContext<'a> {
|
||||
pub infcx: &'a infer::InferCtxt<'a>,
|
||||
pub param_env: &'a ty::ParameterEnvironment,
|
||||
pub unboxed_closure_types: &'a RefCell<DefIdMap<ty::ClosureTy>>,
|
||||
}
|
||||
|
||||
impl<'a> VtableContext<'a> {
|
||||
@ -248,10 +251,13 @@ fn lookup_vtable(vcx: &VtableContext,
|
||||
ty::ty_param(ParamTy {space, idx: n, ..}) => {
|
||||
let env_bounds = &vcx.param_env.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(),
|
||||
param_index { space: space,
|
||||
index: n },
|
||||
param_index {
|
||||
space: space,
|
||||
index: n,
|
||||
},
|
||||
trait_ref.clone())
|
||||
}
|
||||
|
||||
@ -297,6 +303,75 @@ fn lookup_vtable_from_bounds(vcx: &VtableContext,
|
||||
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,
|
||||
span: Span,
|
||||
ty: ty::t,
|
||||
@ -306,6 +381,18 @@ fn search_for_vtable(vcx: &VtableContext,
|
||||
debug!("nrc - search_for_vtable");
|
||||
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 impls_seen = HashSet::new();
|
||||
|
||||
@ -799,7 +886,12 @@ pub fn resolve_impl(tcx: &ty::ctxt,
|
||||
debug!("impl_trait_ref={}", impl_trait_ref.repr(tcx));
|
||||
|
||||
let infcx = &infer::new_infer_ctxt(tcx);
|
||||
let vcx = VtableContext { infcx: infcx, param_env: ¶m_env };
|
||||
let unboxed_closure_types = RefCell::new(DefIdMap::new());
|
||||
let vcx = VtableContext {
|
||||
infcx: infcx,
|
||||
param_env: ¶m_env,
|
||||
unboxed_closure_types: &unboxed_closure_types,
|
||||
};
|
||||
|
||||
// Resolve the vtables for the trait reference on the impl. This
|
||||
// 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,
|
||||
substs: &subst::Substs) -> vtable_res {
|
||||
let generics = ty::lookup_item_type(tcx, ast_util::local_def(id)).generics;
|
||||
let unboxed_closure_types = RefCell::new(DefIdMap::new());
|
||||
let vcx = VtableContext {
|
||||
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,
|
||||
|
@ -30,7 +30,7 @@ use util::ppaux::Repr;
|
||||
use std::cell::Cell;
|
||||
|
||||
use syntax::ast;
|
||||
use syntax::codemap::Span;
|
||||
use syntax::codemap::{DUMMY_SP, Span};
|
||||
use syntax::print::pprust::pat_to_string;
|
||||
use syntax::visit;
|
||||
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);
|
||||
wbcx.visit_expr(e, ());
|
||||
wbcx.visit_upvar_borrow_map();
|
||||
wbcx.visit_unboxed_closure_types();
|
||||
}
|
||||
|
||||
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_unboxed_closure_types();
|
||||
}
|
||||
|
||||
pub fn resolve_impl_res(infcx: &infer::InferCtxt,
|
||||
@ -130,7 +132,9 @@ impl<'cx> Visitor<()> for WritebackCx<'cx> {
|
||||
MethodCall::expr(e.id));
|
||||
|
||||
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() {
|
||||
let _ = self.visit_node_id(ResolvingExpr(e.span),
|
||||
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) {
|
||||
// Resolve any borrowings for the node with id `id`
|
||||
self.visit_adjustments(reason, id);
|
||||
@ -332,6 +356,7 @@ enum ResolveReason {
|
||||
ResolvingPattern(Span),
|
||||
ResolvingUpvar(ty::UpvarId),
|
||||
ResolvingImplRes(Span),
|
||||
ResolvingUnboxedClosure(ast::DefId),
|
||||
}
|
||||
|
||||
impl ResolveReason {
|
||||
@ -344,6 +369,13 @@ impl ResolveReason {
|
||||
ty::expr_span(tcx, upvar_id.closure_expr_id)
|
||||
}
|
||||
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 \
|
||||
supertrait");
|
||||
}
|
||||
|
||||
ResolvingUnboxedClosure(_) => {
|
||||
let span = self.reason.span(self.tcx);
|
||||
self.tcx.sess.span_err(span,
|
||||
"cannot determine a type for this \
|
||||
unboxed closure")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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_param, Polytype, ty_ptr};
|
||||
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::subst::Subst;
|
||||
use middle::ty;
|
||||
@ -75,7 +76,7 @@ fn get_base_type(inference_context: &InferCtxt,
|
||||
}
|
||||
|
||||
match get(resolved_type).sty {
|
||||
ty_enum(..) | ty_struct(..) => {
|
||||
ty_enum(..) | ty_struct(..) | ty_unboxed_closure(..) => {
|
||||
debug!("(getting base type) found base 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| {
|
||||
match get(t).sty {
|
||||
ty_enum(def_id, _) |
|
||||
ty_struct(def_id, _) => {
|
||||
ty_struct(def_id, _) |
|
||||
ty_unboxed_closure(def_id) => {
|
||||
if def_id.krate == ast::LOCAL_CRATE {
|
||||
found_nominal = true;
|
||||
}
|
||||
@ -154,7 +156,8 @@ fn get_base_type_def_id(inference_context: &InferCtxt,
|
||||
Some(base_type) => {
|
||||
match get(base_type).sty {
|
||||
ty_enum(def_id, _) |
|
||||
ty_struct(def_id, _) => {
|
||||
ty_struct(def_id, _) |
|
||||
ty_unboxed_closure(def_id) => {
|
||||
Some(def_id)
|
||||
}
|
||||
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);
|
||||
match ty::get(self_type.ty).sty {
|
||||
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,
|
||||
method_def_id);
|
||||
tcx.destructors.borrow_mut().insert(method_def_id);
|
||||
|
@ -208,9 +208,16 @@ pub fn ensure_trait_methods(ccx: &CrateCtxt,
|
||||
let ty_method = Rc::new(match m {
|
||||
&ast::Required(ref m) => {
|
||||
ty_method_of_trait_method(
|
||||
ccx, trait_id, &trait_def.generics,
|
||||
&m.id, &m.ident, &m.explicit_self,
|
||||
&m.generics, &m.fn_style, &*m.decl)
|
||||
ccx,
|
||||
trait_id,
|
||||
&trait_def.generics,
|
||||
&m.id,
|
||||
&m.ident,
|
||||
&m.explicit_self,
|
||||
m.abi,
|
||||
&m.generics,
|
||||
&m.fn_style,
|
||||
&*m.decl)
|
||||
}
|
||||
|
||||
&ast::Provided(ref m) => {
|
||||
@ -221,6 +228,7 @@ pub fn ensure_trait_methods(ccx: &CrateCtxt,
|
||||
&m.id,
|
||||
&m.pe_ident(),
|
||||
m.pe_explicit_self(),
|
||||
m.pe_abi(),
|
||||
m.pe_generics(),
|
||||
&m.pe_fn_style(),
|
||||
&*m.pe_fn_decl())
|
||||
@ -272,25 +280,25 @@ pub fn ensure_trait_methods(ccx: &CrateCtxt,
|
||||
m_id: &ast::NodeId,
|
||||
m_ident: &ast::Ident,
|
||||
m_explicit_self: &ast::ExplicitSelf,
|
||||
m_abi: abi::Abi,
|
||||
m_generics: &ast::Generics,
|
||||
m_fn_style: &ast::FnStyle,
|
||||
m_decl: &ast::FnDecl) -> ty::Method
|
||||
{
|
||||
let trait_self_ty = ty::mk_param(this.tcx,
|
||||
subst::SelfSpace,
|
||||
0,
|
||||
local_def(trait_id));
|
||||
let ty_generics = ty_generics_for_fn_or_method(
|
||||
this,
|
||||
m_generics,
|
||||
(*trait_generics).clone());
|
||||
m_decl: &ast::FnDecl)
|
||||
-> ty::Method {
|
||||
let trait_self_ty = ty::mk_self_type(this.tcx, local_def(trait_id));
|
||||
|
||||
let (fty, explicit_self_category) =
|
||||
astconv::ty_of_method(this,
|
||||
*m_id,
|
||||
*m_fn_style,
|
||||
trait_self_ty,
|
||||
*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(
|
||||
*m_ident,
|
||||
ty_generics,
|
||||
@ -381,15 +389,29 @@ fn convert_methods(ccx: &CrateCtxt,
|
||||
untransformed_rcvr_ty: ty::t,
|
||||
rcvr_ty_generics: &ty::Generics,
|
||||
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) =
|
||||
astconv::ty_of_method(ccx,
|
||||
m.id,
|
||||
m.pe_fn_style(),
|
||||
untransformed_rcvr_ty,
|
||||
*m.pe_explicit_self(),
|
||||
&*m.pe_fn_decl());
|
||||
&*m.pe_fn_decl(),
|
||||
real_abi);
|
||||
|
||||
// if the method specifies a visibility, use that, otherwise
|
||||
// inherit the visibility from the impl (so `foo` in `pub impl
|
||||
|
@ -223,12 +223,14 @@ pub trait Combine {
|
||||
let onceness = if_ok!(self.oncenesses(a.onceness, b.onceness));
|
||||
let bounds = if_ok!(self.bounds(a.bounds, b.bounds));
|
||||
let sig = if_ok!(self.fn_sigs(&a.sig, &b.sig));
|
||||
let abi = if_ok!(self.abi(a.abi, b.abi));
|
||||
Ok(ty::ClosureTy {
|
||||
fn_style: fn_style,
|
||||
onceness: onceness,
|
||||
store: store,
|
||||
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))
|
||||
}
|
||||
|
||||
(&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)) => {
|
||||
this.tys(a_inner, b_inner).and_then(|typ| Ok(ty::mk_box(tcx, typ)))
|
||||
}
|
||||
|
@ -97,6 +97,9 @@ pub enum MethodOrigin {
|
||||
// fully statically resolved method
|
||||
MethodStatic(ast::DefId),
|
||||
|
||||
// fully statically resolved unboxed closure invocation
|
||||
MethodStaticUnboxedClosure(ast::DefId),
|
||||
|
||||
// method invoked on a type parameter with a bounded trait
|
||||
MethodParam(MethodParam),
|
||||
|
||||
@ -232,6 +235,12 @@ pub enum vtable_origin {
|
||||
*/
|
||||
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
|
||||
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)
|
||||
}
|
||||
|
||||
vtable_unboxed_closure(def_id) => {
|
||||
format!("vtable_unboxed_closure({})", def_id)
|
||||
}
|
||||
|
||||
vtable_error => {
|
||||
format!("vtable_error")
|
||||
}
|
||||
|
@ -715,7 +715,7 @@ impl<'a> ConstraintContext<'a> {
|
||||
match ty::get(ty).sty {
|
||||
ty::ty_nil | ty::ty_bot | ty::ty_bool |
|
||||
ty::ty_char | ty::ty_int(_) | ty::ty_uint(_) |
|
||||
ty::ty_float(_) | ty::ty_str => {
|
||||
ty::ty_float(_) | ty::ty_str | ty::ty_unboxed_closure(..) => {
|
||||
/* leaf type -- noop */
|
||||
}
|
||||
|
||||
|
@ -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_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_unboxed_closure};
|
||||
use middle::ty;
|
||||
use middle::typeck;
|
||||
use middle::typeck::infer;
|
||||
@ -414,6 +415,7 @@ pub fn ty_to_string(cx: &ctxt, typ: t) -> String {
|
||||
bound_str)
|
||||
}
|
||||
ty_str => "str".to_string(),
|
||||
ty_unboxed_closure(..) => "closure".to_string(),
|
||||
ty_vec(ref mt, sz) => {
|
||||
match sz {
|
||||
Some(n) => {
|
||||
@ -878,6 +880,9 @@ impl Repr for typeck::MethodOrigin {
|
||||
&typeck::MethodStatic(def_id) => {
|
||||
format!("MethodStatic({})", def_id.repr(tcx))
|
||||
}
|
||||
&typeck::MethodStaticUnboxedClosure(def_id) => {
|
||||
format!("MethodStaticUnboxedClosure({})", def_id.repr(tcx))
|
||||
}
|
||||
&typeck::MethodParam(ref p) => {
|
||||
p.repr(tcx)
|
||||
}
|
||||
|
@ -239,6 +239,7 @@ mod svh_visitor {
|
||||
SawExprWhile,
|
||||
SawExprMatch,
|
||||
SawExprFnBlock,
|
||||
SawExprUnboxedFn,
|
||||
SawExprProc,
|
||||
SawExprBlock,
|
||||
SawExprAssign,
|
||||
@ -270,6 +271,7 @@ mod svh_visitor {
|
||||
ExprLoop(_, id) => SawExprLoop(id.map(content)),
|
||||
ExprMatch(..) => SawExprMatch,
|
||||
ExprFnBlock(..) => SawExprFnBlock,
|
||||
ExprUnboxedFn(..) => SawExprUnboxedFn,
|
||||
ExprProc(..) => SawExprProc,
|
||||
ExprBlock(..) => SawExprBlock,
|
||||
ExprAssign(..) => SawExprAssign,
|
||||
|
@ -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
|
||||
// static LLVM symbols. Otherwise the linker will just throw llvm
|
||||
// away. We're just calling lots of stuff until we transitively get
|
||||
|
@ -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_err => fail!("ty_err"),
|
||||
}
|
||||
|
@ -30,6 +30,7 @@ pub enum Abi {
|
||||
C,
|
||||
System,
|
||||
RustIntrinsic,
|
||||
RustCall,
|
||||
}
|
||||
|
||||
#[allow(non_camel_case_types)]
|
||||
@ -85,6 +86,7 @@ static AbiDatas: &'static [AbiData] = &[
|
||||
AbiData {abi: C, name: "C", abi_arch: AllArch},
|
||||
AbiData {abi: System, name: "system", abi_arch: AllArch},
|
||||
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).
|
||||
|
@ -503,6 +503,7 @@ pub enum Expr_ {
|
||||
ExprMatch(Gc<Expr>, Vec<Arm>),
|
||||
ExprFnBlock(P<FnDecl>, P<Block>),
|
||||
ExprProc(P<FnDecl>, P<Block>),
|
||||
ExprUnboxedFn(P<FnDecl>, P<Block>),
|
||||
ExprBlock(P<Block>),
|
||||
|
||||
ExprAssign(Gc<Expr>, Gc<Expr>),
|
||||
@ -690,6 +691,7 @@ pub struct TypeMethod {
|
||||
pub ident: Ident,
|
||||
pub attrs: Vec<Attribute>,
|
||||
pub fn_style: FnStyle,
|
||||
pub abi: Abi,
|
||||
pub decl: P<FnDecl>,
|
||||
pub generics: Generics,
|
||||
pub explicit_self: ExplicitSelf,
|
||||
@ -966,13 +968,20 @@ pub struct Method {
|
||||
pub attrs: Vec<Attribute>,
|
||||
pub id: NodeId,
|
||||
pub span: Span,
|
||||
pub node: Method_
|
||||
pub node: Method_,
|
||||
}
|
||||
|
||||
#[deriving(PartialEq, Eq, Encodable, Decodable, Hash, Show)]
|
||||
pub enum Method_ {
|
||||
/// 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
|
||||
MethMac(Mac),
|
||||
}
|
||||
|
@ -320,13 +320,15 @@ impl Map {
|
||||
}
|
||||
NodeForeignItem(i) => PathName(i.ident.name),
|
||||
NodeMethod(m) => match m.node {
|
||||
MethDecl(ident, _, _, _, _, _, _) => PathName(ident.name),
|
||||
MethDecl(ident, _, _, _, _, _, _, _) => PathName(ident.name),
|
||||
MethMac(_) => fail!("no path elem for {:?}", node)
|
||||
},
|
||||
NodeTraitMethod(tm) => match *tm {
|
||||
Required(ref m) => PathName(m.ident.name),
|
||||
Provided(m) => match m.node {
|
||||
MethDecl(ident, _, _, _, _, _, _) => PathName(ident.name),
|
||||
MethDecl(ident, _, _, _, _, _, _, _) => {
|
||||
PathName(ident.name)
|
||||
}
|
||||
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)
|
||||
}
|
||||
Some(NodeMethod(m)) => match m.node {
|
||||
MethDecl(ident, _, _, _, _, _, _) =>
|
||||
MethDecl(ident, _, _, _, _, _, _, _) =>
|
||||
format!("method {} in {} (id={})",
|
||||
token::get_ident(ident),
|
||||
map.path_to_string(id), id),
|
||||
|
@ -8,6 +8,7 @@
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
use abi::Abi;
|
||||
use ast::*;
|
||||
use ast;
|
||||
use ast_util;
|
||||
@ -249,7 +250,14 @@ pub fn trait_method_to_ty_method(method: &TraitMethod) -> TypeMethod {
|
||||
Required(ref m) => (*m).clone(),
|
||||
Provided(m) => {
|
||||
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 {
|
||||
ident: ident,
|
||||
attrs: m.attrs.clone(),
|
||||
@ -260,6 +268,7 @@ pub fn trait_method_to_ty_method(method: &TraitMethod) -> TypeMethod {
|
||||
id: m.id,
|
||||
span: m.span,
|
||||
vis: vis,
|
||||
abi: abi,
|
||||
}
|
||||
},
|
||||
MethMac(_) => fail!("expected non-macro method declaration")
|
||||
@ -749,6 +758,7 @@ pub fn static_has_significant_address(mutbl: ast::Mutability,
|
||||
pub trait PostExpansionMethod {
|
||||
fn pe_ident(&self) -> ast::Ident;
|
||||
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_fn_style(&self) -> ast::FnStyle;
|
||||
fn pe_fn_decl(&self) -> P<ast::FnDecl>;
|
||||
@ -797,25 +807,28 @@ macro_rules! mf_method{
|
||||
// PRE
|
||||
impl PostExpansionMethod for Method {
|
||||
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 {
|
||||
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 {
|
||||
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{
|
||||
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> {
|
||||
mf_method_body!(self,MethDecl(_,_,_,_,decl,_,_),decl)
|
||||
mf_method_body!(self, MethDecl(_,_,_,_,_,decl,_,_),decl)
|
||||
}
|
||||
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 {
|
||||
mf_method_body!(self,MethDecl(_,_,_,_,_,_,vis),vis)
|
||||
mf_method_body!(self, MethDecl(_,_,_,_,_,_,_,vis),vis)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -183,6 +183,8 @@
|
||||
use std::cell::RefCell;
|
||||
use std::gc::{Gc, GC};
|
||||
|
||||
use abi::Abi;
|
||||
use abi;
|
||||
use ast;
|
||||
use ast::{P, EnumDef, Expr, Ident, Generics, StructDef};
|
||||
use ast_util;
|
||||
@ -477,9 +479,13 @@ impl<'a> TraitDef<'a> {
|
||||
nonself_args.as_slice())
|
||||
};
|
||||
|
||||
method_def.create_method(cx, self,
|
||||
type_ident, generics,
|
||||
explicit_self, tys,
|
||||
method_def.create_method(cx,
|
||||
self,
|
||||
type_ident,
|
||||
generics,
|
||||
abi::Rust,
|
||||
explicit_self,
|
||||
tys,
|
||||
body)
|
||||
}).collect();
|
||||
|
||||
@ -513,9 +519,13 @@ impl<'a> TraitDef<'a> {
|
||||
nonself_args.as_slice())
|
||||
};
|
||||
|
||||
method_def.create_method(cx, self,
|
||||
type_ident, generics,
|
||||
explicit_self, tys,
|
||||
method_def.create_method(cx,
|
||||
self,
|
||||
type_ident,
|
||||
generics,
|
||||
abi::Rust,
|
||||
explicit_self,
|
||||
tys,
|
||||
body)
|
||||
}).collect();
|
||||
|
||||
@ -622,9 +632,11 @@ impl<'a> MethodDef<'a> {
|
||||
trait_: &TraitDef,
|
||||
type_ident: Ident,
|
||||
generics: &Generics,
|
||||
abi: Abi,
|
||||
explicit_self: ast::ExplicitSelf,
|
||||
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
|
||||
let fn_generics = self.generics.to_generics(cx, trait_.span, type_ident, generics);
|
||||
|
||||
@ -653,6 +665,7 @@ impl<'a> MethodDef<'a> {
|
||||
span: trait_.span,
|
||||
node: ast::MethDecl(method_ident,
|
||||
fn_generics,
|
||||
abi,
|
||||
explicit_self,
|
||||
ast::NormalFn,
|
||||
fn_decl,
|
||||
|
@ -910,7 +910,14 @@ impl<'a> Folder for PatIdentRenamer<'a> {
|
||||
fn expand_method(m: &ast::Method, fld: &mut MacroExpander) -> SmallVector<Gc<ast::Method>> {
|
||||
let id = fld.new_id(m.id);
|
||||
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)
|
||||
= expand_and_rename_fn_decl_and_block(&*decl,body,fld);
|
||||
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),
|
||||
node: ast::MethDecl(fld.fold_ident(ident),
|
||||
fold_generics(generics, fld),
|
||||
abi,
|
||||
fld.fold_explicit_self(explicit_self),
|
||||
fn_style,
|
||||
rewritten_fn_decl,
|
||||
|
@ -727,6 +727,7 @@ pub fn noop_fold_type_method<T: Folder>(m: &TypeMethod, fld: &mut T) -> TypeMeth
|
||||
ident: fld.fold_ident(m.ident),
|
||||
attrs: m.attrs.iter().map(|a| fld.fold_attribute(*a)).collect(),
|
||||
fn_style: m.fn_style,
|
||||
abi: m.abi,
|
||||
decl: fld.fold_fn_decl(&*m.decl),
|
||||
generics: fold_generics(&m.generics, fld),
|
||||
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,
|
||||
span: folder.new_span(m.span),
|
||||
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),
|
||||
fold_generics(generics, folder),
|
||||
abi,
|
||||
folder.fold_explicit_self(explicit_self),
|
||||
fn_style,
|
||||
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),
|
||||
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(folder.fold_expr(el), folder.fold_expr(er))
|
||||
}
|
||||
|
@ -25,7 +25,7 @@ use ast::{ExprBreak, ExprCall, ExprCast};
|
||||
use ast::{ExprField, ExprFnBlock, ExprIf, ExprIndex};
|
||||
use ast::{ExprLit, ExprLoop, ExprMac};
|
||||
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::{ExprVstoreMutSlice, ExprWhile, ExprForLoop, Field, FnDecl};
|
||||
use ast::{ExprVstoreUniq, Once, Many};
|
||||
@ -59,6 +59,7 @@ use ast::Visibility;
|
||||
use ast;
|
||||
use ast_util::{as_prec, ident_to_path, lit_is_str, operator_prec};
|
||||
use ast_util;
|
||||
use attr;
|
||||
use codemap::{Span, BytePos, Spanned, spanned, mk_sp};
|
||||
use codemap;
|
||||
use parse;
|
||||
@ -1217,6 +1218,16 @@ impl<'a> Parser<'a> {
|
||||
// NB: at the moment, trait methods are public by default; this
|
||||
// could change.
|
||||
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 ident = p.parse_ident();
|
||||
|
||||
@ -1239,6 +1250,7 @@ impl<'a> Parser<'a> {
|
||||
fn_style: style,
|
||||
decl: d,
|
||||
generics: generics,
|
||||
abi: abi,
|
||||
explicit_self: explicit_self,
|
||||
id: ast::DUMMY_NODE_ID,
|
||||
span: mk_sp(lo, hi),
|
||||
@ -1254,7 +1266,14 @@ impl<'a> Parser<'a> {
|
||||
attrs: attrs,
|
||||
id: ast::DUMMY_NODE_ID,
|
||||
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))
|
||||
}
|
||||
|
||||
/// `|args| { ... }` or `{ ...}` like in `do` expressions
|
||||
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`
|
||||
// `|args| 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 decl = parse_decl(self);
|
||||
let body = parse_body(self);
|
||||
let (decl, is_unboxed) = self.parse_fn_block_decl();
|
||||
let body = self.parse_expr();
|
||||
let fakeblock = P(ast::Block {
|
||||
view_items: Vec::new(),
|
||||
stmts: Vec::new(),
|
||||
@ -2674,7 +2653,11 @@ impl<'a> Parser<'a> {
|
||||
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> {
|
||||
@ -3955,18 +3938,30 @@ impl<'a> Parser<'a> {
|
||||
(spanned(lo, hi, explicit_self), fn_decl)
|
||||
}
|
||||
|
||||
/// Parse the |arg, arg| header on a lambda
|
||||
fn parse_fn_block_decl(&mut self) -> P<FnDecl> {
|
||||
let inputs_captures = {
|
||||
// parse the |arg, arg| header on a lambda
|
||||
fn parse_fn_block_decl(&mut self) -> (P<FnDecl>, bool) {
|
||||
let (is_unboxed, inputs_captures) = {
|
||||
if self.eat(&token::OROR) {
|
||||
Vec::new()
|
||||
(false, Vec::new())
|
||||
} else {
|
||||
self.parse_unspanned_seq(
|
||||
&token::BINOP(token::OR),
|
||||
self.expect(&token::BINOP(token::OR));
|
||||
let is_unboxed = self.token == token::BINOP(token::AND) &&
|
||||
self.look_ahead(1, |t| {
|
||||
token::is_keyword(keywords::Mut, t)
|
||||
}) &&
|
||||
self.look_ahead(2, |t| *t == token::COLON);
|
||||
if is_unboxed {
|
||||
self.bump();
|
||||
self.bump();
|
||||
self.bump();
|
||||
}
|
||||
let args = self.parse_seq_to_before_end(
|
||||
&token::BINOP(token::OR),
|
||||
seq_sep_trailing_disallowed(token::COMMA),
|
||||
|p| p.parse_fn_block_arg()
|
||||
)
|
||||
);
|
||||
self.bump();
|
||||
(is_unboxed, args)
|
||||
}
|
||||
};
|
||||
let output = if self.eat(&token::RARROW) {
|
||||
@ -3979,12 +3974,12 @@ impl<'a> Parser<'a> {
|
||||
})
|
||||
};
|
||||
|
||||
P(FnDecl {
|
||||
(P(FnDecl {
|
||||
inputs: inputs_captures,
|
||||
output: output,
|
||||
cf: Return,
|
||||
variadic: false
|
||||
})
|
||||
}), is_unboxed)
|
||||
}
|
||||
|
||||
/// 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)
|
||||
} else {
|
||||
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 ident = self.parse_ident();
|
||||
let generics = self.parse_generics();
|
||||
@ -4087,7 +4087,14 @@ impl<'a> Parser<'a> {
|
||||
});
|
||||
let (inner_attrs, body) = self.parse_inner_attrs_and_block();
|
||||
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)
|
||||
}
|
||||
};
|
||||
|
@ -188,7 +188,7 @@ pub fn method_to_string(p: &ast::Method) -> String {
|
||||
}
|
||||
|
||||
pub fn fn_block_to_string(p: &ast::FnDecl) -> String {
|
||||
to_string(|s| s.print_fn_block_args(p))
|
||||
to_string(|s| s.print_fn_block_args(p, false))
|
||||
}
|
||||
|
||||
pub fn path_to_string(p: &ast::Path) -> String {
|
||||
@ -259,7 +259,8 @@ fn needs_parentheses(expr: &ast::Expr) -> bool {
|
||||
match expr.node {
|
||||
ast::ExprAssign(..) | ast::ExprBinary(..) |
|
||||
ast::ExprFnBlock(..) | ast::ExprProc(..) |
|
||||
ast::ExprAssignOp(..) | ast::ExprCast(..) => true,
|
||||
ast::ExprUnboxedFn(..) | ast::ExprAssignOp(..) |
|
||||
ast::ExprCast(..) => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
@ -1004,9 +1005,20 @@ impl<'a> State<'a> {
|
||||
try!(self.maybe_print_comment(meth.span.lo));
|
||||
try!(self.print_outer_attributes(meth.attrs.as_slice()));
|
||||
match meth.node {
|
||||
ast::MethDecl(ident, ref generics, ref explicit_self, fn_style, decl, body, vis) => {
|
||||
try!(self.print_fn(&*decl, Some(fn_style), abi::Rust,
|
||||
ident, generics, Some(explicit_self.node),
|
||||
ast::MethDecl(ident,
|
||||
ref generics,
|
||||
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));
|
||||
try!(word(&mut self.s, " "));
|
||||
self.print_block_with_attrs(&*body, meth.attrs.as_slice())
|
||||
@ -1446,7 +1458,37 @@ impl<'a> State<'a> {
|
||||
// we are inside.
|
||||
//
|
||||
// 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));
|
||||
// }
|
||||
|
||||
@ -1939,8 +1981,13 @@ impl<'a> State<'a> {
|
||||
}
|
||||
|
||||
pub fn print_fn_block_args(&mut self,
|
||||
decl: &ast::FnDecl) -> IoResult<()> {
|
||||
decl: &ast::FnDecl,
|
||||
is_unboxed: bool)
|
||||
-> IoResult<()> {
|
||||
try!(word(&mut self.s, "|"));
|
||||
if is_unboxed {
|
||||
try!(self.word_space("&mut:"));
|
||||
}
|
||||
try!(self.print_fn_args(decl, None));
|
||||
try!(word(&mut self.s, "|"));
|
||||
|
||||
|
@ -562,7 +562,7 @@ pub fn walk_method_helper<E: Clone, V: Visitor<E>>(visitor: &mut V,
|
||||
method: &Method,
|
||||
env: E) {
|
||||
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_fn(&FkMethod(ident, generics, method),
|
||||
&*decl,
|
||||
@ -594,7 +594,7 @@ pub fn walk_fn<E: Clone, V: Visitor<E>>(visitor: &mut V,
|
||||
FkMethod(_, generics, method) => {
|
||||
visitor.visit_generics(generics, env.clone());
|
||||
match method.node {
|
||||
MethDecl(_, _, ref explicit_self, _, _, _, _) =>
|
||||
MethDecl(_, _, _, ref explicit_self, _, _, _, _) =>
|
||||
visitor.visit_explicit_self(explicit_self, env.clone()),
|
||||
MethMac(ref mac) =>
|
||||
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,
|
||||
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) => {
|
||||
visitor.visit_fn(&FkFnBlock,
|
||||
&**function_declaration,
|
||||
|
@ -18,7 +18,7 @@ struct 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
|
||||
}
|
||||
}
|
||||
@ -29,7 +29,7 @@ struct 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
|
||||
}
|
||||
}
|
||||
@ -39,7 +39,7 @@ struct 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()
|
||||
}
|
||||
}
|
||||
|
@ -18,7 +18,7 @@ struct 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
|
||||
}
|
||||
}
|
||||
|
@ -18,7 +18,7 @@ struct 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
|
||||
}
|
||||
}
|
||||
|
19
src/test/compile-fail/unboxed-closures-type-mismatch.rs
Normal file
19
src/test/compile-fail/unboxed-closures-type-mismatch.rs
Normal 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);
|
||||
}
|
25
src/test/compile-fail/unboxed-closures-vtable-mismatch.rs
Normal file
25
src/test/compile-fail/unboxed-closures-vtable-mismatch.rs
Normal 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);
|
||||
}
|
||||
|
@ -16,7 +16,7 @@ use std::ops::FnMut;
|
||||
struct 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
|
||||
}
|
||||
}
|
||||
|
@ -15,7 +15,7 @@ trait Foo {}
|
||||
struct 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;
|
||||
|
@ -34,7 +34,7 @@ impl Alloy {
|
||||
}
|
||||
|
||||
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 {
|
||||
|
@ -8,7 +8,7 @@
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
#![feature(overloaded_calls)]
|
||||
#![feature(lang_items, overloaded_calls)]
|
||||
|
||||
use std::ops::{Fn, FnMut, FnOnce};
|
||||
|
||||
@ -18,7 +18,7 @@ struct 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
|
||||
}
|
||||
}
|
||||
@ -29,7 +29,7 @@ struct 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
|
||||
}
|
||||
}
|
||||
@ -40,7 +40,7 @@ struct 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
|
||||
}
|
||||
}
|
||||
@ -50,21 +50,21 @@ fn main() {
|
||||
x: 3,
|
||||
y: 3,
|
||||
};
|
||||
let ans = s(3);
|
||||
assert_eq!(ans, 27);
|
||||
let ans = s.call_mut((3,));
|
||||
|
||||
assert_eq!(ans, 27);
|
||||
let s = S2 {
|
||||
x: 3,
|
||||
y: 3,
|
||||
};
|
||||
let ans = s(3);
|
||||
let ans = s.call((3,));
|
||||
assert_eq!(ans, 27);
|
||||
|
||||
let s = S3 {
|
||||
x: 3,
|
||||
y: 3,
|
||||
};
|
||||
let ans = s(3, 1);
|
||||
let ans = s.call_once((3, 1));
|
||||
assert_eq!(ans, 27);
|
||||
}
|
||||
|
||||
|
@ -18,7 +18,7 @@ struct 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
|
||||
}
|
||||
}
|
||||
|
25
src/test/run-pass/unboxed-closures-boxed.rs
Normal file
25
src/test/run-pass/unboxed-closures-boxed.rs
Normal 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);
|
||||
}
|
||||
|
25
src/test/run-pass/unboxed-closures-generic.rs
Normal file
25
src/test/run-pass/unboxed-closures-generic.rs
Normal 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);
|
||||
}
|
||||
|
19
src/test/run-pass/unboxed-closures-simple.rs
Normal file
19
src/test/run-pass/unboxed-closures-simple.rs
Normal 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);
|
||||
}
|
Loading…
Reference in New Issue
Block a user