Skip to content

Commit 7312e0a

Browse files
committed
Auto merge of #30692 - michaelwoerister:mir-overloaded-fn-calls, r=nikomatsakis
So far, calls going through `Fn::call`, `FnMut::call_mut`, or `FnOnce::call_once` have not been translated properly into MIR: The call `f(a, b, c)` where `f: Fn(T1, T2, T3)` would end up in MIR as: ``` call `f` with arguments `a`, `b`, `c` ``` What we really want is: ``` call `Fn::call` with arguments `f`, `a`, `b`, `c` ``` This PR transforms these kinds of overloaded calls during `HIR -> HAIR` translation. What's still a bit funky is that the `Fn` traits expect arguments to be tupled but due to special handling type-checking and trans, we do not actually tuple arguments and everything still checks out fine. So, after this PR we end up with MIR containing calls where function signature and arguments seemingly don't match: ``` call Fn::call(&self, args: (T1, T2, T3)) with arguments `f`, `a`, `b`, `c` ``` instead of ``` call Fn::call(&self, args: (T1, T2, T3)) with arguments `f`, (`a`, `b`, `c`) // <- args tupled! ``` It would be nice if the call traits could go without special handling in MIR and later on.
2 parents dc1f442 + e281509 commit 7312e0a

File tree

4 files changed

+77
-5
lines changed

4 files changed

+77
-5
lines changed

src/librustc_mir/hair/cx/expr.rs

+20-2
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,26 @@ impl<'tcx> Mirror<'tcx> for &'tcx hir::Expr {
4646
}
4747
}
4848

