1 // Copyright 2014 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
12 use super::AutorefArgs;
13 use super::check_argument_types;
14 use super::check_expr;
15 use super::check_method_argument_types;
17 use super::DeferredCallResolution;
19 use super::Expectation;
20 use super::expected_types_for_fn_args;
22 use super::LvaluePreference;
24 use super::structurally_resolved_type;
25 use super::TupleArgumentsFlag;
26 use super::UnresolvedTypeAction;
27 use super::write_call;
31 use middle::ty::{self, Ty, ClosureTyper};
33 use syntax::codemap::Span;
34 use syntax::parse::token;
36 use util::ppaux::Repr;
38 /// Check that it is legal to call methods of the trait corresponding
39 /// to `trait_id` (this only cares about the trait, not the specific
40 /// method that is called)
41 pub fn check_legal_trait_for_method_call(ccx: &CrateCtxt, span: Span, trait_id: ast::DefId) {
43 let did = Some(trait_id);
44 let li = &tcx.lang_items;
46 if did == li.drop_trait() {
47 span_err!(tcx.sess, span, E0040, "explicit use of destructor method");
48 } else if !tcx.sess.features.borrow().unboxed_closures {
49 // the #[feature(unboxed_closures)] feature isn't
50 // activated so we need to enforce the closure
53 let method = if did == li.fn_trait() {
55 } else if did == li.fn_mut_trait() {
57 } else if did == li.fn_once_trait() {
60 return // not a closure method, everything is OK.
63 span_err!(tcx.sess, span, E0174,
64 "explicit use of unboxed closure method `{}` is experimental",
66 span_help!(tcx.sess, span,
67 "add `#![feature(unboxed_closures)]` to the crate attributes to enable");
71 pub fn check_call<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
72 call_expr: &'tcx ast::Expr,
73 callee_expr: &'tcx ast::Expr,
74 arg_exprs: &'tcx [P<ast::Expr>],
75 expected: Expectation<'tcx>)
77 check_expr(fcx, callee_expr);
78 let original_callee_ty = fcx.expr_ty(callee_expr);
79 let (callee_ty, _, result) =
84 UnresolvedTypeAction::Error,
85 LvaluePreference::NoPreference,
87 let autoderefref = ty::AutoDerefRef { autoderefs: idx, autoref: None };
88 try_overloaded_call_step(fcx, call_expr, callee_expr,
94 // this will report an error since original_callee_ty is not a fn
95 confirm_builtin_call(fcx, call_expr, original_callee_ty, arg_exprs, expected);
98 Some(CallStep::Builtin) => {
99 confirm_builtin_call(fcx, call_expr, callee_ty, arg_exprs, expected);
102 Some(CallStep::DeferredClosure(fn_sig)) => {
103 confirm_deferred_closure_call(fcx, call_expr, arg_exprs, expected, fn_sig);
106 Some(CallStep::Overloaded(method_callee)) => {
107 confirm_overloaded_call(fcx, call_expr, callee_expr,
108 arg_exprs, expected, method_callee);
113 enum CallStep<'tcx> {
115 DeferredClosure(ty::FnSig<'tcx>),
116 Overloaded(ty::MethodCallee<'tcx>)
119 fn try_overloaded_call_step<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
120 call_expr: &'tcx ast::Expr,
121 callee_expr: &'tcx ast::Expr,
122 adjusted_ty: Ty<'tcx>,
123 autoderefref: ty::AutoDerefRef<'tcx>)
124 -> Option<CallStep<'tcx>>
126 debug!("try_overloaded_call_step(call_expr={}, adjusted_ty={}, autoderefref={})",
127 call_expr.repr(fcx.tcx()),
128 adjusted_ty.repr(fcx.tcx()),
129 autoderefref.repr(fcx.tcx()));
131 // If the callee is a bare function or a closure, then we're all set.
132 match structurally_resolved_type(fcx, callee_expr.span, adjusted_ty).sty {
133 ty::ty_bare_fn(..) => {
134 fcx.write_adjustment(callee_expr.id,
136 ty::AdjustDerefRef(autoderefref));
137 return Some(CallStep::Builtin);
140 ty::ty_closure(def_id, _, substs) => {
141 assert_eq!(def_id.krate, ast::LOCAL_CRATE);
143 // Check whether this is a call to a closure where we
144 // haven't yet decided on whether the closure is fn vs
145 // fnmut vs fnonce. If so, we have to defer further processing.
146 if fcx.closure_kind(def_id).is_none() {
148 fcx.closure_type(def_id, substs);
150 fcx.infcx().replace_late_bound_regions_with_fresh_var(call_expr.span,
153 fcx.record_deferred_call_resolution(
155 box CallResolution {call_expr: call_expr,
156 callee_expr: callee_expr,
157 adjusted_ty: adjusted_ty,
158 autoderefref: autoderefref,
159 fn_sig: fn_sig.clone(),
160 closure_def_id: def_id});
161 return Some(CallStep::DeferredClosure(fn_sig));
168 try_overloaded_call_traits(fcx, call_expr, callee_expr, adjusted_ty, autoderefref)
169 .map(|method_callee| CallStep::Overloaded(method_callee))
172 fn try_overloaded_call_traits<'a,'tcx>(fcx: &FnCtxt<'a, 'tcx>,
173 call_expr: &ast::Expr,
174 callee_expr: &ast::Expr,
175 adjusted_ty: Ty<'tcx>,
176 autoderefref: ty::AutoDerefRef<'tcx>)
177 -> Option<ty::MethodCallee<'tcx>>
179 // Try the options that are least restrictive on the caller first.
180 for &(opt_trait_def_id, method_name) in [
181 (fcx.tcx().lang_items.fn_trait(), token::intern("call")),
182 (fcx.tcx().lang_items.fn_mut_trait(), token::intern("call_mut")),
183 (fcx.tcx().lang_items.fn_once_trait(), token::intern("call_once")),
185 let trait_def_id = match opt_trait_def_id {
186 Some(def_id) => def_id,
190 match method::lookup_in_trait_adjusted(fcx,
195 autoderefref.clone(),
199 Some(method_callee) => {
200 return Some(method_callee);
208 fn confirm_builtin_call<'a,'tcx>(fcx: &FnCtxt<'a,'tcx>,
209 call_expr: &ast::Expr,
211 arg_exprs: &'tcx [P<ast::Expr>],
212 expected: Expectation<'tcx>)
216 let fn_sig = match callee_ty.sty {
217 ty::ty_bare_fn(_, &ty::BareFnTy {ref sig, ..}) => {
221 fcx.type_error_message(call_expr.span, |actual| {
222 format!("expected function, found `{}`", actual)
225 // This is the "default" function signature, used in case of error.
226 // In that case, we check each argument against "error" in order to
227 // set up all the node type bindings.
228 error_fn_sig = ty::Binder(ty::FnSig {
229 inputs: err_args(fcx.tcx(), arg_exprs.len()),
230 output: ty::FnConverging(fcx.tcx().types.err),
238 // Replace any late-bound regions that appear in the function
239 // signature with region variables. We also have to
240 // renormalize the associated types at this point, since they
241 // previously appeared within a `Binder<>` and hence would not
242 // have been normalized before.
244 fcx.infcx().replace_late_bound_regions_with_fresh_var(call_expr.span,
248 fcx.normalize_associated_types_in(call_expr.span, &fn_sig);
250 // Call the generic checker.
251 let expected_arg_tys = expected_types_for_fn_args(fcx,
256 check_argument_types(fcx,
263 TupleArgumentsFlag::DontTupleArguments);
265 write_call(fcx, call_expr, fn_sig.output);
268 fn confirm_deferred_closure_call<'a,'tcx>(fcx: &FnCtxt<'a,'tcx>,
269 call_expr: &ast::Expr,
270 arg_exprs: &'tcx [P<ast::Expr>],
271 expected: Expectation<'tcx>,
272 fn_sig: ty::FnSig<'tcx>)
274 // `fn_sig` is the *signature* of the cosure being called. We
275 // don't know the full details yet (`Fn` vs `FnMut` etc), but we
276 // do know the types expected for each argument and the return
279 let expected_arg_tys =
280 expected_types_for_fn_args(fcx,
283 fn_sig.output.clone(),
286 check_argument_types(fcx,
293 TupleArgumentsFlag::TupleArguments);
295 write_call(fcx, call_expr, fn_sig.output);
298 fn confirm_overloaded_call<'a,'tcx>(fcx: &FnCtxt<'a, 'tcx>,
299 call_expr: &ast::Expr,
300 callee_expr: &'tcx ast::Expr,
301 arg_exprs: &'tcx [P<ast::Expr>],
302 expected: Expectation<'tcx>,
303 method_callee: ty::MethodCallee<'tcx>)
306 check_method_argument_types(fcx,
312 TupleArgumentsFlag::TupleArguments,
314 write_call(fcx, call_expr, output_type);
316 write_overloaded_call_method_map(fcx, call_expr, method_callee);
319 fn write_overloaded_call_method_map<'a,'tcx>(fcx: &FnCtxt<'a, 'tcx>,
320 call_expr: &ast::Expr,
321 method_callee: ty::MethodCallee<'tcx>) {
322 let method_call = ty::MethodCall::expr(call_expr.id);
323 fcx.inh.method_map.borrow_mut().insert(method_call, method_callee);
326 struct CallResolution<'tcx> {
327 call_expr: &'tcx ast::Expr,
328 callee_expr: &'tcx ast::Expr,
329 adjusted_ty: Ty<'tcx>,
330 autoderefref: ty::AutoDerefRef<'tcx>,
331 fn_sig: ty::FnSig<'tcx>,
332 closure_def_id: ast::DefId,
335 impl<'tcx> Repr<'tcx> for CallResolution<'tcx> {
336 fn repr(&self, tcx: &ty::ctxt<'tcx>) -> String {
337 format!("CallResolution(call_expr={}, callee_expr={}, adjusted_ty={}, \
338 autoderefref={}, fn_sig={}, closure_def_id={})",
339 self.call_expr.repr(tcx),
340 self.callee_expr.repr(tcx),
341 self.adjusted_ty.repr(tcx),
342 self.autoderefref.repr(tcx),
343 self.fn_sig.repr(tcx),
344 self.closure_def_id.repr(tcx))
348 impl<'tcx> DeferredCallResolution<'tcx> for CallResolution<'tcx> {
349 fn resolve<'a>(&mut self, fcx: &FnCtxt<'a,'tcx>) {
350 debug!("DeferredCallResolution::resolve() {}",
351 self.repr(fcx.tcx()));
353 // we should not be invoked until the closure kind has been
354 // determined by upvar inference
355 assert!(fcx.closure_kind(self.closure_def_id).is_some());
357 // We may now know enough to figure out fn vs fnmut etc.
358 match try_overloaded_call_traits(fcx, self.call_expr, self.callee_expr,
359 self.adjusted_ty, self.autoderefref.clone()) {
360 Some(method_callee) => {
361 // One problem is that when we get here, we are going
362 // to have a newly instantiated function signature
363 // from the call trait. This has to be reconciled with
364 // the older function signature we had before. In
365 // principle we *should* be able to fn_sigs(), but we
366 // can't because of the annoying need for a TypeTrace.
367 // (This always bites me, should find a way to
370 ty::assert_no_late_bound_regions(fcx.tcx(),
371 ty::ty_fn_sig(method_callee.ty));
373 debug!("attempt_resolution: method_callee={}",
374 method_callee.repr(fcx.tcx()));
376 for (&method_arg_ty, &self_arg_ty) in
377 method_sig.inputs[1..].iter().zip(self.fn_sig.inputs.iter())
379 demand::eqtype(fcx, self.call_expr.span, self_arg_ty, method_arg_ty);
384 method_sig.output.unwrap(),
385 self.fn_sig.output.unwrap());
387 write_overloaded_call_method_map(fcx, self.call_expr, method_callee);
390 fcx.tcx().sess.span_bug(
392 "failed to find an overloaded call trait for closure call");