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;
18 use super::LvaluePreference;
20 use super::structurally_resolved_type;
21 use super::TupleArgumentsFlag;
22 use super::write_call;
25 use middle::ty::{self, Ty};
27 use syntax::codemap::Span;
28 use syntax::parse::token;
32 /// Check that it is legal to call methods of the trait corresponding
33 /// to `trait_id` (this only cares about the trait, not the specific
34 /// method that is called)
35 pub fn check_legal_trait_for_method_call(ccx: &CrateCtxt, span: Span, trait_id: ast::DefId) {
37 let did = Some(trait_id);
38 let li = &tcx.lang_items;
40 if did == li.drop_trait() {
41 span_err!(tcx.sess, span, E0040, "explicit use of destructor method");
42 } else if !tcx.sess.features.borrow().unboxed_closures {
43 // the #[feature(unboxed_closures)] feature isn't
44 // activated so we need to enforce the closure
47 let method = if did == li.fn_trait() {
49 } else if did == li.fn_mut_trait() {
51 } else if did == li.fn_once_trait() {
54 return // not a closure method, everything is OK.
57 span_err!(tcx.sess, span, E0174,
58 "explicit use of unboxed closure method `{}` is experimental",
60 span_help!(tcx.sess, span,
61 "add `#![feature(unboxed_closures)]` to the crate attributes to enable");
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>])
70 check_expr(fcx, callee_expr);
71 let original_callee_ty = fcx.expr_ty(callee_expr);
72 let (callee_ty, _, result) =
77 LvaluePreference::NoPreference,
79 let autoderefref = ty::AutoDerefRef { autoderefs: idx, autoref: None };
80 try_overloaded_call_step(fcx, call_expr, callee_expr,
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);
90 Some(CallStep::Builtin) => {
91 confirm_builtin_call(fcx, call_expr, callee_ty, arg_exprs);
94 Some(CallStep::Overloaded(method_callee)) => {
95 confirm_overloaded_call(fcx, call_expr, arg_exprs, method_callee);
100 enum CallStep<'tcx> {
102 Overloaded(ty::MethodCallee<'tcx>)
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>>
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,
117 ty::AdjustDerefRef(autoderefref));
118 return Some(CallStep::Builtin);
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")),
130 let trait_def_id = match opt_trait_def_id {
131 Some(def_id) => def_id,
135 match method::lookup_in_trait_adjusted(fcx,
140 autoderefref.clone(),
144 Some(method_callee) => {
145 return Some(CallStep::Overloaded(method_callee));
153 fn confirm_builtin_call<'a,'tcx>(fcx: &FnCtxt<'a,'tcx>,
154 call_expr: &ast::Expr,
156 arg_exprs: &[P<ast::Expr>])
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, ..}) => {
166 fcx.type_error_message(call_expr.span, |actual| {
167 format!("expected function, found `{}`", actual)
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),
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.
189 fcx.infcx().replace_late_bound_regions_with_fresh_var(call_expr.span,
193 fcx.normalize_associated_types_in(call_expr.span, &fn_sig);
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,
200 arg_exprs.as_slice(),
203 TupleArgumentsFlag::DontTupleArguments);
205 write_call(fcx, call_expr, fn_sig.output);
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>)
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,
218 arg_exprs.as_slice(),
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);