let method_call = ty::MethodCall::expr(call_expr.id);
let return_ty = ty::ty_fn_ret(match self.tcx.method_map.borrow().get(&method_call) {
Some(method) => method.ty,
- None => ty::expr_ty(self.tcx, func_or_rcvr)
+ None => ty::expr_ty_adjusted(self.tcx, func_or_rcvr)
});
let func_or_rcvr_exit = self.expr(func_or_rcvr, pred);
ast::ExprCall(ref f, ref args) => {
let diverges = !self.ir.tcx.is_method_call(expr.id) && {
- let t_ret = ty::ty_fn_ret(ty::expr_ty(self.ir.tcx, &**f));
+ let t_ret = ty::ty_fn_ret(ty::expr_ty_adjusted(self.ir.tcx, &**f));
t_ret == ty::FnDiverging
};
let succ = if diverges {
let _icx = push_ctxt("trans_call");
trans_call_inner(in_cx,
Some(common::expr_info(call_ex)),
- expr_ty(in_cx, f),
+ expr_ty_adjusted(in_cx, f),
|cx, _| trans(cx, f),
args,
Some(dest)).bcx
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+use super::autoderef;
+use super::AutorefArgs;
+use super::check_argument_types;
+use super::check_expr;
+use super::check_method_argument_types;
+use super::err_args;
+use super::FnCtxt;
+use super::LvaluePreference;
+use super::method;
+use super::structurally_resolved_type;
+use super::TupleArgumentsFlag;
+use super::write_call;
+
+use middle::infer;
+use middle::ty::{mod, Ty};
use syntax::ast;
use syntax::codemap::Span;
+use syntax::parse::token;
+use syntax::ptr::P;
use CrateCtxt;
/// Check that it is legal to call methods of the trait corresponding
"add `#![feature(unboxed_closures)]` to the crate attributes to enable");
}
}
+
+pub fn check_call<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
+ call_expr: &ast::Expr,
+ callee_expr: &ast::Expr,
+ arg_exprs: &[P<ast::Expr>])
+{
+ check_expr(fcx, callee_expr);
+ let original_callee_ty = fcx.expr_ty(callee_expr);
+ let (callee_ty, _, result) =
+ autoderef(fcx,
+ callee_expr.span,
+ original_callee_ty,
+ Some(callee_expr.id),
+ LvaluePreference::NoPreference,
+ |adj_ty, idx| {
+ let autoderefref = ty::AutoDerefRef { autoderefs: idx, autoref: None };
+ try_overloaded_call_step(fcx, call_expr, callee_expr,
+ adj_ty, autoderefref)
+ });
+
+ match result {
+ None => {
+ // this will report an error since original_callee_ty is not a fn
+ confirm_builtin_call(fcx, call_expr, original_callee_ty, arg_exprs);
+ }
+
+ Some(CallStep::Builtin) => {
+ confirm_builtin_call(fcx, call_expr, callee_ty, arg_exprs);
+ }
+
+ Some(CallStep::Overloaded(method_callee)) => {
+ confirm_overloaded_call(fcx, call_expr, arg_exprs, method_callee);
+ }
+ }
+}
+
+enum CallStep<'tcx> {
+ Builtin,
+ Overloaded(ty::MethodCallee<'tcx>)
+}
+
+fn try_overloaded_call_step<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
+ call_expr: &ast::Expr,
+ callee_expr: &ast::Expr,
+ adjusted_ty: Ty<'tcx>,
+ autoderefref: ty::AutoDerefRef<'tcx>)
+ -> Option<CallStep<'tcx>>
+{
+ // If the callee is a bare function or a closure, then we're all set.
+ match structurally_resolved_type(fcx, callee_expr.span, adjusted_ty).sty {
+ ty::ty_bare_fn(..) | ty::ty_closure(_) => {
+ fcx.write_adjustment(callee_expr.id,
+ callee_expr.span,
+ ty::AdjustDerefRef(autoderefref));
+ return Some(CallStep::Builtin);
+ }
+
+ _ => {}
+ }
+
+ // Try the options that are least restrictive on the caller first.
+ for &(opt_trait_def_id, method_name) in [
+ (fcx.tcx().lang_items.fn_trait(), token::intern("call")),
+ (fcx.tcx().lang_items.fn_mut_trait(), token::intern("call_mut")),
+ (fcx.tcx().lang_items.fn_once_trait(), token::intern("call_once")),
+ ].iter() {
+ let trait_def_id = match opt_trait_def_id {
+ Some(def_id) => def_id,
+ None => continue,
+ };
+
+ match method::lookup_in_trait_adjusted(fcx,
+ call_expr.span,
+ Some(&*callee_expr),
+ method_name,
+ trait_def_id,
+ autoderefref.clone(),
+ adjusted_ty,
+ None) {
+ None => continue,
+ Some(method_callee) => {
+ return Some(CallStep::Overloaded(method_callee));
+ }
+ }
+ }
+
+ None
+}
+
+fn confirm_builtin_call<'a,'tcx>(fcx: &FnCtxt<'a,'tcx>,
+ call_expr: &ast::Expr,
+ callee_ty: Ty<'tcx>,
+ arg_exprs: &[P<ast::Expr>])
+{
+ let error_fn_sig;
+
+ let fn_sig = match callee_ty.sty {
+ ty::ty_bare_fn(_, &ty::BareFnTy {ref sig, ..}) |
+ ty::ty_closure(box ty::ClosureTy {ref sig, ..}) => {
+ sig
+ }
+ _ => {
+ fcx.type_error_message(call_expr.span, |actual| {
+ format!("expected function, found `{}`", actual)
+ }, callee_ty, None);
+
+ // This is the "default" function signature, used in case of error.
+ // In that case, we check each argument against "error" in order to
+ // set up all the node type bindings.
+ error_fn_sig = ty::Binder(ty::FnSig {
+ inputs: err_args(fcx.tcx(), arg_exprs.len()),
+ output: ty::FnConverging(fcx.tcx().types.err),
+ variadic: false
+ });
+
+ &error_fn_sig
+ }
+ };
+
+ // Replace any late-bound regions that appear in the function
+ // signature with region variables. We also have to
+ // renormalize the associated types at this point, since they
+ // previously appeared within a `Binder<>` and hence would not
+ // have been normalized before.
+ let fn_sig =
+ fcx.infcx().replace_late_bound_regions_with_fresh_var(call_expr.span,
+ infer::FnCall,
+ fn_sig).0;
+ let fn_sig =
+ fcx.normalize_associated_types_in(call_expr.span, &fn_sig);
+
+ // Call the generic checker.
+ let arg_exprs: Vec<_> = arg_exprs.iter().collect(); // for some weird reason we take &[&P<...>].
+ check_argument_types(fcx,
+ call_expr.span,
+ fn_sig.inputs[],
+ arg_exprs.as_slice(),
+ AutorefArgs::No,
+ fn_sig.variadic,
+ TupleArgumentsFlag::DontTupleArguments);
+
+ write_call(fcx, call_expr, fn_sig.output);
+}
+
+fn confirm_overloaded_call<'a,'tcx>(fcx: &FnCtxt<'a, 'tcx>,
+ call_expr: &ast::Expr,
+ arg_exprs: &[P<ast::Expr>],
+ method_callee: ty::MethodCallee<'tcx>)
+{
+ let arg_exprs: Vec<_> = arg_exprs.iter().collect(); // for some weird reason we take &[&P<...>].
+ let output_type = check_method_argument_types(fcx,
+ call_expr.span,
+ method_callee.ty,
+ call_expr,
+ arg_exprs.as_slice(),
+ AutorefArgs::No,
+ TupleArgumentsFlag::TupleArguments);
+ let method_call = ty::MethodCall::expr(call_expr.id);
+ fcx.inh.method_map.borrow_mut().insert(method_call, method_callee);
+ write_call(fcx, call_expr, output_type);
+}
+
///
/// Note: this method does not modify the adjustments table. The caller is responsible for
/// inserting an AutoAdjustment record into the `fcx` using one of the suitable methods.
-pub fn autoderef<'a, 'tcx, T, F>(fcx: &FnCtxt<'a, 'tcx>, sp: Span,
+pub fn autoderef<'a, 'tcx, T, F>(fcx: &FnCtxt<'a, 'tcx>,
+ sp: Span,
base_ty: Ty<'tcx>,
expr_id: Option<ast::NodeId>,
mut lvalue_pref: LvaluePreference,
(fcx.tcx().types.err, 0, None)
}
-/// Attempts to resolve a call expression as an overloaded call.
-fn try_overloaded_call<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
- call_expression: &ast::Expr,
- callee: &ast::Expr,
- callee_type: Ty<'tcx>,
- args: &[&P<ast::Expr>])
- -> bool {
- // Bail out if the callee is a bare function or a closure. We check those
- // manually.
- match structurally_resolved_type(fcx, callee.span, callee_type).sty {
- ty::ty_bare_fn(..) | ty::ty_closure(_) => return false,
- _ => {}
- }
-
- // Try the options that are least restrictive on the caller first.
- for &(maybe_function_trait, method_name) in [
- (fcx.tcx().lang_items.fn_trait(), token::intern("call")),
- (fcx.tcx().lang_items.fn_mut_trait(), token::intern("call_mut")),
- (fcx.tcx().lang_items.fn_once_trait(), token::intern("call_once")),
- ].iter() {
- let function_trait = match maybe_function_trait {
- None => continue,
- Some(function_trait) => function_trait,
- };
- let method_callee =
- match method::lookup_in_trait(fcx,
- call_expression.span,
- Some(&*callee),
- method_name,
- function_trait,
- callee_type,
- None) {
- None => continue,
- Some(method_callee) => method_callee,
- };
- let method_call = MethodCall::expr(call_expression.id);
- let output_type = check_method_argument_types(fcx,
- call_expression.span,
- method_callee.ty,
- call_expression,
- args,
- AutorefArgs::No,
- TupleArguments);
- fcx.inh.method_map.borrow_mut().insert(method_call, method_callee);
- write_call(fcx, call_expression, output_type);
-
- return true
- }
-
- false
-}
-
fn try_overloaded_deref<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
span: Span,
method_call: Option<MethodCall>,
check_argument_types(fcx,
sp,
err_inputs[],
- callee_expr,
args_no_rcvr,
autoref_args,
false,
check_argument_types(fcx,
sp,
fty.sig.0.inputs.slice_from(1),
- callee_expr,
args_no_rcvr,
autoref_args,
fty.sig.0.variadic,
fn check_argument_types<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
sp: Span,
fn_inputs: &[Ty<'tcx>],
- _callee_expr: &ast::Expr,
args: &[&P<ast::Expr>],
autoref_args: AutorefArgs,
variadic: bool,
debug!(">> typechecking: expr={} expected={}",
expr.repr(fcx.tcx()), expected.repr(fcx.tcx()));
- // A generic function for doing all of the checking for call expressions
- fn check_call(fcx: &FnCtxt,
- call_expr: &ast::Expr,
- f: &ast::Expr,
- args: &[&P<ast::Expr>]) {
- // Store the type of `f` as the type of the callee
- let fn_ty = fcx.expr_ty(f);
-
- // Extract the function signature from `in_fty`.
- let fn_ty = structurally_resolved_type(fcx, f.span, fn_ty);
-
- // This is the "default" function signature, used in case of error.
- // In that case, we check each argument against "error" in order to
- // set up all the node type bindings.
- let error_fn_sig = ty::Binder(FnSig {
- inputs: err_args(fcx.tcx(), args.len()),
- output: ty::FnConverging(fcx.tcx().types.err),
- variadic: false
- });
-
- let fn_sig = match fn_ty.sty {
- ty::ty_bare_fn(_, &ty::BareFnTy {ref sig, ..}) |
- ty::ty_closure(box ty::ClosureTy {ref sig, ..}) => sig,
- _ => {
- fcx.type_error_message(call_expr.span, |actual| {
- format!("expected function, found `{}`", actual)
- }, fn_ty, None);
- &error_fn_sig
- }
- };
-
- // Replace any late-bound regions that appear in the function
- // signature with region variables. We also have to
- // renormalize the associated types at this point, since they
- // previously appeared within a `Binder<>` and hence would not
- // have been normalized before.
- let fn_sig =
- fcx.infcx().replace_late_bound_regions_with_fresh_var(call_expr.span,
- infer::FnCall,
- fn_sig).0;
- let fn_sig =
- fcx.normalize_associated_types_in(call_expr.span,
- &fn_sig);
-
- // Call the generic checker.
- check_argument_types(fcx,
- call_expr.span,
- fn_sig.inputs[],
- f,
- args,
- AutorefArgs::No,
- fn_sig.variadic,
- DontTupleArguments);
-
- write_call(fcx, call_expr, fn_sig.output);
- }
-
// Checks a method call.
fn check_method_call(fcx: &FnCtxt,
expr: &ast::Expr,
check_block_with_expected(fcx, &**b, expected);
fcx.write_ty(id, fcx.node_ty(b.id));
}
- ast::ExprCall(ref f, ref args) => {
- // Index expressions need to be handled separately, to inform them
- // that they appear in call position.
- check_expr(fcx, &**f);
- let f_ty = fcx.expr_ty(&**f);
-
- let args: Vec<_> = args.iter().map(|x| x).collect();
- if !try_overloaded_call(fcx, expr, &**f, f_ty, args[]) {
- check_call(fcx, expr, &**f, args[]);
- let args_err = args.iter().fold(false,
- |rest_err, a| {
- // is this not working?
- let a_ty = fcx.expr_ty(&***a);
- rest_err || ty::type_is_error(a_ty)});
- if ty::type_is_error(f_ty) || args_err {
- fcx.write_error(id);
- }
- }
+ ast::ExprCall(ref callee, ref args) => {
+ callee::check_call(fcx, expr, &**callee, args.as_slice());
}
ast::ExprMethodCall(ident, ref tps, ref args) => {
check_method_call(fcx, expr, ident, args[], tps[], lvalue_pref);
fn akemi(homura: Homura) {
let Some(ref madoka) = Some(homura.kaname()); //~ ERROR does not implement any method
- madoka.clone(); //~ ERROR the type of this value must be known
+ madoka.clone();
}
fn main() { }
--- /dev/null
+// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Test that the call operator autoderefs when calling a bounded type parameter.
+
+#![feature(unboxed_closures)]
+
+use std::ops::FnMut;
+
+fn call_with_2(x: &fn(int) -> int) -> int
+{
+ x(2) // look ma, no `*`
+}
+
+fn subtract_22(x: int) -> int { x - 22 }
+
+pub fn main() {
+ let subtract_22: fn(int) -> int = subtract_22;
+ let z = call_with_2(&subtract_22);
+ assert_eq!(z, -20);
+}
--- /dev/null
+// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Test that the call operator autoderefs when calling a bounded type parameter.
+
+#![feature(unboxed_closures)]
+
+use std::ops::FnMut;
+
+fn call_with_2<F>(x: &mut F) -> int
+ where F : FnMut(int) -> int
+{
+ x(2) // look ma, no `*`
+}
+
+pub fn main() {
+ let z = call_with_2(&mut |x| x - 22);
+ assert_eq!(z, -20);
+}
--- /dev/null
+// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Test that the call operator autoderefs when calling to an object type.
+
+#![feature(unboxed_closures)]
+
+use std::ops::FnMut;
+
+fn make_adder(x: int) -> Box<FnMut(int)->int + 'static> {
+ box move |y| { x + y }
+}
+
+pub fn main() {
+ let mut adder = make_adder(3);
+ let z = adder(2);
+ println!("{}", z);
+ assert_eq!(z, 5);
+}
+