From 02adaca4dc7eb4594d8bda9a7e04bc0247fc2a74 Mon Sep 17 00:00:00 2001 From: Patrick Walton Date: Wed, 28 May 2014 22:26:56 -0700 Subject: [PATCH] librustc: Implement unboxed closures with mutable receivers --- src/libcore/ops.rs | 4 + src/libcore/prelude.rs | 1 + src/librustc/front/feature_gate.rs | 7 + src/librustc/lint/builtin.rs | 3 + src/librustc/metadata/common.rs | 18 +- src/librustc/metadata/encoder.rs | 40 +++ src/librustc/metadata/tydecode.rs | 18 +- src/librustc/metadata/tyencode.rs | 6 +- src/librustc/middle/astencode.rs | 71 +++- src/librustc/middle/borrowck/check_loans.rs | 1 + src/librustc/middle/cfg/construct.rs | 1 + src/librustc/middle/check_loop.rs | 4 +- src/librustc/middle/dead.rs | 1 + src/librustc/middle/expr_use_visitor.rs | 6 +- src/librustc/middle/freevars.rs | 12 +- src/librustc/middle/kind.rs | 7 +- src/librustc/middle/liveness.rs | 13 +- src/librustc/middle/mem_categorization.rs | 17 +- src/librustc/middle/privacy.rs | 3 +- src/librustc/middle/resolve.rs | 3 +- src/librustc/middle/save/mod.rs | 3 +- src/librustc/middle/subst.rs | 3 + src/librustc/middle/trans/adt.rs | 6 + src/librustc/middle/trans/base.rs | 311 +++++++++++++++--- src/librustc/middle/trans/callee.rs | 224 +++++++++++-- src/librustc/middle/trans/closure.rs | 170 +++++++++- src/librustc/middle/trans/common.rs | 12 +- src/librustc/middle/trans/context.rs | 5 + src/librustc/middle/trans/debuginfo.rs | 12 +- src/librustc/middle/trans/expr.rs | 53 +-- src/librustc/middle/trans/foreign.rs | 13 +- src/librustc/middle/trans/glue.rs | 5 +- src/librustc/middle/trans/intrinsic.rs | 10 +- src/librustc/middle/trans/meth.rs | 89 ++++- src/librustc/middle/trans/monomorphize.rs | 7 + src/librustc/middle/trans/reflect.rs | 16 +- src/librustc/middle/trans/type_of.rs | 93 +++++- src/librustc/middle/ty.rs | 113 ++++++- src/librustc/middle/ty_fold.rs | 7 + src/librustc/middle/typeck/astconv.rs | 15 +- src/librustc/middle/typeck/check/method.rs | 102 +++++- src/librustc/middle/typeck/check/mod.rs | 67 +++- src/librustc/middle/typeck/check/regionck.rs | 4 +- src/librustc/middle/typeck/check/vtable.rs | 114 ++++++- src/librustc/middle/typeck/check/writeback.rs | 43 ++- src/librustc/middle/typeck/coherence.rs | 14 +- src/librustc/middle/typeck/collect.rs | 56 +++- src/librustc/middle/typeck/infer/combine.rs | 9 +- src/librustc/middle/typeck/mod.rs | 13 + src/librustc/middle/typeck/variance.rs | 2 +- src/librustc/util/ppaux.rs | 5 + src/librustc_back/svh.rs | 2 + src/librustc_llvm/lib.rs | 8 + src/librustdoc/clean/mod.rs | 2 + src/libsyntax/abi.rs | 2 + src/libsyntax/ast.rs | 13 +- src/libsyntax/ast_map/mod.rs | 8 +- src/libsyntax/ast_util.rs | 29 +- src/libsyntax/ext/deriving/generic/mod.rs | 27 +- src/libsyntax/ext/expand.rs | 10 +- src/libsyntax/fold.rs | 17 +- src/libsyntax/parse/parser.rs | 119 +++---- src/libsyntax/print/pprust.rs | 61 +++- src/libsyntax/visit.rs | 12 +- .../compile-fail/borrowck-overloaded-call.rs | 6 +- src/test/compile-fail/overloaded-calls-bad.rs | 2 +- .../compile-fail/overloaded-calls-nontuple.rs | 2 +- .../unboxed-closures-type-mismatch.rs | 19 ++ .../unboxed-closures-vtable-mismatch.rs | 25 ++ src/test/run-pass/fn-trait-sugar.rs | 2 +- src/test/run-pass/issue-14958.rs | 2 +- src/test/run-pass/issue-14959.rs | 2 +- src/test/run-pass/overloaded-calls-simple.rs | 16 +- .../run-pass/overloaded-calls-zero-args.rs | 2 +- src/test/run-pass/unboxed-closures-boxed.rs | 25 ++ src/test/run-pass/unboxed-closures-generic.rs | 25 ++ src/test/run-pass/unboxed-closures-simple.rs | 19 ++ 77 files changed, 1905 insertions(+), 384 deletions(-) create mode 100644 src/test/compile-fail/unboxed-closures-type-mismatch.rs create mode 100644 src/test/compile-fail/unboxed-closures-vtable-mismatch.rs create mode 100644 src/test/run-pass/unboxed-closures-boxed.rs create mode 100644 src/test/run-pass/unboxed-closures-generic.rs create mode 100644 src/test/run-pass/unboxed-closures-simple.rs diff --git a/src/libcore/ops.rs b/src/libcore/ops.rs index 53179df4cb9b3..8a1962c2bbd79 100644 --- a/src/libcore/ops.rs +++ b/src/libcore/ops.rs @@ -749,6 +749,7 @@ pub trait DerefMut: Deref { #[lang="fn"] pub trait Fn { /// 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 { #[lang="fn_mut"] pub trait FnMut { /// 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 { #[lang="fn_once"] pub trait FnOnce { /// This is called when the call operator is used. + #[rust_call_abi_hack] fn call_once(self, args: Args) -> Result; } + diff --git a/src/libcore/prelude.rs b/src/libcore/prelude.rs index d8ab89fd504f5..d27689eeaf417 100644 --- a/src/libcore/prelude.rs +++ b/src/libcore/prelude.rs @@ -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}; diff --git a/src/librustc/front/feature_gate.rs b/src/librustc/front/feature_gate.rs index 8b92166388d86..9f15c9a9b3fa0 100644 --- a/src/librustc/front/feature_gate.rs +++ b/src/librustc/front/feature_gate.rs @@ -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, ()); diff --git a/src/librustc/lint/builtin.rs b/src/librustc/lint/builtin.rs index fbe4b211f9752..3f4f512369971 100644 --- a/src/librustc/lint/builtin.rs +++ b/src/librustc/lint/builtin.rs @@ -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, diff --git a/src/librustc/metadata/common.rs b/src/librustc/metadata/common.rs index cdeecf3a080fe..216a575f2fb2b 100644 --- a/src/librustc/metadata/common.rs +++ b/src/librustc/metadata/common.rs @@ -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 { 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; diff --git a/src/librustc/metadata/encoder.rs b/src/librustc/metadata/encoder.rs index a3389ef86e551..b86f5ee6cc2bc 100644 --- a/src/librustc/metadata/encoder.rs +++ b/src/librustc/metadata/encoder.rs @@ -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); diff --git a/src/librustc/metadata/tydecode.rs b/src/librustc/metadata/tydecode.rs index 4156329331471..ffa0cca753904 100644 --- a/src/librustc/metadata/tydecode.rs +++ b/src/librustc/metadata/tydecode.rs @@ -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, } } diff --git a/src/librustc/metadata/tyencode.rs b/src/librustc/metadata/tyencode.rs index bcd6f3ac91abc..15e4e85ddb711 100644 --- a/src/librustc/metadata/tyencode.rs +++ b/src/librustc/metadata/tyencode.rs @@ -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) { diff --git a/src/librustc/middle/astencode.rs b/src/librustc/middle/astencode.rs index fd10fd3c35aae..722715405bce4 100644 --- a/src/librustc/middle/astencode.rs +++ b/src/librustc/middle/astencode.rs @@ -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}", diff --git a/src/librustc/middle/borrowck/check_loans.rs b/src/librustc/middle/borrowck/check_loans.rs index cfec67bf3a395..fecd40dae016a 100644 --- a/src/librustc/middle/borrowck/check_loans.rs +++ b/src/librustc/middle/borrowck/check_loans.rs @@ -832,3 +832,4 @@ impl<'a> CheckLoanCtxt<'a> { self.bccx.loan_path_to_string(loan_path)).as_slice()); } } + diff --git a/src/librustc/middle/cfg/construct.rs b/src/librustc/middle/cfg/construct.rs index 0d8729071ef6b..208a9d057166e 100644 --- a/src/librustc/middle/cfg/construct.rs +++ b/src/librustc/middle/cfg/construct.rs @@ -446,6 +446,7 @@ impl<'a> CFGBuilder<'a> { ast::ExprMac(..) | ast::ExprFnBlock(..) | ast::ExprProc(..) | + ast::ExprUnboxedFn(..) | ast::ExprLit(..) | ast::ExprPath(..) => { self.straightline(expr, pred, []) diff --git a/src/librustc/middle/check_loop.rs b/src/librustc/middle/check_loop.rs index c855d59d50851..ac8faaa6c6db5 100644 --- a/src/librustc/middle/check_loop.rs +++ b/src/librustc/middle/check_loop.rs @@ -42,7 +42,9 @@ impl<'a> Visitor 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), diff --git a/src/librustc/middle/dead.rs b/src/librustc/middle/dead.rs index 33e7554084ac6..9fc589ddf59eb 100644 --- a/src/librustc/middle/dead.rs +++ b/src/librustc/middle/dead.rs @@ -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, diff --git a/src/librustc/middle/expr_use_visitor.rs b/src/librustc/middle/expr_use_visitor.rs index 1e06b3b1fd463..b911e636da091 100644 --- a/src/librustc/middle/expr_use_visitor.rs +++ b/src/librustc/middle/expr_use_visitor.rs @@ -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) } diff --git a/src/librustc/middle/freevars.rs b/src/librustc/middle/freevars.rs index 614972f3d5776..f6887718ec137 100644 --- a/src/librustc/middle/freevars.rs +++ b/src/librustc/middle/freevars.rs @@ -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>; +pub type UnboxedClosureList = DefIdSet; + struct CollectFreevarsVisitor<'a> { seen: NodeSet, refs: Vec, @@ -54,7 +57,8 @@ impl<'a> Visitor 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(), diff --git a/src/librustc/middle/kind.rs b/src/librustc/middle/kind.rs index 4f7cb742d8f86..a45bb69a53ee1 100644 --- a/src/librustc/middle/kind.rs +++ b/src/librustc/middle/kind.rs @@ -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) } diff --git a/src/librustc/middle/liveness.rs b/src/librustc/middle/liveness.rs index 79742d3173434..737b952151b67 100644 --- a/src/librustc/middle/liveness.rs +++ b/src/librustc/middle/liveness.rs @@ -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") diff --git a/src/librustc/middle/mem_categorization.rs b/src/librustc/middle/mem_categorization.rs index e928704b0ccf6..baf7f2dd77650 100644 --- a/src/librustc/middle/mem_categorization.rs +++ b/src/librustc/middle/mem_categorization.rs @@ -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, diff --git a/src/librustc/middle/privacy.rs b/src/librustc/middle/privacy.rs index 74ca13a082135..cdb3f9dbb1dbf 100644 --- a/src/librustc/middle/privacy.rs +++ b/src/librustc/middle/privacy.rs @@ -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, .. }) | diff --git a/src/librustc/middle/resolve.rs b/src/librustc/middle/resolve.rs index 3ff2ef770898c..f1e6db1cab173 100644 --- a/src/librustc/middle/resolve.rs +++ b/src/librustc/middle/resolve.rs @@ -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); diff --git a/src/librustc/middle/save/mod.rs b/src/librustc/middle/save/mod.rs index 2778764d6fada..9f1f4057be6b9 100644 --- a/src/librustc/middle/save/mod.rs +++ b/src/librustc/middle/save/mod.rs @@ -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); diff --git a/src/librustc/middle/subst.rs b/src/librustc/middle/subst.rs index 5c2a70a46fdc8..ef0709316f0af 100644 --- a/src/librustc/middle/subst.rs +++ b/src/librustc/middle/subst.rs @@ -317,6 +317,9 @@ impl VecPerParamSpace { 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, s: Vec, f: Vec) -> VecPerParamSpace { let type_limit = t.len(); let self_limit = t.len() + s.len(); diff --git a/src/librustc/middle/trans/adt.rs b/src/librustc/middle/trans/adt.rs index 3ee61b1d67596..1d0108fa3f7f2 100644 --- a/src/librustc/middle/trans/adt.rs +++ b/src/librustc/middle/trans/adt.rs @@ -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::>(); + 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); diff --git a/src/librustc/middle/trans/base.rs b/src/librustc/middle/trans/base.rs index 3ca188cf2813a..98342bfbcdc32 100644 --- a/src/librustc/middle/trans/base.rs +++ b/src/librustc/middle/trans/base.rs @@ -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 driver::session::Session; +use lint; +use llvm::{BasicBlockRef, ModuleRef, ValueRef, Vector, get_param}; use llvm; -use llvm::{ModuleRef, ValueRef, BasicBlockRef}; -use llvm::{Vector}; use metadata::{csearch, encoder, loader}; -use lint; 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 { 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 { + 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, + monomorphized_arg_types: &[ty::t]) + -> &'a Block<'a> { + let _icx = push_ctxt("copy_unboxed_closure_args_to_allocas"); + let arg_scope_id = cleanup::CustomScope(arg_scope); + + assert_eq!(arg_datums.len(), 1); + + let arg_datum = arg_datums.move_iter().next().unwrap(); + + // Untuple the rest of the arguments. + let tuple_datum = + unpack_datum!(bcx, + arg_datum.to_lvalue_datum_in_scope(bcx, + "argtuple", + arg_scope_id)); + let empty = Vec::new(); + let untupled_arg_types = match ty::get(monomorphized_arg_types[0]).sty { + ty::ty_tup(ref types) => types.as_slice(), + ty::ty_nil => empty.as_slice(), + _ => { + bcx.tcx().sess.span_bug(args[0].pat.span, + "first arg to `rust-call` ABI function \ + wasn't a tuple?!") + } + }; + for j in range(0, args.len()) { + let tuple_element_type = untupled_arg_types[j]; + let tuple_element_datum = + tuple_datum.get_element(tuple_element_type, + |llval| GEPi(bcx, llval, [0, j])); + let tuple_element_datum = tuple_element_datum.to_expr_datum(); + let tuple_element_datum = + unpack_datum!(bcx, + tuple_element_datum.to_rvalue_datum(bcx, + "arg")); + bcx = _match::store_arg(bcx, + args[j].pat, + tuple_element_datum, + arg_scope_id); + + if bcx.fcx.ccx.sess().opts.debuginfo == FullDebugInfo { + debuginfo::create_argument_metadata(bcx, &args[j]); + } + } + + bcx +} + // Ties up the llstaticallocas -> llloadenv -> lltop edges, // and builds the return block. pub fn finish_fn<'a>(fcx: &'a FunctionContext<'a>, @@ -1379,6 +1524,12 @@ pub fn build_return_block(fcx: &FunctionContext, ret_cx: &Block, retty: ty::t) { Ret(ret_cx, retval); } +#[deriving(Clone, Eq, PartialEq)] +pub enum IsUnboxedClosureFlag { + NotUnboxedClosure, + IsUnboxedClosure, +} + // trans_closure: Builds an LLVM function out of a source function. // If the function closes over its environment a closure will be // returned. @@ -1389,7 +1540,11 @@ pub fn trans_closure(ccx: &CrateContext, param_substs: ¶m_substs, id: ast::NodeId, _attributes: &[ast::Attribute], + arg_types: Vec, 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::>(); + 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)); + + 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 = copy_args_to_allocas(&fcx, - arg_scope, - bcx, - decl.inputs.as_slice(), - arg_datums); + 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) diff --git a/src/librustc/middle/trans/callee.rs b/src/librustc/middle/trans/callee.rs index db2d17c85db5f..8eab227ad16f7 100644 --- a/src/librustc/middle/trans/callee.rs +++ b/src/librustc/middle/trans/callee.rs @@ -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, Option<(Datum, ast::NodeId)>), + + // Supply value of arguments as a list of expressions that must be + // translated, for overloaded call operators. + ArgOverloadedCall(&'a [Gc]), } -pub fn trans_args<'a>(cx: &'a Block<'a>, - args: CallArgs, - fn_ty: ty::t, - llargs: &mut Vec , - 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], + fn_ty: ty::t, + llargs: &mut Vec, + 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], + fn_ty: ty::t, + llargs: &mut Vec, + 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 , + 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); diff --git a/src/librustc/middle/trans/closure.rs b/src/librustc/middle/trans/closure.rs index f2400f6bfefe3..a3d8ab1733f97 100644 --- a/src/librustc/middle/trans/closure.rs +++ b/src/librustc/middle/trans/closure.rs @@ -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) + -> &'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::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), + 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_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 { + 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::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, diff --git a/src/librustc/middle/trans/common.rs b/src/librustc/middle/trans/common.rs index 945185f595342..320e291e92865 100644 --- a/src/librustc/middle/trans/common.rs +++ b/src/librustc/middle/trans/common.rs @@ -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 } } diff --git a/src/librustc/middle/trans/context.rs b/src/librustc/middle/trans/context.rs index 8c55f33a0d46d..be39d435ee458 100644 --- a/src/librustc/middle/trans/context.rs +++ b/src/librustc/middle/trans/context.rs @@ -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>, + /// 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), diff --git a/src/librustc/middle/trans/debuginfo.rs b/src/librustc/middle/trans/debuginfo.rs index 8ecdf907fc465..47e941755460f 100644 --- a/src/librustc/middle/trans/debuginfo.rs +++ b/src/librustc/middle/trans/debuginfo.rs @@ -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(_) => { diff --git a/src/librustc/middle/trans/expr.rs b/src/librustc/middle/trans/expr.rs index 60bf80191cb10..e7bde00b3ded9 100644 --- a/src/librustc/middle/trans/expr.rs +++ b/src/librustc/middle/trans/expr.rs @@ -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, + callee: Gc, args: &[Gc], dest: Option) -> &'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)> = - 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 } diff --git a/src/librustc/middle/trans/foreign.rs b/src/librustc/middle/trans/foreign.rs index 56fbccefede5e..d7630d7ec3ab3 100644 --- a/src/librustc/middle/trans/foreign.rs +++ b/src/librustc/middle/trans/foreign.rs @@ -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)); diff --git a/src/librustc/middle/trans/glue.rs b/src/librustc/middle/trans/glue.rs index 40065d0bc5053..aad7ba95a73a9 100644 --- a/src/librustc/middle/trans/glue.rs +++ b/src/librustc/middle/trans/glue.rs @@ -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()); diff --git a/src/librustc/middle/trans/intrinsic.rs b/src/librustc/middle/trans/intrinsic.rs index bb33a5e4f8d2f..2e3d7b291eab1 100644 --- a/src/librustc/middle/trans/intrinsic.rs +++ b/src/librustc/middle/trans/intrinsic.rs @@ -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); diff --git a/src/librustc/middle/trans/meth.rs b/src/librustc/middle/trans/meth.rs index ba44314d962ac..53f89c9d8b879 100644 --- a/src/librustc/middle/trans/meth.rs +++ b/src/librustc/middle/trans/meth.rs @@ -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) 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"), } }); diff --git a/src/librustc/middle/trans/monomorphize.rs b/src/librustc/middle/trans/monomorphize.rs index 6ff6c4741c77c..dac3b6bd8eee4 100644 --- a/src/librustc/middle/trans/monomorphize.rs +++ b/src/librustc/middle/trans/monomorphize.rs @@ -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") } diff --git a/src/librustc/middle/trans/reflect.rs b/src/librustc/middle/trans/reflect.rs index bc156fc37917c..7d8700b942609 100644 --- a/src/librustc/middle/trans/reflect.rs +++ b/src/librustc/middle/trans/reflect.rs @@ -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()) diff --git a/src/librustc/middle/trans/type_of.rs b/src/librustc/middle/trans/type_of.rs index f54ab190d5ef8..94c376c09c86a 100644 --- a/src/librustc/middle/trans/type_of.rs +++ b/src/librustc/middle/trans/type_of.rs @@ -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 { + 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, + inputs: &[ty::t], + output: ty::t, + abi: abi::Abi) + -> Type { let mut atys: Vec = 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); diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs index 95ec43738308e..50563d42e4412 100644 --- a/src/librustc/middle/ty.rs +++ b/src/librustc/middle/ty.rs @@ -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, + /// 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>, + pub node_lint_levels: RefCell>, @@ -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), ty_trait(Box), ty_struct(DefId, Substs), + ty_unboxed_closure(DefId), ty_tup(Vec), 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 { match get(fty).sty { @@ -2669,6 +2709,11 @@ pub fn ty_fn_args(fty: t) -> Vec { 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 { 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 { + 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); + } } }); diff --git a/src/librustc/middle/ty_fold.rs b/src/librustc/middle/ty_fold.rs index c90d9af9b78eb..e2b984959060c 100644 --- a/src/librustc/middle/ty_fold.rs +++ b/src/librustc/middle/ty_fold.rs @@ -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(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(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(_) | diff --git a/src/librustc/middle/typeck/astconv.rs b/src/librustc/middle/typeck/astconv.rs index 6d215282cc45d..56fda06579677 100644 --- a/src/librustc/middle/typeck/astconv.rs +++ b/src/librustc/middle/typeck/astconv.rs @@ -762,6 +762,7 @@ pub fn ast_ty_to_ty( bounds, store, &*f.decl, + abi::Rust, None); ty::mk_closure(tcx, fn_decl) } @@ -780,6 +781,7 @@ pub fn ast_ty_to_ty( bounds, ty::UniqTraitStore, &*f.decl, + abi::Rust, None); ty::mk_closure(tcx, fn_decl) } @@ -879,9 +881,9 @@ pub fn ast_ty_to_ty( } 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( 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( 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( bounds: ty::BuiltinBounds, store: ty::TraitStore, decl: &ast::FnDecl, + abi: abi::Abi, expected_sig: Option) -> ty::ClosureTy { @@ -1117,6 +1121,7 @@ pub fn ty_of_closure( onceness: onceness, store: store, bounds: bounds, + abi: abi, sig: ty::FnSig {binder_id: id, inputs: input_tys, output: output_ty, diff --git a/src/librustc/middle/typeck/check/method.rs b/src/librustc/middle/typeck/check/method.rs index e12fae4f9501e..1805c18eaf10c 100644 --- a/src/librustc/middle/typeck/check/method.rs +++ b/src/librustc/middle/typeck/check/method.rs @@ -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) } diff --git a/src/librustc/middle/typeck/check/mod.rs b/src/librustc/middle/typeck/check/mod.rs index 3b860be0f0134..557fd522fa918 100644 --- a/src/librustc/middle/typeck/check/mod.rs +++ b/src/librustc/middle/typeck/check/mod.rs @@ -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, + unboxed_closure_types: RefCell>, } /// 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) { + // 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, diff --git a/src/librustc/middle/typeck/check/regionck.rs b/src/librustc/middle/typeck/check/regionck.rs index 180dac5382805..22d52d0b7d2a0 100644 --- a/src/librustc/middle/typeck/check/regionck.rs +++ b/src/librustc/middle/typeck/check/regionck.rs @@ -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); } diff --git a/src/librustc/middle/typeck/check/vtable.rs b/src/librustc/middle/typeck/check/vtable.rs index d2a1ef786bd29..ea82a62d6c684 100644 --- a/src/librustc/middle/typeck/check/vtable.rs +++ b/src/librustc/middle/typeck/check/vtable.rs @@ -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>, } 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) + -> Option { + let tcx = vcx.tcx(); + let closure_def_id = match ty::get(ty).sty { + ty::ty_unboxed_closure(closure_def_id) => closure_def_id, + _ => return None, + }; + + let fn_traits = [ + tcx.lang_items.fn_trait(), + tcx.lang_items.fn_mut_trait(), + tcx.lang_items.fn_once_trait() + ]; + for fn_trait in fn_traits.iter() { + match *fn_trait { + Some(ref fn_trait) if *fn_trait == trait_ref.def_id => {} + _ => continue, + }; + + // Check to see whether the argument and return types match. + let unboxed_closure_types = tcx.unboxed_closure_types.borrow(); + let closure_type = match unboxed_closure_types.find(&closure_def_id) { + Some(closure_type) => (*closure_type).clone(), + None => { + // Try the inherited unboxed closure type map. + let unboxed_closure_types = vcx.unboxed_closure_types + .borrow(); + match unboxed_closure_types.find(&closure_def_id) { + Some(closure_type) => (*closure_type).clone(), + None => { + tcx.sess.span_bug(span, + "didn't find unboxed closure type \ + in tcx map or inh map") + } + } + } + }; + + // FIXME(pcwalton): This is a bogus thing to do, but + // it'll do for now until we get the new trait-bound + // region skolemization working. + let (_, new_signature) = + regionmanip::replace_late_bound_regions_in_fn_sig( + tcx, + &closure_type.sig, + |br| { + vcx.infcx.next_region_var(infer::LateBoundRegion(span, + br)) + }); + + let arguments_tuple = *new_signature.inputs.get(0); + let corresponding_trait_ref = Rc::new(ty::TraitRef { + def_id: trait_ref.def_id, + substs: subst::Substs::new_trait( + vec![arguments_tuple, new_signature.output], + Vec::new(), + ty) + }); + + relate_trait_refs(vcx, span, corresponding_trait_ref, trait_ref); + return Some(vtable_unboxed_closure(closure_def_id)) + } + + None +} + fn search_for_vtable(vcx: &VtableContext, span: Span, ty: ty::t, @@ -306,6 +381,18 @@ fn search_for_vtable(vcx: &VtableContext, debug!("nrc - search_for_vtable"); let tcx = vcx.tcx(); + // First, check to see whether this is a call to the `call` method of an + // unboxed closure. If so, and the arguments match, we're done. + match search_for_unboxed_closure_vtable(vcx, + span, + ty, + trait_ref.clone()) { + Some(vtable_origin) => return Some(vtable_origin), + None => {} + } + + // Nope. Continue. + let mut found = Vec::new(); let mut impls_seen = HashSet::new(); @@ -799,7 +886,12 @@ pub fn resolve_impl(tcx: &ty::ctxt, debug!("impl_trait_ref={}", impl_trait_ref.repr(tcx)); let infcx = &infer::new_infer_ctxt(tcx); - let vcx = VtableContext { infcx: infcx, param_env: ¶m_env }; + let unboxed_closure_types = RefCell::new(DefIdMap::new()); + let vcx = VtableContext { + infcx: infcx, + param_env: ¶m_env, + unboxed_closure_types: &unboxed_closure_types, + }; // Resolve the vtables for the trait reference on the impl. This // serves many purposes, best explained by example. Imagine we have: @@ -847,9 +939,11 @@ pub fn resolve_impl(tcx: &ty::ctxt, pub fn trans_resolve_method(tcx: &ty::ctxt, id: ast::NodeId, substs: &subst::Substs) -> vtable_res { let generics = ty::lookup_item_type(tcx, ast_util::local_def(id)).generics; + let unboxed_closure_types = RefCell::new(DefIdMap::new()); let vcx = VtableContext { infcx: &infer::new_infer_ctxt(tcx), - param_env: &ty::construct_parameter_environment(tcx, &ty::Generics::empty(), id) + param_env: &ty::construct_parameter_environment(tcx, &ty::Generics::empty(), id), + unboxed_closure_types: &unboxed_closure_types, }; lookup_vtables(&vcx, diff --git a/src/librustc/middle/typeck/check/writeback.rs b/src/librustc/middle/typeck/check/writeback.rs index 59b65fdbec790..d802e3d14433c 100644 --- a/src/librustc/middle/typeck/check/writeback.rs +++ b/src/librustc/middle/typeck/check/writeback.rs @@ -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") + } } } } diff --git a/src/librustc/middle/typeck/coherence.rs b/src/librustc/middle/typeck/coherence.rs index b9bf8e37dead8..9e6d059650cc5 100644 --- a/src/librustc/middle/typeck/coherence.rs +++ b/src/librustc/middle/typeck/coherence.rs @@ -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); diff --git a/src/librustc/middle/typeck/collect.rs b/src/librustc/middle/typeck/collect.rs index 906cc1e0255aa..5fd9b85d69aa0 100644 --- a/src/librustc/middle/typeck/collect.rs +++ b/src/librustc/middle/typeck/collect.rs @@ -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 diff --git a/src/librustc/middle/typeck/infer/combine.rs b/src/librustc/middle/typeck/infer/combine.rs index d82e6e74778e5..1aae97d3d83e9 100644 --- a/src/librustc/middle/typeck/infer/combine.rs +++ b/src/librustc/middle/typeck/infer/combine.rs @@ -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(this: &C, a: ty::t, b: ty::t) -> cres { 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))) } diff --git a/src/librustc/middle/typeck/mod.rs b/src/librustc/middle/typeck/mod.rs index ad6864ba48792..aebdb5943826a 100644 --- a/src/librustc/middle/typeck/mod.rs +++ b/src/librustc/middle/typeck/mod.rs @@ -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") } diff --git a/src/librustc/middle/typeck/variance.rs b/src/librustc/middle/typeck/variance.rs index a65aa0423a6d0..d230b08096641 100644 --- a/src/librustc/middle/typeck/variance.rs +++ b/src/librustc/middle/typeck/variance.rs @@ -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 */ } diff --git a/src/librustc/util/ppaux.rs b/src/librustc/util/ppaux.rs index 8b8e37fe280d9..c3986d01d3da5 100644 --- a/src/librustc/util/ppaux.rs +++ b/src/librustc/util/ppaux.rs @@ -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) } diff --git a/src/librustc_back/svh.rs b/src/librustc_back/svh.rs index 66bc8c740c47f..cb9519b1eb815 100644 --- a/src/librustc_back/svh.rs +++ b/src/librustc_back/svh.rs @@ -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, diff --git a/src/librustc_llvm/lib.rs b/src/librustc_llvm/lib.rs index 9ee8fa98c7499..4ea4958e544ae 100644 --- a/src/librustc_llvm/lib.rs +++ b/src/librustc_llvm/lib.rs @@ -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 diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index c94759d7d7e8d..9f5df205aa4c3 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -1301,6 +1301,8 @@ impl Clean for ty::t { } } + ty::ty_unboxed_closure(..) => Primitive(Unit), // FIXME(pcwalton) + ty::ty_infer(..) => fail!("ty_infer"), ty::ty_err => fail!("ty_err"), } diff --git a/src/libsyntax/abi.rs b/src/libsyntax/abi.rs index 8b01002831b7e..6f80938362049 100644 --- a/src/libsyntax/abi.rs +++ b/src/libsyntax/abi.rs @@ -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). diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index d9f14bfa15661..394d4a825167d 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -503,6 +503,7 @@ pub enum Expr_ { ExprMatch(Gc, Vec), ExprFnBlock(P, P), ExprProc(P, P), + ExprUnboxedFn(P, P), ExprBlock(P), ExprAssign(Gc, Gc), @@ -690,6 +691,7 @@ pub struct TypeMethod { pub ident: Ident, pub attrs: Vec, pub fn_style: FnStyle, + pub abi: Abi, pub decl: P, pub generics: Generics, pub explicit_self: ExplicitSelf, @@ -966,13 +968,20 @@ pub struct Method { pub attrs: Vec, 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, P, Visibility), + MethDecl(Ident, + Generics, + Abi, + ExplicitSelf, + FnStyle, + P, + P, + Visibility), /// Represents a macro in method position MethMac(Mac), } diff --git a/src/libsyntax/ast_map/mod.rs b/src/libsyntax/ast_map/mod.rs index 50e487b63db1f..c77f7db1c6da0 100644 --- a/src/libsyntax/ast_map/mod.rs +++ b/src/libsyntax/ast_map/mod.rs @@ -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), diff --git a/src/libsyntax/ast_util.rs b/src/libsyntax/ast_util.rs index 5431a3db16ecb..2b98a3bdd28ef 100644 --- a/src/libsyntax/ast_util.rs +++ b/src/libsyntax/ast_util.rs @@ -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; @@ -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 { - mf_method_body!(self,MethDecl(_,_,_,_,decl,_,_),decl) + mf_method_body!(self, MethDecl(_,_,_,_,_,decl,_,_),decl) } fn pe_body(&self) -> P { - 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) } } diff --git a/src/libsyntax/ext/deriving/generic/mod.rs b/src/libsyntax/ext/deriving/generic/mod.rs index f1c1784146a84..871f277a2da28 100644 --- a/src/libsyntax/ext/deriving/generic/mod.rs +++ b/src/libsyntax/ext/deriving/generic/mod.rs @@ -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)> , - body: Gc) -> Gc { + body: Gc) + -> Gc { // 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, diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index 1cbe863e4e4f9..fdb698441fc0c 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -910,7 +910,14 @@ impl<'a> Folder for PatIdentRenamer<'a> { fn expand_method(m: &ast::Method, fld: &mut MacroExpander) -> SmallVector> { 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(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(m: &Method, folder: &mut T) -> SmallVector { + 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(e: Gc, folder: &mut T) -> Gc { 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)) } diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index a77f24f98f818..394288bd9f29b 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -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 { - 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 { - 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, - parse_body: |&mut Parser| -> Gc) - -> Gc { 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 { @@ -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 { - let inputs_captures = { + // parse the |arg, arg| header on a lambda + fn parse_fn_block_decl(&mut self) -> (P, 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) } }; diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index 10caaea86cf4b..dd96118ea49ee 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -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, "|")); diff --git a/src/libsyntax/visit.rs b/src/libsyntax/visit.rs index cd953607ea22b..d5fb75a4d695d 100644 --- a/src/libsyntax/visit.rs +++ b/src/libsyntax/visit.rs @@ -562,7 +562,7 @@ pub fn walk_method_helper>(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>(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>(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, diff --git a/src/test/compile-fail/borrowck-overloaded-call.rs b/src/test/compile-fail/borrowck-overloaded-call.rs index 349a20313fa8c..f134c2aa09bd5 100644 --- a/src/test/compile-fail/borrowck-overloaded-call.rs +++ b/src/test/compile-fail/borrowck-overloaded-call.rs @@ -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() } } diff --git a/src/test/compile-fail/overloaded-calls-bad.rs b/src/test/compile-fail/overloaded-calls-bad.rs index 3c03c87475720..cc01c0b3c9f1c 100644 --- a/src/test/compile-fail/overloaded-calls-bad.rs +++ b/src/test/compile-fail/overloaded-calls-bad.rs @@ -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 } } diff --git a/src/test/compile-fail/overloaded-calls-nontuple.rs b/src/test/compile-fail/overloaded-calls-nontuple.rs index 9bbc4ab3ba3b3..ee2fe3522470a 100644 --- a/src/test/compile-fail/overloaded-calls-nontuple.rs +++ b/src/test/compile-fail/overloaded-calls-nontuple.rs @@ -18,7 +18,7 @@ struct S { } impl FnMut 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 } } diff --git a/src/test/compile-fail/unboxed-closures-type-mismatch.rs b/src/test/compile-fail/unboxed-closures-type-mismatch.rs new file mode 100644 index 0000000000000..09f13b7738694 --- /dev/null +++ b/src/test/compile-fail/unboxed-closures-type-mismatch.rs @@ -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 or the MIT license +// , 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); +} diff --git a/src/test/compile-fail/unboxed-closures-vtable-mismatch.rs b/src/test/compile-fail/unboxed-closures-vtable-mismatch.rs new file mode 100644 index 0000000000000..2ee632b9093c8 --- /dev/null +++ b/src/test/compile-fail/unboxed-closures-vtable-mismatch.rs @@ -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 or the MIT license +// , 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>(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); +} + diff --git a/src/test/run-pass/fn-trait-sugar.rs b/src/test/run-pass/fn-trait-sugar.rs index b0c8d84b6646b..ccb5634f7a290 100644 --- a/src/test/run-pass/fn-trait-sugar.rs +++ b/src/test/run-pass/fn-trait-sugar.rs @@ -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 } } diff --git a/src/test/run-pass/issue-14958.rs b/src/test/run-pass/issue-14958.rs index 045d3cc0458f7..b53c2258736ff 100644 --- a/src/test/run-pass/issue-14958.rs +++ b/src/test/run-pass/issue-14958.rs @@ -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; diff --git a/src/test/run-pass/issue-14959.rs b/src/test/run-pass/issue-14959.rs index 7fbb0657c704b..af0bc78094e5f 100644 --- a/src/test/run-pass/issue-14959.rs +++ b/src/test/run-pass/issue-14959.rs @@ -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 Ingot for HelloWorld { diff --git a/src/test/run-pass/overloaded-calls-simple.rs b/src/test/run-pass/overloaded-calls-simple.rs index 33120defedd8d..76c7e60116f80 100644 --- a/src/test/run-pass/overloaded-calls-simple.rs +++ b/src/test/run-pass/overloaded-calls-simple.rs @@ -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); } diff --git a/src/test/run-pass/overloaded-calls-zero-args.rs b/src/test/run-pass/overloaded-calls-zero-args.rs index f8f7df6b49b33..b868c8c96b5fb 100644 --- a/src/test/run-pass/overloaded-calls-zero-args.rs +++ b/src/test/run-pass/overloaded-calls-zero-args.rs @@ -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 } } diff --git a/src/test/run-pass/unboxed-closures-boxed.rs b/src/test/run-pass/unboxed-closures-boxed.rs new file mode 100644 index 0000000000000..c4b990abf7e65 --- /dev/null +++ b/src/test/run-pass/unboxed-closures-boxed.rs @@ -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 or the MIT license +// , 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> { + (box |&mut: y: int| -> int { x + y }) as Box> +} + +pub fn main() { + let mut adder = make_adder(3); + let z = adder.call_mut((2,)); + println!("{}", z); + assert_eq!(z, 5); +} + diff --git a/src/test/run-pass/unboxed-closures-generic.rs b/src/test/run-pass/unboxed-closures-generic.rs new file mode 100644 index 0000000000000..9d1d81fe259b3 --- /dev/null +++ b/src/test/run-pass/unboxed-closures-generic.rs @@ -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 or the MIT license +// , 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>(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); +} + diff --git a/src/test/run-pass/unboxed-closures-simple.rs b/src/test/run-pass/unboxed-closures-simple.rs new file mode 100644 index 0000000000000..f11096ba5ffc6 --- /dev/null +++ b/src/test/run-pass/unboxed-closures-simple.rs @@ -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 or the MIT license +// , 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); +}