]> git.lizzy.rs Git - rust.git/blob - src/librustc_typeck/check/callee.rs
Auto merge of #30036 - mitaa:doc_id, 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::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 middle::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             if let hir::ExprCall(ref expr, _) = call_expr.node {
235                 let tcx = fcx.tcx();
236                 if let Some(pr) = tcx.def_map.borrow().get(&expr.id) {
237                     if pr.depth == 0 {
238                         if let Some(span) = tcx.map.span_if_local(pr.def_id()) {
239                             tcx.sess.span_note(span, "defined here")
240                         }
241                     }
242                 }
243             }
244
245             // This is the "default" function signature, used in case of error.
246             // In that case, we check each argument against "error" in order to
247             // set up all the node type bindings.
248             error_fn_sig = ty::Binder(ty::FnSig {
249                 inputs: err_args(fcx.tcx(), arg_exprs.len()),
250                 output: ty::FnConverging(fcx.tcx().types.err),
251                 variadic: false
252             });
253
254             &error_fn_sig
255         }
256     };
257
258     // Replace any late-bound regions that appear in the function
259     // signature with region variables. We also have to
260     // renormalize the associated types at this point, since they
261     // previously appeared within a `Binder<>` and hence would not
262     // have been normalized before.
263     let fn_sig =
264         fcx.infcx().replace_late_bound_regions_with_fresh_var(call_expr.span,
265                                                               infer::FnCall,
266                                                               fn_sig).0;
267     let fn_sig =
268         fcx.normalize_associated_types_in(call_expr.span, &fn_sig);
269
270     // Call the generic checker.
271     let expected_arg_tys = expected_types_for_fn_args(fcx,
272                                                       call_expr.span,
273                                                       expected,
274                                                       fn_sig.output,
275                                                       &fn_sig.inputs);
276     check_argument_types(fcx,
277                          call_expr.span,
278                          &fn_sig.inputs,
279                          &expected_arg_tys[..],
280                          arg_exprs,
281                          fn_sig.variadic,
282                          TupleArgumentsFlag::DontTupleArguments);
283
284     write_call(fcx, call_expr, fn_sig.output);
285 }
286
287 fn confirm_deferred_closure_call<'a,'tcx>(fcx: &FnCtxt<'a,'tcx>,
288                                           call_expr: &hir::Expr,
289                                           arg_exprs: &'tcx [P<hir::Expr>],
290                                           expected: Expectation<'tcx>,
291                                           fn_sig: ty::FnSig<'tcx>)
292 {
293     // `fn_sig` is the *signature* of the cosure being called. We
294     // don't know the full details yet (`Fn` vs `FnMut` etc), but we
295     // do know the types expected for each argument and the return
296     // type.
297
298     let expected_arg_tys =
299         expected_types_for_fn_args(fcx,
300                                    call_expr.span,
301                                    expected,
302                                    fn_sig.output.clone(),
303                                    &*fn_sig.inputs);
304
305     check_argument_types(fcx,
306                          call_expr.span,
307                          &*fn_sig.inputs,
308                          &*expected_arg_tys,
309                          arg_exprs,
310                          fn_sig.variadic,
311                          TupleArgumentsFlag::TupleArguments);
312
313     write_call(fcx, call_expr, fn_sig.output);
314 }
315
316 fn confirm_overloaded_call<'a,'tcx>(fcx: &FnCtxt<'a, 'tcx>,
317                                     call_expr: &hir::Expr,
318                                     callee_expr: &'tcx hir::Expr,
319                                     arg_exprs: &'tcx [P<hir::Expr>],
320                                     expected: Expectation<'tcx>,
321                                     method_callee: ty::MethodCallee<'tcx>)
322 {
323     let output_type =
324         check_method_argument_types(fcx,
325                                     call_expr.span,
326                                     method_callee.ty,
327                                     callee_expr,
328                                     arg_exprs,
329                                     TupleArgumentsFlag::TupleArguments,
330                                     expected);
331     write_call(fcx, call_expr, output_type);
332
333     write_overloaded_call_method_map(fcx, call_expr, method_callee);
334 }
335
336 fn write_overloaded_call_method_map<'a,'tcx>(fcx: &FnCtxt<'a, 'tcx>,
337                                              call_expr: &hir::Expr,
338                                              method_callee: ty::MethodCallee<'tcx>) {
339     let method_call = ty::MethodCall::expr(call_expr.id);
340     fcx.inh.tables.borrow_mut().method_map.insert(method_call, method_callee);
341 }
342
343 #[derive(Debug)]
344 struct CallResolution<'tcx> {
345     call_expr: &'tcx hir::Expr,
346     callee_expr: &'tcx hir::Expr,
347     adjusted_ty: Ty<'tcx>,
348     autoderefs: usize,
349     fn_sig: ty::FnSig<'tcx>,
350     closure_def_id: DefId,
351 }
352
353 impl<'tcx> DeferredCallResolution<'tcx> for CallResolution<'tcx> {
354     fn resolve<'a>(&mut self, fcx: &FnCtxt<'a,'tcx>) {
355         debug!("DeferredCallResolution::resolve() {:?}",
356                self);
357
358         // we should not be invoked until the closure kind has been
359         // determined by upvar inference
360         assert!(fcx.infcx().closure_kind(self.closure_def_id).is_some());
361
362         // We may now know enough to figure out fn vs fnmut etc.
363         match try_overloaded_call_traits(fcx, self.call_expr, self.callee_expr,
364                                          self.adjusted_ty, self.autoderefs) {
365             Some(method_callee) => {
366                 // One problem is that when we get here, we are going
367                 // to have a newly instantiated function signature
368                 // from the call trait. This has to be reconciled with
369                 // the older function signature we had before. In
370                 // principle we *should* be able to fn_sigs(), but we
371                 // can't because of the annoying need for a TypeTrace.
372                 // (This always bites me, should find a way to
373                 // refactor it.)
374                 let method_sig = fcx.tcx().no_late_bound_regions(method_callee.ty.fn_sig())
375                                           .unwrap();
376
377                 debug!("attempt_resolution: method_callee={:?}",
378                        method_callee);
379
380                 for (&method_arg_ty, &self_arg_ty) in
381                     method_sig.inputs[1..].iter().zip(&self.fn_sig.inputs)
382                 {
383                     demand::eqtype(fcx, self.call_expr.span, self_arg_ty, method_arg_ty);
384                 }
385
386                 let nilty = fcx.tcx().mk_nil();
387                 demand::eqtype(fcx,
388                                self.call_expr.span,
389                                method_sig.output.unwrap_or(nilty),
390                                self.fn_sig.output.unwrap_or(nilty));
391
392                 write_overloaded_call_method_map(fcx, self.call_expr, method_callee);
393             }
394             None => {
395                 fcx.tcx().sess.span_bug(
396                     self.call_expr.span,
397                     "failed to find an overloaded call trait for closure call");
398             }
399         }
400     }
401 }