]> git.proxmox.com Git - rustc.git/blob - src/librustc_typeck/check/callee.rs
Merge tag 'upstream/1.5.0+dfsg1'
[rustc.git] / src / librustc_typeck / check / callee.rs
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.
4 //
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.
10
11 use super::autoderef;
12 use super::check_argument_types;
13 use super::check_expr;
14 use super::check_method_argument_types;
15 use super::demand;
16 use super::DeferredCallResolution;
17 use super::err_args;
18 use super::Expectation;
19 use super::expected_types_for_fn_args;
20 use super::FnCtxt;
21 use super::method;
22 use super::structurally_resolved_type;
23 use super::TupleArgumentsFlag;
24 use super::UnresolvedTypeAction;
25 use super::write_call;
26
27 use CrateCtxt;
28 use metadata::cstore::LOCAL_CRATE;
29 use middle::def_id::DefId;
30 use middle::infer;
31 use middle::ty::{self, LvaluePreference, Ty};
32 use syntax::codemap::Span;
33 use syntax::parse::token;
34 use syntax::ptr::P;
35
36 use rustc_front::hir;
37
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: DefId) {
42 let tcx = ccx.tcx;
43 let did = Some(trait_id);
44 let li = &tcx.lang_items;
45
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
51 // restrictions.
52
53 let method = if did == li.fn_trait() {
54 "call"
55 } else if did == li.fn_mut_trait() {
56 "call_mut"
57 } else if did == li.fn_once_trait() {
58 "call_once"
59 } else {
60 return // not a closure method, everything is OK.
61 };
62
63 span_err!(tcx.sess, span, E0174,
64 "explicit use of unboxed closure method `{}` is experimental",
65 method);
66 fileline_help!(tcx.sess, span,
67 "add `#![feature(unboxed_closures)]` to the crate attributes to enable");
68 }
69 }
70
71 pub fn check_call<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
72 call_expr: &'tcx hir::Expr,
73 callee_expr: &'tcx hir::Expr,
74 arg_exprs: &'tcx [P<hir::Expr>],
75 expected: Expectation<'tcx>)
76 {
77 check_expr(fcx, callee_expr);
78 let original_callee_ty = fcx.expr_ty(callee_expr);
79 let (callee_ty, _, result) =
80 autoderef(fcx,
81 callee_expr.span,
82 original_callee_ty,
83 Some(callee_expr),
84 UnresolvedTypeAction::Error,
85 LvaluePreference::NoPreference,
86 |adj_ty, idx| {
87 try_overloaded_call_step(fcx, call_expr, callee_expr, adj_ty, idx)
88 });
89
90 match result {
91 None => {
92 // this will report an error since original_callee_ty is not a fn
93 confirm_builtin_call(fcx, call_expr, original_callee_ty, arg_exprs, expected);
94 }
95
96 Some(CallStep::Builtin) => {
97 confirm_builtin_call(fcx, call_expr, callee_ty, arg_exprs, expected);
98 }
99
100 Some(CallStep::DeferredClosure(fn_sig)) => {
101 confirm_deferred_closure_call(fcx, call_expr, arg_exprs, expected, fn_sig);
102 }
103
104 Some(CallStep::Overloaded(method_callee)) => {
105 confirm_overloaded_call(fcx, call_expr, callee_expr,
106 arg_exprs, expected, method_callee);
107 }
108 }
109 }
110
111 enum CallStep<'tcx> {
112 Builtin,
113 DeferredClosure(ty::FnSig<'tcx>),
114 Overloaded(ty::MethodCallee<'tcx>)
115 }
116
117 fn try_overloaded_call_step<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
118 call_expr: &'tcx hir::Expr,
119 callee_expr: &'tcx hir::Expr,
120 adjusted_ty: Ty<'tcx>,
121 autoderefs: usize)
122 -> Option<CallStep<'tcx>>
123 {
124 debug!("try_overloaded_call_step(call_expr={:?}, adjusted_ty={:?}, autoderefs={})",
125 call_expr,
126 adjusted_ty,
127 autoderefs);
128
129 // If the callee is a bare function or a closure, then we're all set.
130 match structurally_resolved_type(fcx, callee_expr.span, adjusted_ty).sty {
131 ty::TyBareFn(..) => {
132 fcx.write_autoderef_adjustment(callee_expr.id, autoderefs);
133 return Some(CallStep::Builtin);
134 }
135
136 ty::TyClosure(def_id, ref substs) => {
137 assert_eq!(def_id.krate, LOCAL_CRATE);
138
139 // Check whether this is a call to a closure where we
140 // haven't yet decided on whether the closure is fn vs
141 // fnmut vs fnonce. If so, we have to defer further processing.
142 if fcx.infcx().closure_kind(def_id).is_none() {
143 let closure_ty =
144 fcx.infcx().closure_type(def_id, substs);
145 let fn_sig =
146 fcx.infcx().replace_late_bound_regions_with_fresh_var(call_expr.span,
147 infer::FnCall,
148 &closure_ty.sig).0;
149 fcx.record_deferred_call_resolution(def_id, Box::new(CallResolution {
150 call_expr: call_expr,
151 callee_expr: callee_expr,
152 adjusted_ty: adjusted_ty,
153 autoderefs: autoderefs,
154 fn_sig: fn_sig.clone(),
155 closure_def_id: def_id
156 }));
157 return Some(CallStep::DeferredClosure(fn_sig));
158 }
159 }
160
161 // Hack: we know that there are traits implementing Fn for &F
162 // where F:Fn and so forth. In the particular case of types
163 // like `x: &mut FnMut()`, if there is a call `x()`, we would
164 // normally translate to `FnMut::call_mut(&mut x, ())`, but
165 // that winds up requiring `mut x: &mut FnMut()`. A little
166 // over the top. The simplest fix by far is to just ignore
167 // this case and deref again, so we wind up with
168 // `FnMut::call_mut(&mut *x, ())`.
169 ty::TyRef(..) if autoderefs == 0 => {
170 return None;
171 }
172
173 _ => {}
174 }
175
176 try_overloaded_call_traits(fcx, call_expr, callee_expr, adjusted_ty, autoderefs)
177 .map(|method_callee| CallStep::Overloaded(method_callee))
178 }
179
180 fn try_overloaded_call_traits<'a,'tcx>(fcx: &FnCtxt<'a, 'tcx>,
181 call_expr: &hir::Expr,
182 callee_expr: &hir::Expr,
183 adjusted_ty: Ty<'tcx>,
184 autoderefs: usize)
185 -> Option<ty::MethodCallee<'tcx>>
186 {
187 // Try the options that are least restrictive on the caller first.
188 for &(opt_trait_def_id, method_name) in &[
189 (fcx.tcx().lang_items.fn_trait(), token::intern("call")),
190 (fcx.tcx().lang_items.fn_mut_trait(), token::intern("call_mut")),
191 (fcx.tcx().lang_items.fn_once_trait(), token::intern("call_once")),
192 ] {
193 let trait_def_id = match opt_trait_def_id {
194 Some(def_id) => def_id,
195 None => continue,
196 };
197
198 match method::lookup_in_trait_adjusted(fcx,
199 call_expr.span,
200 Some(&*callee_expr),
201 method_name,
202 trait_def_id,
203 autoderefs,
204 false,
205 adjusted_ty,
206 None) {
207 None => continue,
208 Some(method_callee) => {
209 return Some(method_callee);
210 }
211 }
212 }
213
214 None
215 }
216
217 fn confirm_builtin_call<'a,'tcx>(fcx: &FnCtxt<'a,'tcx>,
218 call_expr: &hir::Expr,
219 callee_ty: Ty<'tcx>,
220 arg_exprs: &'tcx [P<hir::Expr>],
221 expected: Expectation<'tcx>)
222 {
223 let error_fn_sig;
224
225 let fn_sig = match callee_ty.sty {
226 ty::TyBareFn(_, &ty::BareFnTy {ref sig, ..}) => {
227 sig
228 }
229 _ => {
230 fcx.type_error_message(call_expr.span, |actual| {
231 format!("expected function, found `{}`", actual)
232 }, callee_ty, None);
233
234 // This is the "default" function signature, used in case of error.
235 // In that case, we check each argument against "error" in order to
236 // set up all the node type bindings.
237 error_fn_sig = ty::Binder(ty::FnSig {
238 inputs: err_args(fcx.tcx(), arg_exprs.len()),
239 output: ty::FnConverging(fcx.tcx().types.err),
240 variadic: false
241 });
242
243 &error_fn_sig
244 }
245 };
246
247 // Replace any late-bound regions that appear in the function
248 // signature with region variables. We also have to
249 // renormalize the associated types at this point, since they
250 // previously appeared within a `Binder<>` and hence would not
251 // have been normalized before.
252 let fn_sig =
253 fcx.infcx().replace_late_bound_regions_with_fresh_var(call_expr.span,
254 infer::FnCall,
255 fn_sig).0;
256 let fn_sig =
257 fcx.normalize_associated_types_in(call_expr.span, &fn_sig);
258
259 // Call the generic checker.
260 let expected_arg_tys = expected_types_for_fn_args(fcx,
261 call_expr.span,
262 expected,
263 fn_sig.output,
264 &fn_sig.inputs);
265 check_argument_types(fcx,
266 call_expr.span,
267 &fn_sig.inputs,
268 &expected_arg_tys[..],
269 arg_exprs,
270 fn_sig.variadic,
271 TupleArgumentsFlag::DontTupleArguments);
272
273 write_call(fcx, call_expr, fn_sig.output);
274 }
275
276 fn confirm_deferred_closure_call<'a,'tcx>(fcx: &FnCtxt<'a,'tcx>,
277 call_expr: &hir::Expr,
278 arg_exprs: &'tcx [P<hir::Expr>],
279 expected: Expectation<'tcx>,
280 fn_sig: ty::FnSig<'tcx>)
281 {
282 // `fn_sig` is the *signature* of the cosure being called. We
283 // don't know the full details yet (`Fn` vs `FnMut` etc), but we
284 // do know the types expected for each argument and the return
285 // type.
286
287 let expected_arg_tys =
288 expected_types_for_fn_args(fcx,
289 call_expr.span,
290 expected,
291 fn_sig.output.clone(),
292 &*fn_sig.inputs);
293
294 check_argument_types(fcx,
295 call_expr.span,
296 &*fn_sig.inputs,
297 &*expected_arg_tys,
298 arg_exprs,
299 fn_sig.variadic,
300 TupleArgumentsFlag::TupleArguments);
301
302 write_call(fcx, call_expr, fn_sig.output);
303 }
304
305 fn confirm_overloaded_call<'a,'tcx>(fcx: &FnCtxt<'a, 'tcx>,
306 call_expr: &hir::Expr,
307 callee_expr: &'tcx hir::Expr,
308 arg_exprs: &'tcx [P<hir::Expr>],
309 expected: Expectation<'tcx>,
310 method_callee: ty::MethodCallee<'tcx>)
311 {
312 let output_type =
313 check_method_argument_types(fcx,
314 call_expr.span,
315 method_callee.ty,
316 callee_expr,
317 arg_exprs,
318 TupleArgumentsFlag::TupleArguments,
319 expected);
320 write_call(fcx, call_expr, output_type);
321
322 write_overloaded_call_method_map(fcx, call_expr, method_callee);
323 }
324
325 fn write_overloaded_call_method_map<'a,'tcx>(fcx: &FnCtxt<'a, 'tcx>,
326 call_expr: &hir::Expr,
327 method_callee: ty::MethodCallee<'tcx>) {
328 let method_call = ty::MethodCall::expr(call_expr.id);
329 fcx.inh.tables.borrow_mut().method_map.insert(method_call, method_callee);
330 }
331
332 #[derive(Debug)]
333 struct CallResolution<'tcx> {
334 call_expr: &'tcx hir::Expr,
335 callee_expr: &'tcx hir::Expr,
336 adjusted_ty: Ty<'tcx>,
337 autoderefs: usize,
338 fn_sig: ty::FnSig<'tcx>,
339 closure_def_id: DefId,
340 }
341
342 impl<'tcx> DeferredCallResolution<'tcx> for CallResolution<'tcx> {
343 fn resolve<'a>(&mut self, fcx: &FnCtxt<'a,'tcx>) {
344 debug!("DeferredCallResolution::resolve() {:?}",
345 self);
346
347 // we should not be invoked until the closure kind has been
348 // determined by upvar inference
349 assert!(fcx.infcx().closure_kind(self.closure_def_id).is_some());
350
351 // We may now know enough to figure out fn vs fnmut etc.
352 match try_overloaded_call_traits(fcx, self.call_expr, self.callee_expr,
353 self.adjusted_ty, self.autoderefs) {
354 Some(method_callee) => {
355 // One problem is that when we get here, we are going
356 // to have a newly instantiated function signature
357 // from the call trait. This has to be reconciled with
358 // the older function signature we had before. In
359 // principle we *should* be able to fn_sigs(), but we
360 // can't because of the annoying need for a TypeTrace.
361 // (This always bites me, should find a way to
362 // refactor it.)
363 let method_sig = fcx.tcx().no_late_bound_regions(method_callee.ty.fn_sig())
364 .unwrap();
365
366 debug!("attempt_resolution: method_callee={:?}",
367 method_callee);
368
369 for (&method_arg_ty, &self_arg_ty) in
370 method_sig.inputs[1..].iter().zip(&self.fn_sig.inputs)
371 {
372 demand::eqtype(fcx, self.call_expr.span, self_arg_ty, method_arg_ty);
373 }
374
375 let nilty = fcx.tcx().mk_nil();
376 demand::eqtype(fcx,
377 self.call_expr.span,
378 method_sig.output.unwrap_or(nilty),
379 self.fn_sig.output.unwrap_or(nilty));
380
381 write_overloaded_call_method_map(fcx, self.call_expr, method_callee);
382 }
383 None => {
384 fcx.tcx().sess.span_bug(
385 self.call_expr.span,
386 "failed to find an overloaded call trait for closure call");
387 }
388 }
389 }
390 }