]> git.lizzy.rs Git - rust.git/commitdiff
trans: Reify functions & methods to fn ptrs only where necessary.
authorEduard Burtescu <edy.burt@gmail.com>
Sun, 6 Mar 2016 15:32:47 +0000 (17:32 +0200)
committerEduard Burtescu <edy.burt@gmail.com>
Wed, 9 Mar 2016 14:45:28 +0000 (16:45 +0200)
28 files changed:
src/librustc/middle/subst.rs
src/librustc/middle/traits/mod.rs
src/librustc/middle/traits/project.rs
src/librustc/middle/traits/select.rs
src/librustc/middle/traits/structural_impls.rs
src/librustc/middle/ty/util.rs
src/librustc/mir/repr.rs
src/librustc_mir/build/misc.rs
src/librustc_mir/build/scope.rs
src/librustc_mir/hair/cx/expr.rs
src/librustc_mir/hair/mod.rs
src/librustc_trans/trans/asm.rs
src/librustc_trans/trans/base.rs
src/librustc_trans/trans/callee.rs
src/librustc_trans/trans/closure.rs
src/librustc_trans/trans/collector.rs
src/librustc_trans/trans/common.rs
src/librustc_trans/trans/consts.rs
src/librustc_trans/trans/expr.rs
src/librustc_trans/trans/glue.rs
src/librustc_trans/trans/intrinsic.rs
src/librustc_trans/trans/meth.rs
src/librustc_trans/trans/mir/block.rs
src/librustc_trans/trans/mir/constant.rs
src/librustc_trans/trans/mir/did.rs [deleted file]
src/librustc_trans/trans/mir/mod.rs
src/librustc_trans/trans/mir/rvalue.rs
src/librustc_trans/trans/type_of.rs

index 9cc94402b1651c33e7b5960155e9a8237205a1ff..02dfeb80b928f0c5b18e3adc119806c7026742cc 100644 (file)
@@ -148,11 +148,11 @@ pub fn with_method(self,
         Substs { types: types, regions: regions }
     }
 
-    pub fn with_method_from(self,
+    pub fn with_method_from(&self,
                             meth_substs: &Substs<'tcx>)
                             -> Substs<'tcx>
     {
-        let Substs { types, regions } = self;
+        let Substs { types, regions } = self.clone();
         let types = types.with_slice(FnSpace, meth_substs.types.get_slice(FnSpace));
         let regions = regions.map(|r| {
             r.with_slice(FnSpace, meth_substs.regions().get_slice(FnSpace))
index f0ff0380aaa3109f1172b12fdc4afbd102d03bab..8a2f0c0c093041fe9c6011386bd94031794c03a7 100644 (file)
@@ -278,7 +278,7 @@ pub enum Vtable<'tcx, N> {
 #[derive(Clone, PartialEq, Eq)]
 pub struct VtableImplData<'tcx, N> {
     pub impl_def_id: DefId,
-    pub substs: subst::Substs<'tcx>,
+    pub substs: &'tcx subst::Substs<'tcx>,
     pub nested: Vec<N>
 }
 
index b19771420bd399bfd8b306363c77378e3be7b8ee..e36307feddbf79b3a7ec68bdfcd414bbd19cf97a 100644 (file)
@@ -948,7 +948,7 @@ fn confirm_impl_candidate<'cx,'tcx>(
     for impl_item in &selcx.tcx().impl_items.borrow()[&impl_vtable.impl_def_id] {
         if let ty::TypeTraitItem(ref assoc_ty) = impl_or_trait_items_map[&impl_item.def_id()] {
             if assoc_ty.name == obligation.predicate.item_name {
-                return (assoc_ty.ty.unwrap().subst(selcx.tcx(), &impl_vtable.substs),
+                return (assoc_ty.ty.unwrap().subst(selcx.tcx(), impl_vtable.substs),
                         impl_vtable.nested);
             }
         }
index fbaf5a1306b84b61cf44e5172624a22c4f624445..2ecfa119007b8c88bb8e141ab208270d64d17ba3 100644 (file)
@@ -2305,7 +2305,7 @@ fn vtable_impl(&mut self,
         impl_obligations.append(&mut substs.obligations);
 
         VtableImplData { impl_def_id: impl_def_id,
-                         substs: substs.value,
+                         substs: self.tcx().mk_substs(substs.value),
                          nested: impl_obligations }
     }
 
index 453420e2a54dccfcd2e20a062fd4dcdcf48160bc..903b7c80bafabee8633dabb94537a4537d67def1 100644 (file)
@@ -147,9 +147,10 @@ fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
 
 impl<'tcx, N: TypeFoldable<'tcx>> TypeFoldable<'tcx> for traits::VtableImplData<'tcx, N> {
     fn super_fold_with<F:TypeFolder<'tcx>>(&self, folder: &mut F) -> Self {
+        let substs = self.substs.fold_with(folder);
         traits::VtableImplData {
             impl_def_id: self.impl_def_id,
-            substs: self.substs.fold_with(folder),
+            substs: folder.tcx().mk_substs(substs),
             nested: self.nested.fold_with(folder),
         }
     }
index b9dd0a6af06a2bb1961470096e0f98287654eecc..2b83aaccdc46bba7fa554266b9b27864723765ac 100644 (file)
@@ -602,14 +602,14 @@ pub fn is_adt_dtorck(&self, adt: ty::AdtDef<'tcx>) -> bool {
 #[derive(Debug)]
 pub struct ImplMethod<'tcx> {
     pub method: Rc<ty::Method<'tcx>>,
-    pub substs: Substs<'tcx>,
+    pub substs: &'tcx Substs<'tcx>,
     pub is_provided: bool
 }
 
 impl<'tcx> TyCtxt<'tcx> {
     pub fn get_impl_method(&self,
                            impl_def_id: DefId,
-                           substs: Substs<'tcx>,
+                           substs: &'tcx Substs<'tcx>,
                            name: Name)
                            -> ImplMethod<'tcx>
     {
@@ -636,9 +636,10 @@ pub fn get_impl_method(&self,
                 if meth.name == name {
                     let impl_to_trait_substs = self
                         .make_substs_for_receiver_types(&trait_ref, meth);
+                    let substs = impl_to_trait_substs.subst(self, substs);
                     return ImplMethod {
                         method: meth.clone(),
-                        substs: impl_to_trait_substs.subst(self, &substs),
+                        substs: self.mk_substs(substs),
                         is_provided: true
                     }
                 }
index ce7b1ceb355401d02b08fd3a4c5362affffee396..4556611df594b3dbf533a484adc78ac3a1eea115 100644 (file)
@@ -861,20 +861,10 @@ fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
     }
 }
 
-#[derive(Clone, Copy, Debug, PartialEq, RustcEncodable, RustcDecodable)]
-pub enum ItemKind {
-    Constant,
-    /// This is any sort of callable (usually those that have a type of `fn(…) -> …`). This
-    /// includes functions, constructors, but not methods which have their own ItemKind.
-    Function,
-    Method,
-}
-
 #[derive(Clone, PartialEq, RustcEncodable, RustcDecodable)]
 pub enum Literal<'tcx> {
     Item {
         def_id: DefId,
-        kind: ItemKind,
         substs: &'tcx Substs<'tcx>,
     },
     Value {
index 5d040bcb40ad8e72c2a1e111e47923df09e05d99..8c435b45daeff14953d8e049184d75049f68dad8 100644 (file)
@@ -12,7 +12,6 @@
 //! kind of thing.
 
 use build::Builder;
-use hair::*;
 use rustc::middle::ty::Ty;
 use rustc::mir::repr::*;
 use std::u32;
@@ -59,16 +58,4 @@ pub fn push_usize(&mut self, block: BasicBlock, span: Span, value: usize) -> Lva
             });
         temp
     }
-
-    pub fn item_ref_operand(&mut self,
-                            span: Span,
-                            item_ref: ItemRef<'tcx>)
-                            -> Operand<'tcx> {
-        let literal = Literal::Item {
-            def_id: item_ref.def_id,
-            kind: item_ref.kind,
-            substs: item_ref.substs,
-        };
-        self.literal_operand(span, item_ref.ty, literal)
-    }
 }
index 6b1b3a33d3d79ffc378db85d325d994fa466af9d..3d14ad2374bb43e1fdff70b97d652fc3ee12e972 100644 (file)
@@ -503,7 +503,6 @@ fn lang_function(&mut self, lang_item: lang_items::LangItem) -> Constant<'tcx> {
             ty: self.hir.tcx().lookup_item_type(funcdid).ty,
             literal: Literal::Item {
                 def_id: funcdid,
-                kind: ItemKind::Function,
                 substs: self.hir.tcx().mk_substs(Substs::empty())
             }
         }
@@ -641,7 +640,6 @@ fn build_free<'tcx>(tcx: &TyCtxt<'tcx>,
             ty: tcx.lookup_item_type(free_func).ty.subst(tcx, substs),
             literal: Literal::Item {
                 def_id: free_func,
-                kind: ItemKind::Function,
                 substs: substs
             }
         }),
index ac732828f0ec7fb96040b7a0dc0244c540e63e19..cbd6bed81a68fcfd7f53e337d84d4fa245de2ed4 100644 (file)
@@ -581,7 +581,6 @@ fn method_callee<'a, 'tcx: 'a>(cx: &mut Cx<'a, 'tcx>,
         kind: ExprKind::Literal {
             literal: Literal::Item {
                 def_id: callee.def_id,
-                kind: ItemKind::Method,
                 substs: callee.substs,
             },
         },
@@ -618,14 +617,13 @@ fn convert_path_expr<'a, 'tcx: 'a>(cx: &mut Cx<'a, 'tcx>, expr: &'tcx hir::Expr)
     let substs = cx.tcx.mk_substs(cx.tcx.node_id_item_substs(expr.id).substs);
     // Otherwise there may be def_map borrow conflicts
     let def = cx.tcx.def_map.borrow()[&expr.id].full_def();
-    let (def_id, kind) = match def {
+    let def_id = match def {
         // A regular function.
-        Def::Fn(def_id) => (def_id, ItemKind::Function),
-        Def::Method(def_id) => (def_id, ItemKind::Method),
+        Def::Fn(def_id) | Def::Method(def_id) => def_id,
         Def::Struct(def_id) => match cx.tcx.node_id_to_type(expr.id).sty {
             // A tuple-struct constructor. Should only be reached if not called in the same
             // expression.
-            ty::TyFnDef(..) => (def_id, ItemKind::Function),
+            ty::TyFnDef(..) => def_id,
             // A unit struct which is used as a value. We return a completely different ExprKind
             // here to account for this special case.
             ty::TyStruct(adt_def, substs) => return ExprKind::Adt {
@@ -640,7 +638,7 @@ fn convert_path_expr<'a, 'tcx: 'a>(cx: &mut Cx<'a, 'tcx>, expr: &'tcx hir::Expr)
         Def::Variant(enum_id, variant_id) => match cx.tcx.node_id_to_type(expr.id).sty {
             // A variant constructor. Should only be reached if not called in the same
             // expression.
-            ty::TyFnDef(..) => (variant_id, ItemKind::Function),
+            ty::TyFnDef(..) => variant_id,
             // A unit variant, similar special case to the struct case above.
             ty::TyEnum(adt_def, substs) => {
                 debug_assert!(adt_def.did == enum_id);
@@ -660,7 +658,7 @@ fn convert_path_expr<'a, 'tcx: 'a>(cx: &mut Cx<'a, 'tcx>, expr: &'tcx hir::Expr)
             if let Some(v) = cx.try_const_eval_literal(expr) {
                 return ExprKind::Literal { literal: v };
             } else {
-                (def_id, ItemKind::Constant)
+                def_id
             }
         }
 
@@ -677,7 +675,7 @@ fn convert_path_expr<'a, 'tcx: 'a>(cx: &mut Cx<'a, 'tcx>, expr: &'tcx hir::Expr)
                 &format!("def `{:?}` not yet implemented", def)),
     };
     ExprKind::Literal {
-        literal: Literal::Item { def_id: def_id, kind: kind, substs: substs }
+        literal: Literal::Item { def_id: def_id, substs: substs }
     }
 }
 
index 707dd972003ff465859c9ac24d4961162918e3d5..6a22dce7af9d262f985ac78fe03e4681e0c9673d 100644 (file)
@@ -14,7 +14,7 @@
 //! unit-tested and separated from the Rust source and compiler data
 //! structures.
 
-use rustc::mir::repr::{BinOp, BorrowKind, Field, Literal, Mutability, UnOp, ItemKind,
+use rustc::mir::repr::{BinOp, BorrowKind, Field, Literal, Mutability, UnOp,
     TypedConstVal};
 use rustc::middle::const_eval::ConstVal;
 use rustc::middle::def_id::DefId;
 
 pub mod cx;
 
-#[derive(Clone, Debug)]
-pub struct ItemRef<'tcx> {
-    pub ty: Ty<'tcx>,
-    pub kind: ItemKind,
-    pub def_id: DefId,
-    pub substs: &'tcx Substs<'tcx>,
-}
-
 #[derive(Clone, Debug)]
 pub struct Block<'tcx> {
     pub extent: CodeExtent,
index 33370abc3fcc14e9cd4d1a04f9301611802ed8cc..98e9a1c98ad84387ef62cbef0b1890082a842901 100644 (file)
@@ -50,7 +50,6 @@ pub fn trans_inline_asm<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, ia: &ast::InlineAsm)
                                           expr_ty(bcx, &out.expr),
                                           out_datum,
                                           cleanup::CustomScope(temp_scope),
-                                          callee::DontAutorefArg,
                                           &mut inputs);
             if out.is_rw {
                 ext_inputs.push(*inputs.last().unwrap());
@@ -64,7 +63,6 @@ pub fn trans_inline_asm<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, ia: &ast::InlineAsm)
                                               expr_ty(bcx, &out.expr),
                                               out_datum,
                                               cleanup::CustomScope(temp_scope),
-                                              callee::DontAutorefArg,
                                               &mut ext_inputs);
                 ext_constraints.push(i.to_string());
             }
@@ -80,7 +78,6 @@ pub fn trans_inline_asm<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, ia: &ast::InlineAsm)
                                     expr_ty(bcx, &input),
                                     in_datum,
                                     cleanup::CustomScope(temp_scope),
-                                    callee::DontAutorefArg,
                                     &mut inputs);
     }
     inputs.extend_from_slice(&ext_inputs[..]);
index 02f6ff8bab91efbed20889e34b60798057ffd1db..5088dabfbe78ea02b86b229dd8cb7905a7f9a235 100644 (file)
@@ -195,16 +195,14 @@ fn drop(&mut self) {
 fn get_extern_rust_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
                                 fn_ty: Ty<'tcx>,
                                 name: &str,
-                                did: DefId)
+                                attrs: &[ast::Attribute])
                                 -> ValueRef {
     if let Some(n) = ccx.externs().borrow().get(name) {
         return *n;
     }
 
     let f = declare::declare_rust_fn(ccx, name, fn_ty);
-
-    let attrs = ccx.sess().cstore.item_attrs(did);
-    attributes::from_fn_attrs(ccx, &attrs[..], f);
+    attributes::from_fn_attrs(ccx, &attrs, f);
 
     ccx.externs().borrow_mut().insert(name.to_string(), f);
     f
@@ -621,8 +619,7 @@ fn iter_variant<'blk, 'tcx, F>(cx: Block<'blk, 'tcx>,
 pub fn unsized_info<'ccx, 'tcx>(ccx: &CrateContext<'ccx, 'tcx>,
                                 source: Ty<'tcx>,
                                 target: Ty<'tcx>,
-                                old_info: Option<ValueRef>,
-                                param_substs: &'tcx Substs<'tcx>)
+                                old_info: Option<ValueRef>)
                                 -> ValueRef {
     let (source, target) = ccx.tcx().struct_lockstep_tails(source, target);
     match (&source.sty, &target.sty) {
@@ -641,7 +638,7 @@ pub fn unsized_info<'ccx, 'tcx>(ccx: &CrateContext<'ccx, 'tcx>,
                 def_id: principal.def_id(),
                 substs: substs,
             });
-            consts::ptrcast(meth::get_vtable(ccx, trait_ref, param_substs),
+            consts::ptrcast(meth::get_vtable(ccx, trait_ref),
                             Type::vtable_ptr(ccx))
         }
         _ => ccx.sess().bug(&format!("unsized_info: invalid unsizing {:?} -> {:?}",
@@ -668,7 +665,7 @@ pub fn unsize_thin_ptr<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
             assert!(common::type_is_sized(bcx.tcx(), a));
             let ptr_ty = type_of::in_memory_type_of(bcx.ccx(), b).ptr_to();
             (PointerCast(bcx, src, ptr_ty),
-             unsized_info(bcx.ccx(), a, b, None, bcx.fcx.param_substs))
+             unsized_info(bcx.ccx(), a, b, None))
         }
         _ => bcx.sess().bug("unsize_thin_ptr: called on bad types"),
     }
@@ -900,29 +897,31 @@ pub fn fail_if_zero_or_overflows<'blk, 'tcx>(cx: Block<'blk, 'tcx>,
     }
 }
 
