auto merge of #20443 : nikomatsakis/rust/autoderef-overloaded-calls, r=pcwalton
Use autoderef for call notation. This is consistent in that we now autoderef all postfix operators (`.`, `[]`, and `()`). It also means you can call closures without writing `(*f)()`. Note that this is rebased atop the rollup, so only the final commit is relevant. r? @pcwalton
This commit is contained in:
commit
260e46115b
9 changed files with 268 additions and 135 deletions
|
@ -509,7 +509,7 @@ impl<'a, 'tcx> CFGBuilder<'a, 'tcx> {
|
||||||
let method_call = ty::MethodCall::expr(call_expr.id);
|
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) {
|
let return_ty = ty::ty_fn_ret(match self.tcx.method_map.borrow().get(&method_call) {
|
||||||
Some(method) => method.ty,
|
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);
|
let func_or_rcvr_exit = self.expr(func_or_rcvr, pred);
|
||||||
|
|
|
@ -1149,7 +1149,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
|
||||||
|
|
||||||
ast::ExprCall(ref f, ref args) => {
|
ast::ExprCall(ref f, ref args) => {
|
||||||
let diverges = !self.ir.tcx.is_method_call(expr.id) && {
|
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
|
t_ret == ty::FnDiverging
|
||||||
};
|
};
|
||||||
let succ = if diverges {
|
let succ = if diverges {
|
||||||
|
|
|
@ -576,7 +576,7 @@ pub fn trans_call<'a, 'blk, 'tcx>(in_cx: Block<'blk, 'tcx>,
|
||||||
let _icx = push_ctxt("trans_call");
|
let _icx = push_ctxt("trans_call");
|
||||||
trans_call_inner(in_cx,
|
trans_call_inner(in_cx,
|
||||||
Some(common::expr_info(call_ex)),
|
Some(common::expr_info(call_ex)),
|
||||||
expr_ty(in_cx, f),
|
expr_ty_adjusted(in_cx, f),
|
||||||
|cx, _| trans(cx, f),
|
|cx, _| trans(cx, f),
|
||||||
args,
|
args,
|
||||||
Some(dest)).bcx
|
Some(dest)).bcx
|
||||||
|
|
|
@ -8,8 +8,25 @@
|
||||||
// option. This file may not be copied, modified, or distributed
|
// option. This file may not be copied, modified, or distributed
|
||||||
// except according to those terms.
|
// 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::ast;
|
||||||
use syntax::codemap::Span;
|
use syntax::codemap::Span;
|
||||||
|
use syntax::parse::token;
|
||||||
|
use syntax::ptr::P;
|
||||||
use CrateCtxt;
|
use CrateCtxt;
|
||||||
|
|
||||||
/// Check that it is legal to call methods of the trait corresponding
|
/// Check that it is legal to call methods of the trait corresponding
|
||||||
|
@ -44,3 +61,165 @@ pub fn check_legal_trait_for_method_call(ccx: &CrateCtxt, span: Span, trait_id:
|
||||||
"add `#![feature(unboxed_closures)]` to the crate attributes to enable");
|
"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);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -2229,7 +2229,8 @@ pub enum LvaluePreference {
|
||||||
///
|
///
|
||||||
/// Note: this method does not modify the adjustments table. The caller is responsible for
|
/// 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.
|
/// 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>,
|
base_ty: Ty<'tcx>,
|
||||||
expr_id: Option<ast::NodeId>,
|
expr_id: Option<ast::NodeId>,
|
||||||
mut lvalue_pref: LvaluePreference,
|
mut lvalue_pref: LvaluePreference,
|
||||||
|
@ -2276,58 +2277,6 @@ pub fn autoderef<'a, 'tcx, T, F>(fcx: &FnCtxt<'a, 'tcx>, sp: Span,
|
||||||
(fcx.tcx().types.err, 0, None)
|
(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>,
|
fn try_overloaded_deref<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
|
||||||
span: Span,
|
span: Span,
|
||||||
method_call: Option<MethodCall>,
|
method_call: Option<MethodCall>,
|
||||||
|
@ -2689,7 +2638,6 @@ fn check_method_argument_types<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
|
||||||
check_argument_types(fcx,
|
check_argument_types(fcx,
|
||||||
sp,
|
sp,
|
||||||
err_inputs[],
|
err_inputs[],
|
||||||
callee_expr,
|
|
||||||
args_no_rcvr,
|
args_no_rcvr,
|
||||||
autoref_args,
|
autoref_args,
|
||||||
false,
|
false,
|
||||||
|
@ -2702,7 +2650,6 @@ fn check_method_argument_types<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
|
||||||
check_argument_types(fcx,
|
check_argument_types(fcx,
|
||||||
sp,
|
sp,
|
||||||
fty.sig.0.inputs.slice_from(1),
|
fty.sig.0.inputs.slice_from(1),
|
||||||
callee_expr,
|
|
||||||
args_no_rcvr,
|
args_no_rcvr,
|
||||||
autoref_args,
|
autoref_args,
|
||||||
fty.sig.0.variadic,
|
fty.sig.0.variadic,
|
||||||
|
@ -2722,7 +2669,6 @@ fn check_method_argument_types<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
|
||||||
fn check_argument_types<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
|
fn check_argument_types<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
|
||||||
sp: Span,
|
sp: Span,
|
||||||
fn_inputs: &[Ty<'tcx>],
|
fn_inputs: &[Ty<'tcx>],
|
||||||
_callee_expr: &ast::Expr,
|
|
||||||
args: &[&P<ast::Expr>],
|
args: &[&P<ast::Expr>],
|
||||||
autoref_args: AutorefArgs,
|
autoref_args: AutorefArgs,
|
||||||
variadic: bool,
|
variadic: bool,
|
||||||
|
@ -3106,63 +3052,6 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>,
|
||||||
debug!(">> typechecking: expr={} expected={}",
|
debug!(">> typechecking: expr={} expected={}",
|
||||||
expr.repr(fcx.tcx()), expected.repr(fcx.tcx()));
|
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.
|
// Checks a method call.
|
||||||
fn check_method_call(fcx: &FnCtxt,
|
fn check_method_call(fcx: &FnCtxt,
|
||||||
expr: &ast::Expr,
|
expr: &ast::Expr,
|
||||||
|
@ -4164,24 +4053,8 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>,
|
||||||
check_block_with_expected(fcx, &**b, expected);
|
check_block_with_expected(fcx, &**b, expected);
|
||||||
fcx.write_ty(id, fcx.node_ty(b.id));
|
fcx.write_ty(id, fcx.node_ty(b.id));
|
||||||
}
|
}
|
||||||
ast::ExprCall(ref f, ref args) => {
|
ast::ExprCall(ref callee, ref args) => {
|
||||||
// Index expressions need to be handled separately, to inform them
|
callee::check_call(fcx, expr, &**callee, args.as_slice());
|
||||||
// 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::ExprMethodCall(ident, ref tps, ref args) => {
|
ast::ExprMethodCall(ident, ref tps, ref args) => {
|
||||||
check_method_call(fcx, expr, ident, args[], tps[], lvalue_pref);
|
check_method_call(fcx, expr, ident, args[], tps[], lvalue_pref);
|
||||||
|
|
|
@ -12,7 +12,7 @@ struct Homura;
|
||||||
|
|
||||||
fn akemi(homura: Homura) {
|
fn akemi(homura: Homura) {
|
||||||
let Some(ref madoka) = Some(homura.kaname()); //~ ERROR does not implement any method
|
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() { }
|
fn main() { }
|
||||||
|
|
28
src/test/run-pass/unboxed-closures-call-fn-autoderef.rs
Normal file
28
src/test/run-pass/unboxed-closures-call-fn-autoderef.rs
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
// 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);
|
||||||
|
}
|
26
src/test/run-pass/unboxed-closures-call-sugar-autoderef.rs
Normal file
26
src/test/run-pass/unboxed-closures-call-sugar-autoderef.rs
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
// 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);
|
||||||
|
}
|
|
@ -0,0 +1,27 @@
|
||||||
|
// 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);
|
||||||
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue