From 04b6c4939b6e292b477303f0b970865296f6467d Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Mon, 4 Jan 2016 06:08:11 -0500 Subject: [PATCH] [MIR] Handle overloaded call expressions during HIR -> HAIR translation. --- src/librustc_mir/hair/cx/expr.rs | 22 ++++++++++++++++++++-- src/test/run-pass/mir_trans_calls.rs | 17 +++++++++++++++++ 2 files changed, 37 insertions(+), 2 deletions(-) diff --git a/src/librustc_mir/hair/cx/expr.rs b/src/librustc_mir/hair/cx/expr.rs index ce78a39d599a5..aa6257345fe44 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/test/run-pass/mir_trans_calls.rs b/src/test/run-pass/mir_trans_calls.rs index cf3d3d0720bcc..1ce0618daf36a 100644 --- a/src/test/run-pass/mir_trans_calls.rs +++ b/src/test/run-pass/mir_trans_calls.rs @@ -93,6 +93,19 @@ fn test8() -> isize { Two::two() } +#[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) +} + +#[rustc_mir] +fn test_fn_object(f: &Fn(i32, i32) -> i32, x: i32, y: i32) -> i32 { + 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 +116,8 @@ fn main() { // assert_eq!(test6(&Foo, 12367), 12367); assert_eq!(test7(), 1); assert_eq!(test8(), 2); + + let function_object = (&|x: i32, y: i32| { x + y }) as &Fn(i32, i32) -> i32; + assert_eq!(test_fn_object(function_object, 100, 1), 101); + assert_eq!(test_fn_impl(&function_object, 100, 2), 102); }