49+
hir::ExprCall(ref fun, ref args) => {
50+
if cx.tcx.is_method_call(self.id) {
51+
// The callee is something implementing Fn, FnMut, or FnOnce.
52+
// Find the actual method implementation being called and
53+
// build the appropriate UFCS call expression with the
54+
// callee-object as self parameter.
55+
56+
let method = method_callee(cx, self, ty::MethodCall::expr(self.id));
57+
let mut argrefs = vec![fun.to_ref()];
58+
argrefs.extend(args.iter().map(|a| a.to_ref()));
59+
60+
ExprKind::Call {
61+
fun: method.to_ref(),
62+
args: argrefs,
63+
}
64+
} else {
65+
ExprKind::Call { fun: fun.to_ref(), args: args.to_ref() }
66+
}
67+
}
68+
4969
hir::ExprAddrOf(mutbl, ref expr) => {
5070
let region = match expr_ty.sty {
5171
ty::TyRef(r, _) => r,
@@ -328,8 +348,6 @@ impl<'tcx> Mirror<'tcx> for &'tcx hir::Expr {
328348
ExprKind::Vec { fields: fields.to_ref() },
329349
hir::ExprTup(ref fields) =>
330350
ExprKind::Tuple { fields: fields.to_ref() },
331-
hir::ExprCall(ref fun, ref args) =>
332-
ExprKind::Call { fun: fun.to_ref(), args: args.to_ref() },
333351
};
334352

335353
let temp_lifetime = cx.tcx.region_maps.temporary_scope(self.id);

src/librustc_trans/trans/mir/constant.rs

+4-2
Original file line numberDiff line numberDiff line change
@@ -89,8 +89,10 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
8989
{
9090
let ty = bcx.monomorphize(&constant.ty);
9191
match constant.literal {
92-
mir::Literal::Item { def_id, kind, substs } =>
93-
self.trans_item_ref(bcx, ty, kind, substs, def_id),
92+
mir::Literal::Item { def_id, kind, substs } => {
93+
let substs = bcx.tcx().mk_substs(bcx.monomorphize(&substs));
94+
self.trans_item_ref(bcx, ty, kind, substs, def_id)
95+
}
9496
mir::Literal::Value { ref value } => {
9597
self.trans_constval(bcx, value, ty)
9698
}

src/librustc_trans/trans/mir/did.rs

+27-1
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ use rustc::middle::traits;
2121
use rustc::mir::repr::ItemKind;
2222
use trans::common::{Block, fulfill_obligation};
2323
use trans::base;
24+
use trans::closure;
2425
use trans::expr;
2526
use trans::monomorphize;
2627
use trans::meth;
@@ -38,6 +39,9 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
3839
substs: &'tcx Substs<'tcx>,
3940
did: DefId)
4041
-> OperandRef<'tcx> {
42+
debug!("trans_item_ref(ty={:?}, kind={:?}, substs={:?}, did={})",
43+
ty, kind, substs, bcx.tcx().item_path_str(did));
44+
4145
match kind {
4246
ItemKind::Function => self.trans_fn_ref(bcx, ty, substs, did),
4347
ItemKind::Method => match bcx.tcx().impl_or_trait_item(did).container() {
@@ -68,6 +72,9 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
6872
substs: &'tcx Substs<'tcx>,
6973
did: DefId)
7074
-> OperandRef<'tcx> {
75+
debug!("trans_fn_ref(ty={:?}, substs={:?}, did={})",
76+
ty, substs, bcx.tcx().item_path_str(did));
77+
7178
let did = inline::maybe_instantiate_inline(bcx.ccx(), did);
7279

7380
if !substs.types.is_empty() || is_named_tuple_constructor(bcx.tcx(), did) {
@@ -101,9 +108,14 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
101108
trait_id: DefId,
102109
substs: &'tcx Substs<'tcx>)
103110
-> OperandRef<'tcx> {
111+
debug!("trans_static_method(ty={:?}, method={}, trait={}, substs={:?})",
112+
ty,
113+
bcx.tcx().item_path_str(method_id),
114+
bcx.tcx().item_path_str(trait_id),
115+
substs);
116+
104117
let ccx = bcx.ccx();
105118
let tcx = bcx.tcx();
106-
let mname = tcx.item_name(method_id);
107119
let subst::SeparateVecsPerParamSpace {
108120
types: rcvr_type,
109121
selfs: rcvr_self,
@@ -118,6 +130,9 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
118130
match vtbl {
119131
traits::VtableImpl(traits::VtableImplData { impl_def_id, substs: imp_substs, .. }) => {
120132
assert!(!imp_substs.types.needs_infer());
133+
134+
let mname = tcx.item_name(method_id);
135+
121136
let subst::SeparateVecsPerParamSpace {
122137
types: impl_type,
123138
selfs: impl_self,
@@ -130,6 +145,17 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
130145
let mthsubsts = tcx.mk_substs(mth.substs);
131146
self.trans_fn_ref(bcx, ty, mthsubsts, mth.method.def_id)
132147
},
148+
traits::VtableClosure(data) => {
149+
let trait_closure_kind = bcx.tcx().lang_items.fn_trait_kind(trait_id).unwrap();
150+
let llfn = closure::trans_closure_method(bcx.ccx(),
151+
data.closure_def_id,
152+
data.substs,
153+
trait_closure_kind);
154+
OperandRef {
155+
ty: ty,
156+
val: OperandValue::Immediate(llfn)
157+
}
158+
},
133159
traits::VtableObject(ref data) => {
134160
let idx = traits::get_vtable_index_of_object_method(tcx, data, method_id);
135161
OperandRef::from_rvalue_datum(

src/test/run-pass/mir_trans_calls.rs

+26
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,26 @@ fn test8() -> isize {
9393
Two::two()
9494
}
9595

96+
#[rustc_mir]
97+
fn test_closure<F>(f: &F, x: i32, y: i32) -> i32
98+
where F: Fn(i32, i32) -> i32
99+
{
100+
f(x, y)
101+
}
102+
103+
#[rustc_mir]
104+
fn test_fn_object(f: &Fn(i32, i32) -> i32, x: i32, y: i32) -> i32 {
105+
f(x, y)
106+
}
107+
108+
#[rustc_mir]
109+
fn test_fn_impl(f: &&Fn(i32, i32) -> i32, x: i32, y: i32) -> i32 {
110+
// This call goes through the Fn implementation for &Fn provided in
111+
// core::ops::impls. It expands to a static Fn::call() that calls the
112+
// Fn::call() implemenation of the object shim underneath.
113+
f(x, y)
114+
}
115+
96116
fn main() {
97117
assert_eq!(test1(1, (2, 3), &[4, 5, 6]), (1, (2, 3), &[4, 5, 6][..]));
98118
assert_eq!(test2(98), 98);
@@ -103,4 +123,10 @@ fn main() {
103123
// assert_eq!(test6(&Foo, 12367), 12367);
104124
assert_eq!(test7(), 1);
105125
assert_eq!(test8(), 2);
126+
127+
let closure = |x: i32, y: i32| { x + y };
128+
assert_eq!(test_closure(&closure, 100, 1), 101);
129+
let function_object = &closure as &Fn(i32, i32) -> i32;
130+
assert_eq!(test_fn_object(function_object, 100, 2), 102);
131+
assert_eq!(test_fn_impl(&function_object, 100, 3), 103);
106132
}

0 commit comments

Comments
 (0)