diff --git a/src/librustc_mir/hair/cx/expr.rs b/src/librustc_mir/hair/cx/expr.rs index ce78a39d599..aa6257345fe 100644 --- a/src/librustc_mir/hair/cx/expr.rs +++ b/src/librustc_mir/hair/cx/expr.rs @@ -46,6 +46,26 @@ impl<'tcx> Mirror<'tcx> for &'tcx hir::Expr { } } + hir::ExprCall(ref fun, ref args) => { + if cx.tcx.is_method_call(self.id) { + // The callee is something implementing Fn, FnMut, or FnOnce. + // Find the actual method implementation being called and + // build the appropriate UFCS call expression with the + // callee-object as self parameter. + + let method = method_callee(cx, self, ty::MethodCall::expr(self.id)); + let mut argrefs = vec![fun.to_ref()]; + argrefs.extend(args.iter().map(|a| a.to_ref())); + + ExprKind::Call { + fun: method.to_ref(), + args: argrefs, + } + } else { + ExprKind::Call { fun: fun.to_ref(), args: args.to_ref() } + } + } + hir::ExprAddrOf(mutbl, ref expr) => { let region = match expr_ty.sty { ty::TyRef(r, _) => r, @@ -328,8 +348,6 @@ impl<'tcx> Mirror<'tcx> for &'tcx hir::Expr { ExprKind::Vec { fields: fields.to_ref() }, hir::ExprTup(ref fields) => ExprKind::Tuple { fields: fields.to_ref() }, - hir::ExprCall(ref fun, ref args) => - ExprKind::Call { fun: fun.to_ref(), args: args.to_ref() }, }; let temp_lifetime = cx.tcx.region_maps.temporary_scope(self.id); diff --git a/src/librustc_trans/trans/mir/constant.rs b/src/librustc_trans/trans/mir/constant.rs index 12839df87b1..0f4a0407298 100644 --- a/src/librustc_trans/trans/mir/constant.rs +++ b/src/librustc_trans/trans/mir/constant.rs @@ -89,8 +89,10 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> { { let ty = bcx.monomorphize(&constant.ty); match constant.literal { - mir::Literal::Item { def_id, kind, substs } => - self.trans_item_ref(bcx, ty, kind, substs, def_id), + mir::Literal::Item { def_id, kind, substs } => { + let substs = bcx.tcx().mk_substs(bcx.monomorphize(&substs)); + self.trans_item_ref(bcx, ty, kind, substs, def_id) + } mir::Literal::Value { ref value } => { self.trans_constval(bcx, value, ty) } diff --git a/src/librustc_trans/trans/mir/did.rs b/src/librustc_trans/trans/mir/did.rs index d4a7a7c8b48..737c3dace2e 100644 --- a/src/librustc_trans/trans/mir/did.rs +++ b/src/librustc_trans/trans/mir/did.rs @@ -21,6 +21,7 @@ use rustc::middle::traits; use rustc::mir::repr::ItemKind; use trans::common::{Block, fulfill_obligation}; use trans::base; +use trans::closure; use trans::expr; use trans::monomorphize; use trans::meth; @@ -38,6 +39,9 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> { 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() { @@ -68,6 +72,9 @@ impl<'bcx, 'tcx> MirContext<'bcx, '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) { @@ -101,9 +108,14 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> { 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 mname = tcx.item_name(method_id); let subst::SeparateVecsPerParamSpace { types: rcvr_type, selfs: rcvr_self, @@ -118,6 +130,9 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> { match vtbl { traits::VtableImpl(traits::VtableImplData { impl_def_id, substs: imp_substs, .. }) => { assert!(!imp_substs.types.needs_infer()); + + let mname = tcx.item_name(method_id); + let subst::SeparateVecsPerParamSpace { types: impl_type, selfs: impl_self, @@ -130,6 +145,17 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> { let mthsubsts = tcx.mk_substs(mth.substs); self.trans_fn_ref(bcx, ty, mthsubsts, 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( diff --git a/src/test/run-pass/mir_trans_calls.rs b/src/test/run-pass/mir_trans_calls.rs index cf3d3d0720b..bd236e95d1c 100644 --- a/src/test/run-pass/mir_trans_calls.rs +++ b/src/test/run-pass/mir_trans_calls.rs @@ -93,6 +93,26 @@ fn test8() -> isize { Two::two() } +#[rustc_mir] +fn test_closure(f: &F, x: i32, y: i32) -> i32 + where F: Fn(i32, i32) -> i32 +{ + f(x, y) +} + +#[rustc_mir] +fn test_fn_object(f: &Fn(i32, i32) -> i32, x: i32, y: i32) -> i32 { + f(x, y) +} + +#[rustc_mir] +fn test_fn_impl(f: &&Fn(i32, i32) -> i32, x: i32, y: i32) -> i32 { + // This call goes through the Fn implementation for &Fn provided in + // core::ops::impls. It expands to a static Fn::call() that calls the + // Fn::call() implemenation of the object shim underneath. + f(x, y) +} + fn main() { assert_eq!(test1(1, (2, 3), &[4, 5, 6]), (1, (2, 3), &[4, 5, 6][..])); assert_eq!(test2(98), 98); @@ -103,4 +123,10 @@ fn main() { // assert_eq!(test6(&Foo, 12367), 12367); assert_eq!(test7(), 1); assert_eq!(test8(), 2); + + let closure = |x: i32, y: i32| { x + y }; + assert_eq!(test_closure(&closure, 100, 1), 101); + let function_object = &closure as &Fn(i32, i32) -> i32; + assert_eq!(test_fn_object(function_object, 100, 2), 102); + assert_eq!(test_fn_impl(&function_object, 100, 3), 103); }