From cdb10b884b3975dd897096e052f386f55cf0f4c9 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Tue, 31 Mar 2015 04:38:43 -0400 Subject: [PATCH] A very simple hack to force an autoderef if the callee has type `&mut F`, so that if we have `x: &mut FnMut()`, then `x()` is translated to `FnMut::call_mut(&mut *x, ())` rather than `&mut x`. The latter would require `mut x: &mut FnMut()`, which is really a lot of mut. (Actually, the `mut` is normally required except for the special case of a `&mut F` reference, because that's the one case where we distinguish a unique path like `x` from a mutable path.) --- src/librustc_typeck/check/callee.rs | 24 ++++++++++++++++++------ 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/src/librustc_typeck/check/callee.rs b/src/librustc_typeck/check/callee.rs index 31ac0a57ba0e..3f9c14e0afe3 100644 --- a/src/librustc_typeck/check/callee.rs +++ b/src/librustc_typeck/check/callee.rs @@ -83,9 +83,7 @@ pub fn check_call<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, UnresolvedTypeAction::Error, LvaluePreference::NoPreference, |adj_ty, idx| { - let autoderefref = ty::AutoDerefRef { autoderefs: idx, autoref: None }; - try_overloaded_call_step(fcx, call_expr, callee_expr, - adj_ty, autoderefref) + try_overloaded_call_step(fcx, call_expr, callee_expr, adj_ty, idx) }); match result { @@ -119,13 +117,15 @@ fn try_overloaded_call_step<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, call_expr: &'tcx ast::Expr, callee_expr: &'tcx ast::Expr, adjusted_ty: Ty<'tcx>, - autoderefref: ty::AutoDerefRef<'tcx>) + autoderefs: usize) -> Option> { - debug!("try_overloaded_call_step(call_expr={}, adjusted_ty={}, autoderefref={})", + debug!("try_overloaded_call_step(call_expr={}, adjusted_ty={}, autoderefs={})", call_expr.repr(fcx.tcx()), adjusted_ty.repr(fcx.tcx()), - autoderefref.repr(fcx.tcx())); + autoderefs); + + let autoderefref = ty::AutoDerefRef { autoderefs: autoderefs, autoref: None }; // If the callee is a bare function or a closure, then we're all set. match structurally_resolved_type(fcx, callee_expr.span, adjusted_ty).sty { @@ -161,6 +161,18 @@ fn try_overloaded_call_step<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, } } + // Hack: we know that there are traits implementing Fn for &F + // where F:Fn and so forth. In the particular case of types + // like `x: &mut FnMut()`, if there is a call `x()`, we would + // normally translate to `FnMut::call_mut(&mut x, ())`, but + // that winds up requiring `mut x: &mut FnMut()`. A little + // over the top. The simplest fix by far is to just ignore + // this case and deref again, so we wind up with + // `FnMut::call_mut(&mut *x, ())`. + ty::ty_rptr(..) if autoderefs == 0 => { + return None; + } + _ => {} }