]> 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 2e4a3d9fd7e3ed910a1fd38c8a7bbe27c3b3457a..f186af48321c3d8dd64db0769811eb5e7ca8bfa9 100644 (file)
 use back::abi;
 use back::link;
 use driver::session;
-use lib::llvm::ValueRef;
-use lib::llvm::llvm;
+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::*;
@@ -40,6 +42,7 @@
 use middle::trans::glue;
 use middle::trans::inline;
 use middle::trans::foreign;
+use middle::trans::intrinsic;
 use middle::trans::meth;
 use middle::trans::monomorphize;
 use middle::trans::type_::Type;
@@ -52,8 +55,8 @@
 
 use std::gc::Gc;
 use syntax::ast;
-use synabi = syntax::abi;
 use syntax::ast_map;
+use synabi = syntax::abi;
 
 pub struct MethodData {
     pub llfn: ValueRef,
@@ -63,17 +66,23 @@ 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).
     Fn(/* llfn */ ValueRef),
 
+    Intrinsic(ast::NodeId, subst::Substs),
+
     TraitMethod(MethodData)
 }
 
 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> {
@@ -96,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(
@@ -114,12 +129,46 @@ 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)
                  -> Callee<'a> {
+        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
+            } => {
+                let substs = node_id_substs(bcx, ExprId(ref_expr.id));
+                let def_id = if did.krate != ast::LOCAL_CRATE {
+                    inline::maybe_instantiate_inline(bcx.ccx(), did)
+                } else {
+                    did
+                };
+                Callee { bcx: bcx, data: Intrinsic(def_id.node, substs) }
+            }
             def::DefFn(did, _) |
             def::DefStaticMethod(did, def::FromImpl(_), _) => {
                 fn_callee(bcx, trans_fn_ref(bcx, did, ExprId(ref_expr.id)))
@@ -132,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(..) |
@@ -191,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,
@@ -276,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.
@@ -289,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);
@@ -325,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,
@@ -387,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 => {}
@@ -450,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 = {
@@ -460,10 +523,8 @@ pub fn trans_fn_ref_with_vtables(
         }
     };
 
-    // We must monomorphise if the fn has type parameters, is a rust
-    // intrinsic, or is a default method.  In particular, if we see an
-    // intrinsic that is inlined from a different crate, we want to reemit the
-    // intrinsic instead of trying to call it in the other crate.
+    // 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 {
@@ -473,9 +534,11 @@ pub fn trans_fn_ref_with_vtables(
             || "local item should be in ast map".to_string());
 
         match map_node {
-            ast_map::NodeForeignItem(_) => {
-                tcx.map.get_foreign_abi(def_id.node) == synabi::RustIntrinsic
-            }
+            ast_map::NodeVariant(v) => match v.node.kind {
+                ast::TupleVariantKind(ref args) => args.len() > 0,
+                _ => false
+            },
+            ast_map::NodeStructCtor(_) => true,
             _ => false
         }
     } else {
@@ -513,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 {
@@ -550,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
@@ -662,6 +731,12 @@ pub fn trans_call_inner<'a>(
     let callee = get_callee(bcx, cleanup::CustomScope(arg_cleanup_scope));
     let mut bcx = callee.bcx;
 
+    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) => (f.abi, f.sig.output),
+        _ => fail!("expected bare rust fn or closure in trans_call_inner")
+    };
+
     let (llfn, llenv, llself) = match callee.data {
         Fn(llfn) => {
             (llfn, None, None)
@@ -679,14 +754,29 @@ pub fn trans_call_inner<'a>(
             let llenv = Load(bcx, llenv);
             (llfn, Some(llenv), None)
         }
-    };
+        Intrinsic(node, substs) => {
+            assert!(abi == synabi::RustIntrinsic);
+            assert!(dest.is_some());
 
-    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),
-        _ => fail!("expected bare rust fn or closure in trans_call_inner")
+            return intrinsic::trans_intrinsic_call(bcx, node, callee_ty,
+                                                   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());
+        }
     };
-    let is_rust_fn = abi == synabi::Rust || abi == synabi::RustIntrinsic;
+
+    // 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.
@@ -696,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 {
@@ -704,6 +796,7 @@ pub fn trans_call_inner<'a>(
                 Some(C_undef(llty.ptr_to()))
             }
         }
+        Some(expr::Ignore) => None
     };
 
     let mut llresult = unsafe {
@@ -735,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);
 
@@ -772,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(),
@@ -782,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) {
@@ -814,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>]),
 }
 
-fn trans_args<'a>(cx: &'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)
+                  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);
@@ -834,6 +1049,17 @@ 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 {
@@ -854,6 +1080,14 @@ 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);