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::check_argument_types
;
13 use super::check_expr
;
14 use super::check_method_argument_types
;
16 use super::DeferredCallResolution
;
18 use super::Expectation
;
19 use super::expected_types_for_fn_args
;
22 use super::structurally_resolved_type
;
23 use super::TupleArgumentsFlag
;
24 use super::UnresolvedTypeAction
;
25 use super::write_call
;
28 use metadata
::cstore
::LOCAL_CRATE
;
29 use middle
::def_id
::DefId
;
31 use middle
::ty
::{self, LvaluePreference, Ty}
;
32 use syntax
::codemap
::Span
;
33 use syntax
::parse
::token
;
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
) {
43 let did
= Some(trait_id
);
44 let li
= &tcx
.lang_items
;
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
53 let method
= if did
== li
.fn_trait() {
55 } else if did
== li
.fn_mut_trait() {
57 } else if did
== li
.fn_once_trait() {
60 return // not a closure method, everything is OK.
63 span_err
!(tcx
.sess
, span
, E0174
,
64 "explicit use of unboxed closure method `{}` is experimental",
66 fileline_help
!(tcx
.sess
, span
,
67 "add `#![feature(unboxed_closures)]` to the crate attributes to enable");
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
>)
77 check_expr(fcx
, callee_expr
);
78 let original_callee_ty
= fcx
.expr_ty(callee_expr
);
79 let (callee_ty
, _
, result
) =
84 UnresolvedTypeAction
::Error
,
85 LvaluePreference
::NoPreference
,
87 try_overloaded_call_step(fcx
, call_expr
, callee_expr
, adj_ty
, idx
)
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
);
96 Some(CallStep
::Builtin
) => {
97 confirm_builtin_call(fcx
, call_expr
, callee_ty
, arg_exprs
, expected
);
100 Some(CallStep
::DeferredClosure(fn_sig
)) => {
101 confirm_deferred_closure_call(fcx
, call_expr
, arg_exprs
, expected
, fn_sig
);
104 Some(CallStep
::Overloaded(method_callee
)) => {
105 confirm_overloaded_call(fcx
, call_expr
, callee_expr
,
106 arg_exprs
, expected
, method_callee
);
111 enum CallStep
<'tcx
> {
113 DeferredClosure(ty
::FnSig
<'tcx
>),
114 Overloaded(ty
::MethodCallee
<'tcx
>)
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
>,
122 -> Option
<CallStep
<'tcx
>>
124 debug
!("try_overloaded_call_step(call_expr={:?}, adjusted_ty={:?}, autoderefs={})",
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
);
136 ty
::TyClosure(def_id
, ref substs
) => {
137 assert_eq
!(def_id
.krate
, LOCAL_CRATE
);
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() {
144 fcx
.infcx().closure_type(def_id
, substs
);
146 fcx
.infcx().replace_late_bound_regions_with_fresh_var(call_expr
.span
,
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
157 return Some(CallStep
::DeferredClosure(fn_sig
));
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 => {
176 try_overloaded_call_traits(fcx
, call_expr
, callee_expr
, adjusted_ty
, autoderefs
)
177 .map(|method_callee
| CallStep
::Overloaded(method_callee
))
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
>,
185 -> Option
<ty
::MethodCallee
<'tcx
>>
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")),
193 let trait_def_id
= match opt_trait_def_id
{
194 Some(def_id
) => def_id
,
198 match method
::lookup_in_trait_adjusted(fcx
,
208 Some(method_callee
) => {
209 return Some(method_callee
);
217 fn confirm_builtin_call
<'a
,'tcx
>(fcx
: &FnCtxt
<'a
,'tcx
>,
218 call_expr
: &hir
::Expr
,
220 arg_exprs
: &'tcx
[P
<hir
::Expr
>],
221 expected
: Expectation
<'tcx
>)
225 let fn_sig
= match callee_ty
.sty
{
226 ty
::TyBareFn(_
, &ty
::BareFnTy {ref sig, ..}
) => {
230 fcx
.type_error_message(call_expr
.span
, |actual
| {
231 format
!("expected function, found `{}`", actual
)
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
),
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.
253 fcx
.infcx().replace_late_bound_regions_with_fresh_var(call_expr
.span
,
257 fcx
.normalize_associated_types_in(call_expr
.span
, &fn_sig
);
259 // Call the generic checker.
260 let expected_arg_tys
= expected_types_for_fn_args(fcx
,
265 check_argument_types(fcx
,
268 &expected_arg_tys
[..],
271 TupleArgumentsFlag
::DontTupleArguments
);
273 write_call(fcx
, call_expr
, fn_sig
.output
);
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
>)
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
287 let expected_arg_tys
=
288 expected_types_for_fn_args(fcx
,
291 fn_sig
.output
.clone(),
294 check_argument_types(fcx
,
300 TupleArgumentsFlag
::TupleArguments
);
302 write_call(fcx
, call_expr
, fn_sig
.output
);
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
>)
313 check_method_argument_types(fcx
,
318 TupleArgumentsFlag
::TupleArguments
,
320 write_call(fcx
, call_expr
, output_type
);
322 write_overloaded_call_method_map(fcx
, call_expr
, method_callee
);
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
);
333 struct CallResolution
<'tcx
> {
334 call_expr
: &'tcx hir
::Expr
,
335 callee_expr
: &'tcx hir
::Expr
,
336 adjusted_ty
: Ty
<'tcx
>,
338 fn_sig
: ty
::FnSig
<'tcx
>,
339 closure_def_id
: DefId
,
342 impl<'tcx
> DeferredCallResolution
<'tcx
> for CallResolution
<'tcx
> {
343 fn resolve
<'a
>(&mut self, fcx
: &FnCtxt
<'a
,'tcx
>) {
344 debug
!("DeferredCallResolution::resolve() {:?}",
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());
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
363 let method_sig
= fcx
.tcx().no_late_bound_regions(method_callee
.ty
.fn_sig())
366 debug
!("attempt_resolution: method_callee={:?}",
369 for (&method_arg_ty
, &self_arg_ty
) in
370 method_sig
.inputs
[1..].iter().zip(&self.fn_sig
.inputs
)
372 demand
::eqtype(fcx
, self.call_expr
.span
, self_arg_ty
, method_arg_ty
);
375 let nilty
= fcx
.tcx().mk_nil();
378 method_sig
.output
.unwrap_or(nilty
),
379 self.fn_sig
.output
.unwrap_or(nilty
));
381 write_overloaded_call_method_map(fcx
, self.call_expr
, method_callee
);
384 fcx
.tcx().sess
.span_bug(
386 "failed to find an overloaded call trait for closure call");