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::check_argument_types;
13 use super::check_expr;
14 use super::check_method_argument_types;
16 use super::DeferredCallResolution;
18 use super::Expectation;
19 use super::expected_types_for_fn_args;
21 use super::LvaluePreference;
23 use super::structurally_resolved_type;
24 use super::TupleArgumentsFlag;
25 use super::UnresolvedTypeAction;
26 use super::write_call;
29 use middle::def_id::{DefId, LOCAL_CRATE};
31 use middle::ty::{self, Ty};
33 use syntax::codemap::Span;
34 use syntax::parse::token;
37 /// Check that it is legal to call methods of the trait corresponding
38 /// to `trait_id` (this only cares about the trait, not the specific
39 /// method that is called)
40 pub fn check_legal_trait_for_method_call(ccx: &CrateCtxt, span: Span, trait_id: DefId) {
42 let did = Some(trait_id);
43 let li = &tcx.lang_items;
45 if did == li.drop_trait() {
46 span_err!(tcx.sess, span, E0040, "explicit use of destructor method");
47 } else if !tcx.sess.features.borrow().unboxed_closures {
48 // the #[feature(unboxed_closures)] feature isn't
49 // activated so we need to enforce the closure
52 let method = if did == li.fn_trait() {
54 } else if did == li.fn_mut_trait() {
56 } else if did == li.fn_once_trait() {
59 return // not a closure method, everything is OK.
62 span_err!(tcx.sess, span, E0174,
63 "explicit use of unboxed closure method `{}` is experimental",
65 fileline_help!(tcx.sess, span,
66 "add `#![feature(unboxed_closures)]` to the crate attributes to enable");
70 pub fn check_call<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
71 call_expr: &'tcx ast::Expr,
72 callee_expr: &'tcx ast::Expr,
73 arg_exprs: &'tcx [P<ast::Expr>],
74 expected: Expectation<'tcx>)
76 check_expr(fcx, callee_expr);
77 let original_callee_ty = fcx.expr_ty(callee_expr);
78 let (callee_ty, _, result) =
83 UnresolvedTypeAction::Error,
84 LvaluePreference::NoPreference,
86 try_overloaded_call_step(fcx, call_expr, callee_expr, adj_ty, idx)
91 // this will report an error since original_callee_ty is not a fn
92 confirm_builtin_call(fcx, call_expr, original_callee_ty, arg_exprs, expected);
95 Some(CallStep::Builtin) => {
96 confirm_builtin_call(fcx, call_expr, callee_ty, arg_exprs, expected);
99 Some(CallStep::DeferredClosure(fn_sig)) => {
100 confirm_deferred_closure_call(fcx, call_expr, arg_exprs, expected, fn_sig);
103 Some(CallStep::Overloaded(method_callee)) => {
104 confirm_overloaded_call(fcx, call_expr, callee_expr,
105 arg_exprs, expected, method_callee);
110 enum CallStep<'tcx> {
112 DeferredClosure(ty::FnSig<'tcx>),
113 Overloaded(ty::MethodCallee<'tcx>)
116 fn try_overloaded_call_step<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
117 call_expr: &'tcx ast::Expr,
118 callee_expr: &'tcx ast::Expr,
119 adjusted_ty: Ty<'tcx>,
121 -> Option<CallStep<'tcx>>
123 debug!("try_overloaded_call_step(call_expr={:?}, adjusted_ty={:?}, autoderefs={})",
128 // If the callee is a bare function or a closure, then we're all set.
129 match structurally_resolved_type(fcx, callee_expr.span, adjusted_ty).sty {
130 ty::TyBareFn(..) => {
131 fcx.write_autoderef_adjustment(callee_expr.id, autoderefs);
132 return Some(CallStep::Builtin);
135 ty::TyClosure(def_id, ref substs) => {
136 assert_eq!(def_id.krate, LOCAL_CRATE);
138 // Check whether this is a call to a closure where we
139 // haven't yet decided on whether the closure is fn vs
140 // fnmut vs fnonce. If so, we have to defer further processing.
141 if fcx.infcx().closure_kind(def_id).is_none() {
143 fcx.infcx().closure_type(def_id, substs);
145 fcx.infcx().replace_late_bound_regions_with_fresh_var(call_expr.span,
148 fcx.record_deferred_call_resolution(def_id, Box::new(CallResolution {
149 call_expr: call_expr,
150 callee_expr: callee_expr,
151 adjusted_ty: adjusted_ty,
152 autoderefs: autoderefs,
153 fn_sig: fn_sig.clone(),
154 closure_def_id: def_id
156 return Some(CallStep::DeferredClosure(fn_sig));
160 // Hack: we know that there are traits implementing Fn for &F
161 // where F:Fn and so forth. In the particular case of types
162 // like `x: &mut FnMut()`, if there is a call `x()`, we would
163 // normally translate to `FnMut::call_mut(&mut x, ())`, but
164 // that winds up requiring `mut x: &mut FnMut()`. A little
165 // over the top. The simplest fix by far is to just ignore
166 // this case and deref again, so we wind up with
167 // `FnMut::call_mut(&mut *x, ())`.
168 ty::TyRef(..) if autoderefs == 0 => {
175 try_overloaded_call_traits(fcx, call_expr, callee_expr, adjusted_ty, autoderefs)
176 .map(|method_callee| CallStep::Overloaded(method_callee))
179 fn try_overloaded_call_traits<'a,'tcx>(fcx: &FnCtxt<'a, 'tcx>,
180 call_expr: &ast::Expr,
181 callee_expr: &ast::Expr,
182 adjusted_ty: Ty<'tcx>,
184 -> Option<ty::MethodCallee<'tcx>>
186 // Try the options that are least restrictive on the caller first.
187 for &(opt_trait_def_id, method_name) in &[
188 (fcx.tcx().lang_items.fn_trait(), token::intern("call")),
189 (fcx.tcx().lang_items.fn_mut_trait(), token::intern("call_mut")),
190 (fcx.tcx().lang_items.fn_once_trait(), token::intern("call_once")),
192 let trait_def_id = match opt_trait_def_id {
193 Some(def_id) => def_id,
197 match method::lookup_in_trait_adjusted(fcx,
207 Some(method_callee) => {
208 return Some(method_callee);
216 fn confirm_builtin_call<'a,'tcx>(fcx: &FnCtxt<'a,'tcx>,
217 call_expr: &ast::Expr,
219 arg_exprs: &'tcx [P<ast::Expr>],
220 expected: Expectation<'tcx>)
224 let fn_sig = match callee_ty.sty {
225 ty::TyBareFn(_, &ty::BareFnTy {ref sig, ..}) => {
229 fcx.type_error_message(call_expr.span, |actual| {
230 format!("expected function, found `{}`", actual)
233 // This is the "default" function signature, used in case of error.
234 // In that case, we check each argument against "error" in order to
235 // set up all the node type bindings.
236 error_fn_sig = ty::Binder(ty::FnSig {
237 inputs: err_args(fcx.tcx(), arg_exprs.len()),
238 output: ty::FnConverging(fcx.tcx().types.err),
246 // Replace any late-bound regions that appear in the function
247 // signature with region variables. We also have to
248 // renormalize the associated types at this point, since they
249 // previously appeared within a `Binder<>` and hence would not
250 // have been normalized before.
252 fcx.infcx().replace_late_bound_regions_with_fresh_var(call_expr.span,
256 fcx.normalize_associated_types_in(call_expr.span, &fn_sig);
258 // Call the generic checker.
259 let expected_arg_tys = expected_types_for_fn_args(fcx,
264 check_argument_types(fcx,
267 &expected_arg_tys[..],
270 TupleArgumentsFlag::DontTupleArguments);
272 write_call(fcx, call_expr, fn_sig.output);
275 fn confirm_deferred_closure_call<'a,'tcx>(fcx: &FnCtxt<'a,'tcx>,
276 call_expr: &ast::Expr,
277 arg_exprs: &'tcx [P<ast::Expr>],
278 expected: Expectation<'tcx>,
279 fn_sig: ty::FnSig<'tcx>)
281 // `fn_sig` is the *signature* of the cosure being called. We
282 // don't know the full details yet (`Fn` vs `FnMut` etc), but we
283 // do know the types expected for each argument and the return
286 let expected_arg_tys =
287 expected_types_for_fn_args(fcx,
290 fn_sig.output.clone(),
293 check_argument_types(fcx,
299 TupleArgumentsFlag::TupleArguments);
301 write_call(fcx, call_expr, fn_sig.output);
304 fn confirm_overloaded_call<'a,'tcx>(fcx: &FnCtxt<'a, 'tcx>,
305 call_expr: &ast::Expr,
306 callee_expr: &'tcx ast::Expr,
307 arg_exprs: &'tcx [P<ast::Expr>],
308 expected: Expectation<'tcx>,
309 method_callee: ty::MethodCallee<'tcx>)
312 check_method_argument_types(fcx,
317 TupleArgumentsFlag::TupleArguments,
319 write_call(fcx, call_expr, output_type);
321 write_overloaded_call_method_map(fcx, call_expr, method_callee);
324 fn write_overloaded_call_method_map<'a,'tcx>(fcx: &FnCtxt<'a, 'tcx>,
325 call_expr: &ast::Expr,
326 method_callee: ty::MethodCallee<'tcx>) {
327 let method_call = ty::MethodCall::expr(call_expr.id);
328 fcx.inh.tables.borrow_mut().method_map.insert(method_call, method_callee);
332 struct CallResolution<'tcx> {
333 call_expr: &'tcx ast::Expr,
334 callee_expr: &'tcx ast::Expr,
335 adjusted_ty: Ty<'tcx>,
337 fn_sig: ty::FnSig<'tcx>,
338 closure_def_id: DefId,
341 impl<'tcx> DeferredCallResolution<'tcx> for CallResolution<'tcx> {
342 fn resolve<'a>(&mut self, fcx: &FnCtxt<'a,'tcx>) {
343 debug!("DeferredCallResolution::resolve() {:?}",
346 // we should not be invoked until the closure kind has been
347 // determined by upvar inference
348 assert!(fcx.infcx().closure_kind(self.closure_def_id).is_some());
350 // We may now know enough to figure out fn vs fnmut etc.
351 match try_overloaded_call_traits(fcx, self.call_expr, self.callee_expr,
352 self.adjusted_ty, self.autoderefs) {
353 Some(method_callee) => {
354 // One problem is that when we get here, we are going
355 // to have a newly instantiated function signature
356 // from the call trait. This has to be reconciled with
357 // the older function signature we had before. In
358 // principle we *should* be able to fn_sigs(), but we
359 // can't because of the annoying need for a TypeTrace.
360 // (This always bites me, should find a way to
362 let method_sig = fcx.tcx().no_late_bound_regions(method_callee.ty.fn_sig())
365 debug!("attempt_resolution: method_callee={:?}",
368 for (&method_arg_ty, &self_arg_ty) in
369 method_sig.inputs[1..].iter().zip(&self.fn_sig.inputs)
371 demand::eqtype(fcx, self.call_expr.span, self_arg_ty, method_arg_ty);
374 let nilty = fcx.tcx().mk_nil();
377 method_sig.output.unwrap_or(nilty),
378 self.fn_sig.output.unwrap_or(nilty));
380 write_overloaded_call_method_map(fcx, self.call_expr, method_callee);
383 fcx.tcx().sess.span_bug(
385 "failed to find an overloaded call trait for closure call");