]> git.lizzy.rs Git - rust.git/blobdiff - src/librustc/middle/trans/callee.rs
auto merge of #15999 : Kimundi/rust/fix_folder, r=nikomatsakis
[rust.git] / src / librustc / middle / trans / callee.rs
index 15415620c5bba2ad40830d0a4372ccd257052d7f..f186af48321c3d8dd64db0769811eb5e7ca8bfa9 100644 (file)
 use arena::TypedArena;
 use back::abi;
 use back::link;
-use lib::llvm::ValueRef;
-use lib::llvm::llvm;
+use driver::session;
+use llvm::{ValueRef, get_param};
+use llvm;
 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::*;
@@ -52,6 +55,7 @@
 
 use std::gc::Gc;
 use syntax::ast;
+use syntax::ast_map;
 use synabi = syntax::abi;
 
 pub struct MethodData {
@@ -62,6 +66,10 @@ pub struct MethodData {
 pub enum CalleeData {
     Closure(Datum<Lvalue>),
 
+    // Constructor for enum variant/tuple-like-struct
+    // i.e. Some, Ok
+    NamedTupleConstructor(subst::Substs, ty::Disr),
+
     // Represents a (possibly monomorphized) top-level fn item or method
     // item. Note that this is just the fn-ptr and is not a Rust closure
     // value (which is a pair).
@@ -74,7 +82,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 +105,18 @@ fn datum_callee<'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 +129,10 @@ fn datum_callee<'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)
@@ -123,6 +140,23 @@ fn trans_def<'a>(bcx: &'a Block<'a>, def: def::Def, ref_expr: &ast::Expr)
         debug!("trans_def(def={}, ref_expr={})", def.repr(bcx.tcx()), ref_expr.repr(bcx.tcx()));
         let expr_ty = node_id_type(bcx, ref_expr.id);
         match def {
+            def::DefFn(did, _) if {
+                let def_id = if did.krate != ast::LOCAL_CRATE {
+                    inline::maybe_instantiate_inline(bcx.ccx(), did)
+                } else {
+                    did
+                };
+                match bcx.tcx().map.find(def_id.node) {
+                    Some(ast_map::NodeStructCtor(_)) => true,
+                    _ => false
+                }
+            } => {
+                let substs = node_id_substs(bcx, ExprId(ref_expr.id));
+                Callee {
+                    bcx: bcx,
+                    data: NamedTupleConstructor(substs, 0)
+                }
+            }
             def::DefFn(did, _) if match ty::get(expr_ty).sty {
                 ty::ty_bare_fn(ref f) => f.abi == synabi::RustIntrinsic,
                 _ => false
@@ -147,14 +181,23 @@ fn trans_def<'a>(bcx: &'a Block<'a>, def: def::Def, ref_expr: &ast::Expr)
                                                                 ref_expr.id))
             }
             def::DefVariant(tid, vid, _) => {
-                // nullary variants are not callable
-                assert!(ty::enum_variant_with_id(bcx.tcx(),
-                                                      tid,
-                                                      vid).args.len() > 0u);
-                fn_callee(bcx, trans_fn_ref(bcx, vid, ExprId(ref_expr.id)))
+                let vinfo = ty::enum_variant_with_id(bcx.tcx(), tid, vid);
+                let substs = node_id_substs(bcx, ExprId(ref_expr.id));
+
+                // Nullary variants are not callable
+                assert!(vinfo.args.len() > 0u);
+
+                Callee {
+                    bcx: bcx,
+                    data: NamedTupleConstructor(substs, vinfo.disr_val)
+                }
             }
-            def::DefStruct(def_id) => {
-                fn_callee(bcx, trans_fn_ref(bcx, def_id, ExprId(ref_expr.id)))
+            def::DefStruct(_) => {
+                let substs = node_id_substs(bcx, ExprId(ref_expr.id));
+                Callee {
+                    bcx: bcx,
+                    data: NamedTupleConstructor(substs, 0)
+                }
             }
             def::DefStatic(..) |
             def::DefArg(..) |
@@ -206,9 +249,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,
@@ -291,7 +339,8 @@ pub fn trans_unboxing_shim(bcx: &Block,
                           return_type,
                           &empty_param_substs,
                           None,
-                          &block_arena);
+                          &block_arena,
+                          TranslateItems);
     let mut bcx = init_function(&fcx, false, return_type);
 
     // Create the substituted versions of the self type.
@@ -304,9 +353,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 +387,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 +447,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 +507,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 = {
@@ -475,8 +523,27 @@ pub fn trans_fn_ref_with_vtables(
         }
     };
 
-    // We must monomorphise if the fn has type parameters or is a default method.
-    let must_monomorphise = !substs.types.is_empty() || is_default;
+    // We must monomorphise if the fn has type parameters, is a default method,
+    // or is a named tuple constructor.
+    let must_monomorphise = if !substs.types.is_empty() || is_default {
+        true
+    } else if def_id.krate == ast::LOCAL_CRATE {
+        let map_node = session::expect(
+            ccx.sess(),
+            tcx.map.find(def_id.node),
+            || "local item should be in ast map".to_string());
+
+        match map_node {
+            ast_map::NodeVariant(v) => match v.node.kind {
+                ast::TupleVariantKind(ref args) => args.len() > 0,
+                _ => false
+            },
+            ast_map::NodeStructCtor(_) => true,
+            _ => false
+        }
+    } else {
+        false
+    };
 
     // Create a monomorphic version of generic functions
     if must_monomorphise {
@@ -509,6 +576,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 +616,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 +733,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")
     };
 
@@ -689,12 +762,22 @@ pub fn trans_call_inner<'a>(
                                                    arg_cleanup_scope, args,
                                                    dest.unwrap(), substs);
         }
