]> git.lizzy.rs Git - rust.git/blobdiff - src/librustc/middle/trans/closure.rs
auto merge of #15999 : Kimundi/rust/fix_folder, r=nikomatsakis
[rust.git] / src / librustc / middle / trans / closure.rs
index f2400f6bfefe35c6e7470151cb91d29e035a54fe..98b2ebb70f3cb211c732c68810d8cadb454bd914 100644 (file)
@@ -16,6 +16,7 @@
 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 arena::TypedArena;
 use syntax::ast;
+use syntax::ast_util;
 
 // ___Good to know (tm)__________________________________________________
 //
@@ -285,7 +287,6 @@ fn load_environment<'a>(bcx: &'a Block<'a>,
         let def_id = freevar.def.def_id();
 
         bcx.fcx.llupvars.borrow_mut().insert(def_id.node, upvarptr);
-
         for &env_pointer_alloca in env_pointer_alloca.iter() {
             debuginfo::create_captured_var_metadata(
                 bcx,
@@ -303,6 +304,26 @@ fn load_environment<'a>(bcx: &'a Block<'a>,
     bcx
 }
 
+fn load_unboxed_closure_environment<'a>(
+                                    bcx: &'a Block<'a>,
+                                    freevars: &Vec<freevars::freevar_entry>)
+                                    -> &'a Block<'a> {
+    let _icx = push_ctxt("closure::load_environment");
+
+    if freevars.len() == 0 {
+        return bcx
+    }
+
+    let llenv = bcx.fcx.llenv.unwrap();
+    for (i, freevar) in freevars.iter().enumerate() {
+        let upvar_ptr = GEPi(bcx, llenv, [0, i]);
+        let def_id = freevar.def.def_id();
+        bcx.fcx.llupvars.borrow_mut().insert(def_id.node, upvar_ptr);
+    }
+
+    bcx
+}
+
 fn fill_fn_pair(bcx: &Block, pair: ValueRef, llfn: ValueRef, llenvptr: ValueRef) {
     Store(bcx, llfn, GEPi(bcx, pair, [0u, abi::fn_field_code]));
     let llenvptr = PointerCast(bcx, llenvptr, Type::i8p(bcx.ccx()));
@@ -352,20 +373,151 @@ pub fn trans_expr_fn<'a>(
 
     let freevar_mode = freevars::get_capture_mode(tcx, id);
     let freevars: Vec<freevars::freevar_entry> =
-        freevars::with_freevars(
-            tcx, id,
-            |fv| fv.iter().map(|&fv| fv).collect());
-
-    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),
-                  |bcx| load_environment(bcx, cdata_ty, &freevars, store));
+        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),
+                  bcx.fcx.handle_items);
     fill_fn_pair(bcx, dest_addr, llfn, llbox);
     bcx
 }
 
