]> git.lizzy.rs Git - rust.git/blob - src/librustc_typeck/check/callee.rs
Rollup merge of #21964 - semarie:openbsd-env, r=alexcrichton
[rust.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::AutorefArgs;
13 use super::check_argument_types;
14 use super::check_expr;
15 use super::check_method_argument_types;
16 use super::demand;
17 use super::DeferredCallResolution;
18 use super::err_args;
19 use super::Expectation;
20 use super::expected_types_for_fn_args;
21 use super::FnCtxt;
22 use super::LvaluePreference;
23 use super::method;
24 use super::structurally_resolved_type;
25 use super::TupleArgumentsFlag;
26 use super::UnresolvedTypeAction;
27 use super::write_call;
28
29 use CrateCtxt;
30 use middle::infer;
31 use middle::ty::{self, Ty, ClosureTyper};
32 use syntax::ast;
33 use syntax::codemap::Span;
34 use syntax::parse::token;
35 use syntax::ptr::P;
36 use util::ppaux::Repr;
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: ast::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         span_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 ast::Expr,
73                             callee_expr: &'tcx ast::Expr,
74                             arg_exprs: &'tcx [P<ast::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                       let autoderefref = ty::AutoDerefRef { autoderefs: idx, autoref: None };
88                       try_overloaded_call_step(fcx, call_expr, callee_expr,
89                                                adj_ty, autoderefref)
90                   });
91
92     match result {
93         None => {
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);
96         }
97
98         Some(CallStep::Builtin) => {
99             confirm_builtin_call(fcx, call_expr, callee_ty, arg_exprs, expected);
100         }
101
102         Some(CallStep::DeferredClosure(fn_sig)) => {
103             confirm_deferred_closure_call(fcx, call_expr, arg_exprs, expected, fn_sig);
104         }
105
106         Some(CallStep::Overloaded(method_callee)) => {
107             confirm_overloaded_call(fcx, call_expr, callee_expr,
108                                     arg_exprs, expected, method_callee);
109         }
110     }
111 }
112
113 enum CallStep<'tcx> {
114     Builtin,
115     DeferredClosure(ty::FnSig<'tcx>),
116     Overloaded(ty::MethodCallee<'tcx>)
117 }
118
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>>
125 {
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()));
130
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,
135                                  callee_expr.span,
136                                  ty::AdjustDerefRef(autoderefref));
137             return Some(CallStep::Builtin);
138         }
139
140         ty::ty_closure(def_id, _, substs) => {
141             assert_eq!(def_id.krate, ast::LOCAL_CRATE);
142
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() {
147                 let closure_ty =
148                     fcx.closure_type(def_id, substs);
149                 let fn_sig =
150                     fcx.infcx().replace_late_bound_regions_with_fresh_var(call_expr.span,
151                                                                           infer::FnCall,
152                                                                           &closure_ty.sig).0;
153                 fcx.record_deferred_call_resolution(
154                     def_id,
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));
162             }
163         }
164
165         _ => {}
166     }
167
168     try_overloaded_call_traits(fcx, call_expr, callee_expr, adjusted_ty, autoderefref)
169         .map(|method_callee| CallStep::Overloaded(method_callee))
170 }
171
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>>
178 {
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")),
184     ].iter() {
185         let trait_def_id = match opt_trait_def_id {
186             Some(def_id) => def_id,
187             None => continue,
188         };
189
190         match method::lookup_in_trait_adjusted(fcx,
191                                                call_expr.span,
192                                                Some(&*callee_expr),
193                                                method_name,
194                                                trait_def_id,
195                                                autoderefref.clone(),
196                                                adjusted_ty,
197                                                None) {
198             None => continue,
199             Some(method_callee) => {
200                 return Some(method_callee);
201             }
202         }
203     }
204
205     None
206 }
207
208 fn confirm_builtin_call<'a,'tcx>(fcx: &FnCtxt<'a,'tcx>,
209                                  call_expr: &ast::Expr,
210                                  callee_ty: Ty<'tcx>,
211                                  arg_exprs: &'tcx [P<ast::Expr>],
212                                  expected: Expectation<'tcx>)
213 {
214     let error_fn_sig;
215
216     let fn_sig = match callee_ty.sty {
217         ty::ty_bare_fn(_, &ty::BareFnTy {ref sig, ..}) => {
218             sig
219         }
220         _ => {
221             fcx.type_error_message(call_expr.span, |actual| {
222                 format!("expected function, found `{}`", actual)
223             }, callee_ty, None);
224
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),
231                 variadic: false
232             });
233
234             &error_fn_sig
235         }
236     };
237
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.
243     let fn_sig =
244         fcx.infcx().replace_late_bound_regions_with_fresh_var(call_expr.span,
245                                                               infer::FnCall,
246                                                               fn_sig).0;
247     let fn_sig =
248         fcx.normalize_associated_types_in(call_expr.span, &fn_sig);
249
250     // Call the generic checker.
251     let expected_arg_tys = expected_types_for_fn_args(fcx,
252                                                       call_expr.span,
253                                                       expected,
254                                                       fn_sig.output,
255                                                       &fn_sig.inputs);
256     check_argument_types(fcx,
257                          call_expr.span,
258                          &fn_sig.inputs,
259                          &expected_arg_tys[],
260                          arg_exprs,
261                          AutorefArgs::No,
262                          fn_sig.variadic,
263                          TupleArgumentsFlag::DontTupleArguments);
264
265     write_call(fcx, call_expr, fn_sig.output);
266 }
267
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>)
273 {
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
277     // type.
278
279     let expected_arg_tys =
280         expected_types_for_fn_args(fcx,
281                                    call_expr.span,
282                                    expected,
283                                    fn_sig.output.clone(),
284                                    &*fn_sig.inputs);
285
286     check_argument_types(fcx,
287                          call_expr.span,
288                          &*fn_sig.inputs,
289                          &*expected_arg_tys,
290                          arg_exprs,
291                          AutorefArgs::No,
292                          fn_sig.variadic,
293                          TupleArgumentsFlag::TupleArguments);
294
295     write_call(fcx, call_expr, fn_sig.output);
296 }
297
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>)
304 {
305     let output_type =
306         check_method_argument_types(fcx,
307                                     call_expr.span,
308                                     method_callee.ty,
309                                     callee_expr,
310                                     arg_exprs,
311                                     AutorefArgs::No,
312                                     TupleArgumentsFlag::TupleArguments,
313                                     expected);
314     write_call(fcx, call_expr, output_type);
315
316     write_overloaded_call_method_map(fcx, call_expr, method_callee);
317 }
318
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);
324 }
325
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,
333 }
334
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))
345     }
346 }
347
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()));
352
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());
356
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
368                 // refactor it.)
369                 let method_sig =
370                     ty::assert_no_late_bound_regions(fcx.tcx(),
371                                                      ty::ty_fn_sig(method_callee.ty));
372
373                 debug!("attempt_resolution: method_callee={}",
374                        method_callee.repr(fcx.tcx()));
375
376                 for (&method_arg_ty, &self_arg_ty) in
377                     method_sig.inputs[1..].iter().zip(self.fn_sig.inputs.iter())
378                 {
379                     demand::eqtype(fcx, self.call_expr.span, self_arg_ty, method_arg_ty);
380                 }
381
382                 demand::eqtype(fcx,
383                                self.call_expr.span,
384                                method_sig.output.unwrap(),
385                                self.fn_sig.output.unwrap());
386
387                 write_overloaded_call_method_map(fcx, self.call_expr, method_callee);
388             }
389             None => {
390                 fcx.tcx().sess.span_bug(
391                     self.call_expr.span,
392                     "failed to find an overloaded call trait for closure call");
393             }
394         }
395     }
396 }