+        NamedTupleConstructor(substs, disr) => {
+            assert!(dest.is_some());
+            fcx.pop_custom_cleanup_scope(arg_cleanup_scope);
+
+            let ctor_ty = callee_ty.subst(bcx.tcx(), &substs);
+            return base::trans_named_tuple_constructor(bcx, ctor_ty, disr,
+                                                       args, dest.unwrap());
+        }
     };
 
     // Intrinsics should not become actual functions.
     // We trans them in place in `trans_intrinsic_call`
     assert!(abi != synabi::RustIntrinsic);
 
+    let is_rust_fn = abi == synabi::Rust || abi == synabi::RustCall;
+
     // Generate a location to store the result. If the user does
     // not care about the result, just make a stack slot.
     let opt_llretslot = match dest {
@@ -703,7 +786,9 @@ pub fn trans_call_inner<'a>(
             None
         }
         Some(expr::SaveIn(dst)) => Some(dst),
-        Some(expr::Ignore) => {
+        Some(expr::Ignore) if !is_rust_fn ||
+                type_of::return_uses_outptr(ccx, ret_ty) ||
+                ty::type_needs_drop(bcx.tcx(), ret_ty) => {
             if !type_is_zero_size(ccx, ret_ty) {
                 Some(alloc_ty(bcx, ret_ty, "__llret"))
             } else {
@@ -711,6 +796,7 @@ pub fn trans_call_inner<'a>(
                 Some(C_undef(llty.ptr_to()))
             }
         }
+        Some(expr::Ignore) => None
     };
 
     let mut llresult = unsafe {
@@ -723,7 +809,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 is_rust_fn {
         let mut llargs = Vec::new();
 
         // Push the out-pointer if we use an out-pointer for this
@@ -742,9 +828,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 +869,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(),
@@ -789,15 +884,13 @@ pub fn trans_call_inner<'a>(
 
     // If the caller doesn't care about the result of this fn call,
     // drop the temporary slot we made.
-    match dest {
-        None => {
-            assert!(!type_of::return_uses_outptr(bcx.ccx(), ret_ty));
-        }
-        Some(expr::Ignore) => {
+    match (dest, opt_llretslot) {
+        (Some(expr::Ignore), Some(llretslot)) => {
             // drop the value if it is not being saved.
-            bcx = glue::drop_ty(bcx, opt_llretslot.unwrap(), ret_ty);
+            bcx = glue::drop_ty(bcx, llretslot, ret_ty);
+            call_lifetime_end(bcx, llretslot);
         }
-        Some(expr::SaveIn(_)) => { }
+        _ => {}
     }
 
     if ty::type_is_bot(ret_ty) {
@@ -821,15 +914,130 @@ pub enum CallArgs<'a> {
     // is the left-hand-side and `rhs/rhs_id` is the datum/expr-id of
     // the right-hand-side (if any).
     ArgOverloadedOp(Datum<Expr>, Option<(Datum<Expr>, ast::NodeId)>),
+
+    // Supply value of arguments as a list of expressions that must be
+    // translated, for overloaded call operators.
+    ArgOverloadedCall(&'a [Gc<ast::Expr>]),
 }
 
-pub fn trans_args<'a>(cx: &'a Block<'a>,
-                      args: CallArgs,
-                      fn_ty: ty::t,
-                      llargs: &mut Vec<ValueRef> ,
-                      arg_cleanup_scope: cleanup::ScopeId,
-                      ignore_self: bool)
-                      -> &'a Block<'a> {
+fn trans_args_under_call_abi<'a>(
+                             mut bcx: &'a Block<'a>,
+                             arg_exprs: &[Gc<ast::Expr>],
+                             fn_ty: ty::t,
+                             llargs: &mut Vec<ValueRef>,
+                             arg_cleanup_scope: cleanup::ScopeId,
+                             ignore_self: bool)
+                             -> &'a Block<'a> {
+    // Translate the `self` argument first.
+    let arg_tys = ty::ty_fn_args(fn_ty);
+    if !ignore_self {
+        let arg_datum = unpack_datum!(bcx, expr::trans(bcx, &*arg_exprs[0]));
+        llargs.push(unpack_result!(bcx, {
+            trans_arg_datum(bcx,
+                            *arg_tys.get(0),
+                            arg_datum,
+                            arg_cleanup_scope,
+                            DontAutorefArg)
+        }))
+    }
+
+    // Now untuple the rest of the arguments.
+    let tuple_expr = arg_exprs[1];
+    let tuple_type = node_id_type(bcx, tuple_expr.id);
+
+    match ty::get(tuple_type).sty {
+        ty::ty_tup(ref field_types) => {
+            let tuple_datum = unpack_datum!(bcx,
+                                            expr::trans(bcx, &*tuple_expr));
+            let tuple_lvalue_datum =
+                unpack_datum!(bcx,
+                              tuple_datum.to_lvalue_datum(bcx,
+                                                          "args",
+                                                          tuple_expr.id));
+            let repr = adt::represent_type(bcx.ccx(), tuple_type);
+            let repr_ptr = &*repr;
+            for i in range(0, field_types.len()) {
+                let arg_datum = tuple_lvalue_datum.get_element(
+                    *field_types.get(i),
+                    |srcval| {
+                        adt::trans_field_ptr(bcx, repr_ptr, srcval, 0, i)
+                    });
+                let arg_datum = arg_datum.to_expr_datum();
+                let arg_datum =
+                    unpack_datum!(bcx, arg_datum.to_rvalue_datum(bcx, "arg"));
+                let arg_datum =
+                    unpack_datum!(bcx, arg_datum.to_appropriate_datum(bcx));
+                llargs.push(arg_datum.add_clean(bcx.fcx, arg_cleanup_scope));
+            }
+        }
+        ty::ty_nil => {}
+        _ => {
+            bcx.sess().span_bug(tuple_expr.span,
+                                "argument to `.call()` wasn't a tuple?!")
+        }
+    };
+
+    bcx
+}
+
+fn trans_overloaded_call_args<'a>(
+                              mut bcx: &'a Block<'a>,
+                              arg_exprs: &[Gc<ast::Expr>],
+                              fn_ty: ty::t,
+                              llargs: &mut Vec<ValueRef>,
+                              arg_cleanup_scope: cleanup::ScopeId,
+                              ignore_self: bool)
+                              -> &'a Block<'a> {
+    // Translate the `self` argument first.
+    let arg_tys = ty::ty_fn_args(fn_ty);
+    if !ignore_self {
+        let arg_datum = unpack_datum!(bcx, expr::trans(bcx, &*arg_exprs[0]));
+        llargs.push(unpack_result!(bcx, {
+            trans_arg_datum(bcx,
+                            *arg_tys.get(0),
+                            arg_datum,
+                            arg_cleanup_scope,
+                            DontAutorefArg)
+        }))
+    }
+
+    // Now untuple the rest of the arguments.
+    let tuple_type = *arg_tys.get(1);
+    match ty::get(tuple_type).sty {
+        ty::ty_tup(ref field_types) => {
+            for (i, &field_type) in field_types.iter().enumerate() {
+                let arg_datum =
+                    unpack_datum!(bcx, expr::trans(bcx, &*arg_exprs[i + 1]));
+                llargs.push(unpack_result!(bcx, {
+                    trans_arg_datum(bcx,
+                                    field_type,
+                                    arg_datum,
+                                    arg_cleanup_scope,
+                                    DontAutorefArg)
+                }))
+            }
+        }
+        ty::ty_nil => {}
+        _ => {
+            bcx.sess().span_bug(arg_exprs[0].span,
+                                "argument to `.call()` wasn't a tuple?!")
+        }
+    };
+
+    bcx
+}
+
+pub fn trans_args<'a>(
+                  cx: &'a Block<'a>,
+                  args: CallArgs,
+                  fn_ty: ty::t,
+                  llargs: &mut Vec<ValueRef> ,
+                  arg_cleanup_scope: cleanup::ScopeId,
+                  ignore_self: bool,
+                  abi: synabi::Abi)
+                  -> &'a Block<'a> {
+    debug!("trans_args(abi={})", abi);
+
     let _icx = push_ctxt("trans_args");
     let arg_tys = ty::ty_fn_args(fn_ty);
     let variadic = ty::fn_is_variadic(fn_ty);
@@ -841,6 +1049,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 +1080,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);