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::AutorefArgs
;
13 use super::check_argument_types
;
14 use super::check_expr
;
15 use super::check_method_argument_types
;
17 use super::DeferredCallResolution
;
19 use super::Expectation
;
20 use super::expected_types_for_fn_args
;
22 use super::LvaluePreference
;
24 use super::structurally_resolved_type
;
25 use super::TupleArgumentsFlag
;
26 use super::UnresolvedTypeAction
;
27 use super::write_call
;
31 use middle
::ty
::{self, Ty, ClosureTyper}
;
33 use syntax
::codemap
::Span
;
34 use syntax
::parse
::token
;
36 use util
::ppaux
::Repr
;
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
) {
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 span_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 ast
::Expr
,
73 callee_expr
: &'tcx ast
::Expr
,
74 arg_exprs
: &'tcx
[P
<ast
::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 let autoderefref
= ty
::AutoDerefRef { autoderefs: idx, autoref: None }
;
88 try_overloaded_call_step(fcx
, call_expr
, callee_expr
,
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
);
98 Some(CallStep
::Builtin
) => {
99 confirm_builtin_call(fcx
, call_expr
, callee_ty
, arg_exprs
, expected
);
102 Some(CallStep
::DeferredClosure(fn_sig
)) => {
103 confirm_deferred_closure_call(fcx
, call_expr
, arg_exprs
, expected
, fn_sig
);
106 Some(CallStep
::Overloaded(method_callee
)) => {
107 confirm_overloaded_call(fcx
, call_expr
, callee_expr
,
108 arg_exprs
, expected
, method_callee
);
113 enum CallStep
<'tcx
> {
115 DeferredClosure(ty
::FnSig
<'tcx
>),
116 Overloaded(ty
::MethodCallee
<'tcx
>)
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
>>
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()));
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
,
136 ty
::AdjustDerefRef(autoderefref
));
137 return Some(CallStep
::Builtin
);
140 ty
::ty_closure(def_id
, _
, substs
) => {
141 assert_eq
!(def_id
.krate
, ast
::LOCAL_CRATE
);
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() {
148 fcx
.closure_type(def_id
, substs
);
150 fcx
.infcx().replace_late_bound_regions_with_fresh_var(call_expr
.span
,
153 fcx
.record_deferred_call_resolution(
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
));
168 try_overloaded_call_traits(fcx
, call_expr
, callee_expr
, adjusted_ty
, autoderefref
)
169 .map(|method_callee
| CallStep
::Overloaded(method_callee
))
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
>>
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")),
185 let trait_def_id
= match opt_trait_def_id
{
186 Some(def_id
) => def_id
,
190 match method
::lookup_in_trait_adjusted(fcx
,
195 autoderefref
.clone(),
199 Some(method_callee
) => {
200 return Some(method_callee
);
208 fn confirm_builtin_call
<'a
,'tcx
>(fcx
: &FnCtxt
<'a
,'tcx
>,
209 call_expr
: &ast
::Expr
,
211 arg_exprs
: &'tcx
[P
<ast
::Expr
>],
212 expected
: Expectation
<'tcx
>)
216 let fn_sig
= match callee_ty
.sty
{
217 ty
::ty_bare_fn(_
, &ty
::BareFnTy {ref sig, ..}
) => {
221 fcx
.type_error_message(call_expr
.span
, |actual
| {
222 format
!("expected function, found `{}`", actual
)
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
),
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.
244 fcx
.infcx().replace_late_bound_regions_with_fresh_var(call_expr
.span
,
248 fcx
.normalize_associated_types_in(call_expr
.span
, &fn_sig
);
250 // Call the generic checker.
251 let expected_arg_tys
= expected_types_for_fn_args(fcx
,
256 check_argument_types(fcx
,
259 &expected_arg_tys
[..],
263 TupleArgumentsFlag
::DontTupleArguments
);
265 write_call(fcx
, call_expr
, fn_sig
.output
);
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
>)
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
279 let expected_arg_tys
=
280 expected_types_for_fn_args(fcx
,
283 fn_sig
.output
.clone(),
286 check_argument_types(fcx
,
293 TupleArgumentsFlag
::TupleArguments
);
295 write_call(fcx
, call_expr
, fn_sig
.output
);
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
>)
306 check_method_argument_types(fcx
,
312 TupleArgumentsFlag
::TupleArguments
,
314 write_call(fcx
, call_expr
, output_type
);
316 write_overloaded_call_method_map(fcx
, call_expr
, method_callee
);
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
);
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
,
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
))
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()));
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());
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
370 ty
::no_late_bound_regions(fcx
.tcx(),
371 ty
::ty_fn_sig(method_callee
.ty
)).unwrap();
373 debug
!("attempt_resolution: method_callee={}",
374 method_callee
.repr(fcx
.tcx()));
376 for (&method_arg_ty
, &self_arg_ty
) in
377 method_sig
.inputs
[1..].iter().zip(self.fn_sig
.inputs
.iter())
379 demand
::eqtype(fcx
, self.call_expr
.span
, self_arg_ty
, method_arg_ty
);
384 method_sig
.output
.unwrap(),
385 self.fn_sig
.output
.unwrap());
387 write_overloaded_call_method_map(fcx
, self.call_expr
, method_callee
);
390 fcx
.tcx().sess
.span_bug(
392 "failed to find an overloaded call trait for closure call");