+/// Returns the LLVM function declaration for an unboxed closure, creating it
+/// if necessary. If the ID does not correspond to a closure ID, returns None.
+pub fn get_or_create_declaration_if_unboxed_closure(ccx: &CrateContext,
+                                                    closure_id: ast::DefId)
+                                                    -> Option<ValueRef> {
+    if !ccx.tcx.unboxed_closure_types.borrow().contains_key(&closure_id) {
+        // Not an unboxed closure.
+        return None
+    }
+
+    match ccx.unboxed_closure_vals.borrow().find(&closure_id) {
+        Some(llfn) => {
+            debug!("get_or_create_declaration_if_unboxed_closure(): found \
+                    closure");
+            return Some(*llfn)
+        }
+        None => {}
+    }
+
+    let function_type = ty::mk_unboxed_closure(&ccx.tcx, closure_id);
+    let symbol = ccx.tcx.map.with_path(closure_id.node, |path| {
+        mangle_internal_name_by_path_and_seq(path, "unboxed_closure")
+    });
+
+    let llfn = decl_internal_rust_fn(ccx, function_type, symbol.as_slice());
+
+    // set an inline hint for all closures
+    set_inline_hint(llfn);
+
+    debug!("get_or_create_declaration_if_unboxed_closure(): inserting new \
+            closure {} (type {})",
+           closure_id,
+           ccx.tn.type_to_string(val_ty(llfn)));
+    ccx.unboxed_closure_vals.borrow_mut().insert(closure_id, llfn);
+
+    Some(llfn)
+}
+
+pub fn trans_unboxed_closure<'a>(
+                             mut bcx: &'a Block<'a>,
+                             decl: &ast::FnDecl,
+                             body: &ast::Block,
+                             id: ast::NodeId,
+                             dest: expr::Dest)
+                             -> &'a Block<'a> {
+    let _icx = push_ctxt("closure::trans_unboxed_closure");
+
+    debug!("trans_unboxed_closure()");
+
+    let closure_id = ast_util::local_def(id);
+    let llfn = get_or_create_declaration_if_unboxed_closure(
+        bcx.ccx(),
+        closure_id).unwrap();
+
+    // Untuple the arguments.
+    let unboxed_closure_types = bcx.tcx().unboxed_closure_types.borrow();
+    let /*mut*/ function_type = (*unboxed_closure_types.get(&closure_id)).clone();
+    /*function_type.sig.inputs =
+        match ty::get(*function_type.sig.inputs.get(0)).sty {
+            ty::ty_tup(ref tuple_types) => {
+                tuple_types.iter().map(|x| (*x).clone()).collect()
+            }
+            _ => {
+                bcx.tcx().sess.span_bug(body.span,
+                                        "unboxed closure wasn't a tuple?!")
+            }
+        };*/
+    let function_type = ty::mk_closure(bcx.tcx(), function_type);
+
+    let freevars: Vec<freevars::freevar_entry> =
+        freevars::with_freevars(bcx.tcx(),
+                                id,
+                                |fv| fv.iter().map(|&fv| fv).collect());
+    let freevars_ptr = &freevars;
+
+    trans_closure(bcx.ccx(),
+                  decl,
+                  body,
+                  llfn,
+                  bcx.fcx.param_substs,
+                  id,
+                  [],
+                  ty::ty_fn_args(function_type),
+                  ty::ty_fn_ret(function_type),
+                  ty::ty_fn_abi(function_type),
+                  true,
+                  IsUnboxedClosure,
+                  |bcx| load_unboxed_closure_environment(bcx, freevars_ptr),
+                  bcx.fcx.handle_items);
+
+    // 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.
+    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);
+    }
+    adt::trans_set_discr(bcx, &*repr, dest_addr, 0);
+
+    bcx
+}
+
 pub fn get_wrapper_for_bare_fn(ccx: &CrateContext,
                                closure_ty: ty::t,
                                def: def::Def,
@@ -423,7 +575,7 @@ pub fn get_wrapper_for_bare_fn(ccx: &CrateContext,
     let arena = TypedArena::new();
     let empty_param_substs = param_substs::empty();
     let fcx = new_fn_ctxt(ccx, llfn, -1, true, f.sig.output,
-                          &empty_param_substs, None, &arena);
+                          &empty_param_substs, None, &arena, TranslateItems);
     let bcx = init_function(&fcx, true, f.sig.output);
 
     let args = create_datums_for_fn_args(&fcx,
@@ -438,7 +590,7 @@ pub fn get_wrapper_for_bare_fn(ccx: &CrateContext,
     }
     llargs.extend(args.iter().map(|arg| arg.val));
 
-    let retval = Call(bcx, fn_ptr, llargs.as_slice(), []);
+    let retval = Call(bcx, fn_ptr, llargs.as_slice(), None);
     if type_is_zero_size(ccx, f.sig.output) || fcx.llretptr.get().is_some() {
         RetVoid(bcx);
     } else {