-pub fn trans_external_path<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
-                                     did: DefId,
-                                     t: Ty<'tcx>)
-                                     -> ValueRef {
-    let name = ccx.sess().cstore.item_symbol(did);
-    match t.sty {
-        ty::TyFnDef(_, _, ref fn_ty) => {
-            match ccx.sess().target.target.adjust_abi(fn_ty.abi) {
-                Abi::Rust | Abi::RustCall => {
-                    get_extern_rust_fn(ccx, t, &name[..], did)
-                }
+pub fn get_extern_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
+                               def_id: DefId)
+                               -> datum::Datum<'tcx, datum::Rvalue> {
+    let name = ccx.sess().cstore.item_symbol(def_id);
+    let attrs = ccx.sess().cstore.item_attrs(def_id);
+    let ty = ccx.tcx().lookup_item_type(def_id).ty;
+    match ty.sty {
+        ty::TyFnDef(_, _, fty) => {
+            let abi = fty.abi;
+            let fty = infer::normalize_associated_type(ccx.tcx(), fty);
+            let ty = ccx.tcx().mk_fn_ptr(fty);
+            let llfn = match ccx.sess().target.target.adjust_abi(abi) {
                 Abi::RustIntrinsic | Abi::PlatformIntrinsic => {
-                    ccx.sess().bug("unexpected intrinsic in trans_external_path")
+                    ccx.sess().bug("unexpected intrinsic in get_extern_fn")
+                }
+                Abi::Rust | Abi::RustCall => {
+                    get_extern_rust_fn(ccx, ty, &name, &attrs)
                 }
                 _ => {
-                    let attrs = ccx.sess().cstore.item_attrs(did);
-                    foreign::register_foreign_item_fn(ccx, fn_ty.abi, t, &name, &attrs)
+                    foreign::register_foreign_item_fn(ccx, abi, ty, &name, &attrs)
                 }
-            }
-        }
-        _ => {
-            get_extern_const(ccx, did, t)
+            };
+            datum::immediate_rvalue(llfn, ty)
         }
+        _ => unreachable!("get_extern_fn: expected fn item type, found {}", ty)
     }
 }
 
@@ -2685,8 +2684,7 @@ fn create_entry_fn(ccx: &CrateContext,
                                                                .as_local_node_id(start_def_id) {
                     get_item_val(ccx, start_node_id)
                 } else {
-                    let start_fn_type = ccx.tcx().lookup_item_type(start_def_id).ty;
-                    trans_external_path(ccx, start_def_id, start_fn_type)
+                    get_extern_fn(ccx, start_def_id).val
                 };
                 let args = {
                     let opaque_rust_main =
index 7afd096348506a019a93ed7faf4c419012dd4aaf..05e5ac808d0301301723210db7ededa8ce6cf9c9 100644 (file)
@@ -14,7 +14,6 @@
 //! and methods are represented as just a fn ptr and not a full
 //! closure.
 
-pub use self::AutorefArg::*;
 pub use self::CalleeData::*;
 pub use self::CallArgs::*;
 
@@ -22,7 +21,6 @@
 use back::link;
 use llvm::{self, ValueRef, get_params};
 use middle::cstore::LOCAL_CRATE;
-use middle::def::Def;
 use middle::def_id::DefId;
 use middle::infer;
 use middle::subst;
 use trans::base;
 use trans::base::*;
 use trans::build::*;
-use trans::callee;
 use trans::cleanup;
 use trans::cleanup::CleanupMethods;
 use trans::common::{self, Block, Result, NodeIdAndSpan, ExprId, CrateContext,
                     ExprOrMethodCall, FunctionContext, MethodCallKey};
 use trans::consts;
 use trans::datum::*;
-use trans::debuginfo::{DebugLoc, ToDebugLoc};
+use trans::debuginfo::DebugLoc;
 use trans::declare;
 use trans::expr;
 use trans::glue;
 use trans::type_of;
 use trans::Disr;
 use middle::ty::{self, Ty, TyCtxt, TypeFoldable};
-use middle::ty::MethodCall;
 use rustc_front::hir;
 
 use syntax::abi::Abi;
 use syntax::ast;
+use syntax::codemap::DUMMY_SP;
 use syntax::errors;
 use syntax::ptr::P;
 
-#[derive(Copy, Clone)]
-pub struct MethodData {
-    pub llfn: ValueRef,
-    pub llself: ValueRef,
-}
-
 pub enum CalleeData<'tcx> {
-    // Constructor for enum variant/tuple-like-struct
-    // i.e. Some, Ok
+    /// Constructor for enum variant/tuple-like-struct.
     NamedTupleConstructor(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),
+    /// Function pointer.
+    Fn(ValueRef),
 
-    Intrinsic(ast::NodeId, subst::Substs<'tcx>),
+    Intrinsic(ast::NodeId, &'tcx subst::Substs<'tcx>),
 
-    TraitItem(MethodData)
+    /// Trait object found in the vtable at that index.
+    Virtual(usize)
 }
 
-pub struct Callee<'blk, 'tcx: 'blk> {
-    pub bcx: Block<'blk, 'tcx>,
+pub struct Callee<'tcx> {
     pub data: CalleeData<'tcx>,
     pub ty: Ty<'tcx>
 }
 
-fn trans<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, expr: &hir::Expr)
-                     -> Callee<'blk, 'tcx> {
-    let _icx = push_ctxt("trans_callee");
-    debug!("callee::trans(expr={:?})", expr);
-
-    // pick out special kinds of expressions that can be called:
-    match expr.node {
-        hir::ExprPath(..) => {
-            return trans_def(bcx, bcx.def(expr.id), expr);
+impl<'tcx> Callee<'tcx> {
+    /// Function pointer.
+    pub fn ptr(datum: Datum<'tcx, Rvalue>) -> Callee<'tcx> {
+        Callee {
+            data: Fn(datum.val),
+            ty: datum.ty
         }
-        _ => {}
     }
 
-    // any other expressions are closures:
-    return datum_callee(bcx, expr);
-
-    fn datum_callee<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, expr: &hir::Expr)
-                                -> Callee<'blk, 'tcx> {
-        let DatumBlock { bcx, datum, .. } = expr::trans(bcx, expr);
-        match datum.ty.sty {
-            ty::TyFnDef(..) | ty::TyFnPtr(_) => {
-                Callee {
-                    bcx: bcx,
-                    ty: datum.ty,
-                    data: Fn(datum.to_llscalarish(bcx))
-                }
-            }
-            _ => {
-                bcx.tcx().sess.span_bug(
-                    expr.span,
-                    &format!("type of callee is neither bare-fn nor closure: {}",
-                             datum.ty));
-            }
-        }
+    /// Trait or impl method call.
+    pub fn method_call<'blk>(bcx: Block<'blk, 'tcx>,
+                             method_call: ty::MethodCall)
+                             -> Callee<'tcx> {
+        let method = bcx.tcx().tables.borrow().method_map[&method_call];
+        Callee::method(bcx, method)
     }
 
-    fn fn_callee<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, datum: Datum<'tcx, Rvalue>)
-                             -> Callee<'blk, 'tcx> {
-        Callee {
-            bcx: bcx,
-            data: Fn(datum.val),
-            ty: datum.ty
-        }
+    /// Trait or impl method.
+    pub fn method<'blk>(bcx: Block<'blk, 'tcx>,
+                        method: ty::MethodCallee<'tcx>) -> Callee<'tcx> {
+        let substs = bcx.tcx().mk_substs(bcx.fcx.monomorphize(&method.substs));
+        let ty = bcx.fcx.monomorphize(&method.ty);
+        Callee::def(bcx.ccx(), method.def_id, substs, ty)
     }
 
-    fn trans_def<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
-                             def: Def,
-                             ref_expr: &hir::Expr)
-                             -> Callee<'blk, 'tcx> {
-        debug!("trans_def(def={:?}, ref_expr={:?})", def, ref_expr);
-        let expr_ty = common::node_id_type(bcx, ref_expr.id);
-        match def {
-            Def::Fn(did) if {
-                let maybe_def_id = inline::get_local_instance(bcx.ccx(), did);
-                let maybe_ast_node = maybe_def_id.and_then(|def_id| {
-                    let node_id = bcx.tcx().map.as_local_node_id(def_id).unwrap();
-                    bcx.tcx().map.find(node_id)
-                });
-                match maybe_ast_node {
-                    Some(hir_map::NodeStructCtor(_)) => true,
-                    _ => false
-                }
-            } => {
-                Callee {
-                    bcx: bcx,
+    /// Function or method definition.
+    pub fn def<'a>(ccx: &CrateContext<'a, 'tcx>,
+                   def_id: DefId,
+                   substs: &'tcx subst::Substs<'tcx>,
+                   ty: Ty<'tcx>)
+                   -> Callee<'tcx> {
+        let tcx = ccx.tcx();
+
+        if substs.self_ty().is_some() {
+            // Only trait methods can have a Self parameter.
+            let method_item = tcx.impl_or_trait_item(def_id);
+            let trait_id = method_item.container().id();
+            let trait_ref = ty::Binder(substs.to_trait_ref(tcx, trait_id));
+            let vtbl = common::fulfill_obligation(ccx, DUMMY_SP, trait_ref);
+            return meth::callee_for_trait_impl(ccx, def_id, substs,
+                                               trait_id, ty, vtbl);
+        }
+
+        let maybe_node_id = inline::get_local_instance(ccx, def_id)
+            .and_then(|def_id| tcx.map.as_local_node_id(def_id));
+        let maybe_ast_node = maybe_node_id.and_then(|node_id| {
+            tcx.map.find(node_id)
+        });
+        match maybe_ast_node {
+            Some(hir_map::NodeStructCtor(_)) => {
+                return Callee {
                     data: NamedTupleConstructor(Disr(0)),
-                    ty: expr_ty
-                }
-            }
-            Def::Fn(did) if match expr_ty.sty {
-                ty::TyFnDef(_, _, ref f) => f.abi == Abi::RustIntrinsic ||
-                                            f.abi == Abi::PlatformIntrinsic,
-                _ => false
-            } => {
-                let substs = common::node_id_substs(bcx.ccx(),
-                                                    ExprId(ref_expr.id),
-                                                    bcx.fcx.param_substs);
-                let def_id = inline::maybe_instantiate_inline(bcx.ccx(), did);
-                let node_id = bcx.tcx().map.as_local_node_id(def_id).unwrap();
-                Callee { bcx: bcx, data: Intrinsic(node_id, substs), ty: expr_ty }
-            }
-            Def::Fn(did) => {
-                fn_callee(bcx, trans_fn_ref(bcx.ccx(), did, ExprId(ref_expr.id),
-                                            bcx.fcx.param_substs))
-            }
-            Def::Method(meth_did) => {
-                let method_item = bcx.tcx().impl_or_trait_item(meth_did);
-                let fn_datum = match method_item.container() {
-                    ty::ImplContainer(_) => {
-                        trans_fn_ref(bcx.ccx(), meth_did,
-                                     ExprId(ref_expr.id),
-                                     bcx.fcx.param_substs)
-                    }
-                    ty::TraitContainer(trait_did) => {
-                        meth::trans_static_method_callee(bcx.ccx(),
-                                                         meth_did,
-                                                         trait_did,
-                                                         ref_expr.id,
-                                                         bcx.fcx.param_substs)
-                    }
+                    ty: ty
                 };
-                fn_callee(bcx, fn_datum)
             }
-            Def::Variant(tid, vid) => {
-                let vinfo = bcx.tcx().lookup_adt_def(tid).variant_with_id(vid);
+            Some(hir_map::NodeVariant(_)) => {
+                let vinfo = common::inlined_variant_def(ccx, maybe_node_id.unwrap());
                 assert_eq!(vinfo.kind(), ty::VariantKind::Tuple);
 
-                Callee {
-                    bcx: bcx,
+                return Callee {
                     data: NamedTupleConstructor(Disr::from(vinfo.disr_val)),
-                    ty: expr_ty
-                }
+                    ty: ty
+                };
             }
-            Def::Struct(..) => {
-                Callee {
-                    bcx: bcx,
-                    data: NamedTupleConstructor(Disr(0)),
-                    ty: expr_ty
+            Some(hir_map::NodeForeignItem(fi)) => {
+                let abi = tcx.map.get_foreign_abi(fi.id);
+                if abi == Abi::RustIntrinsic || abi == Abi::PlatformIntrinsic {
+                    return Callee {
+                        data: Intrinsic(fi.id, substs),
+                        ty: ty
+                    };
                 }
             }
-            Def::Static(..) |
-            Def::Const(..) |
-            Def::AssociatedConst(..) |
-            Def::Local(..) |
-            Def::Upvar(..) => {
-                datum_callee(bcx, ref_expr)
-            }
-            Def::Mod(..) | Def::ForeignMod(..) | Def::Trait(..) |
-            Def::Enum(..) | Def::TyAlias(..) | Def::PrimTy(..) |
-            Def::AssociatedTy(..) | Def::Label(..) | Def::TyParam(..) |
-            Def::SelfTy(..) | Def::Err => {
-                bcx.tcx().sess.span_bug(
-                    ref_expr.span,
-                    &format!("cannot translate def {:?} \
-                             to a callable thing!", def));
+            _ => {}
+        }
+        Callee::ptr(trans_fn_ref_with_substs(ccx, def_id, Some(ty), substs))
+    }
+
+    /// This behemoth of a function translates function calls. Unfortunately, in
+    /// order to generate more efficient LLVM output at -O0, it has quite a complex
+    /// signature (refactoring this into two functions seems like a good idea).
+    ///
+    /// In particular, for lang items, it is invoked with a dest of None, and in
+    /// that case the return value contains the result of the fn. The lang item must
+    /// not return a structural type or else all heck breaks loose.
+    ///
+    /// For non-lang items, `dest` is always Some, and hence the result is written
+    /// into memory somewhere. Nonetheless we return the actual return value of the
+    /// function.
+    pub fn call<'a, 'blk>(self, bcx: Block<'blk, 'tcx>,
+                          debug_loc: DebugLoc,
+                          args: CallArgs<'a, 'tcx>,
+                          dest: Option<expr::Dest>)
+                          -> Result<'blk, 'tcx> {
+        trans_call_inner(bcx, debug_loc, self, args, dest)
+    }
+
+    /// Turn the callee into a function pointer.
+    pub fn reify<'a>(self, ccx: &CrateContext<'a, 'tcx>)
+                     -> Datum<'tcx, Rvalue> {
+        match self.data {
+            Fn(llfn) => {
+                let fn_ptr_ty = match self.ty.sty {
+                    ty::TyFnDef(_, _, f) => ccx.tcx().mk_ty(ty::TyFnPtr(f)),
+                    _ => self.ty
+                };
+                immediate_rvalue(llfn, fn_ptr_ty)
             }
+            Virtual(idx) => meth::trans_object_shim(ccx, self.ty, idx),
+            NamedTupleConstructor(_) => match self.ty.sty {
+                ty::TyFnDef(def_id, substs, _) => {
+                    return trans_fn_ref_with_substs(ccx, def_id, Some(self.ty), substs);
+                }
+                _ => unreachable!("expected fn item type, found {}", self.ty)
+            },
+            Intrinsic(..) => unreachable!("intrinsic {} getting reified", self.ty)
         }
     }
 }
@@ -241,7 +209,17 @@ pub fn trans_fn_ref<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
            def_id,
            node,
            substs);
-    trans_fn_ref_with_substs(ccx, def_id, node, param_substs, substs)
+    let ref_ty = match node {
+        ExprId(0) => return trans_fn_ref_with_substs(ccx, def_id, None, substs),
+        ExprId(id) => ccx.tcx().node_id_to_type(id),
+        MethodCallKey(method_call) => {
+            ccx.tcx().tables.borrow().method_map[&method_call].ty
+        }
+    };
+    let ref_ty = monomorphize::apply_param_substs(ccx.tcx(),
+                                                  param_substs,
+                                                  &ref_ty);
+    trans_fn_ref_with_substs(ccx, def_id, Some(ref_ty), substs)
 }
 
 /// Translates an adapter that implements the `Fn` trait for a fn
@@ -290,29 +268,24 @@ pub fn trans_fn_pointer_shim<'a, 'tcx>(
 
     // Construct the "tuply" version of `bare_fn_ty`. It takes two arguments: `self`,
     // which is the fn pointer, and `args`, which is the arguments tuple.
-    let (opt_def_id_and_substs, sig) =
-        match bare_fn_ty.sty {
-            ty::TyFnDef(def_id, substs,
-                        &ty::BareFnTy { unsafety: hir::Unsafety::Normal,
-                                        abi: Abi::Rust,
-                                        ref sig }) => {
-                (Some((def_id, substs)), sig)
-            }
-            ty::TyFnPtr(&ty::BareFnTy { unsafety: hir::Unsafety::Normal,
-                                        abi: Abi::Rust,
-                                        ref sig }) => {
-                (None, sig)
-            }
+    let sig = match bare_fn_ty.sty {
+        ty::TyFnDef(_, _,
+                    &ty::BareFnTy { unsafety: hir::Unsafety::Normal,
+                                    abi: Abi::Rust,
+                                    ref sig }) |
+        ty::TyFnPtr(&ty::BareFnTy { unsafety: hir::Unsafety::Normal,
+                                    abi: Abi::Rust,
+                                    ref sig }) => sig,
 
-            _ => {
-                tcx.sess.bug(&format!("trans_fn_pointer_shim invoked on invalid type: {}",
-                                      bare_fn_ty));
-            }
-        };
+        _ => {
+            tcx.sess.bug(&format!("trans_fn_pointer_shim invoked on invalid type: {}",
+                                    bare_fn_ty));
+        }
+    };
     let sig = tcx.erase_late_bound_regions(sig);
     let sig = infer::normalize_associated_type(ccx.tcx(), &sig);
     let tuple_input_ty = tcx.mk_tup(sig.inputs.to_vec());
-    let bare_tuple_fn = ty::BareFnTy {
+    let tuple_fn_ty = tcx.mk_fn_ptr(ty::BareFnTy {
         unsafety: hir::Unsafety::Normal,
         abi: Abi::RustCall,
         sig: ty::Binder(ty::FnSig {
@@ -321,11 +294,7 @@ pub fn trans_fn_pointer_shim<'a, 'tcx>(
             output: sig.output,
             variadic: false
         })
-    };
-    let tuple_fn_ty = match opt_def_id_and_substs {
-        Some((def_id, substs)) => tcx.mk_fn_def(def_id, substs, bare_tuple_fn),
-        None => tcx.mk_fn_ptr(bare_tuple_fn),
-    };
+    });
     debug!("tuple_fn_ty: {:?}", tuple_fn_ty);
 
     //
@@ -350,11 +319,18 @@ pub fn trans_fn_pointer_shim<'a, 'tcx>(
     let llargs = get_params(fcx.llfn);
 
     let self_idx = fcx.arg_offset();
-    // the first argument (`self`) will be ptr to the fn pointer
-    let llfnpointer = if is_by_ref {
-        Load(bcx, llargs[self_idx])
-    } else {
-        llargs[self_idx]
+    let llfnpointer = match bare_fn_ty.sty {
+        ty::TyFnDef(def_id, substs, _) => {
+            // Function definitions have to be turned into a pointer.
+            Callee::def(ccx, def_id, substs, bare_fn_ty).reify(ccx).val
+        }
+
+        // the first argument (`self`) will be ptr to the fn pointer
+        _ => if is_by_ref {
+            Load(bcx, llargs[self_idx])
+        } else {
+            llargs[self_idx]
+        }
     };
 
     assert!(!fcx.needs_ret_allocas);
@@ -363,13 +339,11 @@ pub fn trans_fn_pointer_shim<'a, 'tcx>(
         expr::SaveIn(fcx.get_ret_slot(bcx, sig.output, "ret_slot"))
     );
 
-    bcx = trans_call_inner(bcx, DebugLoc::None, |bcx, _| {
-        Callee {
-            bcx: bcx,
-            data: Fn(llfnpointer),
-            ty: bare_fn_ty
-        }
-    }, ArgVals(&llargs[(self_idx + 1)..]), dest).bcx;
+    let callee = Callee {
+        data: Fn(llfnpointer),
+        ty: bare_fn_ty
+    };
+    bcx = callee.call(bcx, DebugLoc::None, ArgVals(&llargs[(self_idx + 1)..]), dest).bcx;
 
     finish_fn(&fcx, bcx, sig.output, DebugLoc::None);
 
@@ -388,30 +362,25 @@ pub fn trans_fn_pointer_shim<'a, 'tcx>(
 /// - `node`: node id of the reference to the fn/method, if applicable.
 ///   This parameter may be zero; but, if so, the resulting value may not
 ///   have the right type, so it must be cast before being used.
-/// - `param_substs`: if the `node` is in a polymorphic function, these
-///   are the substitutions required to monomorphize its type
+/// - `ref_ty`: monotype of the reference to the fn/method, if applicable.
+///   This parameter may be None; but, if so, the resulting value may not
+///   have the right type, so it must be cast before being used.
 /// - `substs`: values for each of the fn/method's parameters
 pub fn trans_fn_ref_with_substs<'a, 'tcx>(
     ccx: &CrateContext<'a, 'tcx>,
     def_id: DefId,
-    node: ExprOrMethodCall,
-    param_substs: &'tcx subst::Substs<'tcx>,
-    substs: subst::Substs<'tcx>)
+    ref_ty: Option<Ty<'tcx>>,
+    substs: &'tcx subst::Substs<'tcx>)
     -> Datum<'tcx, Rvalue>
 {
     let _icx = push_ctxt("trans_fn_ref_with_substs");
     let tcx = ccx.tcx();
 
-    debug!("trans_fn_ref_with_substs(def_id={:?}, node={:?}, \
-            param_substs={:?}, substs={:?})",
-           def_id,
-           node,
-           param_substs,
-           substs);
+    debug!("trans_fn_ref_with_substs(def_id={:?}, ref_ty={:?}, substs={:?})",
+           def_id, ref_ty, substs);
 
     assert!(!substs.types.needs_infer());
     assert!(!substs.types.has_escaping_regions());
-    let substs = substs.erase_regions();
 
     // Check whether this fn has an inlined copy and, if so, redirect
     // def_id to the local id of the inlined copy.
@@ -446,43 +415,45 @@ fn is_named_tuple_constructor(tcx: &TyCtxt, def_id: DefId) -> bool {
         // Should be either intra-crate or inlined.
         assert_eq!(def_id.krate, LOCAL_CRATE);
 
-        let substs = tcx.mk_substs(substs);
-        let (val, fn_ty, must_cast) =
+        let substs = tcx.mk_substs(substs.clone().erase_regions());
+        let (mut val, fn_ty, must_cast) =
             monomorphize::monomorphic_fn(ccx, def_id, substs);
-        if must_cast && node != ExprId(0) {
-            // Monotype of the REFERENCE to the function (type params
-            // are subst'd)
-            let ref_ty = match node {
-                ExprId(id) => tcx.node_id_to_type(id),
-                MethodCallKey(method_call) => {
-                    tcx.tables.borrow().method_map[&method_call].ty
-                }
-            };
-            let ref_ty = monomorphize::apply_param_substs(tcx,
-                                                          param_substs,
-                                                          &ref_ty);
-            let llptrty = type_of::type_of(ccx, ref_ty);
+        let fn_ty = ref_ty.unwrap_or(fn_ty);
+        let fn_ptr_ty = match fn_ty.sty {
+            ty::TyFnDef(_, _, fty) => {
+                // Create a fn pointer with the substituted signature.
+                tcx.mk_ty(ty::TyFnPtr(fty))
+            }
+            _ => unreachable!("expected fn item type, found {}", fn_ty)
+        };
+        if must_cast && ref_ty.is_some() {
+            let llptrty = type_of::type_of(ccx, fn_ptr_ty);
             if llptrty != common::val_ty(val) {
-                let val = consts::ptrcast(val, llptrty);
-                return Datum::new(val, ref_ty, Rvalue::new(ByValue));
+                val = consts::ptrcast(val, llptrty);
             }
         }
-        return Datum::new(val, fn_ty, Rvalue::new(ByValue));
+        return immediate_rvalue(val, fn_ptr_ty);
     }
 
-    // Type scheme of the function item (may have type params)
-    let fn_type_scheme = tcx.lookup_item_type(def_id);
-    let fn_type = infer::normalize_associated_type(tcx, &fn_type_scheme.ty);
-
     // Find the actual function pointer.
-    let mut val = {
-        if let Some(node_id) = ccx.tcx().map.as_local_node_id(def_id) {
-            // Internal reference.
-            get_item_val(ccx, node_id)
-        } else {
-            // External reference.
-            trans_external_path(ccx, def_id, fn_type)
-        }
+    let local_node = ccx.tcx().map.as_local_node_id(def_id);
+    let mut datum = if let Some(node_id) = local_node {
+        // Type scheme of the function item (may have type params)
+        let fn_type_scheme = tcx.lookup_item_type(def_id);
+        let fn_type = match fn_type_scheme.ty.sty {
+            ty::TyFnDef(_, _, fty) => {
+                // Create a fn pointer with the normalized signature.
+                tcx.mk_fn_ptr(infer::normalize_associated_type(tcx, fty))
+            }
+            _ => unreachable!("expected fn item type, found {}",
+                              fn_type_scheme.ty)
+        };
+
+        // Internal reference.
+        immediate_rvalue(get_item_val(ccx, node_id), fn_type)
+    } else {
+        // External reference.
+        get_extern_fn(ccx, def_id)
     };
 
     // This is subtle and surprising, but sometimes we have to bitcast
@@ -508,92 +479,36 @@ fn is_named_tuple_constructor(tcx: &TyCtxt, def_id: DefId) -> bool {
     // This can occur on either a crate-local or crate-external
     // reference. It also occurs when testing libcore and in some
     // other weird situations. Annoying.
-    let llptrty = type_of::type_of(ccx, fn_type);
-    if common::val_ty(val) != llptrty {
+    let llptrty = type_of::type_of(ccx, datum.ty);
+    if common::val_ty(datum.val) != llptrty {
         debug!("trans_fn_ref_with_substs(): casting pointer!");
-        val = consts::ptrcast(val, llptrty);
+        datum.val = consts::ptrcast(datum.val, llptrty);
     } else {
         debug!("trans_fn_ref_with_substs(): not casting pointer!");
     }
 
-    Datum::new(val, fn_type, Rvalue::new(ByValue))
+    datum
 }
 
 // ______________________________________________________________________
 // Translating calls
 
-pub fn trans_call<'a, 'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
-                                  call_expr: &hir::Expr,
-                                  f: &hir::Expr,
-                                  args: CallArgs<'a, 'tcx>,
-                                  dest: expr::Dest)
-                                  -> Block<'blk, 'tcx> {
-    let _icx = push_ctxt("trans_call");
-    trans_call_inner(bcx,
-                     call_expr.debug_loc(),
-                     |bcx, _| trans(bcx, f),
-                     args,
-                     Some(dest)).bcx
-}
-
-pub fn trans_method_call<'a, 'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
-                                         call_expr: &hir::Expr,
-                                         rcvr: &hir::Expr,
-                                         args: CallArgs<'a, 'tcx>,
-                                         dest: expr::Dest)
-                                         -> Block<'blk, 'tcx> {
-    let _icx = push_ctxt("trans_method_call");
-    debug!("trans_method_call(call_expr={:?})", call_expr);
-    let method_call = MethodCall::expr(call_expr.id);
-    trans_call_inner(
-        bcx,
-        call_expr.debug_loc(),
-        |cx, arg_cleanup_scope| {
-            meth::trans_method_callee(cx, method_call, Some(rcvr), arg_cleanup_scope)
-        },
-        args,
-        Some(dest)).bcx
-}
-
 pub fn trans_lang_call<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
                                    did: DefId,
                                    args: &[ValueRef],
                                    dest: Option<expr::Dest>,
                                    debug_loc: DebugLoc)
                                    -> Result<'blk, 'tcx> {
-    callee::trans_call_inner(bcx, debug_loc, |bcx, _| {
-        let datum = trans_fn_ref_with_substs(bcx.ccx(),
-                                             did,
-                                             ExprId(0),
-                                             bcx.fcx.param_substs,
-                                             subst::Substs::trans_empty());
-        Callee {
-            bcx: bcx,
-            data: Fn(datum.val),
-            ty: datum.ty
-        }
-    }, ArgVals(args), dest)
+    let datum = trans_fn_ref(bcx.ccx(), did, ExprId(0), bcx.fcx.param_substs);
+    Callee::ptr(datum).call(bcx, debug_loc, ArgVals(args), dest)
 }
 
-/// This behemoth of a function translates function calls. Unfortunately, in
-/// order to generate more efficient LLVM output at -O0, it has quite a complex
-/// signature (refactoring this into two functions seems like a good idea).
-///
-/// In particular, for lang items, it is invoked with a dest of None, and in
-/// that case the return value contains the result of the fn. The lang item must
-/// not return a structural type or else all heck breaks loose.
-///
-/// For non-lang items, `dest` is always Some, and hence the result is written
-/// into memory somewhere. Nonetheless we return the actual return value of the
-/// function.
-pub fn trans_call_inner<'a, 'blk, 'tcx, F>(bcx: Block<'blk, 'tcx>,
-                                           debug_loc: DebugLoc,
-                                           get_callee: F,
-                                           args: CallArgs<'a, 'tcx>,
-                                           dest: Option<expr::Dest>)
-                                           -> Result<'blk, 'tcx> where
-    F: FnOnce(Block<'blk, 'tcx>, cleanup::ScopeId) -> Callee<'blk, 'tcx>,
-{
+fn trans_call_inner<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>,
+                                    debug_loc: DebugLoc,
+                                    callee: Callee<'tcx>,
+                                    args: CallArgs<'a, 'tcx>,
+                                    dest: Option<expr::Dest>)
+                                    -> Result<'blk, 'tcx> {
     // Introduce a temporary cleanup scope that will contain cleanups
     // for the arguments while they are being evaluated. The purpose
     // this cleanup is to ensure that, should a panic occur while
@@ -603,10 +518,6 @@ pub fn trans_call_inner<'a, 'blk, 'tcx, F>(bcx: Block<'blk, 'tcx>,
     // scope will ever execute.
     let fcx = bcx.fcx;
     let ccx = fcx.ccx;
-    let arg_cleanup_scope = fcx.push_custom_cleanup_scope();
-
-    let callee = get_callee(bcx, cleanup::CustomScope(arg_cleanup_scope));
-    let mut bcx = callee.bcx;
 
     let (abi, ret_ty) = match callee.ty.sty {
         ty::TyFnDef(_, _, ref f) | ty::TyFnPtr(ref f) => {
@@ -614,16 +525,10 @@ pub fn trans_call_inner<'a, 'blk, 'tcx, F>(bcx: Block<'blk, 'tcx>,
             let sig = infer::normalize_associated_type(bcx.tcx(), &sig);
             (f.abi, sig.output)
         }
-        _ => panic!("expected bare rust fn or closure in trans_call_inner")
+        _ => panic!("expected fn item or ptr in Callee::call")
     };
 
-    let (llfn, llself) = match callee.data {
-        Fn(llfn) => {
-            (llfn, None)
-        }
-        TraitItem(d) => {
-            (d.llfn, Some(d.llself))
-        }
+    match callee.data {
         Intrinsic(node, substs) => {
             assert!(abi == Abi::RustIntrinsic || abi == Abi::PlatformIntrinsic);
             assert!(dest.is_some());
@@ -635,14 +540,15 @@ pub fn trans_call_inner<'a, 'blk, 'tcx, F>(bcx: Block<'blk, 'tcx>,
                 }
             };
 
+            let arg_cleanup_scope = fcx.push_custom_cleanup_scope();
             return intrinsic::trans_intrinsic_call(bcx, node, callee.ty,
                                                    arg_cleanup_scope, args,
-                                                   dest.unwrap(), substs,
+                                                   dest.unwrap(),
+                                                   substs,
                                                    call_info);
         }
         NamedTupleConstructor(disr) => {
             assert!(dest.is_some());
-            fcx.pop_custom_cleanup_scope(arg_cleanup_scope);
 
             return base::trans_named_tuple_constructor(bcx,
                                                        callee.ty,
@@ -651,7 +557,8 @@ pub fn trans_call_inner<'a, 'blk, 'tcx, F>(bcx: Block<'blk, 'tcx>,
                                                        dest.unwrap(),
                                                        debug_loc);
         }
-    };
+        _ => {}
+    }
 
     // Intrinsics should not become actual functions.
     // We trans them in place in `trans_intrinsic_call`
@@ -691,6 +598,8 @@ pub fn trans_call_inner<'a, 'blk, 'tcx, F>(bcx: Block<'blk, 'tcx>,
         llvm::LLVMGetUndef(Type::nil(ccx).ptr_to().to_ref())
     };
 
+    let arg_cleanup_scope = fcx.push_custom_cleanup_scope();
+
     // The code below invokes the function, using either the Rust
     // conventions (if it is a rust fn) or the native conventions
     // (otherwise).  The important part is that, when all is said
@@ -714,10 +623,7 @@ pub fn trans_call_inner<'a, 'blk, 'tcx, F>(bcx: Block<'blk, 'tcx>,
             }
         }
 
-        // Push a trait object's self.
-        if let Some(llself) = llself {
-            llargs.push(llself);
-        }
+        let arg_start = llargs.len();
 
         // Push the arguments.
         bcx = trans_args(bcx,
@@ -725,16 +631,25 @@ pub fn trans_call_inner<'a, 'blk, 'tcx, F>(bcx: Block<'blk, 'tcx>,
                          callee.ty,
                          &mut llargs,
                          cleanup::CustomScope(arg_cleanup_scope),
-                         llself.is_some(),
                          abi);
 
         fcx.scopes.borrow_mut().last_mut().unwrap().drop_non_lifetime_clean();
 
+        let datum = match callee.data {
+            Fn(f) => immediate_rvalue(f, callee.ty),
+            Virtual(idx) => {
+                // The data and vtable pointers were split by trans_arg_datum.
+                let vtable = llargs.remove(arg_start + 1);
+                meth::get_virtual_method(bcx, vtable, idx, callee.ty)
+            }
+            _ => unreachable!()
+        };
+
         // Invoke the actual rust fn and update bcx/llresult.
         let (llret, b) = base::invoke(bcx,
-                                      llfn,
+                                      datum.val,
                                       &llargs[..],
-                                      callee.ty,
+                                      datum.ty,
                                       debug_loc);
         bcx = b;
         llresult = llret;
@@ -757,16 +672,17 @@ pub fn trans_call_inner<'a, 'blk, 'tcx, F>(bcx: Block<'blk, 'tcx>,
         assert!(dest.is_some());
 
         let mut llargs = Vec::new();
-        let arg_tys = match args {
-            ArgExprs(a) => a.iter().map(|x| common::expr_ty_adjusted(bcx, &x)).collect(),
-            _ => panic!("expected arg exprs.")
+        let (llfn, arg_tys) = match (callee.data, &args) {
+            (Fn(f), &ArgExprs(a)) => {
+                (f, a.iter().map(|x| common::expr_ty_adjusted(bcx, &x)).collect())
+            }
+            _ => panic!("expected fn ptr and arg exprs.")
         };
         bcx = trans_args(bcx,
                          args,
                          callee.ty,
                          &mut llargs,
                          cleanup::CustomScope(arg_cleanup_scope),
-                         false,
                          abi);
         fcx.scopes.borrow_mut().last_mut().unwrap().drop_non_lifetime_clean();
 
@@ -803,23 +719,22 @@ pub fn trans_call_inner<'a, 'blk, 'tcx, F>(bcx: Block<'blk, 'tcx>,
 }
 
 pub enum CallArgs<'a, 'tcx> {
-    // Supply value of arguments as a list of expressions that must be
-    // translated. This is used in the common case of `foo(bar, qux)`.
+    /// Supply value of arguments as a list of expressions that must be
+    /// translated. This is used in the common case of `foo(bar, qux)`.
     ArgExprs(&'a [P<hir::Expr>]),
 
-    // Supply value of arguments as a list of LLVM value refs; frequently
-    // used with lang items and so forth, when the argument is an internal
-    // value.
+    /// Supply value of arguments as a list of LLVM value refs; frequently
+    /// used with lang items and so forth, when the argument is an internal
+    /// value.
     ArgVals(&'a [ValueRef]),
 
-    // For overloaded operators: `(lhs, Option(rhs, rhs_id), autoref)`. `lhs`
-    // is the left-hand-side and `rhs/rhs_id` is the datum/expr-id of
-    // the right-hand-side argument (if any). `autoref` indicates whether the `rhs`
-    // arguments should be auto-referenced
-    ArgOverloadedOp(Datum<'tcx, Expr>, Option<(Datum<'tcx, Expr>, ast::NodeId)>, bool),
+    /// For overloaded operators: `(lhs, Option(rhs))`.
+    /// `lhs` is the left-hand-side and `rhs` is the datum
+    /// of the right-hand-side argument (if any).
+    ArgOverloadedOp(Datum<'tcx, Expr>, Option<Datum<'tcx, Expr>>),
 
-    // Supply value of arguments as a list of expressions that must be
-    // translated, for overloaded call operators.
+    /// Supply value of arguments as a list of expressions that must be
+    /// translated, for overloaded call operators.
     ArgOverloadedCall(Vec<&'a hir::Expr>),
 }
 
@@ -828,8 +743,7 @@ fn trans_args_under_call_abi<'blk, 'tcx>(
                              arg_exprs: &[P<hir::Expr>],
                              fn_ty: Ty<'tcx>,
                              llargs: &mut Vec<ValueRef>,
-                             arg_cleanup_scope: cleanup::ScopeId,
-                             ignore_self: bool)
+                             arg_cleanup_scope: cleanup::ScopeId)
                              -> Block<'blk, 'tcx>
 {
     let sig = bcx.tcx().erase_late_bound_regions(&fn_ty.fn_sig());
@@ -837,15 +751,12 @@ fn trans_args_under_call_abi<'blk, 'tcx>(
     let args = sig.inputs;
 
     // Translate the `self` argument first.
-    if !ignore_self {
-        let arg_datum = unpack_datum!(bcx, expr::trans(bcx, &arg_exprs[0]));
-        bcx = trans_arg_datum(bcx,
-                              args[0],
-                              arg_datum,
-                              arg_cleanup_scope,
-                              DontAutorefArg,
-                              llargs);
-    }
+    let arg_datum = unpack_datum!(bcx, expr::trans(bcx, &arg_exprs[0]));
+    bcx = trans_arg_datum(bcx,
+                          args[0],
+                          arg_datum,
+                          arg_cleanup_scope,
+                          llargs);
 
     // Now untuple the rest of the arguments.
     let tuple_expr = &arg_exprs[1];
@@ -873,7 +784,6 @@ fn trans_args_under_call_abi<'blk, 'tcx>(
                                       field_type,
                                       arg_datum,
                                       arg_cleanup_scope,
-                                      DontAutorefArg,
                                       llargs);
             }
         }
@@ -891,23 +801,19 @@ fn trans_overloaded_call_args<'blk, 'tcx>(
                               arg_exprs: Vec<&hir::Expr>,
                               fn_ty: Ty<'tcx>,
                               llargs: &mut Vec<ValueRef>,
-                              arg_cleanup_scope: cleanup::ScopeId,
-                              ignore_self: bool)
+                              arg_cleanup_scope: cleanup::ScopeId)
                               -> Block<'blk, 'tcx> {
     // Translate the `self` argument first.
     let sig = bcx.tcx().erase_late_bound_regions(&fn_ty.fn_sig());
     let sig = infer::normalize_associated_type(bcx.tcx(), &sig);
     let arg_tys = sig.inputs;
 
-    if !ignore_self {
-        let arg_datum = unpack_datum!(bcx, expr::trans(bcx, arg_exprs[0]));
-        bcx = trans_arg_datum(bcx,
-                              arg_tys[0],
-                              arg_datum,
-                              arg_cleanup_scope,
-                              DontAutorefArg,
-                              llargs);
-    }
+    let arg_datum = unpack_datum!(bcx, expr::trans(bcx, arg_exprs[0]));
+    bcx = trans_arg_datum(bcx,
+                          arg_tys[0],
+                          arg_datum,
+                          arg_cleanup_scope,
+                          llargs);
 
     // Now untuple the rest of the arguments.
     let tuple_type = arg_tys[1];
@@ -920,7 +826,6 @@ fn trans_overloaded_call_args<'blk, 'tcx>(
                                       field_type,
                                       arg_datum,
                                       arg_cleanup_scope,
-                                      DontAutorefArg,
                                       llargs);
             }
         }
@@ -938,7 +843,6 @@ pub fn trans_args<'a, 'blk, 'tcx>(cx: Block<'blk, 'tcx>,
                                   fn_ty: Ty<'tcx>,
                                   llargs: &mut Vec<ValueRef>,
                                   arg_cleanup_scope: cleanup::ScopeId,
-                                  ignore_self: bool,
                                   abi: Abi)
                                   -> Block<'blk, 'tcx> {
     debug!("trans_args(abi={})", abi);
@@ -963,15 +867,11 @@ pub fn trans_args<'a, 'blk, 'tcx>(cx: Block<'blk, 'tcx>,
                                                  arg_exprs,
                                                  fn_ty,
                                                  llargs,
-                                                 arg_cleanup_scope,
-                                                 ignore_self)
+                                                 arg_cleanup_scope)
             }
 
             let num_formal_args = arg_tys.len();
             for (i, arg_expr) in arg_exprs.iter().enumerate() {
-                if i == 0 && ignore_self {
-                    continue;
-                }
                 let arg_ty = if i >= num_formal_args {
                     assert!(variadic);
                     common::expr_ty_adjusted(cx, &arg_expr)
@@ -982,7 +882,6 @@ pub fn trans_args<'a, 'blk, 'tcx>(cx: Block<'blk, 'tcx>,
                 let arg_datum = unpack_datum!(bcx, expr::trans(bcx, &arg_expr));
                 bcx = trans_arg_datum(bcx, arg_ty, arg_datum,
                                       arg_cleanup_scope,
-                                      DontAutorefArg,
                                       llargs);
             }
         }
@@ -991,22 +890,19 @@ pub fn trans_args<'a, 'blk, 'tcx>(cx: Block<'blk, 'tcx>,
                                               arg_exprs,
                                               fn_ty,
                                               llargs,
-                                              arg_cleanup_scope,
-                                              ignore_self)
+                                              arg_cleanup_scope)
         }
-        ArgOverloadedOp(lhs, rhs, autoref) => {
+        ArgOverloadedOp(lhs, rhs) => {
             assert!(!variadic);
 
             bcx = trans_arg_datum(bcx, arg_tys[0], lhs,
                                   arg_cleanup_scope,
-                                  DontAutorefArg,
                                   llargs);
 
-            if let Some((rhs, rhs_id)) = rhs {
+            if let Some(rhs) = rhs {
                 assert_eq!(arg_tys.len(), 2);
                 bcx = trans_arg_datum(bcx, arg_tys[1], rhs,
                                       arg_cleanup_scope,
-                                      if autoref { DoAutorefArg(rhs_id) } else { DontAutorefArg },
                                       llargs);
             } else {
                 assert_eq!(arg_tys.len(), 1);
@@ -1020,17 +916,10 @@ pub fn trans_args<'a, 'blk, 'tcx>(cx: Block<'blk, 'tcx>,
     bcx
 }
 
-#[derive(Copy, Clone)]
-pub enum AutorefArg {
-    DontAutorefArg,
-    DoAutorefArg(ast::NodeId)
-}
-
 pub fn trans_arg_datum<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
                                    formal_arg_ty: Ty<'tcx>,
                                    arg_datum: Datum<'tcx, Expr>,
                                    arg_cleanup_scope: cleanup::ScopeId,
-                                   autoref_arg: AutorefArg,
                                    llargs: &mut Vec<ValueRef>)
                                    -> Block<'blk, 'tcx> {
     let _icx = push_ctxt("trans_arg_datum");
@@ -1044,37 +933,25 @@ pub fn trans_arg_datum<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
 
     debug!("   arg datum: {}", arg_datum.to_string(bcx.ccx()));
 
-    let mut val;
-    // FIXME(#3548) use the adjustments table
-    match autoref_arg {
-        DoAutorefArg(arg_id) => {
-            // We will pass argument by reference
-            // We want an lvalue, so that we can pass by reference and
-            let arg_datum = unpack_datum!(
-                bcx, arg_datum.to_lvalue_datum(bcx, "arg", arg_id));
-            val = arg_datum.val;
-        }
-        DontAutorefArg if common::type_is_fat_ptr(bcx.tcx(), arg_datum_ty) &&
-                !bcx.fcx.type_needs_drop(arg_datum_ty) => {
-            val = arg_datum.val
-        }
-        DontAutorefArg => {
-            // Make this an rvalue, since we are going to be
-            // passing ownership.
-            let arg_datum = unpack_datum!(
-                bcx, arg_datum.to_rvalue_datum(bcx, "arg"));
-
-            // Now that arg_datum is owned, get it into the appropriate
-            // mode (ref vs value).
-            let arg_datum = unpack_datum!(
-                bcx, arg_datum.to_appropriate_datum(bcx));
-
-            // Technically, ownership of val passes to the callee.
-            // However, we must cleanup should we panic before the
-            // callee is actually invoked.
-            val = arg_datum.add_clean(bcx.fcx, arg_cleanup_scope);
-        }
-    }
+    let mut val = if common::type_is_fat_ptr(bcx.tcx(), arg_datum_ty) &&
+                     !bcx.fcx.type_needs_drop(arg_datum_ty) {
+        arg_datum.val
+    } else {
+        // Make this an rvalue, since we are going to be
+        // passing ownership.
+        let arg_datum = unpack_datum!(
+            bcx, arg_datum.to_rvalue_datum(bcx, "arg"));
+
+        // Now that arg_datum is owned, get it into the appropriate
+        // mode (ref vs value).
+        let arg_datum = unpack_datum!(
+            bcx, arg_datum.to_appropriate_datum(bcx));
+
+        // Technically, ownership of val passes to the callee.
+        // However, we must cleanup should we panic before the
+        // callee is actually invoked.
+        arg_datum.add_clean(bcx.fcx, arg_cleanup_scope)
+    };
 
     if type_of::arg_is_indirect(ccx, formal_arg_ty) && formal_arg_ty != arg_datum_ty {
         // this could happen due to e.g. subtyping
index 023ab02bc38d03e91a19f75d8c1f37479318b2b2..95ca250e8444525f812696a08731ee10780a6252 100644 (file)
@@ -17,7 +17,7 @@
 use trans::attributes;
 use trans::base::*;
 use trans::build::*;
-use trans::callee::{self, ArgVals, Callee, TraitItem, MethodData};
+use trans::callee::{self, ArgVals, Callee};
 use trans::cleanup::{CleanupMethods, CustomScope, ScopeId};
 use trans::common::*;
 use trans::datum::{self, Datum, rvalue_scratch_datum, Rvalue};
@@ -271,24 +271,8 @@ pub fn trans_closure_method<'a, 'tcx>(ccx: &'a CrateContext<'a, 'tcx>,
 
     // If the closure is a Fn closure, but a FnOnce is needed (etc),
     // then adapt the self type
-    let closure_kind = ccx.tcx().closure_kind(closure_def_id);
-    trans_closure_adapter_shim(ccx,
-                               closure_def_id,
-                               substs,
-                               closure_kind,
-                               trait_closure_kind,
-                               llfn)
-}
+    let llfn_closure_kind = ccx.tcx().closure_kind(closure_def_id);
 
-fn trans_closure_adapter_shim<'a, 'tcx>(
-    ccx: &'a CrateContext<'a, 'tcx>,
-    closure_def_id: DefId,
-    substs: ty::ClosureSubsts<'tcx>,
-    llfn_closure_kind: ty::ClosureKind,
-    trait_closure_kind: ty::ClosureKind,
-    llfn: ValueRef)
-    -> ValueRef
-{
     let _icx = push_ctxt("trans_closure_adapter_shim");
     let tcx = ccx.tcx();
 
@@ -393,7 +377,7 @@ fn trans_fn_once_adapter_shim<'a, 'tcx>(
                       &block_arena);
     let mut bcx = init_function(&fcx, false, ret_ty);
 
-    let llargs = get_params(fcx.llfn);
+    let mut llargs = get_params(fcx.llfn);
 
     // the first argument (`self`) will be the (by value) closure env.
     let self_scope = fcx.push_custom_cleanup_scope();
@@ -408,21 +392,17 @@ fn trans_fn_once_adapter_shim<'a, 'tcx>(
 
     debug!("trans_fn_once_adapter_shim: env_datum={}",
            bcx.val_to_string(env_datum.val));
+    llargs[self_idx] = env_datum.val;
 
     let dest =
         fcx.llretslotptr.get().map(
             |_| expr::SaveIn(fcx.get_ret_slot(bcx, ret_ty, "ret_slot")));
 
-    let callee_data = TraitItem(MethodData { llfn: llreffn,
-                                             llself: env_datum.val });
-
-    bcx = callee::trans_call_inner(bcx, DebugLoc::None, |bcx, _| {
-        Callee {
-            bcx: bcx,
-            data: callee_data,
-            ty: llref_fn_ty
-        }
-    }, ArgVals(&llargs[(self_idx + 1)..]), dest).bcx;
+    let callee = Callee {
+        data: callee::Fn(llreffn),
+        ty: llref_fn_ty
+    };
+    bcx = callee.call(bcx, DebugLoc::None, ArgVals(&llargs[self_idx..]), dest).bcx;
 
     fcx.pop_and_trans_custom_cleanup_scope(bcx, self_scope);
 
index 4bd150605c9ef3318a8b5c558a190178861ce832..abfd127f38860d9ff4026fbf813423cbc01d17ce 100644 (file)
@@ -542,14 +542,9 @@ fn visit_operand(&mut self, operand: &mir::Operand<'tcx>) {
         debug!("visiting operand {:?}", *operand);
 
         let callee = match *operand {
-            mir::Operand::Constant(mir::Constant {
-                literal: mir::Literal::Item {
-                    def_id,
-                    kind,
-                    substs
-                },
-                ..
-            }) if is_function_or_method(kind) => Some((def_id, substs)),
+            mir::Operand::Constant(mir::Constant { ty: &ty::TyS {
+                sty: ty::TyFnDef(def_id, substs, _), ..
+            }, .. }) => Some((def_id, substs)),
             _ => None
         };
 
@@ -588,14 +583,6 @@ fn visit_operand(&mut self, operand: &mir::Operand<'tcx>) {
 
         self.super_operand(operand);
 
-        fn is_function_or_method(item_kind: mir::ItemKind) -> bool {
-            match item_kind {
-                mir::ItemKind::Constant => false,
-                mir::ItemKind::Function |
-                mir::ItemKind::Method   => true
-            }
-        }
-
         fn can_result_in_trans_item<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
                                               def_id: DefId)
                                               -> bool {
@@ -690,7 +677,7 @@ fn find_drop_glue_neighbors<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
         if can_have_local_instance(ccx, destructor_did) {
             let trans_item = create_fn_trans_item(ccx,
                                                   destructor_did,
-                                                  ccx.tcx().mk_substs(substs),
+                                                  substs,
                                                   &Substs::trans_empty());
             output.push(trans_item);
         }
@@ -833,9 +820,9 @@ fn do_static_trait_method_dispatch<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
         {
             let callee_substs = impl_substs.with_method_from(&rcvr_substs);
             let impl_method = tcx.get_impl_method(impl_did,
-                                                  callee_substs,
+                                                  tcx.mk_substs(callee_substs),
                                                   trait_method.name);
-            Some((impl_method.method.def_id, tcx.mk_substs(impl_method.substs)))
+            Some((impl_method.method.def_id, impl_method.substs))
         }
         // If we have a closure or a function pointer, we will also encounter
         // the concrete closure/function somewhere else (during closure or fn
@@ -993,10 +980,9 @@ fn create_trans_items_for_vtable_methods<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
                         // create translation items
                         .filter_map(|impl_method| {
                             if can_have_local_instance(ccx, impl_method.method.def_id) {
-                                let substs = ccx.tcx().mk_substs(impl_method.substs);
                                 Some(create_fn_trans_item(ccx,
                                                           impl_method.method.def_id,
-                                                          substs,
+                                                          impl_method.substs,
                                                           &Substs::trans_empty()))
                             } else {
                                 None
@@ -1175,12 +1161,12 @@ fn create_trans_items_for_default_impls<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
                     // The substitutions we have are on the impl, so we grab
                     // the method type from the impl to substitute into.
                     let mth = tcx.get_impl_method(impl_def_id,
-                                                  callee_substs.clone(),
+                                                  callee_substs,
                                                   default_impl.name);
 
                     assert!(mth.is_provided);
 
-                    let predicates = mth.method.predicates.predicates.subst(tcx, &mth.substs);
+                    let predicates = mth.method.predicates.predicates.subst(tcx, mth.substs);
                     if !normalize_and_test_predicates(ccx, predicates.into_vec()) {
                         continue;
                     }
index f489f1f62ac608842e61fd955d39a2283890e266..34ef4f4acec5e4d763eaa6b19f530f6081256bed 100644 (file)
@@ -1228,7 +1228,7 @@ pub enum ExprOrMethodCall {
 pub fn node_id_substs<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
                                 node: ExprOrMethodCall,
                                 param_substs: &subst::Substs<'tcx>)
-                                -> subst::Substs<'tcx> {
+                                -> &'tcx subst::Substs<'tcx> {
     let tcx = ccx.tcx();
 
     let substs = match node {
@@ -1245,9 +1245,9 @@ pub fn node_id_substs<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
                               node, substs));
     }
 
-    monomorphize::apply_param_substs(tcx,
-                                     param_substs,
-                                     &substs.erase_regions())
+    ccx.tcx().mk_substs(monomorphize::apply_param_substs(tcx,
+                                                         param_substs,
+                                                         &substs.erase_regions()))
 }
 
 pub fn langcall(bcx: Block,
index bec73c7cedc09e533266d56a0dcc4a9f8336483b..6c47cab64effe7f2a2ec1111e7a4e620ff8086ae 100644 (file)
@@ -28,6 +28,7 @@
 use middle::def_id::DefId;
 use trans::{adt, closure, debuginfo, expr, inline, machine};
 use trans::base::{self, push_ctxt};
+use trans::callee::Callee;
 use trans::collector::{self, TransItem};
 use trans::common::{self, type_is_sized, ExprOrMethodCall, node_id_substs, C_nil, const_get_elt};
 use trans::common::{CrateContext, C_integral, C_floating, C_bool, C_str_slice, C_bytes, val_ty};
@@ -211,7 +212,7 @@ fn const_fn_call<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
     let arg_ids = args.iter().map(|arg| arg.pat.id);
     let fn_args = arg_ids.zip(arg_vals.iter().cloned()).collect();
 
-    let substs = ccx.tcx().mk_substs(node_id_substs(ccx, node, param_substs));
+    let substs = node_id_substs(ccx, node, param_substs);
     match fn_like.body().expr {
         Some(ref expr) => {
             const_expr(ccx, &expr, substs, Some(&fn_args), trueconst).map(|(res, _)| res)
@@ -355,8 +356,16 @@ pub fn const_expr<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
     let opt_adj = cx.tcx().tables.borrow().adjustments.get(&e.id).cloned();
     match opt_adj {
         Some(AdjustReifyFnPointer) => {
-            // FIXME(#19925) once fn item types are
-            // zero-sized, we'll need to do something here
+            match ety.sty {
+                ty::TyFnDef(def_id, substs, _) => {
+                    let datum = Callee::def(cx, def_id, substs, ety).reify(cx);
+                    llconst = datum.val;
+                    ety_adjusted = datum.ty;
+                }
+                _ => {
+                    unreachable!("{} cannot be reified to a fn ptr", ety)
+                }
+            }
         }
         Some(AdjustUnsafeFnPointer) | Some(AdjustMutToConstPointer) => {
             // purely a type-level thing
@@ -413,8 +422,7 @@ pub fn const_expr<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
                     .expect("consts: unsizing got non-pointer target type").ty;
                 let ptr_ty = type_of::in_memory_type_of(cx, unsized_ty).ptr_to();
                 let base = ptrcast(base, ptr_ty);
-                let info = base::unsized_info(cx, pointee_ty, unsized_ty,
-                                              old_info, param_substs);
+                let info = base::unsized_info(cx, pointee_ty, unsized_ty, old_info);
 
                 if old_info.is_none() {
                     let prev_const = cx.const_unsized().borrow_mut()
@@ -894,9 +902,7 @@ fn const_expr_unadjusted<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
                         cx.sess().span_bug(e.span, "const fn argument not found")
                     }
                 }
-                Def::Fn(..) | Def::Method(..) => {
-                    expr::trans_def_fn_unadjusted(cx, e, def, param_substs).val
-                }
+                Def::Fn(..) | Def::Method(..) => C_nil(cx),
                 Def::Const(def_id) | Def::AssociatedConst(def_id) => {
                     load_const(cx, try!(get_const_val(cx, def_id, e, param_substs)),
                                ety)
@@ -908,23 +914,14 @@ fn const_expr_unadjusted<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
                             let repr = adt::represent_type(cx, ety);
                             adt::trans_const(cx, &repr, Disr::from(vinfo.disr_val), &[])
                         }
-                        ty::VariantKind::Tuple => {
-                            expr::trans_def_fn_unadjusted(cx, e, def, param_substs).val
-                        }
+                        ty::VariantKind::Tuple => C_nil(cx),
                         ty::VariantKind::Struct => {
                             cx.sess().span_bug(e.span, "path-expr refers to a dict variant!")
                         }
                     }
                 }
-                Def::Struct(..) => {
-                    if let ty::TyFnDef(..) = ety.sty {
-                        // Tuple struct.
-                        expr::trans_def_fn_unadjusted(cx, e, def, param_substs).val
-                    } else {
-                        // Unit struct.
-                        C_null(type_of::type_of(cx, ety))
-                    }
-                }
+                // Unit struct or ctor.
+                Def::Struct(..) => C_null(type_of::type_of(cx, ety)),
                 _ => {
                     cx.sess().span_bug(e.span, "expected a const, fn, struct, \
                                                 or variant def")
index 00ce0f8109491fa2f64c823a4f0482a440f353b1..ae03f58bce0cf81d01bd1edc69eb479203ce82a9 100644 (file)
 use middle::const_qualif::ConstQualif;
 use middle::def::Def;
 use middle::subst::Substs;
-use trans::{_match, adt, asm, base, callee, closure, consts, controlflow};
+use trans::{_match, adt, asm, base, closure, consts, controlflow};
 use trans::base::*;
 use trans::build::*;
+use trans::callee::{Callee, ArgExprs, ArgOverloadedCall, ArgOverloadedOp};
 use trans::cleanup::{self, CleanupMethods, DropHintMethods};
 use trans::common::*;
 use trans::datum::*;
@@ -66,7 +67,6 @@
 use trans::declare;
 use trans::glue;
 use trans::machine;
-use trans::meth;
 use trans::tvec;
 use trans::type_of;
 use trans::Disr;
@@ -85,7 +85,6 @@
 
 use syntax::{ast, codemap};
 use syntax::parse::token::InternedString;
-use syntax::ptr::P;
 use std::mem;
 
 // Destinations
@@ -349,11 +348,7 @@ fn adjustment_required<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
     }
 
     match adjustment {
-        AdjustReifyFnPointer => {
-            // FIXME(#19925) once fn item types are
-            // zero-sized, we'll need to return true here
-            false
-        }
+        AdjustReifyFnPointer => true,
         AdjustUnsafeFnPointer | AdjustMutToConstPointer => {
             // purely a type-level thing
             false
@@ -388,8 +383,15 @@ fn apply_adjustments<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
            adjustment);
     match adjustment {
         AdjustReifyFnPointer => {
-            // FIXME(#19925) once fn item types are
-            // zero-sized, we'll need to do something here
+            match datum.ty.sty {
+                ty::TyFnDef(def_id, substs, _) => {
+                    datum = Callee::def(bcx.ccx(), def_id, substs, datum.ty)
+                        .reify(bcx.ccx()).to_expr_datum();
+                }
+                _ => {
+                    unreachable!("{} cannot be reified to a fn ptr", datum.ty)
+                }
+            }
         }
         AdjustUnsafeFnPointer | AdjustMutToConstPointer => {
             // purely a type-level thing
@@ -492,8 +494,7 @@ fn coerce_unsized<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
                 (val, None)
             };
 
-            let info = unsized_info(bcx.ccx(), inner_source, inner_target,
-                                    old_info, bcx.fcx.param_substs);
+            let info = unsized_info(bcx.ccx(), inner_source, inner_target, old_info);
 
             // Compute the base pointer. This doesn't change the pointer value,
             // but merely its type.
@@ -785,15 +786,10 @@ fn trans_index<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
     let index_expr_debug_loc = index_expr.debug_loc();
 
     // Check for overloaded index.
-    let method_ty = ccx.tcx()
-                       .tables
-                       .borrow()
-                       .method_map
-                       .get(&method_call)
-                       .map(|method| method.ty);
-    let elt_datum = match method_ty {
-        Some(method_ty) => {
-            let method_ty = monomorphize_type(bcx, method_ty);
+    let method = ccx.tcx().tables.borrow().method_map.get(&method_call).cloned();
+    let elt_datum = match method {
+        Some(method) => {
+            let method_ty = monomorphize_type(bcx, method.ty);
 
             let base_datum = unpack_datum!(bcx, trans(bcx, base));
 
@@ -811,19 +807,16 @@ fn trans_index<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
                 Some(elt_tm) => elt_tm.ty,
             };
 
-            // Overloaded. Evaluate `trans_overloaded_op`, which will
-            // invoke the user's index() method, which basically yields
-            // a `&T` pointer.  We can then proceed down the normal
-            // path (below) to dereference that `&T`.
+            // Overloaded. Invoke the index() method, which basically
+            // yields a `&T` pointer.  We can then proceed down the
+            // normal path (below) to dereference that `&T`.
             let scratch = rvalue_scratch_datum(bcx, ref_ty, "overloaded_index_elt");
-            unpack_result!(bcx,
-                           trans_overloaded_op(bcx,
-                                               index_expr,
-                                               method_call,
-                                               base_datum,
-                                               Some((ix_datum, idx.id)),
-                                               Some(SaveIn(scratch.val)),
-                                               false));
+
+            bcx = Callee::method(bcx, method)
+                .call(bcx, index_expr_debug_loc,
+                      ArgOverloadedOp(base_datum, Some(ix_datum)),
+                      Some(SaveIn(scratch.val))).bcx;
+
             let datum = scratch.to_expr_datum();
             let lval = Lvalue::new("expr::trans_index overload");
             if type_is_sized(bcx.tcx(), elt_ty) {
@@ -899,24 +892,18 @@ fn trans_def<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
 
     let _icx = push_ctxt("trans_def_lvalue");
     match def {
-        Def::Fn(..) | Def::Method(..) |
-        Def::Struct(..) | Def::Variant(..) => {
-            let datum = trans_def_fn_unadjusted(bcx.ccx(), ref_expr, def,
-                                                bcx.fcx.param_substs);
-            DatumBlock::new(bcx, datum.to_expr_datum())
-        }
         Def::Static(did, _) => {
             let const_ty = expr_ty(bcx, ref_expr);
             let val = get_static_val(bcx.ccx(), did, const_ty);
             let lval = Lvalue::new("expr::trans_def");
             DatumBlock::new(bcx, Datum::new(val, const_ty, LvalueExpr(lval)))
         }
-        Def::Const(_) | Def::AssociatedConst(_) => {
-            bcx.sess().span_bug(ref_expr.span,
-                "constant expression should not reach expr::trans_def")
+        Def::Local(..) | Def::Upvar(..) => {
+            DatumBlock::new(bcx, trans_local_var(bcx, def).to_expr_datum())
         }
         _ => {
-            DatumBlock::new(bcx, trans_local_var(bcx, def).to_expr_datum())
+            bcx.sess().span_bug(ref_expr.span,
+                &format!("{:?} should not reach expr::trans_def", def))
         }
     }
 }
@@ -1024,17 +1011,18 @@ fn trans_rvalue_stmt_unadjusted<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
             }
         }
         hir::ExprAssignOp(op, ref dst, ref src) => {
-            let has_method_map = bcx.tcx()
-                                    .tables
-                                    .borrow()
-                                    .method_map
-                                    .contains_key(&MethodCall::expr(expr.id));
+            let method = bcx.tcx().tables
+                                  .borrow()
+                                  .method_map
+                                  .get(&MethodCall::expr(expr.id)).cloned();
 
-            if has_method_map {
+            if let Some(method) = method {
                 let dst = unpack_datum!(bcx, trans(bcx, &dst));
                 let src_datum = unpack_datum!(bcx, trans(bcx, &src));
-                trans_overloaded_op(bcx, expr, MethodCall::expr(expr.id), dst,
-                                    Some((src_datum, src.id)), None, false).bcx
+
+                Callee::method(bcx, method)
+                    .call(bcx, expr.debug_loc(),
+                          ArgOverloadedOp(dst, Some(src_datum)), None).bcx
             } else {
                 trans_assign_op(bcx, expr, op, &dst, &src)
             }
@@ -1061,6 +1049,9 @@ fn trans_rvalue_dps_unadjusted<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
 
     debuginfo::set_source_location(bcx.fcx, expr.id, expr.span);
 
+    // Entry into the method table if this is an overloaded call/op.
+    let method_call = MethodCall::expr(expr.id);
+
     match expr.node {
         hir::ExprType(ref e, _) => {
             trans_into(bcx, &e, dest)
@@ -1144,47 +1135,54 @@ fn trans_rvalue_dps_unadjusted<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
                                         &expr.attrs).unwrap_or(bcx)
         }
         hir::ExprCall(ref f, ref args) => {
-            if bcx.tcx().is_method_call(expr.id) {
-                trans_overloaded_call(bcx,
-                                      expr,
-                                      &f,
-                                      &args[..],
-                                      Some(dest))
+            let method = bcx.tcx().tables.borrow().method_map.get(&method_call).cloned();
+            let (callee, args) = if let Some(method) = method {
+                let mut all_args = vec![&**f];
+                all_args.extend(args.iter().map(|e| &**e));
+
+                (Callee::method(bcx, method), ArgOverloadedCall(all_args))
             } else {
-                callee::trans_call(bcx,
-                                   expr,
-                                   &f,
-                                   callee::ArgExprs(&args[..]),
-                                   dest)
-            }
+                let f = unpack_datum!(bcx, trans(bcx, f));
+                (match f.ty.sty {
+                    ty::TyFnDef(def_id, substs, _) => {
+                        Callee::def(bcx.ccx(), def_id, substs, f.ty)
+                    }
+                    ty::TyFnPtr(_) => {
+                        let f = unpack_datum!(bcx,
+                            f.to_rvalue_datum(bcx, "callee"));
+                        Callee::ptr(f)
+                    }
+                    _ => {
+                        bcx.tcx().sess.span_bug(expr.span,
+                            &format!("type of callee is not a fn: {}", f.ty));
+                    }
+                }, ArgExprs(&args))
+            };
+            callee.call(bcx, expr.debug_loc(), args, Some(dest)).bcx
         }
         hir::ExprMethodCall(_, _, ref args) => {
-            callee::trans_method_call(bcx,
-                                      expr,
-                                      &args[0],
-                                      callee::ArgExprs(&args[..]),
-                                      dest)
+            Callee::method_call(bcx, method_call)
+                .call(bcx, expr.debug_loc(), ArgExprs(&args), Some(dest)).bcx
         }
-        hir::ExprBinary(op, ref lhs, ref rhs) => {
+        hir::ExprBinary(op, ref lhs, ref rhs_expr) => {
             // if not overloaded, would be RvalueDatumExpr
             let lhs = unpack_datum!(bcx, trans(bcx, &lhs));
-            let rhs_datum = unpack_datum!(bcx, trans(bcx, &rhs));
-            trans_overloaded_op(bcx, expr, MethodCall::expr(expr.id), lhs,
-                                Some((rhs_datum, rhs.id)), Some(dest),
-                                !rustc_front::util::is_by_value_binop(op.node)).bcx
+            let mut rhs = unpack_datum!(bcx, trans(bcx, &rhs_expr));
+            if !rustc_front::util::is_by_value_binop(op.node) {
+                rhs = unpack_datum!(bcx, auto_ref(bcx, rhs, rhs_expr));
+            }
+
+            Callee::method_call(bcx, method_call)
+                .call(bcx, expr.debug_loc(),
+                      ArgOverloadedOp(lhs, Some(rhs)), Some(dest)).bcx
         }
-        hir::ExprUnary(op, ref subexpr) => {
+        hir::ExprUnary(_, ref subexpr) => {
             // if not overloaded, would be RvalueDatumExpr
             let arg = unpack_datum!(bcx, trans(bcx, &subexpr));
-            trans_overloaded_op(bcx, expr, MethodCall::expr(expr.id),
-                                arg, None, Some(dest), !rustc_front::util::is_by_value_unop(op)).bcx
-        }
-        hir::ExprIndex(ref base, ref idx) => {
-            // if not overloaded, would be RvalueDatumExpr
-            let base = unpack_datum!(bcx, trans(bcx, &base));
-            let idx_datum = unpack_datum!(bcx, trans(bcx, &idx));
-            trans_overloaded_op(bcx, expr, MethodCall::expr(expr.id), base,
-                                Some((idx_datum, idx.id)), Some(dest), true).bcx
+
+            Callee::method_call(bcx, method_call)
+                .call(bcx, expr.debug_loc(),
+                      ArgOverloadedOp(arg, None), Some(dest)).bcx
         }
         hir::ExprCast(..) => {
             // Trait casts used to come this way, now they should be coercions.
@@ -1218,26 +1216,22 @@ fn trans_def_dps_unadjusted<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
         Ignore => { return bcx; }
     };
 
+    let ty = expr_ty(bcx, ref_expr);
+    if let ty::TyFnDef(..) = ty.sty {
+        // Zero-sized function or ctor.
+        return bcx;
+    }
+
     match def {
         Def::Variant(tid, vid) => {
             let variant = bcx.tcx().lookup_adt_def(tid).variant_with_id(vid);
-            if let ty::VariantKind::Tuple = variant.kind() {
-                // N-ary variant.
-                let llfn = callee::trans_fn_ref(bcx.ccx(), vid,
-                                                ExprId(ref_expr.id),
-                                                bcx.fcx.param_substs).val;
-                Store(bcx, llfn, lldest);
-                return bcx;
-            } else {
-                // Nullary variant.
-                let ty = expr_ty(bcx, ref_expr);
-                let repr = adt::represent_type(bcx.ccx(), ty);
-                adt::trans_set_discr(bcx, &repr, lldest, Disr::from(variant.disr_val));
-                return bcx;
-            }
+            // Nullary variant.
+            let ty = expr_ty(bcx, ref_expr);
+            let repr = adt::represent_type(bcx.ccx(), ty);
+            adt::trans_set_discr(bcx, &repr, lldest, Disr::from(variant.disr_val));
+            bcx
         }
         Def::Struct(..) => {
-            let ty = expr_ty(bcx, ref_expr);
             match ty.sty {
                 ty::TyStruct(def, _) if def.has_dtor() => {
                     let repr = adt::represent_type(bcx.ccx(), ty);
@@ -1255,41 +1249,6 @@ fn trans_def_dps_unadjusted<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
     }
 }
 
-pub fn trans_def_fn_unadjusted<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
-                                         ref_expr: &hir::Expr,
-                                         def: Def,
-                                         param_substs: &'tcx Substs<'tcx>)
-                                         -> Datum<'tcx, Rvalue> {
-    let _icx = push_ctxt("trans_def_datum_unadjusted");
-
-    match def {
-        Def::Fn(did) |
-        Def::Struct(did) | Def::Variant(_, did) => {
-            callee::trans_fn_ref(ccx, did, ExprId(ref_expr.id), param_substs)
-        }
-        Def::Method(method_did) => {
-            match ccx.tcx().impl_or_trait_item(method_did).container() {
-                ty::ImplContainer(_) => {
-                    callee::trans_fn_ref(ccx, method_did,
-                                         ExprId(ref_expr.id),
-                                         param_substs)
-                }
-                ty::TraitContainer(trait_did) => {
-                    meth::trans_static_method_callee(ccx, method_did,
-                                                     trait_did, ref_expr.id,
-                                                     param_substs)
-                }
-            }
-        }
-        _ => {
-            ccx.tcx().sess.span_bug(ref_expr.span, &format!(
-                    "trans_def_fn_unadjusted invoked on: {:?} for {:?}",
-                    def,
-                    ref_expr));
-        }
-    }
-}
-
 /// Translates a reference to a local variable or argument. This always results in an lvalue datum.
 pub fn trans_local_var<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
                                    def: Def)
@@ -1898,51 +1857,6 @@ fn trans_binary<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
     }
 }
 
-fn trans_overloaded_op<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
-                                   expr: &hir::Expr,
-                                   method_call: MethodCall,
-                                   lhs: Datum<'tcx, Expr>,
-                                   rhs: Option<(Datum<'tcx, Expr>, ast::NodeId)>,
-                                   dest: Option<Dest>,
-                                   autoref: bool)
-                                   -> Result<'blk, 'tcx> {
-    callee::trans_call_inner(bcx,
-                             expr.debug_loc(),
-                             |bcx, arg_cleanup_scope| {
-                                meth::trans_method_callee(bcx,
-                                                          method_call,
-                                                          None,
-                                                          arg_cleanup_scope)
-                             },
-                             callee::ArgOverloadedOp(lhs, rhs, autoref),
-                             dest)
-}
-
-fn trans_overloaded_call<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>,
-                                         expr: &hir::Expr,
-                                         callee: &'a hir::Expr,
-                                         args: &'a [P<hir::Expr>],
-                                         dest: Option<Dest>)
-                                         -> Block<'blk, 'tcx> {
-    debug!("trans_overloaded_call {}", expr.id);
-    let method_call = MethodCall::expr(expr.id);
-    let mut all_args = vec!(callee);
-    all_args.extend(args.iter().map(|e| &**e));
-    unpack_result!(bcx,
-                   callee::trans_call_inner(bcx,
-                                            expr.debug_loc(),
-                                            |bcx, arg_cleanup_scope| {
-                                                meth::trans_method_callee(
-                                                    bcx,
-                                                    method_call,
-                                                    None,
-                                                    arg_cleanup_scope)
-                                            },
-                                            callee::ArgOverloadedCall(all_args),
-                                            dest));
-    bcx
-}
-
 pub fn cast_is_noop<'tcx>(tcx: &TyCtxt<'tcx>,
                           expr: &hir::Expr,
                           t_in: Ty<'tcx>,
@@ -2179,18 +2093,12 @@ fn deref_once<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
     let mut bcx = bcx;
 
     // Check for overloaded deref.
-    let method_ty = ccx.tcx()
-                       .tables
-                       .borrow()
-                       .method_map
-                       .get(&method_call).map(|method| method.ty);
-
-    let datum = match method_ty {
-        Some(method_ty) => {
-            let method_ty = monomorphize_type(bcx, method_ty);
-
-            // Overloaded. Evaluate `trans_overloaded_op`, which will
-            // invoke the user's deref() method, which basically
+    let method = ccx.tcx().tables.borrow().method_map.get(&method_call).cloned();
+    let datum = match method {
+        Some(method) => {
+            let method_ty = monomorphize_type(bcx, method.ty);
+
+            // Overloaded. Invoke the deref() method, which basically
             // converts from the `Smaht<T>` pointer that we have into
             // a `&T` pointer.  We can then proceed down the normal
             // path (below) to dereference that `&T`.
@@ -2205,9 +2113,10 @@ fn deref_once<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
                 ccx.tcx().no_late_bound_regions(&method_ty.fn_ret()).unwrap().unwrap();
             let scratch = rvalue_scratch_datum(bcx, ref_ty, "overloaded_deref");
 
-            unpack_result!(bcx, trans_overloaded_op(bcx, expr, method_call,
-                                                    datum, None, Some(SaveIn(scratch.val)),
-                                                    false));
+            bcx = Callee::method(bcx, method)
+                .call(bcx, expr.debug_loc(),
+                      ArgOverloadedOp(datum, None),
+                      Some(SaveIn(scratch.val))).bcx;
             scratch.to_expr_datum()
         }
         None => {
@@ -2524,18 +2433,13 @@ fn expr_kind(tcx: &TyCtxt, expr: &hir::Expr) -> ExprKind {
     match expr.node {
         hir::ExprPath(..) => {
             match tcx.resolve_expr(expr) {
-                Def::Struct(..) | Def::Variant(..) => {
-                    if let ty::TyFnDef(..) = tcx.node_id_to_type(expr.id).sty {
-                        // ctor function
-                        ExprKind::RvalueDatum
-                    } else {
-                        ExprKind::RvalueDps
-                    }
+                // Put functions and ctors with the ADTs, as they
+                // are zero-sized, so DPS is the cheapest option.
+                Def::Struct(..) | Def::Variant(..) |
+                Def::Fn(..) | Def::Method(..) => {
+                    ExprKind::RvalueDps
                 }
 
-                // Fn pointers are just scalar values.
-                Def::Fn(..) | Def::Method(..) => ExprKind::RvalueDatum,
-
                 // Note: there is actually a good case to be made that
                 // DefArg's, particularly those of immediate type, ought to
                 // considered rvalues.
index 0b2ab58a835a23a4b6fe601288b18f5ea7b59f80..d5f8cff495600397c853f0cf9e65c5933441350b 100644 (file)
@@ -356,27 +356,18 @@ fn trans_struct_drop<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
         &unsized_args
     };
 
-    bcx = callee::trans_call_inner(bcx, DebugLoc::None, |bcx, _| {
-        let trait_ref = ty::Binder(ty::TraitRef {
-            def_id: tcx.lang_items.drop_trait().unwrap(),
-            substs: tcx.mk_substs(Substs::trans_empty().with_self_ty(t))
-        });
-        let vtbl = match fulfill_obligation(bcx.ccx(), DUMMY_SP, trait_ref) {
-            traits::VtableImpl(data) => data,
-            _ => tcx.sess.bug(&format!("dtor for {:?} is not an impl???", t))
-        };
-        let dtor_did = def.destructor().unwrap();
-        let datum = callee::trans_fn_ref_with_substs(bcx.ccx(),
-                                                     dtor_did,
-                                                     ExprId(0),
-                                                     bcx.fcx.param_substs,
-                                                     vtbl.substs);
-        callee::Callee {
-            bcx: bcx,
-            data: callee::Fn(datum.val),
-            ty: datum.ty
-        }
-    }, callee::ArgVals(args), Some(expr::Ignore)).bcx;
+    let trait_ref = ty::Binder(ty::TraitRef {
+        def_id: tcx.lang_items.drop_trait().unwrap(),
+        substs: tcx.mk_substs(Substs::trans_empty().with_self_ty(t))
+    });
+    let vtbl = match fulfill_obligation(bcx.ccx(), DUMMY_SP, trait_ref) {
+        traits::VtableImpl(data) => data,
+        _ => tcx.sess.bug(&format!("dtor for {:?} is not an impl???", t))
+    };
+    let dtor_did = def.destructor().unwrap();
+    bcx = callee::Callee::ptr(callee::trans_fn_ref_with_substs(
+            bcx.ccx(), dtor_did, None, vtbl.substs))
+        .call(bcx, DebugLoc::None, callee::ArgVals(args), Some(expr::Ignore)).bcx;
 
     bcx.fcx.pop_and_trans_custom_cleanup_scope(bcx, contents_scope)
 }
index 70c8681dbc1c311f15b81422d5d457e84329bf48..dff6652e5419bc1821ae9754f3a5a57533558cbf 100644 (file)
@@ -163,7 +163,7 @@ pub fn trans_intrinsic_call<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>,
                                             cleanup_scope: cleanup::CustomScopeIndex,
                                             args: callee::CallArgs<'a, 'tcx>,
                                             dest: expr::Dest,
-                                            substs: subst::Substs<'tcx>,
+                                            substs: &'tcx subst::Substs<'tcx>,
                                             call_info: NodeIdAndSpan)
                                             -> Result<'blk, 'tcx> {
     let fcx = bcx.fcx;
@@ -364,7 +364,6 @@ pub fn trans_intrinsic_call<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>,
                              callee_ty,
                              &mut llargs,
                              cleanup::CustomScope(cleanup_scope),
-                             false,
                              Abi::RustIntrinsic);
 
     fcx.scopes.borrow_mut().last_mut().unwrap().drop_non_lifetime_clean();
@@ -1397,7 +1396,7 @@ fn span_invalid_monomorphization_error(a: &Session, b: Span, c: &str) {
 fn generic_simd_intrinsic<'blk, 'tcx, 'a>
     (bcx: Block<'blk, 'tcx>,
      name: &str,
-     substs: subst::Substs<'tcx>,
+     substs: &'tcx subst::Substs<'tcx>,
      callee_ty: Ty<'tcx>,
      args: Option<&[P<hir::Expr>]>,
      llargs: &[ValueRef],
@@ -1505,11 +1504,7 @@ macro_rules! require_simd {
             None => bcx.sess().span_bug(call_info.span,
                                         "intrinsic call with unexpected argument shape"),
         };
-        let vector = match consts::const_expr(
-            bcx.ccx(),
-            vector,
-            tcx.mk_substs(substs),
-            None,
+        let vector = match consts::const_expr(bcx.ccx(), vector, substs, None,
             consts::TrueConst::Yes, // this should probably help simd error reporting
         ) {
             Ok((vector, _)) => vector,
index 4b18ff05b188e69094fce5bfcb4e77f266acf248..78b86dafa18ad83dd31172f1930d6036fb916f5e 100644 (file)
@@ -18,9 +18,8 @@
 use middle::traits;
 use trans::base::*;
 use trans::build::*;
-use trans::callee::*;
-use trans::callee;
-use trans::cleanup;
+use trans::callee::{Callee, Virtual, ArgVals,
+                    trans_fn_pointer_shim, trans_fn_ref_with_substs};
 use trans::closure;
 use trans::common::*;
 use trans::consts;
 use trans::expr;
 use trans::glue;
 use trans::machine;
-use trans::monomorphize;
 use trans::type_::Type;
 use trans::type_of::*;
 use middle::ty::{self, Ty, TyCtxt};
-use middle::ty::MethodCall;
 
 use syntax::ast;
 use syntax::attr;
@@ -92,263 +89,99 @@ pub fn trans_impl(ccx: &CrateContext,
     }
 }
 
-pub fn trans_method_callee<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
-                                       method_call: MethodCall,
-                                       self_expr: Option<&hir::Expr>,
-                                       arg_cleanup_scope: cleanup::ScopeId)
-                                       -> Callee<'blk, 'tcx> {
-    let _icx = push_ctxt("meth::trans_method_callee");
-
-    let method = bcx.tcx().tables.borrow().method_map[&method_call];
-
-    match bcx.tcx().impl_or_trait_item(method.def_id).container() {
-        ty::ImplContainer(_) => {
-            debug!("trans_method_callee: static, {:?}", method.def_id);
-            let datum = callee::trans_fn_ref(bcx.ccx(),
-                                             method.def_id,
-                                             MethodCallKey(method_call),
-                                             bcx.fcx.param_substs);
-            Callee {
-                bcx: bcx,
-                data: Fn(datum.val),
-                ty: datum.ty
-            }
-        }
-
-        ty::TraitContainer(trait_def_id) => {
-            let trait_ref = method.substs.to_trait_ref(bcx.tcx(), trait_def_id);
-            let trait_ref = ty::Binder(bcx.monomorphize(&trait_ref));
-            let span = bcx.tcx().map.span(method_call.expr_id);
-            debug!("method_call={:?} trait_ref={:?} trait_ref id={:?} substs={:?}",
-                   method_call,
-                   trait_ref,
-                   trait_ref.0.def_id,
-                   trait_ref.0.substs);
-            let origin = fulfill_obligation(bcx.ccx(), span, trait_ref);
-            debug!("origin = {:?}", origin);
-            trans_monomorphized_callee(bcx,
-                                       method_call,
-                                       self_expr,
-                                       trait_def_id,
-                                       method.def_id,
-                                       method.ty,
-                                       origin,
-                                       arg_cleanup_scope)
-        }
-    }
-}
-
-pub fn trans_static_method_callee<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
-                                            method_id: DefId,
-                                            trait_id: DefId,
-                                            expr_id: ast::NodeId,
-                                            param_substs: &'tcx subst::Substs<'tcx>)
-                                            -> Datum<'tcx, Rvalue>
-{
-    let _icx = push_ctxt("meth::trans_static_method_callee");
-    let tcx = ccx.tcx();
-
-    debug!("trans_static_method_callee(method_id={:?}, trait_id={}, \
-            expr_id={})",
-           method_id,
-           tcx.item_path_str(trait_id),
-           expr_id);
-
-    let mname = tcx.item_name(method_id);
-
-    debug!("trans_static_method_callee: method_id={:?}, expr_id={}, \
-            name={}", method_id, expr_id, mname);
-
-    // Find the substitutions for the fn itself. This includes
-    // type parameters that belong to the trait but also some that
-    // belong to the method:
-    let rcvr_substs = node_id_substs(ccx, ExprId(expr_id), param_substs);
-    debug!("rcvr_substs={:?}", rcvr_substs);
-    let trait_ref = ty::Binder(rcvr_substs.to_trait_ref(tcx, trait_id));
-    let vtbl = fulfill_obligation(ccx, DUMMY_SP, trait_ref);
-
-    // Now that we know which impl is being used, we can dispatch to
-    // the actual function:
-    match vtbl {
-        traits::VtableImpl(traits::VtableImplData {
-            impl_def_id: impl_did,
-            substs: impl_substs,
-            nested: _ }) =>
-        {
-            let callee_substs = impl_substs.with_method_from(&rcvr_substs);
-            let mth = tcx.get_impl_method(impl_did, callee_substs, mname);
-            trans_fn_ref_with_substs(ccx, mth.method.def_id, ExprId(expr_id),
-                                     param_substs,
-                                     mth.substs)
-        }
-        traits::VtableObject(ref data) => {
-            let idx = traits::get_vtable_index_of_object_method(tcx, data, method_id);
-            trans_object_shim(ccx,
-                              data.upcast_trait_ref.clone(),
-                              method_id,
-                              idx)
-        }
-        _ => {
-            // FIXME(#20847): handle at least VtableFnPointer
-            tcx.sess.bug(&format!("static call to invalid vtable: {:?}",
-                                 vtbl));
-        }
-    }
-}
-
-fn trans_monomorphized_callee<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
-                                          method_call: MethodCall,
-                                          self_expr: Option<&hir::Expr>,
-                                          trait_id: DefId,
-                                          method_id: DefId,
-                                          method_ty: Ty<'tcx>,
-                                          vtable: traits::Vtable<'tcx, ()>,
-                                          arg_cleanup_scope: cleanup::ScopeId)
-                                          -> Callee<'blk, 'tcx> {
-    let _icx = push_ctxt("meth::trans_monomorphized_callee");
+/// Compute the appropriate callee, give na method's ID, trait ID,
+/// substitutions and a Vtable for that trait.
+pub fn callee_for_trait_impl<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
+                                       method_id: DefId,
+                                       substs: &'tcx subst::Substs<'tcx>,
+                                       trait_id: DefId,
+                                       method_ty: Ty<'tcx>,
+                                       vtable: traits::Vtable<'tcx, ()>)
+                                       -> Callee<'tcx> {
+    let _icx = push_ctxt("meth::callee_for_trait_impl");
     match vtable {
         traits::VtableImpl(vtable_impl) => {
-            let ccx = bcx.ccx();
             let impl_did = vtable_impl.impl_def_id;
-            let mname = match ccx.tcx().impl_or_trait_item(method_id) {
-                ty::MethodTraitItem(method) => method.name,
-                _ => {
-                    bcx.tcx().sess.bug("can't monomorphize a non-method trait \
-                                        item")
-                }
-            };
+            let mname = ccx.tcx().item_name(method_id);
             // create a concatenated set of substitutions which includes
             // those from the impl and those from the method:
-            let meth_substs = node_id_substs(ccx,
-                                             MethodCallKey(method_call),
-                                             bcx.fcx.param_substs);
-            let impl_substs = vtable_impl.substs.with_method_from(&meth_substs);
-            let mth = bcx.tcx().get_impl_method(impl_did, impl_substs, mname);
-            // translate the function
-            let datum = trans_fn_ref_with_substs(bcx.ccx(),
-                                                 mth.method.def_id,
-                                                 MethodCallKey(method_call),
-                                                 bcx.fcx.param_substs,
-                                                 mth.substs);
-
-            Callee { bcx: bcx, data: Fn(datum.val), ty: datum.ty }
+            let impl_substs = vtable_impl.substs.with_method_from(&substs);
+            let substs = ccx.tcx().mk_substs(impl_substs);
+            let mth = ccx.tcx().get_impl_method(impl_did, substs, mname);
+
+            // Translate the function, bypassing Callee::def.
+            // That is because default methods have the same ID as the
+            // trait method used to look up the impl method that ended
+            // up here, so calling Callee::def would infinitely recurse.
+            Callee::ptr(trans_fn_ref_with_substs(ccx, mth.method.def_id,
+                                                 Some(method_ty), mth.substs))
         }
         traits::VtableClosure(vtable_closure) => {
             // The substitutions should have no type parameters remaining
             // after passing through fulfill_obligation
-            let trait_closure_kind = bcx.tcx().lang_items.fn_trait_kind(trait_id).unwrap();
-            let llfn = closure::trans_closure_method(bcx.ccx(),
+            let trait_closure_kind = ccx.tcx().lang_items.fn_trait_kind(trait_id).unwrap();
+            let llfn = closure::trans_closure_method(ccx,
                                                      vtable_closure.closure_def_id,
                                                      vtable_closure.substs,
                                                      trait_closure_kind);
-            Callee {
-                bcx: bcx,
-                data: Fn(llfn),
-                ty: monomorphize_type(bcx, method_ty)
-            }
+            let fn_ptr_ty = match method_ty.sty {
+                ty::TyFnDef(_, _, fty) => ccx.tcx().mk_ty(ty::TyFnPtr(fty)),
+                _ => unreachable!("expected fn item type, found {}",
+                                  method_ty)
+            };
+            Callee::ptr(immediate_rvalue(llfn, fn_ptr_ty))
         }
         traits::VtableFnPointer(fn_ty) => {
-            let trait_closure_kind = bcx.tcx().lang_items.fn_trait_kind(trait_id).unwrap();
-            let llfn = trans_fn_pointer_shim(bcx.ccx(), trait_closure_kind, fn_ty);
-            Callee {
-                bcx: bcx,
-                data: Fn(llfn),
-                ty: monomorphize_type(bcx, method_ty)
-            }
+            let trait_closure_kind = ccx.tcx().lang_items.fn_trait_kind(trait_id).unwrap();
+            let llfn = trans_fn_pointer_shim(ccx, trait_closure_kind, fn_ty);
+            let fn_ptr_ty = match method_ty.sty {
+                ty::TyFnDef(_, _, fty) => ccx.tcx().mk_ty(ty::TyFnPtr(fty)),
+                _ => unreachable!("expected fn item type, found {}",
+                                  method_ty)
+            };
+            Callee::ptr(immediate_rvalue(llfn, fn_ptr_ty))
         }
         traits::VtableObject(ref data) => {
-            let idx = traits::get_vtable_index_of_object_method(bcx.tcx(), data, method_id);
-            if let Some(self_expr) = self_expr {
-                if let ty::TyFnDef(_, _, ref fty) = monomorphize_type(bcx, method_ty).sty {
-                    let ty = opaque_method_ty(bcx.tcx(), fty);
-                    return trans_trait_callee(bcx, ty, idx, self_expr, arg_cleanup_scope);
-                }
+            Callee {
+                data: Virtual(traits::get_vtable_index_of_object_method(
+                    ccx.tcx(), data, method_id)),
+                ty: method_ty
             }
-            let datum = trans_object_shim(bcx.ccx(),
-                                          data.upcast_trait_ref.clone(),
-                                          method_id,
-                                          idx);
-            Callee { bcx: bcx, data: Fn(datum.val), ty: datum.ty }
         }
         traits::VtableBuiltin(..) |
         traits::VtableDefaultImpl(..) |
         traits::VtableParam(..) => {
-            bcx.sess().bug(
+            ccx.sess().bug(
                 &format!("resolved vtable bad vtable {:?} in trans",
                         vtable));
         }
     }
 }
 
-/// Create a method callee where the method is coming from a trait object (e.g., Box<Trait> type).
-/// In this case, we must pull the fn pointer out of the vtable that is packaged up with the
-/// object. Objects are represented as a pair, so we first evaluate the self expression and then
-/// extract the self data and vtable out of the pair.
-fn trans_trait_callee<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
-                                  opaque_fn_ty: Ty<'tcx>,
-                                  vtable_index: usize,
-                                  self_expr: &hir::Expr,
-                                  arg_cleanup_scope: cleanup::ScopeId)
-                                  -> Callee<'blk, 'tcx> {
-    let _icx = push_ctxt("meth::trans_trait_callee");
-    let mut bcx = bcx;
-
-    // Translate self_datum and take ownership of the value by
-    // converting to an rvalue.
-    let self_datum = unpack_datum!(
-        bcx, expr::trans(bcx, self_expr));
-
-    let llval = if bcx.fcx.type_needs_drop(self_datum.ty) {
-        let self_datum = unpack_datum!(
-            bcx, self_datum.to_rvalue_datum(bcx, "trait_callee"));
-
-        // Convert to by-ref since `trans_trait_callee_from_llval` wants it
-        // that way.
-        let self_datum = unpack_datum!(
-            bcx, self_datum.to_ref_datum(bcx));
-
-        // Arrange cleanup in case something should go wrong before the
-        // actual call occurs.
-        self_datum.add_clean(bcx.fcx, arg_cleanup_scope)
-    } else {
-        // We don't have to do anything about cleanups for &Trait and &mut Trait.
-        assert!(self_datum.kind.is_by_ref());
-        self_datum.val
-    };
-
-    let llself = Load(bcx, expr::get_dataptr(bcx, llval));
-    let llvtable = Load(bcx, expr::get_meta(bcx, llval));
-    trans_trait_callee_from_llval(bcx, opaque_fn_ty, vtable_index, llself, llvtable)
-}
-
-/// Same as `trans_trait_callee()` above, except that it is given a by-ref pointer to the object
-/// pair.
-fn trans_trait_callee_from_llval<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
-                                             opaque_fn_ty: Ty<'tcx>,
-                                             vtable_index: usize,
-                                             llself: ValueRef,
-                                             llvtable: ValueRef)
-                                             -> Callee<'blk, 'tcx> {
-    let _icx = push_ctxt("meth::trans_trait_callee");
+/// Extracts a method from a trait object's vtable, at the
+/// specified index, and casts it to the given type.
+pub fn get_virtual_method<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
+                                      llvtable: ValueRef,
+                                      vtable_index: usize,
+                                      method_ty: Ty<'tcx>)
+                                      -> Datum<'tcx, Rvalue> {
+    let _icx = push_ctxt("meth::get_virtual_method");
     let ccx = bcx.ccx();
 
     // Load the data pointer from the object.
-    debug!("trans_trait_callee_from_llval(callee_ty={}, vtable_index={}, llself={}, llvtable={})",
-           opaque_fn_ty,
+    debug!("get_virtual_method(callee_ty={}, vtable_index={}, llvtable={})",
+           method_ty,
            vtable_index,
-           bcx.val_to_string(llself),
            bcx.val_to_string(llvtable));
 
-    // Replace the self type (&Self or Box<Self>) with an opaque pointer.
     let mptr = Load(bcx, GEPi(bcx, llvtable, &[vtable_index + VTABLE_OFFSET]));
 
-    Callee {
-        bcx: bcx,
-        data: TraitItem(MethodData {
-            llfn: PointerCast(bcx, mptr, type_of(ccx, opaque_fn_ty)),
-            llself: PointerCast(bcx, llself, Type::i8p(ccx)),
-        }),
-        ty: opaque_fn_ty
+    // Replace the self type (&Self or Box<Self>) with an opaque pointer.
+    if let ty::TyFnDef(_, _, fty) = method_ty.sty {
+        let opaque_ty = opaque_method_ty(ccx.tcx(), fty);
+        immediate_rvalue(PointerCast(bcx, mptr, type_of(ccx, opaque_ty)), opaque_ty)
+    } else {
+        immediate_rvalue(mptr, method_ty)
     }
 }
 
@@ -373,41 +206,24 @@ fn trans_trait_callee_from_llval<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
 ///
 /// In fact, all virtual calls can be thought of as normal trait calls
 /// that go through this shim function.
-pub fn trans_object_shim<'a, 'tcx>(
-    ccx: &'a CrateContext<'a, 'tcx>,
-    upcast_trait_ref: ty::PolyTraitRef<'tcx>,
-    method_id: DefId,
-    vtable_index: usize)
-    -> Datum<'tcx, Rvalue>
-{
+pub fn trans_object_shim<'a, 'tcx>(ccx: &'a CrateContext<'a, 'tcx>,
+                                   method_ty: Ty<'tcx>,
+                                   vtable_index: usize)
+                                   -> Datum<'tcx, Rvalue> {
     let _icx = push_ctxt("trans_object_shim");
     let tcx = ccx.tcx();
 
-    debug!("trans_object_shim(upcast_trait_ref={:?}, method_id={:?})",
-           upcast_trait_ref,
-           method_id);
+    debug!("trans_object_shim(vtable_index={}, method_ty={:?})",
+           vtable_index,
+           method_ty);
 
-    // Upcast to the trait in question and extract out the substitutions.
-    let upcast_trait_ref = tcx.erase_late_bound_regions(&upcast_trait_ref);
-    let object_substs = upcast_trait_ref.substs.clone().erase_regions();
-    debug!("trans_object_shim: object_substs={:?}", object_substs);
+    let ret_ty = tcx.erase_late_bound_regions(&method_ty.fn_ret());
+    let ret_ty = infer::normalize_associated_type(tcx, &ret_ty);
 
-    // Lookup the type of this method as declared in the trait and apply substitutions.
-    let method_ty = match tcx.impl_or_trait_item(method_id) {
-        ty::MethodTraitItem(method) => method,
-        _ => {
-            tcx.sess.bug("can't create a method shim for a non-method item")
-        }
+    let shim_fn_ty = match method_ty.sty {
+        ty::TyFnDef(_, _, fty) => tcx.mk_ty(ty::TyFnPtr(fty)),
+        _ => unreachable!("expected fn item type, found {}", method_ty)
     };
-    let fty = monomorphize::apply_param_substs(tcx, &object_substs, &method_ty.fty);
-
-    let ret_ty = ccx.tcx().erase_late_bound_regions(&fty.sig.output());
-    let ret_ty = infer::normalize_associated_type(ccx.tcx(), &ret_ty);
-
-    let method_fn_ty = opaque_method_ty(tcx, &fty);
-    let shim_fn_ty = tcx.mk_fn_ptr(fty);
-    debug!("trans_object_shim: shim_fn_ty={:?} method_fn_ty={:?}",
-           shim_fn_ty, method_fn_ty);
 
     //
     let function_name = link::mangle_internal_name_by_type_and_seq(ccx, shim_fn_ty, "object_shim");
@@ -444,14 +260,11 @@ pub fn trans_object_shim<'a, 'tcx>(
     debug!("trans_object_shim: method_offset_in_vtable={}",
            vtable_index);
 
-    bcx = trans_call_inner(bcx,
-                           DebugLoc::None,
-                           |bcx, _| trans_trait_callee_from_llval(bcx,
-                                                                  method_fn_ty,
-                                                                  vtable_index,
-                                                                  llself, llvtable),
-                           ArgVals(&llargs[(self_idx + 2)..]),
-                           dest).bcx;
+    let callee = Callee {
+        data: Virtual(vtable_index),
+        ty: method_ty
+    };
+    bcx = callee.call(bcx, DebugLoc::None, ArgVals(&llargs[self_idx..]), dest).bcx;
 
     finish_fn(&fcx, bcx, ret_ty, DebugLoc::None);
 
@@ -465,8 +278,7 @@ pub fn trans_object_shim<'a, 'tcx>(
 /// making an object `Foo<Trait>` from a value of type `Foo<T>`, then
 /// `trait_ref` would map `T:Trait`.
 pub fn get_vtable<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
-                            trait_ref: ty::PolyTraitRef<'tcx>,
-                            param_substs: &'tcx subst::Substs<'tcx>)
+                            trait_ref: ty::PolyTraitRef<'tcx>)
                             -> ValueRef
 {
     let tcx = ccx.tcx();
@@ -502,8 +314,7 @@ pub fn get_vtable<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
                             Some(mth) => {
                                 trans_fn_ref_with_substs(ccx,
                                                          mth.method.def_id,
-                                                         ExprId(0),
-                                                         param_substs,
+                                                         None,
                                                          mth.substs).val
                             }
                             None => nullptr
@@ -566,7 +377,7 @@ pub fn get_vtable<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
 
 pub fn get_vtable_methods<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
                                     impl_id: DefId,
-                                    substs: subst::Substs<'tcx>)
+                                    substs: &'tcx subst::Substs<'tcx>)
                                     -> Vec<Option<ty::util::ImplMethod<'tcx>>>
 {
     let tcx = ccx.tcx();
@@ -617,7 +428,7 @@ pub fn get_vtable_methods<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
 
             // The substitutions we have are on the impl, so we grab
             // the method type from the impl to substitute into.
-            let mth = tcx.get_impl_method(impl_id, substs.clone(), name);
+            let mth = tcx.get_impl_method(impl_id, substs, name);
 
             debug!("get_vtable_methods: mth={:?}", mth);
 
@@ -627,7 +438,7 @@ pub fn get_vtable_methods<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
             // method could then never be called, so we do not want to
             // try and trans it, in that case. Issue #23435.
             if mth.is_provided {
-                let predicates = mth.method.predicates.predicates.subst(tcx, &mth.substs);
+                let predicates = mth.method.predicates.predicates.subst(tcx, mth.substs);
                 if !normalize_and_test_predicates(ccx, predicates.into_vec()) {
                     debug!("get_vtable_methods: predicates do not hold");
                     return None;
index db93b77c47d9c2ed47ad6e6dd45f4ec82798d99c..50283c0959c3f37a5f613d2456119b0822aef196 100644 (file)
@@ -9,73 +9,27 @@
 // except according to those terms.
 
 use llvm::{BasicBlockRef, ValueRef, OperandBundleDef};
-use rustc::middle::ty::{self, Ty};
+use rustc::middle::ty;
 use rustc::mir::repr as mir;
 use syntax::abi::Abi;
 use trans::adt;
 use trans::attributes;
 use trans::base;
 use trans::build;
+use trans::callee::{Callee, Fn, Virtual};
 use trans::common::{self, Block, BlockAndBuilder};
 use trans::debuginfo::DebugLoc;
 use trans::Disr;
 use trans::foreign;
+use trans::meth;
 use trans::type_of;
 use trans::glue;
 use trans::type_::Type;
 
 use super::{MirContext, drop};
 use super::operand::OperandValue::{FatPtr, Immediate, Ref};
-use super::operand::OperandRef;
-
-#[derive(PartialEq, Eq)]
-enum AbiStyle {
-    Foreign,
-    RustCall,
-    Rust
-}
 
 impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
-    fn abi_style(&self, fn_ty: Ty<'tcx>) -> AbiStyle {
-        match fn_ty.sty {
-            ty::TyFnDef(_, _, ref f) | ty::TyFnPtr(ref f) => {
-                // We do not translate intrinsics here (they shouldn’t be functions)
-                assert!(f.abi != Abi::RustIntrinsic && f.abi != Abi::PlatformIntrinsic);
-
-                match f.abi {
-                    Abi::Rust => AbiStyle::Rust,
-                    Abi::RustCall => AbiStyle::RustCall,
-                    _ => AbiStyle::Foreign
-                }
-            }
-            _ => unreachable!()
-        }
-    }
-
-    fn arg_operands(&mut self,
-                    bcx: &BlockAndBuilder<'bcx, 'tcx>,
-                    abi_style: AbiStyle,
-                    args: &[mir::Operand<'tcx>])
-                    -> Vec<OperandRef<'tcx>>
-    {
-        match abi_style {
-            AbiStyle::Foreign | AbiStyle::Rust => {
-                args.iter().map(|arg| self.trans_operand(bcx, arg)).collect()
-            }
-            AbiStyle::RustCall => match args.split_last() {
-                None => vec![],
-                Some((tup, self_ty)) => {
-                    // we can reorder safely because of MIR
-                    let untupled_args = self.trans_operand_untupled(bcx, tup);
-                    self_ty
-                        .iter().map(|arg| self.trans_operand(bcx, arg))
-                        .chain(untupled_args.into_iter())
-                        .collect()
-                }
-            }
-        }
-    }
-
     pub fn trans_block(&mut self, bb: mir::BasicBlock) {
         debug!("trans_block({:?})", bb);
 
@@ -198,9 +152,8 @@ pub fn trans_block(&mut self, bb: mir::BasicBlock) {
             }
 
             mir::Terminator::Call { ref func, ref args, ref destination, ref cleanup } => {
-                // Create the callee. This will always be a fn ptr and hence a kind of scalar.
+                // Create the callee. This is a fn ptr or zero-sized and hence a kind of scalar.
                 let callee = self.trans_operand(&bcx, func);
-                let attrs = attributes::from_fn_type(bcx.ccx(), callee.ty);
                 let debugloc = DebugLoc::None;
                 // The arguments we'll be passing. Plus one to account for outptr, if used.
                 let mut llargs = Vec::with_capacity(args.len() + 1);
@@ -208,9 +161,23 @@ pub fn trans_block(&mut self, bb: mir::BasicBlock) {
                 // filled when `is_foreign` is `true` and foreign calls are minority of the cases.
                 let mut arg_tys = Vec::new();
 
+                let (callee, fty) = match callee.ty.sty {
+                    ty::TyFnDef(def_id, substs, f) => {
+                        (Callee::def(bcx.ccx(), def_id, substs, callee.ty), f)
+                    }
+                    ty::TyFnPtr(f) => {
+                        (Callee {
+                            data: Fn(callee.immediate()),
+                            ty: callee.ty
+                        }, f)
+                    }
+                    _ => unreachable!("{} is not callable", callee.ty)
+                };
+
+                // We do not translate intrinsics here (they shouldn’t be functions)
+                assert!(fty.abi != Abi::RustIntrinsic && fty.abi != Abi::PlatformIntrinsic);
                 // Foreign-ABI functions are translated differently
-                let abi_style = self.abi_style(callee.ty);
-                let is_foreign = abi_style == AbiStyle::Foreign;
+                let is_foreign = fty.abi != Abi::Rust && fty.abi != Abi::RustCall;
 
                 // Prepare the return value destination
                 let (ret_dest_ty, must_copy_dest) = if let Some((ref d, _)) = *destination {
@@ -226,19 +193,58 @@ pub fn trans_block(&mut self, bb: mir::BasicBlock) {
                     (None, false)
                 };
 
-                // Process the rest of the args.
-                for operand in self.arg_operands(&bcx, abi_style, args) {
-                    match operand.val {
-                        Ref(llval) | Immediate(llval) => llargs.push(llval),
-                        FatPtr(b, e) => {
-                            llargs.push(b);
-                            llargs.push(e);
+                // Split the rust-call tupled arguments off.
+                let (args, rest) = if fty.abi == Abi::RustCall && !args.is_empty() {
+                    let (tup, args) = args.split_last().unwrap();
+                    // we can reorder safely because of MIR
+                    (args, self.trans_operand_untupled(&bcx, tup))
+                } else {
+                    (&args[..], vec![])
+                };
+
+                let datum = {
+                    let mut arg_ops = args.iter().map(|arg| {
+                        self.trans_operand(&bcx, arg)
+                    }).chain(rest.into_iter());
+
+                    // Get the actual pointer we can call.
+                    // This can involve vtable accesses or reification.
+                    let datum = if let Virtual(idx) = callee.data {
+                        assert!(!is_foreign);
+
+                        // Grab the first argument which is a trait object.
+                        let vtable = match arg_ops.next().unwrap().val {
+                            FatPtr(data, vtable) => {
+                                llargs.push(data);
+                                vtable
+                            }
+                            _ => unreachable!("expected FatPtr for Virtual call")
+                        };
+
+                        bcx.with_block(|bcx| {
+                            meth::get_virtual_method(bcx, vtable, idx, callee.ty)
+                        })
+                    } else {
+                        callee.reify(bcx.ccx())
+                    };
+
+                    // Process the rest of the args.
+                    for operand in arg_ops {
+                        match operand.val {
+                            Ref(llval) | Immediate(llval) => llargs.push(llval),
+                            FatPtr(b, e) => {
+                                llargs.push(b);
+                                llargs.push(e);
+                            }
+                        }
+                        if is_foreign {
+                            arg_tys.push(operand.ty);
                         }
                     }
-                    if is_foreign {
-                        arg_tys.push(operand.ty);
-                    }
-                }
+
+                    datum
+                };
+                let attrs = attributes::from_fn_type(bcx.ccx(), datum.ty);
 
                 // Many different ways to call a function handled here
                 match (is_foreign, cleanup, destination) {
@@ -247,7 +253,7 @@ pub fn trans_block(&mut self, bb: mir::BasicBlock) {
                         let cleanup = self.bcx(cleanup);
                         let landingpad = self.make_landing_pad(cleanup);
                         let unreachable_blk = self.unreachable_block();
-                        bcx.invoke(callee.immediate(),
+                        bcx.invoke(datum.val,
                                    &llargs[..],
                                    unreachable_blk.llbb,
                                    landingpad.llbb(),
@@ -260,7 +266,7 @@ pub fn trans_block(&mut self, bb: mir::BasicBlock) {
                     (false, &Some(cleanup), &Some((_, success))) => {
                         let cleanup = self.bcx(cleanup);
                         let landingpad = self.make_landing_pad(cleanup);
-                        let invokeret = bcx.invoke(callee.immediate(),
+                        let invokeret = bcx.invoke(datum.val,
                                                    &llargs[..],
                                                    self.llblock(success),
                                                    landingpad.llbb(),
@@ -283,7 +289,7 @@ pub fn trans_block(&mut self, bb: mir::BasicBlock) {
                         });
                     },
                     (false, _, &None) => {
-                        bcx.call(callee.immediate(),
+                        bcx.call(datum.val,
                                  &llargs[..],
                                  cleanup_bundle.as_ref(),
                                  Some(attrs));
@@ -291,7 +297,7 @@ pub fn trans_block(&mut self, bb: mir::BasicBlock) {
                         bcx.unreachable();
                     }
                     (false, _, &Some((_, target))) => {
-                        let llret = bcx.call(callee.immediate(),
+                        let llret = bcx.call(datum.val,
                                              &llargs[..],
                                              cleanup_bundle.as_ref(),
                                              Some(attrs));
@@ -313,8 +319,8 @@ pub fn trans_block(&mut self, bb: mir::BasicBlock) {
                             .expect("return destination is not set");
                         bcx = bcx.map_block(|bcx| {
                             foreign::trans_native_call(bcx,
-                                                       callee.ty,
-                                                       callee.immediate(),
+                                                       datum.ty,
+                                                       datum.val,
                                                        dest.llval,
                                                        &llargs[..],
                                                        arg_tys,
index 7f03069385fec747cd6f514b93fed24d3b5234d2..a0615a6cf5b18041c5e57e78e30cc3e10c3e9a95 100644 (file)
 
 use back::abi;
 use llvm::ValueRef;
-use middle::subst::Substs;
 use middle::ty::{Ty, TypeFoldable};
-use rustc::middle::const_eval::ConstVal;
+use rustc::middle::const_eval::{self, ConstVal};
 use rustc::mir::repr as mir;
 use trans::common::{self, BlockAndBuilder, C_bool, C_bytes, C_floating_f64, C_integral,
-                    C_str_slice};
+                    C_str_slice, C_nil, C_undef};
 use trans::consts;
 use trans::expr;
+use trans::inline;
 use trans::type_of;
 
 use super::operand::{OperandRef, OperandValue};
@@ -32,7 +32,7 @@ pub fn trans_constval(&mut self,
                           -> OperandRef<'tcx>
     {
         let ccx = bcx.ccx();
-        let val = self.trans_constval_inner(bcx, cv, ty, bcx.fcx().param_substs);
+        let val = self.trans_constval_inner(bcx, cv, ty);
         let val = if common::type_is_immediate(ccx, ty) {
             OperandValue::Immediate(val)
         } else if common::type_is_fat_ptr(bcx.tcx(), ty) {
@@ -55,8 +55,7 @@ pub fn trans_constval(&mut self,
     fn trans_constval_inner(&mut self,
                             bcx: &BlockAndBuilder<'bcx, 'tcx>,
                             cv: &ConstVal,
-                            ty: Ty<'tcx>,
-                            param_substs: &'tcx Substs<'tcx>)
+                            ty: Ty<'tcx>)
                             -> ValueRef
     {
         let ccx = bcx.ccx();
@@ -75,8 +74,7 @@ fn trans_constval_inner(&mut self,
                     expr::trans(bcx, expr).datum.val
                 })
             },
-            ConstVal::Function(did) =>
-                self.trans_fn_ref(bcx, ty, param_substs, did).immediate()
+            ConstVal::Function(_) => C_nil(ccx)
         }
     }
 
@@ -85,13 +83,31 @@ pub fn trans_constant(&mut self,
                           constant: &mir::Constant<'tcx>)
                           -> OperandRef<'tcx>
     {
+        let ty = bcx.monomorphize(&constant.ty);
         match constant.literal {
-            mir::Literal::Item { def_id, kind, substs } => {
+            mir::Literal::Item { def_id, substs } => {
+                // Shortcut for zero-sized types, including function item
+                // types, which would not work with lookup_const_by_id.
+                if common::type_is_zero_size(bcx.ccx(), ty) {
+                    let llty = type_of::type_of(bcx.ccx(), ty);
+                    return OperandRef {
+                        val: OperandValue::Immediate(C_undef(llty)),
+                        ty: ty
+                    };
+                }
+
                 let substs = bcx.tcx().mk_substs(bcx.monomorphize(&substs));
-                self.trans_item_ref(bcx, constant.ty, kind, substs, def_id)
+                let def_id = inline::maybe_instantiate_inline(bcx.ccx(), def_id);
+                let expr = const_eval::lookup_const_by_id(bcx.tcx(), def_id, None, Some(substs))
+                            .expect("def was const, but lookup_const_by_id failed");
+                // FIXME: this is falling back to translating from HIR. This is not easy to fix,
+                // because we would have somehow adapt const_eval to work on MIR rather than HIR.
+                let d = bcx.with_block(|bcx| {
+                    expr::trans(bcx, expr)
+                });
+                OperandRef::from_rvalue_datum(d.datum.to_rvalue_datum(d.bcx, "").datum)
             }
             mir::Literal::Value { ref value } => {
-                let ty = bcx.monomorphize(&constant.ty);
                 self.trans_constval(bcx, value, ty)
             }
         }
diff --git a/src/librustc_trans/trans/mir/did.rs b/src/librustc_trans/trans/mir/did.rs
deleted file mode 100644 (file)
index 5b6af47..0000000
+++ /dev/null
@@ -1,171 +0,0 @@
-// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-//! Code for translating references to other items (DefIds).
-
-use syntax::codemap::DUMMY_SP;
-use rustc::front::map;
-use rustc::middle::ty::{self, Ty, TyCtxt, TypeFoldable};
-use rustc::middle::subst::Substs;
-use rustc::middle::const_eval;
-use rustc::middle::def_id::DefId;
-use rustc::middle::traits;
-use rustc::mir::repr::ItemKind;
-use trans::common::{BlockAndBuilder, fulfill_obligation};
-use trans::base;
-use trans::closure;
-use trans::expr;
-use trans::monomorphize;
-use trans::meth;
-use trans::inline;
-
-use super::MirContext;
-use super::operand::{OperandRef, OperandValue};
-
-impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
-    /// Translate reference to item.
-    pub fn trans_item_ref(&mut self,
-                          bcx: &BlockAndBuilder<'bcx, 'tcx>,
-                          ty: Ty<'tcx>,
-                          kind: ItemKind,
-                          substs: &'tcx Substs<'tcx>,
-                          did: DefId)
-                          -> OperandRef<'tcx> {
-        debug!("trans_item_ref(ty={:?}, kind={:?}, substs={:?}, did={})",
-            ty, kind, substs, bcx.tcx().item_path_str(did));
-
-        match kind {
-            ItemKind::Function => self.trans_fn_ref(bcx, ty, substs, did),
-            ItemKind::Method => match bcx.tcx().impl_or_trait_item(did).container() {
-                ty::ImplContainer(_) => self.trans_fn_ref(bcx, ty, substs, did),
-                ty::TraitContainer(tdid) => self.trans_trait_method(bcx, ty, did, tdid, substs)
-            },
-            ItemKind::Constant => {
-                let did = inline::maybe_instantiate_inline(bcx.ccx(), did);
-                let expr = const_eval::lookup_const_by_id(bcx.tcx(), did, None, Some(substs))
-                            .expect("def was const, but lookup_const_by_id failed");
-                // FIXME: this is falling back to translating from HIR. This is not easy to fix,
-                // because we would have somehow adapt const_eval to work on MIR rather than HIR.
-                let d = bcx.with_block(|bcx| {
-                    expr::trans(bcx, expr)
-                });
-                OperandRef::from_rvalue_datum(d.datum.to_rvalue_datum(d.bcx, "").datum)
-            }
-        }
-    }
-
-    /// Translates references to a function-like items.
-    ///
-    /// That includes regular functions, non-static methods, struct and enum variant constructors,
-    /// closures and possibly more.
-    ///
-    /// This is an adaptation of callee::trans_fn_ref_with_substs.
-    pub fn trans_fn_ref(&mut self,
-                        bcx: &BlockAndBuilder<'bcx, 'tcx>,
-                        ty: Ty<'tcx>,
-                        substs: &'tcx Substs<'tcx>,
-                        did: DefId)
-                        -> OperandRef<'tcx> {
-        debug!("trans_fn_ref(ty={:?}, substs={:?}, did={})",
-            ty, substs, bcx.tcx().item_path_str(did));
-
-        let did = inline::maybe_instantiate_inline(bcx.ccx(), did);
-
-        if !substs.types.is_empty() || is_named_tuple_constructor(bcx.tcx(), did) {
-            let (val, fn_ty, _) = monomorphize::monomorphic_fn(bcx.ccx(), did, substs);
-            // FIXME: cast fnptr to proper type if necessary
-            OperandRef {
-                ty: fn_ty,
-                val: OperandValue::Immediate(val)
-            }
-        } else {
-            let val = if let Some(node_id) = bcx.tcx().map.as_local_node_id(did) {
-                base::get_item_val(bcx.ccx(), node_id)
-            } else {
-                base::trans_external_path(bcx.ccx(), did, ty)
-            };
-            // FIXME: cast fnptr to proper type if necessary
-            OperandRef {
-                ty: ty,
-                val: OperandValue::Immediate(val)
-            }
-        }
-    }
-
-    /// Translates references to trait methods.
-    ///
-    /// This is an adaptation of meth::trans_static_method_callee
-    pub fn trans_trait_method(&mut self,
-                              bcx: &BlockAndBuilder<'bcx, 'tcx>,
-                              ty: Ty<'tcx>,
-                              method_id: DefId,
-                              trait_id: DefId,
-                              substs: &'tcx Substs<'tcx>)
-                              -> OperandRef<'tcx> {
-        debug!("trans_static_method(ty={:?}, method={}, trait={}, substs={:?})",
-                ty,
-                bcx.tcx().item_path_str(method_id),
-                bcx.tcx().item_path_str(trait_id),
-                substs);
-
-        let ccx = bcx.ccx();
-        let tcx = bcx.tcx();
-        let trait_ref = ty::Binder(substs.to_trait_ref(tcx, trait_id));
-        let vtbl = fulfill_obligation(ccx, DUMMY_SP, trait_ref);
-        match vtbl {
-            traits::VtableImpl(traits::VtableImplData {
-                impl_def_id, substs: impl_substs, ..
-            }) => {
-                assert!(!impl_substs.types.needs_infer());
-
-                let mname = tcx.item_name(method_id);
-
-                let callee_substs = impl_substs.with_method_from(substs);
-                let mth = tcx.get_impl_method(impl_def_id, callee_substs, mname);
-                let mth_substs = tcx.mk_substs(mth.substs);
-                self.trans_fn_ref(bcx, ty, mth_substs, mth.method.def_id)
-            },
-            traits::VtableClosure(data) => {
-                let trait_closure_kind = bcx.tcx().lang_items.fn_trait_kind(trait_id).unwrap();
-                let llfn = closure::trans_closure_method(bcx.ccx(),
-                                                         data.closure_def_id,
-                                                         data.substs,
-                                                         trait_closure_kind);
-                OperandRef {
-                    ty: ty,
-                    val: OperandValue::Immediate(llfn)
-                }
-            },
-            traits::VtableObject(ref data) => {
-                let idx = traits::get_vtable_index_of_object_method(tcx, data, method_id);
-                OperandRef::from_rvalue_datum(
-                    meth::trans_object_shim(ccx, data.upcast_trait_ref.clone(), method_id, idx)
-                )
-            }
-            _ => {
-                tcx.sess.bug(&format!("static call to invalid vtable: {:?}", vtbl));
-            }
-        }
-   }
-}
-
-fn is_named_tuple_constructor(tcx: &TyCtxt, def_id: DefId) -> bool {
-    let node_id = match tcx.map.as_local_node_id(def_id) {
-        Some(n) => n,
-        None => { return false; }
-    };
-    match tcx.map.find(node_id).expect("local item should be in ast map") {
-        map::NodeVariant(v) => {
-            v.node.data.is_tuple()
-        }
-        map::NodeStructCtor(_) => true,
-        _ => false
-    }
-}
index 40dc22e31aa6c9a930fc005709156da7ccb5fb0e..4ad2e035945f3baaac56dbfaf2487732ece9a781 100644 (file)
@@ -196,7 +196,6 @@ fn arg_value_refs<'bcx, 'tcx>(bcx: &BlockAndBuilder<'bcx, 'tcx>,
 mod analyze;
 mod block;
 mod constant;
-mod did;
 mod drop;
 mod lvalue;
 mod operand;
index 541df43b49b9a19f32f0e9aeb95799ff75739def..ce10ed425f63afe92ff8b15425ee77910d5cc47e 100644 (file)
@@ -15,6 +15,7 @@
 
 use trans::asm;
 use trans::base;
+use trans::callee::Callee;
 use trans::common::{self, BlockAndBuilder, Result};
 use trans::debuginfo::DebugLoc;
 use trans::declare;
@@ -193,9 +194,20 @@ pub fn trans_rvalue_operand(&mut self,
                 let cast_ty = bcx.monomorphize(&cast_ty);
 
                 let val = match *kind {
-                    mir::CastKind::ReifyFnPointer |
+                    mir::CastKind::ReifyFnPointer => {
+                        match operand.ty.sty {
+                            ty::TyFnDef(def_id, substs, _) => {
+                                OperandValue::Immediate(
+                                    Callee::def(bcx.ccx(), def_id, substs, operand.ty)
+                                        .reify(bcx.ccx()).val)
+                            }
+                            _ => {
+                                unreachable!("{} cannot be reified to a fn ptr", operand.ty)
+                            }
+                        }
+                    }
                     mir::CastKind::UnsafeFnPointer => {
-                        // these are no-ops at the LLVM level
+                        // this is a no-op at the LLVM level
                         operand.val
                     }
                     mir::CastKind::Unsize => {
index 8b4ed9b87980d49a5bd89ec4d1d94162458bb274..b78bf9bfc3fb27f15552eb161f1c98e348acb7aa 100644 (file)
@@ -190,7 +190,8 @@ pub fn sizing_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>) -> Typ
             }
         }
 
-        ty::TyFnDef(..) | ty::TyFnPtr(_) => Type::i8p(cx),
+        ty::TyFnDef(..) => Type::nil(cx),
+        ty::TyFnPtr(_) => Type::i8p(cx),
 
         ty::TyArray(ty, size) => {
             let llty = sizing_type_of(cx, ty);
@@ -395,9 +396,8 @@ pub fn in_memory_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>) ->
       ty::TySlice(ty) => in_memory_type_of(cx, ty),
       ty::TyStr | ty::TyTrait(..) => Type::i8(cx),
 
-      ty::TyFnDef(_, _, ref f) | ty::TyFnPtr(ref f) => {
-        // FIXME(#19925) once fn item types are
-        // zero-sized, we'll need to do something here
+      ty::TyFnDef(..) => Type::nil(cx),
+      ty::TyFnPtr(f) => {
         if f.abi == Abi::Rust || f.abi == Abi::RustCall {
             let sig = cx.tcx().erase_late_bound_regions(&f.sig);
             let sig = infer::normalize_associated_type(cx.tcx(), &sig);