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