librustc: Implement unboxed closures with mutable receivers

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

View File

@ -749,6 +749,7 @@ pub trait DerefMut<Result>: Deref<Result> {
#[lang="fn"]
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;
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -163,6 +163,12 @@ fn represent_type_uncached(cx: &CrateContext, t: ty::t) -> Repr {
return Univariant(mk_struct(cx, ftys.as_slice(), packed), dtor)
}
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);

View File

@ -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: &param_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)

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -39,10 +39,56 @@ pub fn type_of_explicit_arg(ccx: &CrateContext, arg_ty: ty::t) -> Type {
}
}
pub fn type_of_rust_fn(cx: &CrateContext, has_env: bool,
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);

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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: &param_env };
let unboxed_closure_types = RefCell::new(DefIdMap::new());
let vcx = VtableContext {
infcx: infcx,
param_env: &param_env,
unboxed_closure_types: &unboxed_closure_types,
};
// Resolve the vtables for the trait reference on the impl. This
// 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,

View File

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

View File

@ -25,7 +25,8 @@ use middle::ty::{t, ty_bool, ty_char, ty_bot, ty_box, ty_enum, ty_err};
use middle::ty::{ty_str, ty_vec, ty_float, ty_infer, ty_int, ty_nil};
use middle::ty::{ty_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);

View File

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

View File

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

View File

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

View File

@ -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 */
}

View File

@ -21,6 +21,7 @@ use middle::ty::{ty_bool, ty_char, ty_bot, ty_box, ty_struct, ty_enum};
use middle::ty::{ty_err, ty_str, ty_vec, ty_float, ty_bare_fn, ty_closure};
use middle::ty::{ty_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)
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -910,7 +910,14 @@ impl<'a> Folder for PatIdentRenamer<'a> {
fn expand_method(m: &ast::Method, fld: &mut MacroExpander) -> SmallVector<Gc<ast::Method>> {
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,

View File

@ -727,6 +727,7 @@ pub fn noop_fold_type_method<T: Folder>(m: &TypeMethod, fld: &mut T) -> TypeMeth
ident: fld.fold_ident(m.ident),
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))
}

View File

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

View File

@ -188,7 +188,7 @@ pub fn method_to_string(p: &ast::Method) -> String {
}
pub fn fn_block_to_string(p: &ast::FnDecl) -> String {
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, "|"));

View File

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

View File

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

View File

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

View File

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

View File

@ -0,0 +1,19 @@
// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#![feature(unboxed_closures)]
use std::ops::FnMut;
pub fn main() {
let mut f = |&mut: x: int, y: int| -> int { x + y };
let z = f.call_mut((1u, 2)); //~ ERROR mismatched types
println!("{}", z);
}

View File

@ -0,0 +1,25 @@
// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#![feature(unboxed_closures)]
use std::ops::FnMut;
fn call_it<F:FnMut<(int,int),int>>(y: int, mut f: F) -> int {
f.call_mut((2, y))
}
pub fn main() {
let f = |&mut: x: uint, y: int| -> int { (x as int) + y };
let z = call_it(3, f); //~ ERROR expected core::ops::FnMut
//~^ ERROR expected core::ops::FnMut
println!("{}", z);
}

View File

@ -16,7 +16,7 @@ use std::ops::FnMut;
struct S;
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
}
}

View File

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

View File

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

View File

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

View File

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

View File

@ -0,0 +1,25 @@
// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#![feature(unboxed_closures)]
use std::ops::FnMut;
fn make_adder(x: int) -> Box<FnMut<(int,),int>> {
(box |&mut: y: int| -> int { x + y }) as Box<FnMut<(int,),int>>
}
pub fn main() {
let mut adder = make_adder(3);
let z = adder.call_mut((2,));
println!("{}", z);
assert_eq!(z, 5);
}

View File

@ -0,0 +1,25 @@
// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#![feature(unboxed_closures)]
use std::ops::FnMut;
fn call_it<F:FnMut<(int,int),int>>(y: int, mut f: F) -> int {
f.call_mut((2, y))
}
pub fn main() {
let f = |&mut: x: int, y: int| -> int { x + y };
let z = call_it(3, f);
println!("{}", z);
assert_eq!(z, 5);
}

View File

@ -0,0 +1,19 @@
// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#![feature(unboxed_closures)]
use std::ops::FnMut;
pub fn main() {
let mut f = |&mut: x: int, y: int| -> int { x + y };
let z = f.call_mut((1, 2));
assert_eq!(z, 3);
}