Skip to content

Commit 237c4fc

Browse files
committed
Make call notation use autoderef. Fixes rust-lang#18742.
1 parent 2aa86db commit 237c4fc

File tree

9 files changed

+268
-135
lines changed

9 files changed

+268
-135
lines changed

Diff for: src/librustc/middle/cfg/construct.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -509,7 +509,7 @@ impl<'a, 'tcx> CFGBuilder<'a, 'tcx> {
509509
let method_call = ty::MethodCall::expr(call_expr.id);
510510
let return_ty = ty::ty_fn_ret(match self.tcx.method_map.borrow().get(&method_call) {
511511
Some(method) => method.ty,
512-
None => ty::expr_ty(self.tcx, func_or_rcvr)
512+
None => ty::expr_ty_adjusted(self.tcx, func_or_rcvr)
513513
});
514514

515515
let func_or_rcvr_exit = self.expr(func_or_rcvr, pred);

Diff for: src/librustc/middle/liveness.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1149,7 +1149,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
11491149

11501150
ast::ExprCall(ref f, ref args) => {
11511151
let diverges = !self.ir.tcx.is_method_call(expr.id) && {
1152-
let t_ret = ty::ty_fn_ret(ty::expr_ty(self.ir.tcx, &**f));
1152+
let t_ret = ty::ty_fn_ret(ty::expr_ty_adjusted(self.ir.tcx, &**f));
11531153
t_ret == ty::FnDiverging
11541154
};
11551155
let succ = if diverges {

Diff for: src/librustc_trans/trans/callee.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -576,7 +576,7 @@ pub fn trans_call<'a, 'blk, 'tcx>(in_cx: Block<'blk, 'tcx>,
576576
let _icx = push_ctxt("trans_call");
577577
trans_call_inner(in_cx,
578578
Some(common::expr_info(call_ex)),
579-
expr_ty(in_cx, f),
579+
expr_ty_adjusted(in_cx, f),
580580
|cx, _| trans(cx, f),
581581
args,
582582
Some(dest)).bcx

Diff for: src/librustc_typeck/check/callee.rs

+179
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,25 @@
88
// option. This file may not be copied, modified, or distributed
99
// except according to those terms.
1010

11+
use super::autoderef;
12+
use super::AutorefArgs;
13+
use super::check_argument_types;
14+
use super::check_expr;
15+
use super::check_method_argument_types;
16+
use super::err_args;
17+
use super::FnCtxt;
18+
use super::LvaluePreference;
19+
use super::method;
20+
use super::structurally_resolved_type;
21+
use super::TupleArgumentsFlag;
22+
use super::write_call;
23+
24+
use middle::infer;
25+
use middle::ty::{mod, Ty};
1126
use syntax::ast;
1227
use syntax::codemap::Span;
28+
use syntax::parse::token;
29+
use syntax::ptr::P;
1330
use CrateCtxt;
1431

1532
/// Check that it is legal to call methods of the trait corresponding
@@ -44,3 +61,165 @@ pub fn check_legal_trait_for_method_call(ccx: &CrateCtxt, span: Span, trait_id:
4461
"add `#![feature(unboxed_closures)]` to the crate attributes to enable");
4562
}
4663
}
64+
65+
pub fn check_call<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
66+
call_expr: &ast::Expr,
67+
callee_expr: &ast::Expr,
68+
arg_exprs: &[P<ast::Expr>])
69+
{
70+
check_expr(fcx, callee_expr);
71+
let original_callee_ty = fcx.expr_ty(callee_expr);
72+
let (callee_ty, _, result) =
73+
autoderef(fcx,
74+
callee_expr.span,
75+
original_callee_ty,
76+
Some(callee_expr.id),
77+
LvaluePreference::NoPreference,
78+
|adj_ty, idx| {
79+
let autoderefref = ty::AutoDerefRef { autoderefs: idx, autoref: None };
80+
try_overloaded_call_step(fcx, call_expr, callee_expr,
81+
adj_ty, autoderefref)
82+
});
83+
84+
match result {
85+
None => {
86+
// this will report an error since original_callee_ty is not a fn
87+
confirm_builtin_call(fcx, call_expr, original_callee_ty, arg_exprs);
88+
}
89+
90+
Some(CallStep::Builtin) => {
91+
confirm_builtin_call(fcx, call_expr, callee_ty, arg_exprs);
92+
}
93+
94+
Some(CallStep::Overloaded(method_callee)) => {
95+
confirm_overloaded_call(fcx, call_expr, arg_exprs, method_callee);
96+
}
97+
}
98+
}
99+
100+
enum CallStep<'tcx> {
101+
Builtin,
102+
Overloaded(ty::MethodCallee<'tcx>)
103+
}
104+
105+
fn try_overloaded_call_step<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
106+
call_expr: &ast::Expr,
107+
callee_expr: &ast::Expr,
108+
adjusted_ty: Ty<'tcx>,
109+
autoderefref: ty::AutoDerefRef<'tcx>)
110+
-> Option<CallStep<'tcx>>
111+
{
112+
// If the callee is a bare function or a closure, then we're all set.
113+
match structurally_resolved_type(fcx, callee_expr.span, adjusted_ty).sty {
114+
ty::ty_bare_fn(..) | ty::ty_closure(_) => {
115+
fcx.write_adjustment(callee_expr.id,
116+
callee_expr.span,
117+
ty::AdjustDerefRef(autoderefref));
118+
return Some(CallStep::Builtin);
119+
}
120+
121+
_ => {}
122+
}
123+
124+
// Try the options that are least restrictive on the caller first.
125+
for &(opt_trait_def_id, method_name) in [
126+
(fcx.tcx().lang_items.fn_trait(), token::intern("call")),
127+
(fcx.tcx().lang_items.fn_mut_trait(), token::intern("call_mut")),
128+
(fcx.tcx().lang_items.fn_once_trait(), token::intern("call_once")),
129+
].iter() {
130+
let trait_def_id = match opt_trait_def_id {
131+
Some(def_id) => def_id,
132+
None => continue,
133+
};
134+
135+
match method::lookup_in_trait_adjusted(fcx,
136+
call_expr.span,
137+
Some(&*callee_expr),
138+
method_name,
139+
trait_def_id,
140+
autoderefref.clone(),
141+
adjusted_ty,
142+
None) {
143+
None => continue,
144+
Some(method_callee) => {
145+
return Some(CallStep::Overloaded(method_callee));
146+
}
147+
}
148+
}
149+
150+
None
151+
}
152+
153+
fn confirm_builtin_call<'a,'tcx>(fcx: &FnCtxt<'a,'tcx>,
154+
call_expr: &ast::Expr,
155+
callee_ty: Ty<'tcx>,
156+
arg_exprs: &[P<ast::Expr>])
157+
{
158+
let error_fn_sig;
159+
160+
let fn_sig = match callee_ty.sty {
161+
ty::ty_bare_fn(_, &ty::BareFnTy {ref sig, ..}) |
162+
ty::ty_closure(box ty::ClosureTy {ref sig, ..}) => {
163+
sig
164+
}
165+
_ => {
166+
fcx.type_error_message(call_expr.span, |actual| {
167+
format!("expected function, found `{}`", actual)
168+
}, callee_ty, None);
169+
170+
// This is the "default" function signature, used in case of error.
171+
// In that case, we check each argument against "error" in order to
172+
// set up all the node type bindings.
173+
error_fn_sig = ty::Binder(ty::FnSig {
174+
inputs: err_args(fcx.tcx(), arg_exprs.len()),
175+
output: ty::FnConverging(fcx.tcx().types.err),
176+
variadic: false
177+
});
178+
179+
&error_fn_sig
180+
}
181+
};
182+
183+
// Replace any late-bound regions that appear in the function
184+
// signature with region variables. We also have to
185+
// renormalize the associated types at this point, since they
186+
// previously appeared within a `Binder<>` and hence would not
187+
// have been normalized before.
188+
let fn_sig =
189+
fcx.infcx().replace_late_bound_regions_with_fresh_var(call_expr.span,
190+
infer::FnCall,
191+
fn_sig).0;
192+
let fn_sig =
193+
fcx.normalize_associated_types_in(call_expr.span, &fn_sig);
194+
195+
// Call the generic checker.
196+
let arg_exprs: Vec<_> = arg_exprs.iter().collect(); // for some weird reason we take &[&P<...>].
197+
check_argument_types(fcx,
198+
call_expr.span,
199+
fn_sig.inputs[],
200+
arg_exprs.as_slice(),
201+
AutorefArgs::No,
202+
fn_sig.variadic,
203+
TupleArgumentsFlag::DontTupleArguments);
204+
205+
write_call(fcx, call_expr, fn_sig.output);
206+
}
207+
208+
fn confirm_overloaded_call<'a,'tcx>(fcx: &FnCtxt<'a, 'tcx>,
209+
call_expr: &ast::Expr,
210+
arg_exprs: &[P<ast::Expr>],
211+
method_callee: ty::MethodCallee<'tcx>)
212+
{
213+
let arg_exprs: Vec<_> = arg_exprs.iter().collect(); // for some weird reason we take &[&P<...>].
214+
let output_type = check_method_argument_types(fcx,
215+
call_expr.span,
216+
method_callee.ty,
217+
call_expr,
218+
arg_exprs.as_slice(),
219+
AutorefArgs::No,
220+
TupleArgumentsFlag::TupleArguments);
221+
let method_call = ty::MethodCall::expr(call_expr.id);
222+
fcx.inh.method_map.borrow_mut().insert(method_call, method_callee);
223+
write_call(fcx, call_expr, output_type);
224+
}
225+

0 commit comments

Comments
 (0)