1
Fork 0

refactor check_call_inner to have a better name and be readable

This commit is contained in:
Niko Matsakis 2013-03-26 16:27:34 -04:00
parent babe506333
commit 1745a2cd08

View file

@ -1122,9 +1122,7 @@ pub fn check_expr_with_unifier(fcx: @mut FnCtxt,
unifier: &fn()) { unifier: &fn()) {
debug!(">> typechecking %s", fcx.expr_to_str(expr)); debug!(">> typechecking %s", fcx.expr_to_str(expr));
// A generic function to factor out common logic from call and fn check_argument_types(
// overloaded operations
fn check_call_inner(
fcx: @mut FnCtxt, fcx: @mut FnCtxt,
sp: span, sp: span,
call_expr_id: ast::node_id, call_expr_id: ast::node_id,
@ -1134,18 +1132,24 @@ pub fn check_expr_with_unifier(fcx: @mut FnCtxt,
sugar: ast::CallSugar, sugar: ast::CallSugar,
deref_args: DerefArgs) -> ty::t deref_args: DerefArgs) -> ty::t
{ {
/*!
*
* Generic function that factors out common logic from
* function calls, method calls and overloaded operators.
*/
let tcx = fcx.ccx.tcx; let tcx = fcx.ccx.tcx;
// Replace all region parameters in the arguments and return // Replace all region parameters in the arguments and return
// type with fresh region variables. // type with fresh region variables.
debug!("check_call_inner: before universal quant., in_fty=%s", debug!("check_argument_types: before universal quant., in_fty=%s",
fcx.infcx().ty_to_str(in_fty)); fcx.infcx().ty_to_str(in_fty));
let formal_tys; let sty = structure_of(fcx, sp, in_fty);
// FIXME(#3678) For now, do not permit calls to C abi functions. // FIXME(#3678) For now, do not permit calls to C abi functions.
match structure_of(fcx, sp, in_fty) { match sty {
ty::ty_bare_fn(ty::BareFnTy {abis, _}) => { ty::ty_bare_fn(ty::BareFnTy {abis, _}) => {
if !abis.is_rust() { if !abis.is_rust() {
tcx.sess.span_err( tcx.sess.span_err(
@ -1157,68 +1161,65 @@ pub fn check_expr_with_unifier(fcx: @mut FnCtxt,
_ => {} _ => {}
} }
// This is subtle: we expect `fty` to be a function type, which // Extract the function signature from `in_fty`.
// normally introduce a level of binding. In this case, we want to let sig = match sty {
// process the types bound by the function but not by any nested ty::ty_bare_fn(ty::BareFnTy {sig: sig, _}) |
// functions. Therefore, we match one level of structure. ty::ty_closure(ty::ClosureTy {sig: sig, _}) => sig,
let ret_ty = match structure_of(fcx, sp, in_fty) {
ty::ty_bare_fn(ty::BareFnTy {sig: ref sig, _}) |
ty::ty_closure(ty::ClosureTy {sig: ref sig, _}) => {
let (_, _, sig) =
replace_bound_regions_in_fn_sig(
tcx, @Nil, None, sig,
|_br| fcx.infcx().next_region_var(
sp, call_expr_id));
let supplied_arg_count = args.len();
// Grab the argument types, supplying fresh type variables
// if the wrong number of arguments were supplied
let expected_arg_count = sig.inputs.len();
formal_tys = if expected_arg_count == supplied_arg_count {
sig.inputs.map(|a| a.ty)
} else {
let suffix = match sugar {
ast::NoSugar => "",
ast::DoSugar => " (including the closure passed by \
the `do` keyword)",
ast::ForSugar => " (including the closure passed by \
the `for` keyword)"
};
let msg = fmt!("this function takes %u parameter%s but \
%u parameter%s supplied%s",
expected_arg_count,
if expected_arg_count == 1 {""}
else {"s"},
supplied_arg_count,
if supplied_arg_count == 1 {" was"}
else {"s were"},
suffix);
tcx.sess.span_err(sp, msg);
vec::from_fn(supplied_arg_count, |_| ty::mk_err(tcx))
};
sig.output
}
_ => { _ => {
fcx.type_error_message(sp, |actual| { fcx.type_error_message(sp, |actual| {
fmt!("expected function or foreign function but \ fmt!("expected function but \
found `%s`", actual) }, in_fty, None); found `%s`", actual) }, in_fty, None);
// check each arg against "error", in order to set up // check each arg against "error", in order to set up
// all the node type bindings // all the node type bindings
formal_tys = args.map(|_x| ty::mk_err(tcx)); FnSig {bound_lifetime_names: opt_vec::Empty,
ty::mk_err(tcx) inputs: args.map(|_x| ty::arg {mode: ast::expl(ast::by_copy),
ty: ty::mk_err(tcx)}),
output: ty::mk_err(tcx)}
} }
}; };
debug!("check_call_inner: after universal quant., \ // Replace any bound regions that appear in the function
formal_tys=%? ret_ty=%s", // signature with region variables
let (_, _, sig) =
replace_bound_regions_in_fn_sig(
tcx, @Nil, None, &sig,
|_br| fcx.infcx().next_region_var(
sp, call_expr_id));
// Grab the argument types, supplying fresh type variables
// if the wrong number of arguments were supplied
let supplied_arg_count = args.len();
let expected_arg_count = sig.inputs.len();
let formal_tys = if expected_arg_count == supplied_arg_count {
sig.inputs.map(|a| a.ty)
} else {
let suffix = match sugar {
ast::NoSugar => "",
ast::DoSugar => " (including the closure passed by \
the `do` keyword)",
ast::ForSugar => " (including the closure passed by \
the `for` keyword)"
};
let msg = fmt!("this function takes %u parameter%s but \
%u parameter%s supplied%s",
expected_arg_count,
if expected_arg_count == 1 {""}
else {"s"},
supplied_arg_count,
if supplied_arg_count == 1 {" was"}
else {"s were"},
suffix);
tcx.sess.span_err(sp, msg);
vec::from_elem(supplied_arg_count, ty::mk_err(tcx))
};
debug!("check_argument_types: after universal quant., \
formal_tys=%? sig.output=%s",
formal_tys.map(|t| fcx.infcx().ty_to_str(*t)), formal_tys.map(|t| fcx.infcx().ty_to_str(*t)),
fcx.infcx().ty_to_str(ret_ty)); fcx.infcx().ty_to_str(sig.output));
// Check the arguments. // Check the arguments.
// We do this in a pretty awful way: first we typecheck any arguments // We do this in a pretty awful way: first we typecheck any arguments
@ -1269,7 +1270,7 @@ pub fn check_expr_with_unifier(fcx: @mut FnCtxt,
} }
} }
ret_ty sig.output
} }
// A generic function for checking assignment expressions // A generic function for checking assignment expressions
@ -1284,43 +1285,23 @@ pub fn check_expr_with_unifier(fcx: @mut FnCtxt,
// The callee checks for bot / err, we don't need to // The callee checks for bot / err, we don't need to
} }
// A generic function for doing all of the checking for call or
// method expressions
fn check_call_or_method(fcx: @mut FnCtxt,
sp: span,
call_expr_id: ast::node_id,
fn_ty: ty::t,
expr: @ast::expr,
args: &[@ast::expr],
sugar: ast::CallSugar)
{
// Call the generic checker.
let ret_ty = check_call_inner(fcx, sp, call_expr_id,
fn_ty, expr, args, sugar,
DontDerefArgs);
// Pull the return type out of the type of the function.
fcx.write_ty(call_expr_id, ret_ty);
// Callee checks for bot and err, no need for that
}
// A generic function for doing all of the checking for call expressions // A generic function for doing all of the checking for call expressions
fn check_call(fcx: @mut FnCtxt, fn check_call(fcx: @mut FnCtxt,
sp: span, call_expr: @ast::expr,
call_expr_id: ast::node_id,
f: @ast::expr, f: @ast::expr,
args: &[@ast::expr], args: &[@ast::expr],
sugar: ast::CallSugar) { sugar: ast::CallSugar) {
// Index expressions need to be handled separately, to inform them // Index expressions need to be handled separately, to inform them
// that they appear in call position. // that they appear in call position.
let mut _bot = check_expr(fcx, f); check_expr(fcx, f);
check_call_or_method(fcx,
sp, // Call the generic checker.
call_expr_id, let ret_ty = check_argument_types(fcx, call_expr.span, call_expr.id,
fcx.expr_ty(f), fcx.expr_ty(f), f, args, sugar,
f, DontDerefArgs);
args,
sugar) // Pull the return type out of the type of the function.
fcx.write_ty(call_expr.id, ret_ty);
} }
// Checks a method call. // Checks a method call.
@ -1369,13 +1350,14 @@ pub fn check_expr_with_unifier(fcx: @mut FnCtxt,
} }
} }
check_call_or_method(fcx, // Call the generic checker.
expr.span, let fn_ty = fcx.node_ty(expr.callee_id);
expr.id, let ret_ty = check_argument_types(fcx, expr.span, expr.id,
fcx.node_ty(expr.callee_id), fn_ty, expr, args, sugar,
expr, DontDerefArgs);
args,
sugar) // Pull the return type out of the type of the function.
fcx.write_ty(expr.id, ret_ty);
} }
// A generic function for checking the then and else in an if // A generic function for checking the then and else in an if
@ -1423,10 +1405,10 @@ pub fn check_expr_with_unifier(fcx: @mut FnCtxt,
let method_ty = fcx.node_ty(op_ex.callee_id); let method_ty = fcx.node_ty(op_ex.callee_id);
let method_map = fcx.inh.method_map; let method_map = fcx.inh.method_map;
method_map.insert(op_ex.id, *origin); method_map.insert(op_ex.id, *origin);
check_call_inner(fcx, op_ex.span, check_argument_types(fcx, op_ex.span,
op_ex.id, method_ty, op_ex.id, method_ty,
op_ex, args, op_ex, args,
ast::NoSugar, deref_args) ast::NoSugar, deref_args)
} }
_ => { _ => {
let tcx = fcx.tcx(); let tcx = fcx.tcx();
@ -1434,9 +1416,9 @@ pub fn check_expr_with_unifier(fcx: @mut FnCtxt,
// Check the args anyway // Check the args anyway
// so we get all the error messages // so we get all the error messages
let expected_ty = ty::mk_err(tcx); let expected_ty = ty::mk_err(tcx);
check_call_inner(fcx, op_ex.span, op_ex.id, check_argument_types(fcx, op_ex.span, op_ex.id,
expected_ty, op_ex, args, expected_ty, op_ex, args,
ast::NoSugar, deref_args); ast::NoSugar, deref_args);
ty::mk_err(tcx) ty::mk_err(tcx)
} }
} }
@ -2546,7 +2528,7 @@ pub fn check_expr_with_unifier(fcx: @mut FnCtxt,
fcx.write_ty(id, fcx.node_ty(b.node.id)); fcx.write_ty(id, fcx.node_ty(b.node.id));
} }
ast::expr_call(f, ref args, sugar) => { ast::expr_call(f, ref args, sugar) => {
check_call(fcx, expr.span, expr.id, f, *args, sugar); check_call(fcx, expr, f, *args, sugar);
let f_ty = fcx.expr_ty(f); let f_ty = fcx.expr_ty(f);
let (args_bot, args_err) = args.foldl((false, false), let (args_bot, args_err) = args.foldl((false, false),
|&(rest_bot, rest_err), a| { |&(rest_bot, rest_err), a| {